| /* |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| */ |
| |
| /* MiotCL Fp^12 functions */ |
| /* FP12 elements are of the form a+i.b+i^2.c */ |
| |
| package XXX |
| |
| //import "fmt" |
| |
| type FP12 struct { |
| a *FP4 |
| b *FP4 |
| c *FP4 |
| } |
| |
| /* Constructors */ |
| func NewFP12fp4(d *FP4) *FP12 { |
| F:=new(FP12) |
| F.a=NewFP4copy(d) |
| F.b=NewFP4int(0) |
| F.c=NewFP4int(0) |
| return F |
| } |
| |
| func NewFP12int(d int) *FP12 { |
| F:=new(FP12) |
| F.a=NewFP4int(d) |
| F.b=NewFP4int(0) |
| F.c=NewFP4int(0) |
| return F |
| } |
| |
| func NewFP12fp4s(d *FP4,e *FP4,f *FP4) *FP12 { |
| F:=new(FP12) |
| F.a=NewFP4copy(d) |
| F.b=NewFP4copy(e) |
| F.c=NewFP4copy(f) |
| return F |
| } |
| |
| func NewFP12copy(x *FP12) *FP12 { |
| F:=new(FP12) |
| F.a=NewFP4copy(x.a) |
| F.b=NewFP4copy(x.b) |
| F.c=NewFP4copy(x.c) |
| return F |
| } |
| |
| /* reduce all components of this mod Modulus */ |
| func (F *FP12) reduce() { |
| F.a.reduce() |
| F.b.reduce() |
| F.c.reduce() |
| } |
| /* normalise all components of this */ |
| func (F *FP12) norm() { |
| F.a.norm() |
| F.b.norm() |
| F.c.norm() |
| } |
| /* test x==0 ? */ |
| func (F *FP12) iszilch() bool { |
| //F.reduce() |
| return (F.a.iszilch() && F.b.iszilch() && F.c.iszilch()) |
| } |
| |
| /* Conditional move */ |
| func (F *FP12) cmove(g *FP12,d int) { |
| F.a.cmove(g.a,d) |
| F.b.cmove(g.b,d) |
| F.c.cmove(g.c,d) |
| } |
| |
| /* Constant time select from pre-computed table */ |
| func (F *FP12) selector(g []*FP12,b int32) { |
| |
| m:=b>>31 |
| babs:=(b^m)-m |
| |
| babs=(babs-1)/2 |
| |
| F.cmove(g[0],teq(babs,0)) // conditional move |
| F.cmove(g[1],teq(babs,1)) |
| F.cmove(g[2],teq(babs,2)) |
| F.cmove(g[3],teq(babs,3)) |
| F.cmove(g[4],teq(babs,4)) |
| F.cmove(g[5],teq(babs,5)) |
| F.cmove(g[6],teq(babs,6)) |
| F.cmove(g[7],teq(babs,7)) |
| |
| invF:=NewFP12copy(F) |
| invF.conj() |
| F.cmove(invF,int(m&1)) |
| } |
| |
| /* test x==1 ? */ |
| func (F *FP12) Isunity() bool { |
| one:=NewFP4int(1) |
| return (F.a.Equals(one) && F.b.iszilch() && F.c.iszilch()) |
| } |
| /* return 1 if x==y, else 0 */ |
| func (F *FP12) Equals(x *FP12) bool { |
| return (F.a.Equals(x.a) && F.b.Equals(x.b) && F.c.Equals(x.c)) |
| } |
| |
| /* extract a from this */ |
| func (F *FP12) geta() *FP4 { |
| return F.a |
| } |
| /* extract b */ |
| func (F *FP12) getb() *FP4 { |
| return F.b |
| } |
| /* extract c */ |
| func (F *FP12) getc() *FP4 { |
| return F.c |
| } |
| /* copy this=x */ |
| func (F *FP12) Copy(x *FP12) { |
| F.a.copy(x.a) |
| F.b.copy(x.b) |
| F.c.copy(x.c) |
| } |
| /* set this=1 */ |
| func (F *FP12) one() { |
| F.a.one() |
| F.b.zero() |
| F.c.zero() |
| } |
| /* this=conj(this) */ |
| func (F *FP12) conj() { |
| F.a.conj() |
| F.b.nconj() |
| F.c.conj() |
| } |
| |
| /* Granger-Scott Unitary Squaring */ |
| func (F *FP12) usqr() { |
| A:=NewFP4copy(F.a) |
| B:=NewFP4copy(F.c) |
| C:=NewFP4copy(F.b) |
| D:=NewFP4int(0) |
| |
| F.a.sqr() |
| D.copy(F.a); D.add(F.a) |
| F.a.add(D) |
| |
| F.a.norm(); |
| A.nconj() |
| |
| A.add(A) |
| F.a.add(A) |
| B.sqr() |
| B.times_i() |
| |
| D.copy(B); D.add(B) |
| B.add(D) |
| B.norm(); |
| |
| C.sqr() |
| D.copy(C); D.add(C) |
| C.add(D) |
| C.norm(); |
| |
| F.b.conj() |
| F.b.add(F.b) |
| F.c.nconj() |
| |
| F.c.add(F.c) |
| F.b.add(B) |
| F.c.add(C) |
| F.reduce() |
| |
| } |
| |
| /* Chung-Hasan SQR2 method from http://cacr.uwaterloo.ca/techreports/2006/cacr2006-24.pdf */ |
| func (F *FP12) sqr() { |
| A:=NewFP4copy(F.a) |
| B:=NewFP4copy(F.b) |
| C:=NewFP4copy(F.c) |
| D:=NewFP4copy(F.a) |
| |
| A.sqr() |
| B.mul(F.c) |
| B.add(B); B.norm() |
| C.sqr() |
| D.mul(F.b) |
| D.add(D) |
| |
| F.c.add(F.a) |
| F.c.add(F.b); F.c.norm() |
| F.c.sqr() |
| |
| F.a.copy(A) |
| |
| A.add(B) |
| A.norm(); |
| A.add(C) |
| A.add(D) |
| A.norm(); |
| |
| A.neg() |
| B.times_i(); |
| C.times_i() |
| |
| F.a.add(B) |
| |
| F.b.copy(C); F.b.add(D) |
| F.c.add(A) |
| F.norm() |
| } |
| |
| /* FP12 full multiplication this=this*y */ |
| func (F *FP12) Mul(y *FP12) { |
| z0:=NewFP4copy(F.a) |
| z1:=NewFP4int(0) |
| z2:=NewFP4copy(F.b) |
| z3:=NewFP4int(0) |
| t0:=NewFP4copy(F.a) |
| t1:=NewFP4copy(y.a) |
| |
| z0.mul(y.a) |
| z2.mul(y.b) |
| |
| t0.add(F.b); t0.norm() |
| t1.add(y.b); t1.norm() |
| |
| z1.copy(t0); z1.mul(t1) |
| t0.copy(F.b); t0.add(F.c); t0.norm() |
| |
| t1.copy(y.b); t1.add(y.c); t1.norm() |
| z3.copy(t0); z3.mul(t1) |
| |
| t0.copy(z0); t0.neg() |
| t1.copy(z2); t1.neg() |
| |
| z1.add(t0) |
| //z1.norm(); |
| F.b.copy(z1); F.b.add(t1) |
| |
| z3.add(t1) |
| z2.add(t0) |
| |
| t0.copy(F.a); t0.add(F.c); t0.norm() |
| t1.copy(y.a); t1.add(y.c); t1.norm() |
| t0.mul(t1) |
| z2.add(t0) |
| |
| t0.copy(F.c); t0.mul(y.c) |
| t1.copy(t0); t1.neg() |
| |
| F.c.copy(z2); F.c.add(t1) |
| z3.add(t1) |
| t0.times_i() |
| F.b.add(t0) |
| z3.norm() |
| z3.times_i() |
| F.a.copy(z0); F.a.add(z3) |
| F.norm() |
| } |
| |
| /* Special case of multiplication arises from special form of ATE pairing line function */ |
| func (F *FP12) smul(y *FP12,twist int ) { |
| if twist==D_TYPE { |
| z0:=NewFP4copy(F.a) |
| z2:=NewFP4copy(F.b) |
| z3:=NewFP4copy(F.b) |
| t0:=NewFP4int(0) |
| t1:=NewFP4copy(y.a) |
| |
| z0.mul(y.a) |
| z2.pmul(y.b.real()); |
| F.b.add(F.a) |
| t1.real().add(y.b.real()) |
| |
| t1.norm(); F.b.norm() |
| F.b.mul(t1) |
| z3.add(F.c); z3.norm() |
| z3.pmul(y.b.real()) |
| |
| t0.copy(z0); t0.neg() |
| t1.copy(z2); t1.neg() |
| |
| F.b.add(t0) |
| //F.b.norm(); |
| |
| F.b.add(t1) |
| z3.add(t1); z3.norm() |
| z2.add(t0) |
| |
| t0.copy(F.a); t0.add(F.c); t0.norm() |
| t0.mul(y.a) |
| F.c.copy(z2); F.c.add(t0) |
| |
| z3.times_i() |
| F.a.copy(z0); F.a.add(z3) |
| } |
| if twist==M_TYPE { |
| z0:=NewFP4copy(F.a) |
| z1:=NewFP4int(0) |
| z2:=NewFP4int(0) |
| z3:=NewFP4int(0) |
| t0:=NewFP4copy(F.a) |
| t1:=NewFP4int(0) |
| |
| z0.mul(y.a) |
| t0.add(F.b) |
| t0.norm() |
| |
| z1.copy(t0); z1.mul(y.a) |
| t0.copy(F.b); t0.add(F.c) |
| t0.norm() |
| |
| z3.copy(t0) //z3.mul(y.c); |
| z3.pmul(y.c.getb()) |
| z3.times_i() |
| |
| t0.copy(z0); t0.neg() |
| |
| z1.add(t0) |
| F.b.copy(z1) |
| z2.copy(t0) |
| |
| t0.copy(F.a); t0.add(F.c) |
| t1.copy(y.a); t1.add(y.c) |
| |
| t0.norm() |
| t1.norm() |
| |
| t0.mul(t1) |
| z2.add(t0) |
| |
| t0.copy(F.c) |
| |
| t0.pmul(y.c.getb()) |
| t0.times_i() |
| |
| t1.copy(t0); t1.neg() |
| |
| F.c.copy(z2); F.c.add(t1) |
| z3.add(t1) |
| t0.times_i() |
| F.b.add(t0) |
| z3.norm() |
| z3.times_i() |
| F.a.copy(z0); F.a.add(z3) |
| } |
| F.norm() |
| } |
| |
| /* this=1/this */ |
| func (F *FP12) Inverse() { |
| f0:=NewFP4copy(F.a) |
| f1:=NewFP4copy(F.b) |
| f2:=NewFP4copy(F.a) |
| f3:=NewFP4int(0) |
| |
| F.norm() |
| f0.sqr() |
| f1.mul(F.c) |
| f1.times_i() |
| f0.sub(f1); f0.norm() |
| |
| f1.copy(F.c); f1.sqr() |
| f1.times_i() |
| f2.mul(F.b) |
| f1.sub(f2); f1.norm() |
| |
| f2.copy(F.b); f2.sqr() |
| f3.copy(F.a); f3.mul(F.c) |
| f2.sub(f3); f2.norm() |
| |
| f3.copy(F.b); f3.mul(f2) |
| f3.times_i() |
| F.a.mul(f0) |
| f3.add(F.a) |
| F.c.mul(f1) |
| F.c.times_i() |
| |
| f3.add(F.c); f3.norm() |
| f3.inverse() |
| F.a.copy(f0); F.a.mul(f3) |
| F.b.copy(f1); F.b.mul(f3) |
| F.c.copy(f2); F.c.mul(f3) |
| } |
| |
| /* this=this^p using Frobenius */ |
| func (F *FP12) frob(f *FP2) { |
| f2:=NewFP2copy(f) |
| f3:=NewFP2copy(f) |
| |
| f2.sqr() |
| f3.mul(f2) |
| |
| F.a.frob(f3); |
| F.b.frob(f3); |
| F.c.frob(f3); |
| |
| F.b.pmul(f); |
| F.c.pmul(f2); |
| } |
| |
| /* trace function */ |
| func (F *FP12) trace() *FP4 { |
| t:=NewFP4int(0) |
| t.copy(F.a) |
| t.imul(3) |
| t.reduce() |
| return t; |
| } |
| |
| /* convert from byte array to FP12 */ |
| func FP12_fromBytes(w []byte) *FP12 { |
| var t [int(MODBYTES)]byte |
| MB:=int(MODBYTES) |
| |
| for i:=0;i<MB;i++ {t[i]=w[i]} |
| a:=FromBytes(t[:]) |
| for i:=0;i<MB;i++ {t[i]=w[i+MB]} |
| b:=FromBytes(t[:]) |
| c:=NewFP2bigs(a,b) |
| |
| for i:=0;i<MB;i++ {t[i]=w[i+2*MB]} |
| a=FromBytes(t[:]) |
| for i:=0;i<MB;i++ {t[i]=w[i+3*MB]} |
| b=FromBytes(t[:]) |
| d:=NewFP2bigs(a,b) |
| |
| e:=NewFP4fp2s(c,d) |
| |
| |
| for i:=0;i<MB;i++ {t[i]=w[i+4*MB]} |
| a=FromBytes(t[:]) |
| for i:=0;i<MB;i++ {t[i]=w[i+5*MB]} |
| b=FromBytes(t[:]) |
| c=NewFP2bigs(a,b) |
| |
| for i:=0;i<MB;i++ {t[i]=w[i+6*MB]} |
| a=FromBytes(t[:]) |
| for i:=0;i<MB;i++ {t[i]=w[i+7*MB]} |
| b=FromBytes(t[:]) |
| d=NewFP2bigs(a,b) |
| |
| f:=NewFP4fp2s(c,d) |
| |
| |
| for i:=0;i<MB;i++ {t[i]=w[i+8*MB]} |
| a=FromBytes(t[:]) |
| for i:=0;i<MB;i++ {t[i]=w[i+9*MB]} |
| b=FromBytes(t[:]); |
| |
| c=NewFP2bigs(a,b) |
| |
| for i:=0;i<MB;i++ {t[i]=w[i+10*MB]} |
| a=FromBytes(t[:]) |
| for i:=0;i<MB;i++ {t[i]=w[i+11*MB]} |
| b=FromBytes(t[:]) |
| d=NewFP2bigs(a,b) |
| |
| g:=NewFP4fp2s(c,d) |
| |
| return NewFP12fp4s(e,f,g) |
| } |
| |
| /* convert this to byte array */ |
| func (F *FP12) ToBytes(w []byte) { |
| var t [int(MODBYTES)]byte |
| MB:=int(MODBYTES) |
| F.a.geta().GetA().ToBytes(t[:]) |
| for i:=0;i<MB;i++ {w[i]=t[i]} |
| F.a.geta().GetB().ToBytes(t[:]) |
| for i:=0;i<MB;i++ {w[i+MB]=t[i]} |
| F.a.getb().GetA().ToBytes(t[:]) |
| for i:=0;i<MB;i++ {w[i+2*MB]=t[i]} |
| F.a.getb().GetB().ToBytes(t[:]) |
| for i:=0;i<MB;i++ {w[i+3*MB]=t[i]} |
| |
| F.b.geta().GetA().ToBytes(t[:]) |
| for i:=0;i<MB;i++ {w[i+4*MB]=t[i]} |
| F.b.geta().GetB().ToBytes(t[:]) |
| for i:=0;i<MB;i++ {w[i+5*MB]=t[i]} |
| F.b.getb().GetA().ToBytes(t[:]) |
| for i:=0;i<MB;i++ {w[i+6*MB]=t[i]} |
| F.b.getb().GetB().ToBytes(t[:]) |
| for i:=0;i<MB;i++ {w[i+7*MB]=t[i]} |
| |
| F.c.geta().GetA().ToBytes(t[:]) |
| for i:=0;i<MB;i++ {w[i+8*MB]=t[i]} |
| F.c.geta().GetB().ToBytes(t[:]) |
| for i:=0;i<MB;i++ {w[i+9*MB]=t[i]} |
| F.c.getb().GetA().ToBytes(t[:]) |
| for i:=0;i<MB;i++ {w[i+10*MB]=t[i]} |
| F.c.getb().GetB().ToBytes(t[:]) |
| for i:=0;i<MB;i++ {w[i+11*MB]=t[i]} |
| } |
| |
| /* convert to hex string */ |
| func (F *FP12) ToString() string { |
| return ("["+F.a.toString()+","+F.b.toString()+","+F.c.toString()+"]") |
| } |
| |
| /* this=this^e */ |
| func (F *FP12) Pow(e *BIG) *FP12 { |
| //F.norm() |
| e1:=NewBIGcopy(e) |
| e1.norm() |
| e3:=NewBIGcopy(e1) |
| e3.pmul(3) |
| e3.norm() |
| sf:=NewFP12copy(F) |
| sf.norm() |
| w:=NewFP12copy(sf) |
| //z:=NewBIGcopy(e) |
| //r:=NewFP12int(1) |
| |
| nb:=e3.nbits() |
| for i:=nb-2;i>=1;i-- { |
| w.usqr() |
| bt:=e3.bit(i)-e1.bit(i) |
| if bt==1 { |
| w.Mul(sf) |
| } |
| if bt==-1 { |
| sf.conj() |
| w.Mul(sf) |
| sf.conj() |
| } |
| } |
| w.reduce() |
| return w |
| /* |
| for true { |
| bt:=z.parity() |
| z.fshr(1) |
| if bt==1 {r.Mul(w)} |
| if z.iszilch() {break} |
| w.usqr() |
| } |
| r.reduce(); |
| return r; */ |
| } |
| |
| /* constant time powering by small integer of max length bts */ |
| func (F *FP12) pinpow(e int,bts int) { |
| var R []*FP12 |
| R=append(R,NewFP12int(1)) |
| R=append(R,NewFP12copy(F)) |
| |
| for i:=bts-1;i>=0;i-- { |
| b:=(e>>uint(i))&1 |
| R[1-b].Mul(R[b]) |
| R[b].usqr() |
| } |
| F.Copy(R[0]) |
| } |
| |
| /* Fast compressed FP4 power of unitary FP12 */ |
| func (F *FP12) Compow(e *BIG,r *BIG) *FP4 { |
| q:=NewBIGints(Modulus) |
| //r:=NewBIGints(CURVE_Order) |
| f:=NewFP2bigs(NewBIGints(Fra),NewBIGints(Frb)) |
| |
| m:=NewBIGcopy(q) |
| m.Mod(r) |
| |
| a:=NewBIGcopy(e) |
| a.Mod(m) |
| |
| b:=NewBIGcopy(e) |
| b.div(m) |
| |
| g1:=NewFP12copy(F); |
| c:=g1.trace() |
| |
| if b.iszilch() { |
| c=c.xtr_pow(e) |
| return c |
| } |
| |
| g2:=NewFP12copy(F) |
| g2.frob(f) |
| cp:=g2.trace() |
| |
| g1.conj() |
| g2.Mul(g1) |
| cpm1:=g2.trace() |
| g2.Mul(g1) |
| cpm2:=g2.trace() |
| |
| c=c.xtr_pow2(cp,cpm1,cpm2,a,b) |
| return c |
| } |
| |
| /* p=q0^u0.q1^u1.q2^u2.q3^u3 */ |
| // Bos & Costello https://eprint.iacr.org/2013/458.pdf |
| // Faz-Hernandez & Longa & Sanchez https://eprint.iacr.org/2013/158.pdf |
| // Side channel attack secure |
| |
| func pow4(q []*FP12,u []*BIG) *FP12 { |
| var g []*FP12 |
| var w [NLEN*int(BASEBITS)+1]int8 |
| var s [NLEN*int(BASEBITS)+1]int8 |
| var t []*BIG |
| r:=NewFP12int(0) |
| p:=NewFP12int(0) |
| mt:=NewBIGint(0) |
| |
| for i:=0;i<4;i++ { |
| t=append(t,NewBIGcopy(u[i])) |
| } |
| |
| g=append(g,NewFP12copy(q[0])) // q[0] |
| g=append(g,NewFP12copy(g[0])); g[1].Mul(q[1]) // q[0].q[1] |
| g=append(g,NewFP12copy(g[0])); g[2].Mul(q[2]) // q[0].q[2] |
| g=append(g,NewFP12copy(g[1])); g[3].Mul(q[2]) // q[0].q[1].q[2] |
| g=append(g,NewFP12copy(g[0])); g[4].Mul(q[3]) // q[0].q[3] |
| g=append(g,NewFP12copy(g[1])); g[5].Mul(q[3]) // q[0].q[1].q[3] |
| g=append(g,NewFP12copy(g[2])); g[6].Mul(q[3]) // q[0].q[2].q[3] |
| g=append(g,NewFP12copy(g[3])); g[7].Mul(q[3]) // q[0].q[1].q[2].q[3] |
| |
| // Make it odd |
| pb:=1-t[0].parity() |
| t[0].inc(pb) |
| // t[0].norm(); |
| |
| // Number of bits |
| mt.zero() |
| for i:=0;i<4;i++ { |
| t[i].norm() |
| mt.or(t[i]) |
| } |
| |
| nb:=1+mt.nbits(); |
| |
| // Sign pivot |
| s[nb-1]=1 |
| for i:=0;i<nb-1;i++ { |
| t[0].fshr(1) |
| s[i]=2*int8(t[0].parity())-1 |
| } |
| |
| // Recoded exponent |
| for i:=0; i<nb; i++ { |
| w[i]=0 |
| k:=1 |
| for j:=1; j<4; j++ { |
| bt:=s[i]*int8(t[j].parity()) |
| t[j].fshr(1) |
| t[j].dec(int(bt)>>1) |
| t[j].norm() |
| w[i]+=bt*int8(k) |
| k*=2 |
| } |
| } |
| |
| // Main loop |
| p.selector(g,int32(2*w[nb-1]+1)) |
| for i:=nb-2;i>=0;i-- { |
| p.usqr() |
| r.selector(g,int32(2*w[i]+s[i])) |
| p.Mul(r) |
| } |
| |
| // apply correction |
| r.Copy(q[0]); r.conj() |
| r.Mul(p) |
| p.cmove(r,pb) |
| |
| p.reduce() |
| return p; |
| } |
| |
| /* |
| func pow4(q []*FP12,u []*BIG) *FP12 { |
| var a [4]int8 |
| var g []*FP12 |
| var s []*FP12 |
| c:=NewFP12int(1) |
| p:=NewFP12int(0) |
| var w [NLEN*int(BASEBITS)+1]int8 |
| var t []*BIG |
| mt:=NewBIGint(0) |
| |
| for i:=0;i<4;i++ { |
| t=append(t,NewBIGcopy(u[i])) |
| } |
| |
| s=append(s,NewFP12int(0)) |
| s=append(s,NewFP12int(0)) |
| |
| g=append(g,NewFP12copy(q[0])); s[0].Copy(q[1]); s[0].conj(); g[0].Mul(s[0]) |
| g=append(g,NewFP12copy(g[0])) |
| g=append(g,NewFP12copy(g[0])) |
| g=append(g,NewFP12copy(g[0])) |
| g=append(g,NewFP12copy(q[0])); g[4].Mul(q[1]) |
| g=append(g,NewFP12copy(g[4])) |
| g=append(g,NewFP12copy(g[4])) |
| g=append(g,NewFP12copy(g[4])) |
| |
| s[1].Copy(q[2]); s[0].Copy(q[3]); s[0].conj(); s[1].Mul(s[0]) |
| s[0].Copy(s[1]); s[0].conj(); g[1].Mul(s[0]) |
| g[2].Mul(s[1]) |
| g[5].Mul(s[0]) |
| g[6].Mul(s[1]) |
| s[1].Copy(q[2]); s[1].Mul(q[3]) |
| s[0].Copy(s[1]); s[0].conj(); g[0].Mul(s[0]) |
| g[3].Mul(s[1]) |
| g[4].Mul(s[0]) |
| g[7].Mul(s[1]) |
| |
| // if power is even add 1 to power, and add q to correction |
| |
| for i:=0;i<4;i++ { |
| if t[i].parity()==0 { |
| t[i].inc(1); t[i].norm() |
| c.Mul(q[i]) |
| } |
| mt.add(t[i]); mt.norm() |
| } |
| c.conj() |
| nb:=1+mt.nbits() |
| |
| // convert exponent to signed 1-bit window |
| for j:=0;j<nb;j++ { |
| for i:=0;i<4;i++ { |
| a[i]=int8(t[i].lastbits(2)-2) |
| t[i].dec(int(a[i])); t[i].norm(); |
| t[i].fshr(1) |
| } |
| w[j]=(8*a[0]+4*a[1]+2*a[2]+a[3]) |
| } |
| w[nb]=int8(8*t[0].lastbits(2)+4*t[1].lastbits(2)+2*t[2].lastbits(2)+t[3].lastbits(2)) |
| p.Copy(g[(w[nb]-1)/2]) |
| |
| for i:=nb-1;i>=0;i-- { |
| m:=w[i]>>7 |
| j:=(w[i]^m)-m // j=abs(w[i]) |
| j=(j-1)/2 |
| s[0].Copy(g[j]); s[1].Copy(g[j]); s[1].conj() |
| p.usqr() |
| p.Mul(s[m&1]); |
| } |
| p.Mul(c) // apply correction |
| p.reduce() |
| return p; |
| } |
| */ |
| |