/* Scott's AKE Client/Server testbed See http://www.compapp.dcu.ie/research/CA_Working_Papers/wp02.html#0202 Compile as cl /O2 /GX ake1kmt.cpp big.cpp zzn.cpp ecn.cpp miracl.lib Requires file xk1.ecs which contains details of non-supersingular elliptic curve, with security multiplier k=1. The prime p is 1024 bits xk1.ecs is generated by make_k1.cpp */ #include #include #include "ecn.h" #include "zzn.h" #include using namespace std; #ifdef MR_COUNT_OPS extern "C" { int fpc=0; int fpa=0; int fpx=0; } #endif //#define ENDO Miracl precision(32,0); // Using SHA-512 as basic hash algorithm #define HASH_LEN 64 // // Tate Pairing Code // // Extract ECn point in internal ZZn format // void extract(ECn& A,ZZn& x,ZZn& y) { x=(A.get_point())->X; y=(A.get_point())->Y; } void extract(ECn& A,ZZn& x,ZZn& y,ZZn& z) { big t; x=(A.get_point())->X; y=(A.get_point())->Y; t=(A.get_point())->Z; if (A.get_status()!=MR_EPOINT_GENERAL) z=(ZZn)1; else z=t; } void insert(ECn& A,ZZn& x,ZZn& y,ZZn &z) { copy(x.getzzn(),(A.get_point())->X); copy(y.getzzn(),(A.get_point())->Y); copy(z.getzzn(),(A.get_point())->Z); A.get_point()->marker=MR_EPOINT_GENERAL; } // // Add A=A+B (or A=A+A) // Calculate numerators and denominators // Line from A to destination B. Let A=(x,y) // Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) // Also evaluate vertical line through destination // void g(ECn& A,ECn& B,ZZn& Qx,ZZn& Qy,ZZn& bQx,ZZn& num,ZZn& denom,ZZn& num2,ZZn& denom2,BOOL last) { ZZn lam,x,y,z,x2,y2,z2,t1,t2,t3; ZZn zz,zzz; // Evaluate line from A - lam is line slope extract(A,x,y,z); zz=z*z; zzz=zz*z; if (&A==&B) { // double t1=x*x; lam=t1+t1+t1; t2=y*y; t3=x*t2; t3+=t3; t3+=t3; x2=lam*lam-(t3+t3); z2=z*y; z2+=z2; t1=t2+t2; t2=t1*t1; t2+=t2; t3-=x2; y2=lam*t3-t2; } else { // add ZZn xs,ys; extract(B,xs,ys); t1=zz*xs; lam=zzz*ys; t1-=x; lam-=y; z2=z*t1; t3=t1*t1; t2=t3*t1; t3*=x; t1=t3+t3; x2=lam*lam-t1-t2; t2*=y; t3-=x2; y2=lam*t3-t2; } t1=z2*z2; lam*=z; lam*=z2; t2=zzz*Qy; num=t1*(t2-y)-lam*(zz*Qx-x); denom=zzz*(t1*Qx-x2); if (!last) { num2=t1*(t2+y)+lam*(zz*bQx-x); denom2=zzz*(t1*bQx-x2); } else { num2=-zz*bQx+x; denom2=zz; } insert(A,x2,y2,z2); return; } void g(ECn& A,ECn& B,ZZn& Qx,ZZn& Qy,ZZn& num,ZZn& denom,BOOL last) { ZZn lam,x,y,z,x2,y2,z2,t1,t2,t3; ZZn zz,zzz; // Evaluate line from A - lam is line slope extract(A,x,y,z); zz=z*z; zzz=zz*z; if (&A==&B) { // double t1=x*x; lam=t1+t1+t1; t2=y*y; t3=x*t2; t3+=t3; t3+=t3; x2=lam*lam-(t3+t3); z2=z*y; z2+=z2; t1=t2+t2; t2=t1*t1; t2+=t2; t3-=x2; y2=lam*t3-t2; } else { // add ZZn xs,ys; extract(B,xs,ys); t1=zz*xs; lam=zzz*ys; t1-=x; lam-=y; z2=z*t1; t3=t1*t1; t2=t3*t1; t3*=x; t1=t3+t3; x2=lam*lam-t1-t2; t2*=y; t3-=x2; y2=lam*t3-t2; } t1=z2*z2; lam*=z; lam*=z2; t2=zzz*Qy; if (!last) { num=t1*(t2-y)-lam*(zz*Qx-x); denom=zzz*(t1*Qx-x2); } else { num=-zz*Qx+x; denom=zz; } insert(A,x2,y2,z2); return; } // // Tate Pairing - Note no denominator elimination possible // // P is a point of order q. Q(x,y) is a point of order m.q. // Note that P and Q are points on the curve over Fp // BOOL fast_tate_pairing(ECn& P,ZZn& Qx,ZZn& Qy,ZZn& bQx,Big& q,Big& cofactor,ZZn& res) { int i,j,nb; ECn A,W; ZZn ha,had,hab,ha2,had2; ZZn n,d,n2,d2; ha=had=ha2=had2=1; #ifdef MR_COUNT_OPS fpc=fpa=fpx=0; #endif normalise(P); A=P; #ifndef ENDO // Here I am not using the endomorphism... nb=bits(q); for (i=nb-2;i>=1;i--) { ha*=ha; had*=had; g(A,A,Qx,Qy,n,d,FALSE); ha*=n; had*=d; if (bit(q,i)==1) { g(A,P,Qx,Qy,n,d,FALSE); ha*=n; had*=d; } } ha*=ha; had*=had; g(A,A,Qx,Qy,n,d,FALSE); ha*=n; had*=d; g(A,P,Qx,Qy,n,d,TRUE); ha*=n; had*=d; ha/=had; #else // lambda=pow((Big)2,80)+pow((Big)2,16); // Use endomorphism for half length loop.. for (i=0;i<64;i++) { ha*=ha; ha2*=ha2; had*=had; had2*=had2; g(A,A,Qx,Qy,bQx,n,d,n2,d2,FALSE); ha*=n; ha2*=n2; had*=d; had2*=d2; } g(A,P,Qx,Qy,bQx,n,d,n2,d2,FALSE); ha*=n; ha2*=n2; had*=d; had2*=d2; for (i=0;i<16;i++) { ha*=ha; ha2*=ha2; had*=had; had2*=had2; g(A,A,Qx,Qy,bQx,n,d,n2,d2,FALSE); ha*=n; ha2*=n2; had*=d; had2*=d2; } g(A,P,Qx,Qy,bQx,n,d,n2,d2,TRUE); ha*=n; had*=d; ha2*=n2; had2*=d2; ha/=had; ha2/=had2; hab=ha; for (i=0;i<64;i++) ha*=ha; ha*=hab; for (i=0;i<16;i++) ha*=ha; ha*=ha2; #endif res=ha; res=res*res*res; // wipes out multiples of zeta res=pow(res,cofactor); // since p=1 mod 4, -1 gets wiped out as well res=pow(res,cofactor); res=pow(res,q); #ifdef MR_COUNT_OPS cout << "Tate fpc= " << fpc << endl; cout << "Tate fpa= " << fpa << endl; cout << "Tate fpx= " << fpx << endl; fpa=fpc=fpx=0; #endif if (res==(ZZn)1) return FALSE; return TRUE; } // // Pairing ecap(.) function // BOOL ecap(ECn& P,ECn& Q,Big& order,ZZn& zeta,Big& cofactor,ZZn& res) { BOOL Ok; Big Qx,Qy; ZZn bQx; Q.get(Qx,Qy); bQx=zeta*zeta*(ZZn)Qx; Ok=fast_tate_pairing(P,(ZZn)Qx,(ZZn)Qy,bQx,order,cofactor,res); if (Ok) return TRUE; return FALSE; } // // Hash functions // Big H1(char *string) { // Hash a zero-terminated string to a number < modulus Big h,p; char s[HASH_LEN]; int i,j; sha512 sh; shs512_init(&sh); for (i=0;;i++) { if (string[i]==0) break; shs512_process(&sh,string[i]); } shs512_hash(&sh,s); p=get_modulus(); h=1; j=0; i=1; forever { h*=256; if (j==HASH_LEN) {h+=i++; j=0;} else h+=s[j++]; if (h>=p) break; } h%=p; return h; } Big H2(ZZn x) { // Hash an Fp to a big number sha sh; Big a,b,h,p; char s[20]; int i,j,m; shs_init(&sh); a=x; while (a>0) { m=a%256; shs_process(&sh,m); a/=256; } shs_hash(&sh,s); h=from_binary(20,s); return h; } // Hash and map an Identity to a curve point E_(Fp) ECn hash_and_map(char *ID,Big cof) { ECn Q; Big x0=H1(ID); while (!Q.set(x0)) x0+=1; Q*=cof; return Q; } ECn hash(char *ID) { ECn Q; Big x0=H1(ID); while (!Q.set(x0)) x0+=1; return Q; } ECn map_f(ECn& P,ZZn& zeta) { ECn R; Big x,y; P.get(x,y); ZZn X=x; X=zeta*X; x=Big(X); if (!R.set(x,y)) cout << "something wrong in map_f" << endl; return R; } ECn pi1(ECn P,ZZn& zeta,Big lambda) { ECn T,R; T=lambda*P; R=map_f(P,zeta); R-=T; return R; } ECn pi2(ECn P,ZZn& zeta,Big lambda) { ECn T,R; T=lambda*P; T=lambda*T; R=map_f(P,zeta); R-=T; return R; } int main() { ifstream common("xk1.ecs"); // elliptic curve parameters miracl* mip=&precision; ECn Alice,Bob,sA,sB; ECn B2,Server,sS; ZZn X,Y,res,sp,ap,bp,c,third,zeta; Big r,a,b,s,ss,p,q,x,y,B,cf,t,lambda,cofactor; int i,bts,A; time_t seed; common >> bts; mip->IOBASE=16; common >> p; common >> A; common >> B; // q=pow((Big)2,159)+pow((Big)2,17)+1; lambda=pow((Big)2,80)+pow((Big)2,16); q=lambda*lambda+lambda+1; cofactor=sqrt((p-1)/(3*q*q)); cf=3*cofactor; cout << "cofactor in bits= " << bits(cf) << endl; // cout << "cf= " << cf << endl; i=1; do { zeta=(ZZn)pow((Big)++i,(p-1)/3,p); } while (zeta==1); // cout << "zeta= " << zeta << endl; // zeta*=zeta; // may be needed to get right root... i=2; do { lambda=pow((Big)++i,(q-1)/3,q); } while (lambda==1); // cout << "lambda= " << lambda << endl; time(&seed); irand((long)seed); ecurve(A,B,p,MR_PROJECTIVE); mip->IOBASE=16; // hash Identities to curve point ss=rand(q); // TA's super-secret cout << "Mapping Server ID to point" << endl; Server=hash_and_map("Server",cf); // Server=hash("Server"); //Server*=3; Server=pi2(Server,zeta,lambda); // Place Server into distinguised group 2 // cout << "Server= " << Server << endl; cout << "Mapping Alice & Bob ID's to points" << endl; Alice=hash_and_map("Alice",cf); Alice=pi1(Alice,zeta,lambda); // got to put Alice and Bob into David's "distinguished" group // so that endomorphism applies Bob= hash_and_map("Robert",cf); Bob=pi1(Bob,zeta,lambda); // ecap(Alice,map_f(Bob,zeta),q,zeta,cofactor,res); // cout << "e(Alice,phi(Bob)) = " << res << endl; // ecap(Bob,map_f(Alice,zeta),q,zeta,cofactor,res); // cout << "e(Bob,phi(Alice)) = " << res << endl; // exit(0); // Calculating e(P,P) != 1 ?? third=inverse((ZZn)3,q); // 1/3 mod q ecap(Alice,3*Alice,q,zeta,cofactor,res); // Note the 3 cout << "e(Alice,Alice)= " << pow(res,third) << endl; //exit(0); ecap(Alice,Bob,q,zeta,cofactor,res); cout << "e(Alice,Bob)= " << res << endl; ecap(Bob,Alice,q,zeta,cofactor,res); cout << "e(Bob,Alice)= " << res << endl; ecap(Alice,Server,q,zeta,cofactor,res); cout << "e(Alice,Server)= " << res << endl; // The pairing is symmetric! zeta*=zeta; // (its the "other" cube root) needed with ENDO ecap(Server,Alice,q,zeta,cofactor,res); cout << "e(Server,Alice)= " << res << endl; zeta*=zeta; cout << "Alice, Bob and the Server visit Trusted Authority" << endl; sS=ss*Server; sA=ss*Alice; sB=ss*Bob; cout << "Alice and Server Key exchange" << endl; a=rand(q); // Alice's random number s=rand(q); // Server's random number //#ifndef MR_COUNT_OPS //for (i=0;i<1000;i++) //#endif if (!ecap(sA,Server,q,zeta,cofactor,res)) cout << "Trouble" << endl; ap=pow(res,a); if (!ecap(Alice,sS,q,zeta,cofactor,res)) cout << "Trouble" << endl; sp=pow(res,s); cout << "Alice Key= " << H2(pow(sp,a)) << endl; cout << "Server Key= " << H2(pow(ap,s)) << endl; cout << "Bob and Server Key exchange" << endl; b=rand(q); // Bob's random number s=rand(q); // Server's random number if (!ecap(sB,Server,q,zeta,cofactor,res)) cout << "Trouble" << endl; bp=pow(res,b); if (!ecap(Bob,sS,q,zeta,cofactor,res)) cout << "Trouble" << endl; sp=pow(res,s); cout << "Bob's Key= " << H2(pow(sp,b)) << endl; cout << "Server Key= " << H2(pow(bp,s)) << endl; cout << "Alice and Bob's attempted Key exchange" << endl; ecap(sB,Alice,q,zeta,cofactor,res); ap=pow(res,a); ecap(Bob,sA,q,zeta,cofactor,res); bp=pow(res,b); if (ap==1) cout << "Bob's Key = 1" << endl; else cout << "Bob's Key= " << H2(pow(ap,b)) << endl; if (bp==1) cout << "Alice's Key = 1" << endl; else cout << "Alice's Key= " << H2(pow(bp,a)) << endl; return 0; }