615 lines
12 KiB
C++
615 lines
12 KiB
C++
|
|
/***************************************************************************
|
|
*
|
|
Copyright 2013 CertiVox UK Ltd. *
|
|
*
|
|
This file is part of CertiVox MIRACL Crypto SDK. *
|
|
*
|
|
The CertiVox MIRACL Crypto SDK provides developers with an *
|
|
extensive and efficient set of cryptographic functions. *
|
|
For further information about its features and functionalities please *
|
|
refer to http://www.certivox.com *
|
|
*
|
|
* The CertiVox MIRACL Crypto SDK is free software: you can *
|
|
redistribute it and/or modify it under the terms of the *
|
|
GNU Affero General Public License as published by the *
|
|
Free Software Foundation, either version 3 of the License, *
|
|
or (at your option) any later version. *
|
|
*
|
|
* The CertiVox MIRACL Crypto SDK is distributed in the hope *
|
|
that it will be useful, but WITHOUT ANY WARRANTY; without even the *
|
|
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
See the GNU Affero General Public License for more details. *
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public *
|
|
License along with CertiVox MIRACL Crypto SDK. *
|
|
If not, see <http://www.gnu.org/licenses/>. *
|
|
*
|
|
You can be released from the requirements of the license by purchasing *
|
|
a commercial license. Buying such a license is mandatory as soon as you *
|
|
develop commercial activities involving the CertiVox MIRACL Crypto SDK *
|
|
without disclosing the source code of your own applications, or shipping *
|
|
the CertiVox MIRACL Crypto SDK with a closed source product. *
|
|
*
|
|
***************************************************************************/
|
|
/*
|
|
* ss.cpp
|
|
*
|
|
* Super-Singular curve, eta_T pairing embedding degree 4
|
|
*
|
|
* Provides high level interface to pairing functions
|
|
*
|
|
* GT=pairing(G1,G1)
|
|
*
|
|
* This is calculated on a Pairing Friendly Curve (PFC), which must first be defined.
|
|
*
|
|
* G1 is a point over the base field
|
|
* GT is a finite field point over the 4-th extension, where 4 is the embedding degree.
|
|
*/
|
|
|
|
|
|
#define MR_PAIRING_SS2
|
|
#include "pairing_1.h"
|
|
|
|
// Using SHA256 as basic hash algorithm
|
|
//
|
|
// Hash function
|
|
//
|
|
|
|
#define HASH_LEN 32
|
|
|
|
Big H1(char *string)
|
|
{ // Hash a zero-terminated string to a number < modulus
|
|
Big h;
|
|
char s[HASH_LEN];
|
|
int i,j,M;
|
|
sha256 sh;
|
|
|
|
shs256_init(&sh);
|
|
|
|
for (i=0;;i++)
|
|
{
|
|
if (string[i]==0) break;
|
|
shs256_process(&sh,string[i]);
|
|
}
|
|
shs256_hash(&sh,s);
|
|
M=get_mip()->M;
|
|
h=1; j=0; i=1;
|
|
forever
|
|
{
|
|
h*=256;
|
|
if (j==HASH_LEN) {h+=i++; j=0;}
|
|
else h+=s[j++];
|
|
if (bits(h)>=M) break;
|
|
}
|
|
while (bits(h)>=M) h/=2;
|
|
return h;
|
|
}
|
|
|
|
// general hash
|
|
|
|
void PFC::start_hash(void)
|
|
{
|
|
shs256_init(&SH);
|
|
}
|
|
|
|
Big PFC::finish_hash_to_group(void)
|
|
{
|
|
Big hash;
|
|
Big o=pow((Big)2,2*S);
|
|
char s[HASH_LEN];
|
|
shs256_hash(&SH,s);
|
|
hash=from_binary(HASH_LEN,s);
|
|
return hash%o;
|
|
}
|
|
|
|
void PFC::add_to_hash(const GT& x)
|
|
{
|
|
int i,m;
|
|
GF2m xx[4];
|
|
Big a;
|
|
GF2m4x w=x.g;
|
|
|
|
w.get(xx[0],xx[1],xx[2],xx[3]);
|
|
|
|
for (i=0;i<4;i++)
|
|
{
|
|
a=(Big)xx[i];
|
|
while (a>0)
|
|
{
|
|
m=a%256;
|
|
shs256_process(&SH,m);
|
|
a/=256;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PFC::add_to_hash(const G1& x)
|
|
{
|
|
Big a,X,Y;
|
|
int i,m;
|
|
x.g.get(X,Y);
|
|
a=X;
|
|
while (a>0)
|
|
{
|
|
m=a%256;
|
|
shs256_process(&SH,m);
|
|
a/=256;
|
|
}
|
|
a=Y;
|
|
while (a>0)
|
|
{
|
|
m=a%256;
|
|
shs256_process(&SH,m);
|
|
a/=256;
|
|
}
|
|
}
|
|
|
|
void PFC::add_to_hash(const Big& x)
|
|
{
|
|
int m;
|
|
Big a=x;
|
|
while (a>0)
|
|
{
|
|
m=a%256;
|
|
shs256_process(&SH,m);
|
|
a/=256;
|
|
}
|
|
}
|
|
|
|
// random multiplier
|
|
|
|
void PFC::random(Big& w)
|
|
{
|
|
if (RNG==NULL) w=rand(2*S,2);
|
|
else w=strong_rand(RNG,2*S,2);
|
|
}
|
|
|
|
// random AES key
|
|
|
|
void PFC::rankey(Big& k)
|
|
{
|
|
if (RNG==NULL) k=rand(S,2);
|
|
else k=strong_rand(RNG,S,2);
|
|
}
|
|
|
|
// Compress and hash a GF2m4x to a big number
|
|
|
|
Big H2(GF2m4x x)
|
|
{
|
|
sha256 sh;
|
|
Big a,hash;
|
|
GF2m xx[4];
|
|
char s[HASH_LEN];
|
|
int i,j,m;
|
|
|
|
shs256_init(&sh);
|
|
x.get(xx[0],xx[1],xx[2],xx[3]);
|
|
|
|
for (i=0;i<4;i++)
|
|
{
|
|
a=xx[i];
|
|
while (a>0)
|
|
{
|
|
m=a%256;
|
|
shs256_process(&sh,m);
|
|
a/=256;
|
|
}
|
|
}
|
|
shs256_hash(&sh,s);
|
|
hash=from_binary(HASH_LEN,s);
|
|
return hash;
|
|
}
|
|
|
|
//
|
|
// Extract ECn point in internal GF2m format
|
|
//
|
|
|
|
void extract(EC2& A,GF2m& x,GF2m& y)
|
|
{
|
|
x=(A.get_point())->X;
|
|
y=(A.get_point())->Y;
|
|
}
|
|
|
|
// Does nothing...
|
|
|
|
int PFC::precomp_for_pairing(G1& w)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// eta_T Pairing G1 x G1 -> GT
|
|
//
|
|
// P is a point of order q in G1. Q is also a point of order q in G1.
|
|
//
|
|
// Note miller -> miller variable
|
|
// Loop unrolled x2 for speed
|
|
//
|
|
|
|
GT PFC::miller_loop(const G1& PP,const G1& QQ)
|
|
{
|
|
GF2m xp,yp,xq,yq,t;
|
|
GF2m4x miller,w,u,u0,u1,v,f,res;
|
|
EC2 P,Q;
|
|
GT mill;
|
|
int i,imod4,m=get_mip()->M;
|
|
|
|
P=PP.g; Q=QQ.g;
|
|
normalise(P); normalise(Q);
|
|
extract(P,xp,yp);
|
|
extract(Q,xq,yq);
|
|
|
|
imod4=((m+1)/2)%4;
|
|
if (imod4==1)
|
|
{ // (X=1) // (Y=0)
|
|
t=xp; // 0 (X+1)
|
|
f.set(t*(xp+xq+1)+yq+yp+B,t+xq+1,t+xq,0); // 0 (Y)
|
|
miller=1;
|
|
for (i=0;i<(m-3)/2;i+=2)
|
|
{
|
|
t=xp+1; xp=sqrt(xp); yp=sqrt(yp); // 1 (X)
|
|
u0.set(t*(xp+xq+1)+yp+yq,t+xq+1,t+xq,0); // 1 0 (X) ((X+1)*(xp+1)+Y)
|
|
xq*=xq; yq*=yq;
|
|
|
|
t=xp+1; xp=sqrt(xp); yp=sqrt(yp);
|
|
u1.set(t*(xp+xq+1)+yp+yq,t+xq+1,t+xq,0);
|
|
xq*=xq; yq*=yq;
|
|
|
|
u=mul(u0,u1);
|
|
miller*=u;
|
|
}
|
|
|
|
// final step
|
|
|
|
t=xp+1; xp=sqrt(xp); yp=sqrt(yp);
|
|
u.set(t*(xp+xq+1)+yp+yq,t+xq+1,t+xq,0);
|
|
miller*=u;
|
|
}
|
|
|
|
if (imod4==0)
|
|
{ // (X=0) // (Y=0)
|
|
t=xp+1; // 1 (X+1)
|
|
f.set(t*(xq+xp+1)+yq+yp+B,t+xq+1,t+xq,0); // 0 (Y)
|
|
miller=1;
|
|
|
|
for (i=0;i<(m-1)/2;i+=2)
|
|
{
|
|
// loop is unrolled x 2
|
|
t=xp; xp=sqrt(xp); yp=sqrt(yp); // 0 (X)
|
|
u0.set(t*(xp+xq)+yp+yq+xp+1,t+xq+1,t+xq,0); // 0 xp+1 (X) ((X+1)*(xp+1)+Y
|
|
xq*=xq; yq*=yq;
|
|
|
|
t=xp; xp=sqrt(xp); yp=sqrt(yp);
|
|
u1.set(t*(xp+xq)+yp+yq+xp+1,t+xq+1,t+xq,0);
|
|
xq*=xq; yq*=yq;
|
|
|
|
u=mul(u0,u1);
|
|
miller*=u;
|
|
}
|
|
}
|
|
|
|
if (imod4==2)
|
|
{ // (X=0) // (Y=1)
|
|
t=xp+1; // 1 (X+1)
|
|
f.set(t*(xq+xp+1)+yq+yp+B+1,t+xq+1,t+xq,0); // 1 (Y)
|
|
miller=1;
|
|
for (i=0;i<(m-1)/2;i+=2)
|
|
{
|
|
t=xp; xp=sqrt(xp); yp=sqrt(yp); // 0 (X)
|
|
u0.set(t*(xp+xq)+yp+yq+xp,t+xq+1,t+xq,0); // 0 xp+0 (X) ((X+1)*(xp+1)+Y)
|
|
xq*=xq; yq*=yq;
|
|
t=xp; xp=sqrt(xp); yp=sqrt(yp);
|
|
u1.set(t*(xp+xq)+yp+yq+xp,t+xq+1,t+xq,0);
|
|
xq*=xq; yq*=yq;
|
|
u=mul(u0,u1);
|
|
miller*=u;
|
|
}
|
|
}
|
|
|
|
if (imod4==3)
|
|
{ // (X=1) // (Y=1)
|
|
t=xp; // 0 (X+1)
|
|
f.set(t*(xq+xp+1)+yq+yp+B+1,t+xq+1,t+xq,0); // 1 (Y)
|
|
|
|
miller=1;
|
|
for (i=0;i<(m-3)/2;i+=2)
|
|
{
|
|
t=xp+1; xp=sqrt(xp); yp=sqrt(yp); // 1 (X)
|
|
u0.set(t*(xp+xq+1)+yp+yq+1,t+xq+1,t+xq,0); // 1 1 (X) ((X+1)*(xp+1)+Y)
|
|
xq*=xq; yq*=yq;
|
|
|
|
t=xp+1; xp=sqrt(xp); yp=sqrt(yp);
|
|
u1.set(t*(xp+xq+1)+yp+yq+1,t+xq+1,t+xq,0);
|
|
xq*=xq; yq*=yq;
|
|
|
|
u=mul(u0,u1);
|
|
miller*=u;
|
|
}
|
|
// final step
|
|
|
|
t=xp+1; xp=sqrt(xp); yp=sqrt(yp);
|
|
u.set(t*(xp+xq+1)+yp+yq+1,t+xq+1,t+xq,0);
|
|
miller*=u;
|
|
}
|
|
|
|
miller*=f;
|
|
mill.g=miller;
|
|
return mill;
|
|
}
|
|
|
|
GT PFC::final_exp(const GT& z)
|
|
{
|
|
int i,m,TYPE;
|
|
GT res;
|
|
GF2m4x r,u,v,w,y;
|
|
// raising to the power (2^m-2^[m+1)/2]+1)(2^[(m+1)/2]+1)(2^(2m)-1) or (2^m+2^[(m+1)/2]+1)(2^[(m+1)/2]-1)(2^(2m)-1)
|
|
// 6 Frobenius, 4 big field muls...
|
|
y=z.g;
|
|
|
|
if (B==0)
|
|
{
|
|
if (M%8==1 || M%8==7) TYPE=1;
|
|
else TYPE=2;
|
|
}
|
|
if (B==1)
|
|
{
|
|
if (M%8==3 || M%8==5) TYPE=1;
|
|
else TYPE=2;
|
|
}
|
|
|
|
u=v=w=y;
|
|
for (i=0;i<(M+1)/2;i++) u*=u;
|
|
|
|
if (TYPE==1)
|
|
{
|
|
u.powq();
|
|
w.powq();
|
|
v=w;
|
|
w.powq();
|
|
r=w;
|
|
w.powq();
|
|
w*=u;
|
|
w*=y;
|
|
r*=v;
|
|
u.powq();
|
|
u.powq();
|
|
r*=u;
|
|
}
|
|
else
|
|
{
|
|
u.powq();
|
|
v.powq();
|
|
w=u*v;
|
|
v.powq();
|
|
w*=v;
|
|
v.powq();
|
|
u.powq();
|
|
u.powq();
|
|
r=v*u;
|
|
r*=y;
|
|
}
|
|
|
|
r/=w;
|
|
res.g=r;
|
|
return res;
|
|
}
|
|
|
|
// initialise Pairing Friendly Curve
|
|
|
|
PFC::PFC(int s, csprng *rng)
|
|
{
|
|
int t,u,v,b,words,mod_bits;
|
|
|
|
if (s!=80 && s!=128)
|
|
{
|
|
cout << "No suitable curve available" << endl;
|
|
exit(0);
|
|
}
|
|
|
|
if (s==80) mod_bits=379;
|
|
if (s==128) mod_bits=1223;
|
|
|
|
words=(mod_bits/MIRACL)+1;
|
|
|
|
#ifdef MR_SIMPLE_BASE
|
|
miracl *mip=mirsys((MIRACL/4)*words,16);
|
|
#else
|
|
miracl *mip=mirsys(words,0);
|
|
mip->IOBASE=16;
|
|
#endif
|
|
|
|
ord=new Big;
|
|
|
|
S=s;
|
|
M=mod_bits;
|
|
if (s==80)
|
|
{
|
|
t=253; u=251; v=59; B=1; CF=1;
|
|
*ord=pow((Big)2,M)+pow((Big)2,(M+1)/2)+1; //TYPE=1
|
|
}
|
|
if (s==128)
|
|
{
|
|
t=255; u=0; v=0; B=0; CF=5;
|
|
*ord=pow((Big)2,M)+pow((Big)2,(M+1)/2)+1; //TYPE=1
|
|
}
|
|
*ord/=CF;
|
|
|
|
#ifdef MR_AFFINE_ONLY
|
|
ecurve2(-M,t,u,v,(Big)1,(Big)B,TRUE,MR_AFFINE);
|
|
#else
|
|
ecurve2(-M,t,u,v,(Big)1,(Big)B,TRUE,MR_PROJECTIVE);
|
|
#endif
|
|
|
|
RNG=rng;
|
|
}
|
|
|
|
G1 PFC::mult(const G1& w,const Big& k)
|
|
{
|
|
G1 z=w;
|
|
z.g*=k;
|
|
return z;
|
|
}
|
|
|
|
GT PFC::power(const GT& w,const Big& k)
|
|
{
|
|
GT z;
|
|
z.g=powu(w.g,k);
|
|
return z;
|
|
}
|
|
|
|
// Precomputation not used here
|
|
|
|
//
|
|
// Spill precomputation on pairing to byte array
|
|
//
|
|
|
|
int PFC::spill(G1& w,char *& bytes)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Restore precomputation on pairing to byte array
|
|
//
|
|
|
|
void PFC::restore(char * bytes,G1& w)
|
|
{
|
|
}
|
|
|
|
//
|
|
// spill precomputation on GT to byte array
|
|
//
|
|
|
|
int GT::spill(char *& bytes)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// restore precomputation for GT from byte array
|
|
//
|
|
|
|
void GT::restore(char *bytes)
|
|
{
|
|
}
|
|
|
|
//
|
|
// spill precomputation on G1 to byte array
|
|
//
|
|
|
|
int G1::spill(char *& bytes)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// restore precomputation for G1 from byte array
|
|
//
|
|
|
|
void G1::restore(char *bytes)
|
|
{
|
|
}
|
|
|
|
void PFC::hash_and_map(G1& w,char *ID)
|
|
{
|
|
Big x0=H1(ID);
|
|
while (!w.g.set(x0,x0)) x0+=1;
|
|
w.g*=CF;
|
|
}
|
|
|
|
void PFC::random(G1& w)
|
|
{
|
|
Big x0;
|
|
if (RNG==NULL) x0=rand(M,2);
|
|
else x0=strong_rand(RNG,M,2);
|
|
|
|
while (!w.g.set(x0,x0)) x0+=1;
|
|
w.g*=CF;
|
|
}
|
|
|
|
Big PFC::hash_to_aes_key(const GT& w)
|
|
{
|
|
Big m=pow((Big)2,S);
|
|
return H2(w.g)%m;
|
|
}
|
|
|
|
// hash to group multiplier
|
|
|
|
Big PFC::hash_to_group(char *ID)
|
|
{
|
|
Big m=H1(ID);
|
|
Big o=pow((Big)2,2*S);
|
|
return m%o;
|
|
}
|
|
|
|
GT operator*(const GT& x,const GT& y)
|
|
{
|
|
GT z=x;
|
|
z.g*=y.g;
|
|
return z;
|
|
}
|
|
|
|
// elements in GT are unitary
|
|
|
|
GT operator/(const GT& x,const GT& y)
|
|
{
|
|
GT z=x;
|
|
z.g*=conj(y.g);
|
|
return z;
|
|
}
|
|
|
|
G1 operator+(const G1& x,const G1& y)
|
|
{
|
|
G1 z=x;
|
|
z.g+=y.g;
|
|
return z;
|
|
}
|
|
|
|
G1 operator-(const G1& x)
|
|
{
|
|
G1 z=x;
|
|
z.g=-z.g;
|
|
return z;
|
|
}
|
|
|
|
// Fast PFC group membership check
|
|
|
|
BOOL PFC::member(const GT &z)
|
|
{
|
|
GF2m4x w=z.g;
|
|
GF2m4x r=z.g;
|
|
if (pow(r,CF)==1) return FALSE;
|
|
w.powq();
|
|
if (r*w==pow(r,pow((Big)2,(M+1)/2))) return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
GT PFC::pairing(const G1& x,const G1& y)
|
|
{
|
|
GT z;
|
|
z=miller_loop(x,y);
|
|
z=final_exp(z);
|
|
return z;
|
|
}
|
|
|
|
GT PFC::multi_pairing(int n,G1 **y,G1 **x)
|
|
{
|
|
int i;
|
|
GT z=1;
|
|
for (i=0;i<n;i++)
|
|
z=z*miller_loop(*y[i],*x[i]);
|
|
z=final_exp(z);
|
|
return z;
|
|
|
|
}
|
|
|
|
int PFC::precomp_for_mult(G1& w,BOOL small)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int PFC::precomp_for_power(GT& w,BOOL small)
|
|
{
|
|
return 0;
|
|
} |