BOOL fast_tate_pairing(ECn& P,ZZn6& Qx,ZZn6& Qy,Big& q,Big &cf,ZZn6& res) { int i,j,n,nb,nbw,nzs; ECn A,P2,t[16]; ZZn6 w,hc,z2n,zn[16]; res=zn[0]=1; t[0]=P2=A=P; g(P2,P2,Qx,Qy,z2n,TRUE); // P2=P+P // // Build windowing table // for (i=1;i<16;i++) { g(A,P2,Qx,Qy,hc,TRUE); t[i]=A; zn[i]=z2n*zn[i-1]*hc; } A=P; // reset A /* Left to right method */ nb=bits(q); for (i=nb-2;i>=0;i-=(nbw+nzs)) { n=window(q,i,&nbw,&nzs); // standard MIRACL windowing for (j=0;j<nbw;j++) { res*=res; g(A,A,Qx,Qy,res,FALSE); } if (n>0) { res*=zn[n/2]; g(A,t[n/2],Qx,Qy,res,FALSE); } for (j=0;j<nzs;j++) { res*=res; g(A,A,Qx,Qy,res,FALSE); } if (res.iszero()) return FALSE; } if (!A.iszero() || res.iszero()) return FALSE; res=pow(res,cf); // ^(p*p-p+1)/q w=res; w.powq(); res*=w; // ^(p+1) w=res; w.powq(); w.powq(); w.powq(); res=w/res; // ^(p^3-1) if (res.isunity()) return FALSE; return TRUE; }
ZZn6 sqrt(const ZZn6& x) { // sqrt(a+xb) = sqrt((a+sqrt(a*a-n*b*b))/2)+x.b/(2*sqrt((a+sqrt(a*a-n*b*b))/2)) // sqrt(a) = x.sqrt(a/n) // where x*x=n ZZn6 w; ZZn3 a,s,t; if (x.iszero()) return w; if (x.b.iszero()) { w.unitary=x.unitary; a=x.a; if (qr(a)) { s=sqrt(a); w.a=s; w.b=0; } else { a=txd(a); s=sqrt(a); w.a=0; w.b=s; } return w; } s=x.b; s*=s; a=x.a; a*=a; a-=tx(s); s=sqrt(a); if (s.iszero()) return w; w.unitary=x.unitary; if (qr((x.a+s)/2)) { a=sqrt((x.a+s)/2); } else { a=sqrt((x.a-s)/2); if (a.iszero()) return w; } w.a=a; w.b=x.b/(2*a); return w; }
BOOL qr(const ZZn6& x) { ZZn3 a,s; if (x.iszero()) return TRUE; if (x.b.iszero()) return TRUE; s=x.b; s*=s; a=x.a; a*=a; a-=tx(s); if (!qr(a)) return FALSE; return TRUE; /* s=sqrt(a); if (qr((x.a+s)/2) || qr((x.a-s)/2)) return TRUE; exit(0); return FALSE; */ }
BOOL ate(ECn3& Q,ECn& P,Big &x,ZZn2& X,ZZn6& res) { int i,j,n,nb,nbw,nzs; ECn3 A; ZZn Px,Py; ZZn6 w; Big q=x*x-x+1; #ifdef MR_COUNT_OPS fpc=fpa=fpx=0; #endif normalise(P); #ifdef PROJECTIVE Q.norm(); #endif extract(P,Px,Py); Px+=Px; // because x^6+2 is irreducible.. simplifies line function calculation Py+=Py; res=1; A=Q; // reset A nb=bits(x); res.mark_as_miller(); for (i=nb-2;i>=0;i--) { res*=res; res*=g(A,A,Px,Py); if (bit(x,i)==1) res*=g(A,Q,Px,Py); if (res.iszero()) return FALSE; } #ifdef MR_COUNT_OPS printf("After Miller fpc= %d fpa= %d fpx= %d\n",fpc,fpa,fpx); #endif // if (!A.iszero() || res.iszero()) return FALSE; w=res; w.powq(X); res*=w; // ^(p+1) w=res; w.powq(X); w.powq(X); w.powq(X); res=w/res; // ^(p^3-1) // exploit the clever "trick" for a half-length exponentiation! res.mark_as_unitary(); w=res; res.powq(X); // res*=res; // res=pow(res,CF); if (x<0) res/=powu(w,-x); else res*=powu(w,x); #ifdef MR_COUNT_OPS printf("After pairing fpc= %d fpa= %d fpx= %d\n",fpc,fpa,fpx); fpa=fpc=fpx=0; #endif if (res==(ZZn6)1) return FALSE; return TRUE; }
GT PFC::multi_miller(int n,G2** QQ,G1** PP) { GT z; ZZn *Px,*Py; int i,j,*k,nb; ECn3 *Q,*A; ECn P; ZZn6 res; Big X=*x; Px=new ZZn[n]; Py=new ZZn[n]; Q=new ECn3[n]; A=new ECn3[n]; k=new int[n]; nb=bits(X); res=1; for (j=0;j<n;j++) { k[j]=0; P=PP[j]->g; normalise(P); Q[j]=QQ[j]->g; extract(P,Px[j],Py[j]); Px[j]+=Px[j]; Py[j]+=Py[j]; } for (j=0;j<n;j++) { #ifdef MR_ECN3_PROJECTIVE Q[j].norm(); #endif A[j]=Q[j]; } for (i=nb-2;i>=0;i--) { res*=res; for (j=0;j<n;j++) { if (QQ[j]->ptable==NULL) res*=g(A[j],A[j],Px[j],Py[j]); else res*=gp(QQ[j]->ptable,k[j],Px[j],Py[j]); } if (bit(X,i)==1) for (j=0;j<n;j++) { if (QQ[j]->ptable==NULL) res*=g(A[j],Q[j],Px[j],Py[j]); else res*=gp(QQ[j]->ptable,k[j],Px[j],Py[j]); } if (res.iszero()) return 0; } delete [] k; delete [] A; delete [] Q; delete [] Py; delete [] Px; z.g=res; return z; }
BOOL fast_tate_pairing(ECn& P,ZZn3& Qx,ZZn3& Qy,Big &x,ZZn2& X,ZZn6& res) { int i,j,n,nb,nbw,nzs; ECn A,P2,t[PRECOMP]; ZZn6 w,hc,z2n,zn[PRECOMP]; Big q=x*x-x+1; res=zn[0]=1; t[0]=P2=A=P; z2n=g(P2,P2,Qx,Qy); // P2=P+P normalise(P2); // // Build windowing table // for (i=1;i<PRECOMP;i++) { hc=g(A,P2,Qx,Qy); t[i]=A; zn[i]=z2n*zn[i-1]*hc; } multi_norm(PRECOMP,t); // make t points Affine /* A=P; // reset A nb=bits(q); for (i=nb-2;i>=0;i--) { res*=res; res*=g(A,A,Qx,Qy); if (bit(q,i)==1) res*=g(A,P,Qx,Qy); if (res.iszero()) return FALSE; } */ A=P; // reset A nb=bits(q); for (i=nb-2;i>=0;i-=(nbw+nzs)) { // windowing helps a little.. n=window(q,i,&nbw,&nzs,WINDOW_SIZE); // standard MIRACL windowing for (j=0;j<nbw;j++) { res*=res; res*=g(A,A,Qx,Qy); } if (n>0) { res*=zn[n/2]; res*=g(A,t[n/2],Qx,Qy); } for (j=0;j<nzs;j++) { res*=res; res*=g(A,A,Qx,Qy); } if (res.iszero()) return FALSE; } #ifdef MR_COUNT_OPS printf("After Miller fpc= %d fpa= %d fpx= %d\n",fpc,fpa,fpx); #endif // if (!A.iszero() || res.iszero()) return FALSE; w=res; w.powq(X); res*=w; // ^(p+1) w=res; w.powq(X); w.powq(X); w.powq(X); res=w/res; // ^(p^3-1) // exploit the clever "trick" for a half-length exponentiation! res.mark_as_unitary(); w=res; res.powq(X); // res*=res; // res=pow(res,CF); if (x<0) res/=powu(w,-x); else res*=powu(w,x); if (res==(ZZn6)1) return FALSE; return TRUE; }