KGC_TEST/KGC/miracl/source/curve/cm.cpp

1363 lines
33 KiB
C++

/*
* cm.cpp - Finding an elliptic curve and point of nearly prime order
* See IEEE 1363 Annex A for documentation!
*
* !!! New much improved version - March 2002
* !!! Now tested for D up to 10^7
*
* !!! New faster version - uses Floats instead of Flashs - November 2003
* !!! Now 100 times faster!
* !!! Now tested for D up to and beyond 10^9
*
* !!! New invariants - gamma2, w3, w5, w7 and w13. Thanks to Marcel Martin.
*
* Sometimes its better to use the -IEEE flag, as this can often be faster
* than the Gamma2 invariant, as although it requires a bigger "class number",
* it needs less precision.
*
* Uses functions from the MIRACL multiprecision library, specifically
* classes:-
* Float - Big floating point
* Complex - Big Complex float
* Big - Big integer
* ZZn - Big integers mod an integer
* FPoly - Big Float polynomial
* Poly - Big ZZn polynomial
*
* Written by Mike Scott, Dublin, Ireland. March 1998 - March 2004
*
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstring>
#include "ecn.h"
#include "complex.h"
#include "flpoly.h"
#include "poly.h"
using namespace std;
miracl *mip;
FPoly T[25]; // Reduced class Polynomial.
static char *s;
BOOL fout,suppress,three;
// F(z) Function A.13.3
Complex Fz(Complex z)
{
Complex t;
int sign=1;
Complex osum,sum=(Float)1;
if (z.iszero()) return sum;
Complex zi=z;
Complex zj=z*z;
Complex r=z;
Complex z3=zj*z;
forever
{ // do 2 terms at a time....
t=zi+zj;
osum=sum;
if (sign) sum-=t;
else sum+=t;
if (sum==osum) break;
r*=z3;
zi*=r; zj*=r; zj*=z;
sign=1-sign;
}
return sum;
}
// Fj(A,B,C) function A.13.3
Complex F(int j,Big A,Big B,Big C,Big D,int N)
{
Complex t,theta24,theta,theta2,theta3,theta6;
Float sd;
if (j>=3)
{ // Gamma 2 and Morain's invariants
sd=-sqrt((Float)D);
t=Complex(sd*fpi(),(fpi()*(Float)B));
t/=((Float)A);
theta=exp(t);
if (j==3)
{
theta3=theta;
theta3*=theta3;
theta3*=theta;
theta6=theta3;
theta6*=theta6;
t=theta*pow((Fz(theta6)/Fz(theta3)),8);
return (256*t*t*t+1)/t;
}
if (j==4)
{
return (pow(Fz(theta)/Fz(pow(theta,N)),24/(N-1))/theta);
}
return 0;
}
sd=-sqrt((Float)D);
t=Complex(sd*fpi(),(fpi()*(Float)B));
t/=(Float)(24*A);
theta24=exp(t); // theta^(1/24)
theta=pow(theta24,24); // theta
if (j!=2)
t=recip(theta24); // -24th root
else
t=theta24*theta24; // 12th root
theta2=theta;
theta2*=theta2;
if (j==0) return (t*Fz(-theta)/Fz(theta2));
if (j==1) return (t*Fz(theta)/Fz(theta2));
if (j==2) return (sqrt((Float)2)*t*Fz(theta2*theta2)/Fz(theta2));
return 0;
}
int geti(Big D)
{
Big d=D%8;
if (d==1 || d==2 || d==6 || d==7) return 3;
if (d==3)
{
if (D%3==0) return 2;
else return 0;
}
if (d==5) return 6;
return 0;
}
int getk(Big D)
{
Big d=D%8;
if (d==1 || d==2 || d==6) return 2;
if (d==3 || d==7) return 1;
if (d==5) return 4;
return 0;
}
int getN(Big D)
{
if (D%13==0) return 13;
if (D%7==0) return 7;
if (D%5==0) return 5;
if (D%3==0) return 3;
return 2;
}
// A.13.3
void class_poly(Complex& lam,Float *Fi2,Big A,Big B,Big C,Big D,BOOL conj,BOOL P1363)
{
Big ac,l,t;
int i,j,k,g,e,m,n,dm8;
Complex cinv;
if (P1363)
{
g=1;
if (D%3==0) g=3;
ac=A*C;
if (ac%2==1)
{
j=0;
l=A-C+A*A*C;
}
if (C%2==0) j=1;
if (A%2==0) j=2;
if (A%2==0)
{
t=(C*C-1)/8;
if (t%2==0) m=1;
else m=-1;
}
else
{
t=(A*A-1)/8;
if (t%2==0) m=1;
else m=-1;
}
dm8=D%8;
i=geti(D);
k=getk(D);
switch (dm8)
{
case 1:
case 2: n=m;
if (C%2==0) l=A+2*C-A*C*C;
if (A%2==0) l=A-C-A*C*C;
break;
case 3: if (ac%2==1) n=1;
else n=-m;
if (C%2==0) l=A+2*C-A*C*C;
if (A%2==0) l=A-C+5*A*C*C;
break;
case 5: n=1;
if (C%2==0) l=A-C+A*A*C;
if (A%2==0) l=A-C-A*C*C;
break;
case 6: n=m;
if (C%2==0) l=A+2*C-A*C*C;
if (A%2==0) l=A-C-A*C*C;
break;
case 7: if (ac%2==0) n=1;
else n=m;
if (C%2==0) l=A+2*C-A*C*C;
if (A%2==0) l=A-C-A*C*C;
break;
default: break;
}
e=(k*B*l)%48;
if (e<0) e+=48;
cinv=pow(lam,e);
cinv*=(n*Fi2[i]);
cinv=pow(cinv*pow(F(j,A,B,C,D,0),k),g);
}
else
{
int N=getN(D);
// adjust A and B
if (N==2)
{
j=3;
if (A%3!=0)
{
if (B%3!=0)
{
if ((B+A+A)%3!=0) B+=(4*A);
else B+=(A+A);
}
}
else
{
if (B%3!=0)
{
if (C%3!=0)
{
if ((C+B)%3!=0) B+=(4*A);
else B+=(A+A);
}
}
}
A*=3;
}
else
{
j=4;
if ((A%N)==0)
{
A=C;
B=-B;
}
while (B%N!=0) B+=(A+A);
A*=N;
}
cinv=F(j,A,B,C,D,N);
}
// multiply polynomial by new term(s)
FPoly F;
if (conj)
{ // conjugate pair
// t^2-2a+(a^2+b^2) , where cinv=a+ib
F.addterm((Float)1,2);
F.addterm(-2*real(cinv),1);
F.addterm(real(cinv)*real(cinv)+imaginary(cinv)*imaginary(cinv),0);
}
else
{ // t-cinv
F.addterm((Float)1,1);
F.addterm(-real(cinv),0);
// store as a linear polynomial, or combine 2 to make a quadratic
if (T[0].iszero())
{
T[0]=F;
return;
}
else
{
F=T[0]*F; // got a quadratic
T[0].clear();
}
}
// accumulate Polynomial as 2^m degree components
// This allows the use of karatsuba via the "special" function
// This is the time critical bit....
for (i=1;;i++)
{
if (T[i].iszero())
{
T[i]=F; // store this 2^i degree polynomial
break;
}
else
{
F=special(T[i],F); // e.g. if i=1 two quadratics make a quartic..
T[i].clear();
}
}
}
// A.13.2
// Set P1363 to False to calculate class number a la Cohen
int groups(Complex& lam,Float *Fi2,unsigned long D,BOOL doit,BOOL P1363)
{
unsigned long s,t,A,C,B,TB,lim;
int cn=0;
s=mr_lsqrt(D/3,1);
for (B=0;B<=s;B+=1)
{
// cout << "B= " << B << " s= " << s << endl;
t=D+B*B;
if (!P1363)
{
if (t%4!=0) continue;
else t/=4;
}
// cout << "t= " << t << endl;
lim=mr_lsqrt(t,1);
// cout << "lim= " << lim << endl;
if (P1363) A=2*B;
else A=B;
if (A==0) A+=1;
for(;;)
{
while (t%A!=0)
{
A+=1;
if (A>lim) break;
}
if (A>lim) break;
C=t/A;
TB=B;
if (P1363) TB*=2;
if (lgcd(lgcd(A,TB),C)==1)
{ // output more class group members
BOOL conj;
if (TB>0 && C>A && A>TB)
{
conj=TRUE;
cn+=2;
if (doit)
{
if (!suppress) cout << ".." << flush;
}
}
else
{
conj=FALSE;
cn+=1;
if (doit)
{
if (!suppress) cout << "." << flush;
}
}
if (doit) class_poly(lam,Fi2,(Big)A,(Big)B,(Big)C,(Big)D,conj,P1363);
}
A+=1;
}
}
return cn; // class number
}
// check congruence conditions A14.2.1
BOOL isaD(unsigned long d,int pm8,Big k)
{
unsigned int dm8;
unsigned long i;
BOOL sqr;
dm8=d%8;
if (k==1 && dm8!=3) return FALSE;
if ((k==2 || k==3) && dm8==7) return FALSE;
if (pm8==3 && (dm8==1 || dm8==4 || dm8==5 || dm8==6)) return FALSE;
if (pm8==5 && dm8%2==0) return FALSE;
if (pm8==7 && (dm8==1 || dm8==2 || dm8==4 || dm8==5)) return FALSE;
sqr=FALSE;
for (i=2;;i++)
{
if (d%(i*i)==0)
{
sqr=TRUE;
break;
}
if (i*i>d) break;
}
if (sqr) return FALSE;
return TRUE;
}
// Testing for CM discriminants A.14.2.2
Big floor(Big N,Big D)
{
Big R;
if (N==0) return 0;
if (N>0 && D>0) return N/D;
if (N<0 && D<0) return (-N)/(-D);
R=N/D;
if (N%D!=0) R-=1;
return R;
}
BOOL isacm(Big p,unsigned long D,Big &W,Big &V)
{
Big B2,A,B,C,t,X,Y,ld,delta;
B=sqrt(p-(Big)D,p);
A=p;
C=(B*B+(Big)D)/p;
X=1;
Y=0;
ld=0;
while (1)
{
if (C>=A)
{
B2=2*B;
if (B2<0) B2=-B2;
if (A>=B2) break;
}
delta=floor(2*B+C,2*C);
// are we stuck in hopeless loop? This can't happen now - thanks Marcel
if (delta==0 && ld==0) return FALSE;
ld=delta;
t=X;
X=(delta*X+Y);
Y=-t;
t=C;
C=(A+C*delta*delta-2*B*delta);
B=(t*delta-B);
A=t;
}
if (D==11 && A==3)
{
t=X;
X=Y;
Y=-t;
B=-B;
t=C;
C=A;
A=t;
}
if (D==1 || D==3)
{
W=2*X;
V=2*Y;
return TRUE;
}
else V=0;
if (A==1)
{
W=2*X;
return TRUE;
}
if (A==4)
{
W=4*X+B*Y;
return TRUE;
}
return FALSE;
}
// Constructing a Curve (and Point if order is prime)
// A.14.4
BOOL get_curve(Complex& lam,Float *Fi2,ofstream& ofile,Big r,Big other_r,Big ord,unsigned long D,Big p,Big W,int m,BOOL always)
{
Poly polly;
Big A0,B0,k;
BOOL unstable;
char c;
int i,j,terms,class_number;
BOOL P1363,pord=prime(ord);
P1363=TRUE;
if (!always && D>3 && D%8==3) P1363=FALSE;
k=r;
while (k%ord==0) k/=ord;
if (!suppress)
{
if (D>1000 && D%3==0) cout << "D= " << D << " (Divisible by 3 - might need extra precision)" << endl;
else cout << "D= " << D << endl;
if (P1363) cout << "IEEE-1363 invariant" << endl;
else
{
switch (getN(D))
{
case 2: cout << "Gamma2 invariant" << endl;
break;
case 3: cout << "w3 invariant" << endl;
break;
case 5: cout << "w5 invariant" << endl;
break;
case 7: cout << "w7 invariant" << endl;
break;
case 13: cout << "w13 invariant" << endl;
break;
}
}
cout << "D mod 24 = " << D%24 << endl;
if (prime(ord)) cout << "K= " << k << endl;
}
class_number=groups(lam,Fi2,D,FALSE,P1363);
cout << "class number= " << class_number << endl;
cout << "Group order= " << ord << endl;
cout << "do you want to proceed with this one (Y/N)? " ;
cin >> c;
if (c=='N' || c=='n')
{
if (!suppress) cout << "finding a curve..." << endl;
return FALSE;
}
modulo(p);
// A.14.4.1
if (D==1)
{
A0=1; B0=0;
}
if (D==3)
{
A0=0; B0=1;
}
if (D!=1 && D!=3)
{
FPoly Acc;
for (i=0;i<25;i++) T[i].clear();
if (!suppress) cout << "constructing polynomial";
groups(lam,Fi2,D,TRUE,P1363);
// Construct Polynomial from its 2^m degree components..
for (i=24;i>=0;i--)
{
if (!T[i].iszero())
{
Acc=T[i]; // find the first component..
T[i].clear();
break;
}
}
if (i>0)
{
for (j=i-1;j>0;j--)
{
if (!T[j].iszero())
{
Acc=special(Acc,T[j]); // special karatsuba function
T[j].clear(); // multiply into accumulator
}
}
if (!T[0].iszero())
{ // check for a left-over linear poly
Acc=Acc*T[0];
T[0].clear();
}
}
for (i=0;i<25;i++) T[i].clear();
terms=degree(Acc);
Float f,rem;
Big whole;
int nbits,maxbits=0;
unstable=FALSE;
for (i=terms;i>=0;i--)
{
f=Acc.coeff(i);
if (f>0)
f+=makefloat(1,10000);
else f-=makefloat(1,10000);
whole=f.trunc(&rem);
nbits=bits(whole);
if (nbits>maxbits) maxbits=nbits;
polly.addterm((ZZn)whole,i);
if (fabs(rem)>makefloat(1,100))
{
unstable=TRUE;
break;
}
}
Acc.clear();
if (!suppress) cout << endl;
if (unstable)
{
if (!suppress) cout << "Curve abandoned - numerical instability!" << endl;
if (!suppress) cout << "Curve abandoned - double MIRACL precision and try again!" << endl;
if (!suppress) cout << "finding a curve..." << endl;
return FALSE;
}
if (!suppress)
{
cout << polly << endl;
cout << "Maximum precision required in bits= " << maxbits << endl;
}
}
// save space with smaller miracl
mirexit();
mip=mirsys(128,0);
modulo(p);
ECn pt,G;
Big a,b,x,y;
Big w,eps;
int at;
Poly g,spolly=polly; // smaller polly
polly.clear();
forever
{
if (D!=1 && D!=3)
{
if (!suppress) cout << "Factoring polynomial of degree " << degree(spolly) << " ....." << endl;
if (P1363)
{
if (W%2==0)
{
ZZn V;
g=factor(spolly,1);
V=-g.coeff(0);
V=pow(V,24/(lgcd(D,3)*getk(D)));
V*=pow((ZZn)2,(4*geti(D))/getk(D));
if (D%2!=0) V=-V;
A0=(Big)((ZZn)(-3)*(V+64)*(V+16));
B0=(Big)((ZZn)2*(V+64)*(V+64)*(V-8));
}
else
{
Poly V,w,w1,w2,w3,a,b;
g=factor(spolly,3);
if (D%3!=0)
w.addterm(-1,24);
else
w.addterm(-256,8);
V=w%g;
w.clear();
w1=V; w2=V; w3=V;
w1.addterm(64,0);
w2.addterm(256,0);
w3.addterm(-512,0);
a=w1*w2;
a.multerm(-3,0);
a=a%g;
b=w1*w1*w3;
b.multerm(2,0);
b=b%g;
a=((a*a)*a)%g;
b=(b*b)%g;
for (int d=degree(g)-1;d>=0;d--)
{
ZZn t,c=a.coeff(d);
if (c!=(ZZn)0)
{
t=b.coeff(d);
A0=(Big)(c*t);
B0=(Big)(c*t*t);
if (d==1) break;
}
}
}
}
else
{
ZZn X,J,X2,K;
g=factor(spolly,1);
X=-g.coeff(0);
X2=X*X;
switch (getN(D))
{
case 2: J=X2*X;
break;
case 3: J=(pow((X+3),3)*(X+27))/X;
break;
case 5: J=pow((X2+10*X+5),3)/X;
break;
case 7: J=(pow((X2+5*X+1),3)*(X2+13*X+49))/X;
break;
case 13: J=(pow((X2*X2+7*X2*X+20*X2+19*X+1),3)*(X2+5*X+13))/X;
default: break;
}
K=J/(J-1728);
A0=-3*K;
B0=2*K;
}
}
// A.14.4.2
// but try -3 first, followed by small positive values for A
a=A0;
b=B0;
at=-3;
if (D==3) at=1;
forever
{
if (D==1)
{
if (at<100)
eps=(ZZn)at/(ZZn)A0;
else eps=rand(p);
a=modmult(A0,eps,p);
}
if (D==3)
{
if (at<100)
eps=(ZZn)at/(ZZn)B0;
else eps=rand(p);
b=modmult(B0,eps,p);
}
if (D!=1 && D!=3)
{
if (at<100)
{ // transform a to be simple if possible
w=(ZZn)at/ZZn(A0);
if (jacobi(w,p)!=1)
{
if (at==-3) at=1;
else at++;
continue;
}
eps=sqrt(w,p);
} else eps=rand(p);
a=modmult(A0,pow(eps,2,p),p);
b=modmult(B0,pow(eps,3,p),p);
}
ecurve(a,b,p,MR_PROJECTIVE);
for (int xc=1;;xc++)
{
if (!pt.set((Big)xc)) continue;
pt*=k;
if (pt.iszero()) continue;
break;
}
G=pt; // check its not the other one...
if (r!=ord || !(other_r*G).iszero())
{
pt*=ord;
if (pt.iszero()) break;
}
if (at==-3) at=1;
else at++;
}
if (a==(p-3)) a=-3;
if (D!=1 && D!=3 && three && a!=-3) continue;
// check MOV condition
// A.12.1
BOOL MOV=TRUE;
w=1;
for (i=1;i<100;i++)
{
w=modmult(w,p,ord);
if (w==1)
{
MOV=FALSE;
if (!suppress)
{
if (i==1 || pord) cout << "\n*** Failed MOV condition - k = " << i << endl;
else cout << "\n*** Failed MOV condition - k <= " << i << endl;
}
break;
}
}
if (!suppress)
{
if (MOV) cout << "MOV condition OK" << endl;
if (pord) cout << "\nCurve and Point Found" << endl;
else cout << "\nCurve Found" << endl;
}
cout << "A= " << a << endl;
cout << "B= " << b << endl;
G.get(x,y);
cout << "P= " << p << endl;
cout << "R= " << ord;
if (pord)
{
cout << " a " << bits(ord) << " bit prime" << endl;
cout << "X= " << x << endl;
cout << "Y= " << y << endl;
}
else cout << " NOT prime" << endl;
cout << endl;
if (D!=1 && D!=3 )
{
cout << "Try for different random factorisation (Y/N)? ";
cin >> c;
if (c=='Y' || c=='y') continue;
}
break;
}
if (pord) cout << "\nCurve and Point OK (Y/N)? " ;
else cout << "\nCurve OK (Y/N)? " ;
cin >> c;
if (c=='N' || c=='n')
{
if (!suppress) cout << "finding a curve..." << endl;
mirexit();
int precision=(1<<m);
mip=mirsys(precision+2,0); // restart with new precision
setprecision(m);
gprime(1000000);
mip->RPOINT=ON;
return FALSE;
}
if (fout)
{
ofile << bits(p) << endl;
mip->IOBASE=16;
ofile << p << endl;
ofile << a << endl;
ofile << b << endl;
ofile << ord << endl;
if (pord)
{
ofile << x << endl;
ofile << y << endl;
}
mip->IOBASE=10;
}
exit(0);
return TRUE;
}
// Code to parse formula
// This code isn't mine, but its public domain
// Shamefully I forget the source
//
// NOTE: It may be necessary on some platforms to change the operators * and #
#if defined(unix)
#define TIMES '.'
#define RAISE '^'
#else
#define TIMES '*'
#define RAISE '#'
#endif
void eval_power (Big& oldn,Big& n,char op)
{
if (op) n=pow(oldn,toint(n)); // power(oldn,size(n),n,n);
}
void eval_product (Big& oldn,Big& n,char op)
{
switch (op)
{
case TIMES:
n*=oldn;
break;
case '/':
n=oldn/n;
break;
case '%':
n=oldn%n;
}
}
void eval_sum (Big& oldn,Big& n,char op)
{
switch (op)
{
case '+':
n+=oldn;
break;
case '-':
n=oldn-n;
}
}
void eval (Big& t)
{
Big oldn[3];
Big n;
int i;
char oldop[3];
char op;
char minus;
for (i=0;i<3;i++)
{
oldop[i]=0;
}
LOOP:
while (*s==' ')
s++;
if (*s=='-') /* Unary minus */
{
s++;
minus=1;
}
else
minus=0;
while (*s==' ')
s++;
if (*s=='(' || *s=='[' || *s=='{') /* Number is subexpression */
{
s++;
eval(t);
n=t;
}
else /* Number is decimal value */
{
for (i=0;s[i]>='0' && s[i]<='9';i++)
;
if (!i) /* No digits found */
{
cout << "Error - invalid number" << endl;
exit (20);
}
op=s[i];
s[i]=0;
n=atoi(s);
s+=i;
*s=op;
}
if (minus) n=-n;
do
op=*s++;
while (op==' ');
if (op==0 || op==')' || op==']' || op=='}')
{
eval_power (oldn[2],n,oldop[2]);
eval_product (oldn[1],n,oldop[1]);
eval_sum (oldn[0],n,oldop[0]);
t=n;
return;
}
else
{
if (op==RAISE)
{
eval_power (oldn[2],n,oldop[2]);
oldn[2]=n;
oldop[2]=RAISE;
}
else
{
if (op==TIMES || op=='/' || op=='%')
{
eval_power (oldn[2],n,oldop[2]);
oldop[2]=0;
eval_product (oldn[1],n,oldop[1]);
oldn[1]=n;
oldop[1]=op;
}
else
{
if (op=='+' || op=='-')
{
eval_power (oldn[2],n,oldop[2]);
oldop[2]=0;
eval_product (oldn[1],n,oldop[1]);
oldop[1]=0;
eval_sum (oldn[0],n,oldop[0]);
oldn[0]=n;
oldop[0]=op;
}
else /* Error - invalid operator */
{
cout << "Error - invalid operator" << endl;
exit (20);
}
}
}
}
goto LOOP;
}
int main(int argc,char **argv)
{
BOOL good,dir,always;
int i,ip,m,precision;
unsigned long SD,D;
ofstream ofile;
mip=mirsys(128,0);
Big p,k,t;
argv++; argc--;
irand(0L);
if (argc<1)
{
cout << "Incorrect Usage" << endl;
cout << "Program tries to find Elliptic Curve mod a prime P and point of prime order" << endl;
cout << "that is a point (X,Y) on the curve y^2=x^3+Ax+B of order R" << endl;
cout << "where R is large and prime > |P/K|. (K defaults to 256)" << endl;
cout << "cm <prime number P>" << endl;
cout << "OR" << endl;
cout << "cm -f <formula for P>" << endl;
#if defined(unix)
cout << "e.g. cm -f 2^192-2^64-1" << endl;
#else
cout << "e.g. cm -f 2#192-2#64-1" << endl;
#endif
cout << "To suppress commentary, use flag -s. To insist on A= -3, use flag -t" << endl;
cout << "(the commentary will make some sense to readers of IEEE 1363 Annex)" << endl;
cout << "To search downwards for a prime, use flag -d" << endl;
cout << "To output to a file, use flag -o <filename>" << endl;
cout << "To set maximum co-factor size K, use e.g. flag -K8" << endl;
cout << "To set infinite co-factor size K, use flag -K0" << endl;
cout << "(In this case the reported R is the number of points on the curve)" << endl;
cout << "To start searching from a particular D value, use e.g. flag -D10000" << endl;
cout << "To set MIRACL precision to 2^n words, use e.g. flag -Pn (default -P5)" << endl;
cout << "If program fails, try again with n=n+1" << endl;
cout << "To insist on IEEE-1363 invariants, use flag -IEEE" << endl;
#if defined(unix)
cout << "e.g. cm -f 2^224-2^96+1 -K12 -D4000000 -P9 -o common.ecs" << endl;
#else
cout << "e.g. cm -f 2#224-2#96+1 -K12 -D4000000 -P9 -o common.ecs" << endl;
#endif
cout << "Freeware from Certivox, Dublin, Ireland" << endl;
cout << "Full C++ source code and MIRACL multiprecision library available" << endl;
cout << "Email to mscott@indigo.ie for details" << endl;
return 0;
}
gprime(1000);
m=5;
ip=0;
k=256;
SD=1;
suppress=FALSE;
fout=FALSE;
dir=FALSE;
three=FALSE;
always=FALSE;
p=0;
while (ip<argc)
{
if (strcmp(argv[ip],"-f")==0)
{
if (p==0)
{
ip++;
s=argv[ip++];
t=0;
eval(t);
p=t;
continue;
}
else
{
cout << "Error in command line" << endl;
return 0;
}
}
if (strcmp(argv[ip],"-s")==0)
{
ip++;
suppress=TRUE;
continue;
}
if (strcmp(argv[ip],"-t")==0)
{
ip++;
three=TRUE;
continue;
}
if (strcmp(argv[ip],"-d")==0)
{
ip++;
dir=TRUE;
continue;
}
if (strncmp(argv[ip],"-K",2)==0)
{
k=argv[ip]+2;
ip++;
continue;
}
if (strncmp(argv[ip],"-D",2)==0)
{
SD=atol(argv[ip]+2);
ip++;
continue;
}
if (strncmp(argv[ip],"-P",2)==0)
{
m=atoi(argv[ip]+2);
ip++;
continue;
}
if (strncmp(argv[ip],"-IEEE",5)==0)
{
always=TRUE;
ip++;
continue;
}
if (strcmp(argv[ip],"-o")==0)
{
ip++;
fout=TRUE;
ofile.open(argv[ip++]);
continue;
}
if (p==0) p=argv[ip++];
else
{
cout << "Error in command line" << endl;
return 0;
}
}
if (!prime(p))
{
int incr=0;
cout << "That number is not prime!" << endl;
if (dir)
{
cout << "Looking for next lower prime" << endl;
p-=1; incr++;
while (!prime(p)) { p-=1; incr++; }
cout << "Prime P = P-" << incr << endl;
}
else
{
cout << "Looking for next higher prime" << endl;
p+=1; incr++;
while (!prime(p)) { p+=1; incr++; }
cout << "Prime P = P+" << incr << endl;
}
cout << "Prime P = " << p << endl;
}
if (p<100)
{
cout << "Prime is too small - use another method!" << endl;
return 0;
}
if (bits(p)>2048)
{
cout << "Prime is too big - sorry" << endl;
return 0;
}
Big W,V,K,r1,r2,ord,rmin;
if (k==0) rmin=1;
else rmin=(p-2*sqrt(p))/k;
if (rmin==0)
{
cout << "Bad k co-factor value" << endl;
return 0;
}
W=sqrt(p)+1;
K=(W*W)/rmin;
if (!suppress) cout << "P mod 8 = " << p%8 << endl;
if (!suppress) cout << "P is " << bits(p) << " bits long" << endl;
if (!suppress) cout << "precomputations..." << endl;
mirexit();
if (m<4) m=4;
precision=(1<<m);
mip=mirsys(precision+2,0); // restart with new precision
setprecision(m);
if (!suppress) cout << "precision in bits = " << precision*MIRACL << endl;
gprime(65536);
mip->RPOINT=ON;
Complex lam;
Float Fi2[7];
Float pi24;
pi24=fpi()/24;
lam=exp(Complex((Float)0,pi24));
Fi2[0]=1;
Fi2[2]=reciprocal(nroot((Float)2,3)); // pow((Float)2,Float(-1,3));
Fi2[3]=reciprocal(sqrt((Float)2)); // pow((Float)2,Float(-1,2));
Fi2[6]=(Float)1/2;
if (!suppress) cout << "finding a curve..." << endl;
for (D=SD;;D++)
{
if (three && D==3) continue;
if (!isaD(D,p%8,K)) continue;
if (jacobi(p-(Big)D,p)==-1) continue;
good=TRUE;
// A.14.2.3
for (i=1;;i++)
{
unsigned long sp=mip->PRIMES[i];
if (D==sp || sp*sp>D) break;
if (D%sp==0 && jacobi(p,(Big)sp)==-1)
{
good=FALSE;
break;
}
}
if (!good) continue;
if (!isacm(p,D,W,V)) continue;
r1=p+1+W;
r2=p+1-W;
if (k==0) ord=r1;
else
{
ord=trial_divide(r1);
if (!prime(ord) && r1%k==0) ord=r1/k;
}
if (ord==1) ord=r1;
if (ord>=rmin && (k==0 || prime(ord)))
get_curve(lam,Fi2,ofile,r1,r2,ord,D,p,W,m,always);
if (k==0) ord=r2;
else
{
ord=trial_divide(r2);
if (!prime(ord) && r2%k==0) ord=r2/k;
}
if (ord==1) ord=r2;
if (ord>=rmin && (k==0 || prime(ord)))
get_curve(lam,Fi2,ofile,r2,r1,ord,D,p,W,m,always);
if (D==1)
{
r1=p+1+V;
r2=p+1-V;
if (k==0) ord=r1;
else
{
ord=trial_divide(r1);
if (!prime(ord) && r1%k==0) ord=r1/k;
}
if (ord==1) ord=r1;
if (ord>=rmin && (k==0 || prime(ord)))
get_curve(lam,Fi2,ofile,r1,r2,ord,D,p,W,m,always);
if (k==0) ord=r2;
else
{
ord=trial_divide(r2);
if (!prime(ord) && r2%k==0) ord=r2/k;
}
if (ord==1) ord=r2;
if (ord>=rmin && (k==0 || prime(ord)))
get_curve(lam,Fi2,ofile,r2,r1,ord,D,p,W,m,always);
}
if (D==3)
{
r1=p+1+(W+3*V)/2;
r2=p+1-(W+3*V)/2;
if (k==0) ord=r1;
else
{
ord=trial_divide(r1);
if (!prime(ord) && r1%k==0) ord=r1/k;
}
if (ord==1) ord=r1;
if (ord>=rmin && (k==0 || prime(ord)))
get_curve(lam,Fi2,ofile,r1,r2,ord,D,p,W,m,always);
if (k==0) ord=r2;
else
{
ord=trial_divide(r2);
if (!prime(ord) && r2%k==0) ord=r2/k;
}
if (ord==1) ord=r2;
if (ord>=rmin && (k==0 || prime(ord)))
get_curve(lam,Fi2,ofile,r2,r1,ord,D,p,W,m,always);
r1=p+1+(W-3*V)/2;
r2=p+1-(W-3*V)/2;
if (k==0) ord=r1;
else
{
ord=trial_divide(r1);
if (!prime(ord) && r1%k==0) ord=r1/k;
}
if (ord==1) ord=r1;
if (ord>=rmin && (k==0 || prime(ord)))
get_curve(lam,Fi2,ofile,r1,r2,ord,D,p,W,m,always);
if (k==0) ord=r2;
else
{
ord=trial_divide(r2);
if (!prime(ord) && r2%k==0) ord=r2/k;
}
if (ord==1) ord=r2;
if (ord>=rmin && (k==0 || prime(ord)))
get_curve(lam,Fi2,ofile,r2,r1,ord,D,p,W,m,always);
}
}
cout << "No satisfactory curve found" << endl;
return 0;
}