// // Program to find Brezing & Weng pairing friendly curves // http://eprint.iacr.org/2003/143 // // Finds families of elliptic curves with groups of points of order r over the prime field p with // embedding degree k, where k>2. The program tries to find curves with minimum rho=log(p)/log(r), // as such curves may be optimal for fast implementation. The total number of points on the curve is // p+1-t, where t is the trace. // // To get an actual curve, substitute for x, (ensure p(x) is prime and that r(x) has a large prime factor) // and use the CM program to find actual curve parameters. // // This method is based on the fact that (t(x)-1) should be a k-th root of unity mod r(x), and r(x) // only has k-th roots of unity if it is a divisor of phi_k(t(x)-1), as x^k=1 mod Phi_k(x) // A simple way to generate t(x) and r(x) is to choose r(x) as Phi_{nk}(x) and then t(x)-1=x^n is a // k-th root of unity. However this method is not exhaustive, and there could be better solutions. // (That is there may be suitable r(x) which are not of the form Phi_{nk}(x), so these curves are not // necessarily optimal). // // Omega indicates the degree of loop reduction possible compared to the Tate pairing, with the Ate // or Eta pairing // // This program uses the NTL number theoretic library available from http://www.shoup.net/ntl/ // // Nov. 2007 - modified to search for the best Ate or Eta Omega // // Mike Scott (2007) // #include #include "NTL/ZZXFactoring.h" NTL_CLIENT using namespace std; #define POWER #define MAXK 64 #define BM 10 // these limits have been tested as sufficient for K<=64 #define BD 20 void output(ZZX& p) { int i,leading=1; ZZ c; if (p==0) { cout << "0" << endl; return; } int len=p.rep.length(); if (p.rep[0]!=0) { leading=0; cout << p.rep[0]; } if (len==1) return; c=p.rep[1]; if (c<0) { c=-c; cout << "-"; } else if (c>0 && !leading) cout << "+"; if (c!=0) { leading=0; if (c==1) cout << "x"; else cout << c << "*x"; } if (len==2) return; for (i=2;i0 && !leading) cout << "+"; if (c!=0) { leading=0; if (c!=1) cout << c << "*"; if (i==2) cout << "x*x"; else #ifdef POWER cout << "pow(x," << i << ")"; #else cout << "x^" << i; #endif } } } int outputfactors(ZZX &f) { int i; ZZ c; vec_pair_ZZX_long factors; factor(c,factors,f); if (c!=1) cout << c << "."; for (i=0;i1) cout << "^" << factors[i].b; } return factors.length(); } // // Composition. Give g(x) return f(x)=g(b(x)) // ZZX compose(ZZX &g,ZZX &b) { ZZX c; int i,d=deg(g); // vec_ZZX table(INIT_SIZE,d+1); ZZX table[100]; table[0]=1; for (i=1;i<=d;i++) table[i]=(table[i-1]*b); clear(c); for (i=0;i<=d;i++) { c+=g.rep[i]*table[i]; // table(i).kill(); } return c; } int omega(ZZX &p,ZZX &pkr) { // input phi(k)/r ZZX t,f=pkr; int biggest=0; while (deg(f)>=0) { t=f%p; if (deg(t)>biggest) biggest=deg(t); f/=p; } return biggest; } // evaluate f(x) ZZ eval(ZZX &f,int x) { ZZ y,xx; y=0; xx=1; for (int i=0;i<=deg(f);i++) { y+=coeff(f,i)*xx; xx*=x; } return y; } unsigned int igcd(unsigned int x,unsigned int y) { /* integer GCD, returns GCD of x and y */ unsigned int r; if (y==0) return x; while ((r=x%y)!=0) x=y,y=r; return y; } // for given x evaluate f(x) mod m int evalmod(ZZX &f,int x,int m) { int y,xx; y=0; xx=1; for (int i=0;i<=deg(f);i++) { y+=(to_long(coeff(f,i))%m)*xx; y%=m; xx=(x*xx)%m; } if (y<0) y+=m; return y; } // check if f(x)/m has integer solutions int solutions(ZZX &f,int m) { int s=0; for (int x=0;xd) break; } if (sqr) return 0; return 1; } // basis for prime p ZZX rib(long p,long n,ZZX& phi) { int j; ZZ r; ZZX s,t,b; ZZX zeta,z,iz,izeta,f,inf; b=1; SetCoeff(zeta,n/p,1); z=zeta; t=InvTrunc(phi,n/p); izeta=(1-phi*t)/zeta; iz=izeta; for (j=1;j<=(p-1)/2;j++) { b=MulMod(b,(z-iz)%phi,phi); z*=zeta; iz*=izeta; } return b; } // // square root of -d in Q(x), D is negative // Murphy & Fitzpatrick // http://eprint.iacr.org/2005/302 // int sqrt(ZZX& r,long n,long d,ZZX& phi) { long p,dd; ZZX zeta4,zeta8; if (d<=0 || (d>1 && n%d!=0)) return 0; if (d%2==0 && n%8!=0) return 0; if (d%4!=3 && n%4!=0) return 0; if (n%4==0) {SetCoeff(zeta4,n/4,1);zeta4%=phi;} if (n%8==0) {SetCoeff(zeta8,n/8,1);zeta8%=phi;} if (d==1) { r=zeta4; return 1; } r=1; dd=d; for (p=2;p<=dd;p++) { if (d%p!=0) continue; dd/=p; if (p==2) { r=MulMod(zeta8,r,phi); r=MulMod((1+zeta4),r,phi); } else { r=MulMod(rib(p,n,phi),r,phi); } } if (d%4==1) r=MulMod(zeta4,r,phi); if (d%2==0 && (4-(d/2)%4)%4==1) r=MulMod(zeta4,r,phi); return 1; } int main(int argc,char **argv) { int nn,i,j,m,K,mode,min_K,max_K,fp,fast; long ww,d,W,x,bd,bn; // ZZ m; ZZX h,g,a,b,p,r,ff,q,kg; ZZX pru,w,T,lambda; int twist,small_ate,small_eta; unsigned int rho_n,rho_d,best_rho_n,best_rho_d,omega_n,omega_d,best_omega_n,best_omega_d,gcd; unsigned int delta_n,delta_d,best_delta_n,best_delta_d; argv++; argc--; fast=0; if (argc!=1) {K=0; mode=0;} else {K=atoi(argv[0]); mode=1; if (K<0) {K=-K; fast=1;}} if (K!=0 && (K<3 || K>MAXK)) return 0; // generate cyclotomic polynomials vec_ZZX phi(INIT_SIZE, BM*MAXK); for (i = 1; i <= BM*MAXK; i++) { ZZX t; t = 1; for (j = 1; j <= i-1; j++) if (i % j == 0) t *= phi(j); phi(i) = (ZZX(i, 1) - 1)/t; // ZZX(i, a) == X^i * a } /* ZZX bnp=ZZX(4,36)+ZZX(3,36)+ZZX(2,24)+ZZX(1,6)+ZZX(0,1); ZZX bntm1=ZZX(2,6); ZZX bnq=bnp-bntm1; ZZX cof=(bnp*bnp*bnp*bnp-bnp*bnp+ZZX(0,1))/bnq; cout << "cof= ";outputfactors(cof); cout << endl; exit(0); */ if (mode==0) { cout << "Finds best Brezing and Weng families of pairing friendly elliptic curves" << endl; cout << "To find all individual curves - bandw K, where 3<=K<=" << MAXK << endl; cout << "To just see best curves (smallest rho found so far) = bandw -K" << endl; cout << "A smaller omega means a shorter Miller loop for ETA or ATE pairing" << endl; cout << "Note that sometimes the ETA pairing is possible, as well as ATE" << endl; // cout << "A smaller delta means a faster Ate pairing" << endl; min_K=3; max_K=MAXK; } else {min_K=max_K=K;} for (K=min_K;K<=max_K; K++) { best_rho_n=2; best_rho_d=1; bd=0; bn=0; best_omega_n=1; best_omega_d=1; // best_delta_n=1; best_delta_d=1; // Try r(x) as Phi_{nK}(x) - why? Because thats what B&W did. for (nn=1;nn<=BM;nn++) { r=phi(nn*K); // set K-th root of unity clear(g); SetCoeff(g,nn,1); kg=g%r; // Try for small discriminants... for (d=1;d<=BD;d++) { if (!squarefree(d)) continue; W=4*d; // find square root of -d mod r if (!sqrt(h,nn*K,d,r)) continue; // try for all the other K-th roots... g=kg; for (j=1;j