564 lines
11 KiB
C++
564 lines
11 KiB
C++
/*
|
|
|
|
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 <iostream>
|
|
#include <fstream>
|
|
#include "ecn.h"
|
|
#include "zzn.h"
|
|
#include <ctime>
|
|
|
|
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;
|
|
}
|