KGC_TEST/KGCAPP/3rdparty/miracl/source/curve/pairing/mnt.cpp

510 lines
14 KiB
C++

/*
* program to generate MNT Elliptic curves
*
* Compile as (for example)
* cl /O2 /GX mnt.cpp big.cpp miracl.lib
*
* See Miyaji, Nakabayashi & Takano "New explicit conditions of elliptic curve
* traces for FR-reduction", IEICE Trans. Fundementals., Vol. E84A, No. 5,May
* 2001
*
* Invoke as mnt N where k= 3,4 or 6
*
* Security level is preportional to the difficulty of the associated
* discrete log problem in bits. e.g. if p is 160 bits and k=6, then
* discrete log problem is 160*6=960 bits.
*
* To find actual elliptic curve use CM utility
* For example from output:-
*
* *** Found one - 165 bits
* D= 998
* p= 28795013727143986241793993458326894706197949151527
* NP= 28795013727143986241793989663922216291941998151802
* = 78*369166842655692131305051149537464311435153822459
* (a 159-bit prime)
*
* Execute
* cm 28795013727143986241793993458326894706197949151527 -D998 -K78
*
* New! Now also finds "extended" MNT curves. By allowing a co-factor > 1
* many more curves will be found.
*
* However this can cause a problem for our Pell code. A "." indicates that
* only a partial search was possible.
*
* Mike Scott 4/07/2002
*
*/
#include <cstring>
#include <iostream>
#include <fstream>
#include <iomanip>
#include "big.h"
using namespace std;
// Solve the Pell equation
int pell(int max,Big D,Big F,Big& X,Big& Y,Big *SX,Big *SY,BOOL& complete)
{
int i,j,ns;
BOOL SMALLD;
Big A,P,Q,SD,G,B,OG,OB,NG,NB,T;
complete=FALSE;
SMALLD=FALSE;
if (D<F*F) SMALLD=TRUE;
SD=sqrt(D);
if (SD*SD==D) return 0;
P=0; Q=1;
OG=-P;
OB=1;
G=Q;
B=0;
ns=0;
X=Y=0;
for (i=1;;i++)
{
A=(P+SD)/Q;
P=A*Q-P;
Q=(D-P*P)/Q;
NG=A*G+OG; // G is getting bigger all the time....
NB=A*B+OB;
OG=G; OB=B;
G=NG; B=NB;
if (!SMALLD && bits(G)>max) return ns;
// abort - these are only solutions
T=G*G-D*B*B;
if (T == F/4)
{
SX[ns]=2*G; SY[ns]=2*B;
ns++;
}
if (T == F)
{
SX[ns]=G; SY[ns]=B;
ns++;
}
if (i>0 && Q==1) break;
}
if (i%2==1)
for (j=0;j<i;j++)
{
A=(P+SD)/Q;
P=A*Q-P;
Q=(D-P*P)/Q;
NG=A*G+OG;
NB=A*B+OB;
OG=G; OB=B;
G=NG; B=NB;
if (!SMALLD && bits(G)>max) return ns;
T=G*G-D*B*B;
if (T == F/4)
{
SX[ns]=2*G; SY[ns]=2*B;
ns++;
}
if (T == F)
{
SX[ns]=G; SY[ns]=B;
ns++;
}
}
complete=TRUE; // we got to the end....
X=G; Y=B; // minimal solution of x^2-dy^2=1
// can be used to find more solutions....
if (SMALLD)
{ // too small - do it the hard way
Big ylim1,ylim2,R;
ns=0;
if (F<0)
{
ylim1=sqrt(-F/D);
ylim2=sqrt(-F*(X+1)/(2*D));
}
else
{
ylim1=0;
ylim2=sqrt(F*(X-1)/(2*D));
}
// This might take too long...
// Should really implement LMM method here
if (ylim2-ylim1>300)
{
cout << "." << flush;
ylim2=ylim1+300;
}
for (B=ylim1;B<ylim2;B+=1)
{
R=F+D*B*B;
if (R<0) continue;
G=sqrt(R);
if (G*G==R)
{
SX[ns]=G; SY[ns]=B;
ns++;
}
}
}
return ns;
}
void multiply(Big& td,Big& a,Big& b,Big& c,Big& d)
{ // (c+td.d) = (a+td.b)(c+td.d)
Big t;
t=a*c+b*d*td;
d=c*b+a*d;
c=t;
}
BOOL squfree(int d)
{ // check if d is square-free
int i,s;
miracl *mip=get_mip();
for (i=0;;i++)
{
s=mip->PRIMES[i];
if ((d%(s*s))==0) return FALSE;
if ((s*s)>d) break;
}
return TRUE;
}
void results(BOOL fout,ofstream& ofile,int d,Big p,Big nrp,Big ord,BOOL prime_ord)
{
Big cf=nrp/ord;
cout << "*** Found one - " << bits(p) << " bits" << endl;
cout << " D= " << d << endl;
cout << " p= " << p << " p%24= " << p%24 << endl;
cout << "NP= " << nrp << endl;
if (cf>1) cout << " = " << cf << "*" << ord << endl;
if (prime_ord)
{
if (cf==1)
cout << " (a " << bits(ord) << "-bit prime) !\n" << endl;
else
cout << " (a " << bits(ord) << "-bit prime)\n" << endl;
}
else cout << endl;
if (fout)
{
ofile << "*** Found one - " << bits(p) << " bits" << endl;
ofile << " D= " << d << endl;
ofile << " p= " << p << " p%24= " << p%24 << endl;
ofile << "NP= " << nrp << endl;
if (cf>1) ofile << " = " << cf << "*" << ord << endl;
if (prime_ord)
{
if (cf==1)
ofile << " (a " << bits(ord) << "-bit prime) !" << endl;
else
ofile << " (a " << bits(ord) << "-bit prime)" << endl;
ofile << " cm " << p << " -D" << d << " -K" << cf << endl << endl;
}
else ofile << endl;
}
}
int main(int argc,char **argv)
{
ofstream ofile;
int MIN_SECURITY,MAX_SECURITY,MIN_D,MAX_D,MIN_P;
int ip,j,d,m,mm,solutions,mnt,start,N,precision,max;
BOOL fout,complete;
// Defaults
MIN_SECURITY=768;
MAX_SECURITY=1536;
MIN_D=1;
MAX_D=10000;
MIN_P=128;
fout=FALSE;
precision=100;
m=1;
argc--; argv++;
if (argc<1)
{
cout << "Wrong number of parameters" << endl;
cout << "Utility to find MNT elliptic curves" << endl;
cout << "The output from this program must be processed by the" << endl;
cout << "CM (Complex Multiplication) utility to find the actual" << endl;
cout << "curve parameters" << endl;
cout << "See comments at start of source file mnt.cpp for more details" << endl;
cout << "mnt k, where k=3,4 or 6 is the security multiplier" << endl;
cout << "Flags allowed, e.g. mnt 6 -c2 -d100 -D1000 -m1000 -M2000" << endl;
cout << "-c: cofactor (number of points on curve will be multiple of cofactor)" << endl;
cout << "-d: min value of D, -D: max value of D" << endl;
cout << "-m: min security level, -M: max security level (RSA equivalent bits)" << endl;
cout << "-p: min prime size/field size in bits" << endl;
cout << "Increase co-factor for more curves" << endl;
cout << "Defaults -c1 -d0 -D10000 -m768 -M1536 -p128" << endl;
cout << "To output to a file, use flag -o <filename>" << endl;
exit(0);
}
N=atoi(argv[0]);
if (N!=3 && N!=4 && N!=6)
{
cout << "Wrong parameter - should be 3,4 or 6" << endl;
exit(0);
}
ip=1;
while (ip<argc)
{ // look for flags
if (strncmp(argv[ip],"-d",2)==0)
{
MIN_D=atoi(argv[ip]+2);
ip++;
continue;
}
if (strncmp(argv[ip],"-D",2)==0)
{
MAX_D=atoi(argv[ip]+2);
ip++;
continue;
}
if (strncmp(argv[ip],"-m",2)==0)
{
MIN_SECURITY=atoi(argv[ip]+2);
ip++;
continue;
}
if (strncmp(argv[ip],"-M",2)==0)
{
MAX_SECURITY=atoi(argv[ip]+2);
ip++;
continue;
}
if (strncmp(argv[ip],"-p",2)==0)
{
MIN_P=atoi(argv[ip]+2);
ip++;
continue;
}
if (strncmp(argv[ip],"-c",2)==0)
{
m=atoi(argv[ip]+2);
ip++;
continue;
}
if (strcmp(argv[ip],"-o")==0)
{
ip++;
if (ip<argc)
{
fout=TRUE;
ofile.open(argv[ip++]);
continue;
}
else
{
cout << "Error in command line" << endl;
return 0;
}
}
cout << "Error in command line" << endl;
return 0;
}
if (m<1 || m>8)
{
cout << "Co-factor must be > 0 and <= 8" << endl;
exit(0);
}
miracl *mip=mirsys(precision,0);
Big F,T,M,D,W,K,C,mmax,td,X,Y,x,y,w,xn,yn,t0,u0,p,k,nrp,ord,R;
Big SX[20],SY[20];
start=1;
if (1<MIN_D) start=MIN_D;
mmax=m;
mnt=0;
for (M=1;M<=mmax;M+=1)
{
for (R=1;;R+=1)
{
if (N==4)
{ // R=1,2,5,... 1 or 2 mod 4
if (R%4!=1 && R%4!=2) continue;
if (R%3==0) continue;
if (R>=4*M) break; // Hasse limit
if (gcd(R,M)!=1) continue;
T=R*R-4*M*M;
}
else
{ // R=1,3,7,9,13,... 1 or 3 mod 6
if (R%6!=1 && R%6!=3) continue;
if (R%5==0 || R%2==0) continue;
if (R>=4*M) break; // Hasse limit
if (gcd(R,M)!=1) continue;
if (N==3) T=(R+M)*(R+M)-4*M*M;
else T=(R-M)*(R-M)-4*M*M;
}
// Check that quadratic polynomial for p does not factor
// i.e. b^2-4ac is not a square
// The prime p will be of the form M*Phi_N(x)/R + x
if (T>=0)
{
W=sqrt(T);
if (W*W==T) continue; // p cannot be prime - has factors
}
// There are probably more conditions like these .....
if (N==6)
{
if (M==4 && R==3) continue; // p cannot be prime - multiple of 3
if (R>3 && (R/3)%3==0) continue;
}
cout << "\nM= " << M << " R= " << R << endl << endl;
if (fout) ofile << "\nM= " << M << " R= " << R << endl << endl;
K=(4*M-R);
if (N==3) C=2*M+R;
if (N==4) C=R;
if (N==6) C=-(2*M-R);
F=C*C-K*K;
// CM equation is R.D.V^2 = 4*M*Phi_N(x)-R*(x-1)^2
// Substitute x=(X-C)/K (to get rid of x term)
// Pell equation is then X^2-R*K*D.V^2 = F
// Our Pell code runs into problems if F is too big
// This hack makes F a bit smaller - better for Pell
// If M is even x must be odd...
mm=1;
if (M%2==0 && F%4==0)
{
mm=2; F/=4;
}
max=10+MAX_SECURITY/(2*N);
gprime(100000); // > 2^16
for (d=start;d<=MAX_D;d++)
{
// D must be square-free
if (!squfree(d)) continue;
td=R*K*d;
solutions=pell(max,td,F,t0,u0,SX,SY,complete);
if (!solutions) continue;
for (j=0;j<solutions;j++)
{
X=SX[j];
Y=SY[j];
forever
{
if (bits(mm*X) > max) break; // primes are too big
if ((mm*X-C)%K == 0)
{
x=(mm*X-C)/K;
if (N==3) p=x*x+x+1;
if (N==4) p=x*x+1;
if (N==6) p=x*x-x+1;
if (R==1 || p%R==0)
{
p=(M*p)/R+x;
if (N*bits(p) > MAX_SECURITY) break;
if (bits(p)>=MIN_P && N*bits(p)>= MIN_SECURITY && prime(p))
{
nrp=p+1-(x+1);
ord=trial_divide(nrp);
if (prime(ord))
{
if (bits(ord)>=MIN_P)
{
mnt++;
results(fout,ofile,d,p,nrp,ord,TRUE);
}
}
// else
// { // ord has at least a 16-bit factor...
// if (bits(ord)>=MIN_P+16)
// {
// mnt++;
// results(fout,ofile,d,p,nrp,ord,FALSE);
// }
// }
}
}
}
if ((-mm*X-C)%K == 0)
{
x=(-mm*X-C)/K;
if (N==3) p=x*x+x+1;
if (N==4) p=x*x+1;
if (N==6) p=x*x-x+1;
if (R==1 || p%R==0)
{
p=(M*p)/R+x;
if (N*bits(p) > MAX_SECURITY) break;
if (bits(p)>=MIN_P && N*bits(p)>= MIN_SECURITY && prime(p))
{
nrp=p+1-(x+1);
ord=trial_divide(nrp);
if (prime(ord))
{
if (bits(ord)>=MIN_P)
{
results(fout,ofile,d,p,nrp,ord,TRUE);
mnt++;
}
}
// else
// {
// if (bits(ord)>=MIN_P+16)
// {
// results(fout,ofile,d,p,nrp,ord,FALSE);
// mnt++;
// }
// }
}
}
}
if (!complete) break; // no more solutions
multiply(td,t0,u0,X,Y);
}
}
}
}
}
if (fout) ofile << mnt << " MNT elliptic curves found in this range" << endl;
cout << mnt << " MNT elliptic curves found in this range" << endl;
return 0;
}