www.pudn.com > miracl.zip > CM.CPP


/* 
 * 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 
 * 
 * Note that less precision (one-third) is needed if D is not divisible by 3 
 * See Lay & Zimmer "Constructing Elliptic curves with Given Group Order over  
 * Large Finite Fields" 
 * 
 * Uses functions from the MIRACL multiprecision library, specifically 
 * classes:- 
 * Flash   - Big floating point (actually floating slash - but looks like  
 *                               floating point) 
 * Complex - Big Complex flash 
 * Big     - Big integer 
 * ZZn     - Big integers mod an integer 
 * FPoly   - Big Flash polynomial 
 * Poly    - Big ZZn polynomial 
 * 
 * Written by Mike Scott, Dublin, Ireland. March 1998  
 * 
 * Full MIRACL source is available from  
 * ftp.computing.dcu.ie/pub/crypto/miracl.zip 
 * 
 * MIRACL is a shareware source code product. 
 * However it is free for educational and non-profit making use 
 * Queries to mike@computing.dcu.ie 
 * Web page http://indigo.ie/~mscott 
 */ 
 
#include  
#include  
#include  
#include  
#include  
#include "comflash.h" 
#include "fpoly.h" 
#include "poly.h" 
 
using namespace std; 
 
miracl *mip; 
 
FPoly T;  // Reduced class Polynomial.  
static char *s; 
BOOL fout,suppress; 
 
// F(z) Function A.13.3 
 
Complex Fz(Complex z) 
{ 
    Complex t; 
    int sign=1; 
    Complex sum=(Flash)1; 
 
    if (z.iszero()) return sum; 
 
    Complex zi=z; 
    Complex zj=z*z; 
    Complex r=z; 
    Complex z3=zj*z; 
 
    forever 
    { 
        if (zi.iszero() && zj.iszero()) break;    
        t=zi+zj; 
        if (sign) sum-=t; 
        else      sum+=t; 
 
        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) 
{ 
    Complex t,theta24,theta,theta2; 
    Flash sd; 
    Big D=A*C-B*B; 
    sd=-sqrt((Flash)D); 
 
    t=Complex(sd*pi()/(24*A),(pi()*B)/(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((Flash)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;  
} 
 
// A.13.3 
 
void class_poly(Complex& lam,Flash *Fi2,Big A,Big B,Big C,Big D,BOOL conj) 
{ 
    Big ac,l,t; 
    int i,j,k,g,e,m,n,dm8,a2,c2; 
    Complex cinv; 
 
    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),k),g); 
 
 // 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((Flash)1,2); 
        F.addterm(-2*real(cinv),1); 
        F.addterm(real(cinv)*real(cinv)+imaginary(cinv)*imaginary(cinv),0); 
    } 
    else  
    { // t-cinv 
        F.addterm((Flash)1,1); 
        F.addterm(-real(cinv),0); 
    } 
    T=T*F;    // accumulate Polynomial 
} 
 
// A.13.2 
 
int groups(Complex& lam,Flash *Fi2,Big D,BOOL doit,Flash& sigma) 
{ 
    Big s,t,A,C,B,lim; 
    int cn=0; 
    s=sqrt(D/3); 
    sigma=0; 
    for (B=0;B<=s;B+=1) 
    { 
// cout << "B= " << B << " s= " << s << endl; 
        t=D+B*B; 
        lim=sqrt(t); 
        A=2*B; 
        if (A==0) A+=1; 
        for(;;) 
        { 
            while (t%A!=0)  
            { 
                A+=1; 
                if (A>lim) break; 
            } 
 
            if (A>lim) break; 
            C=t/A; 
            
            if (gcd(gcd(A,2*B),C)==1) 
            { // output more class group members 
                BOOL conj; 
                if (2*B>0 && C>A && A>2*B)  
                {  
                    conj=TRUE; 
                    cn+=2; 
                    if (doit) 
                    {  
                        if (!suppress) cout << ".." << flush;  
                    }   
//                    else sigma+=(Flash)2/(Flash)A; 
                } 
                else 
                { 
                    conj=FALSE; 
                    cn+=1; 
                    if (doit) 
                    {    
                        if (!suppress) cout << "." << flush;  
                    } 
//                    else sigma+=(Flash)1/(Flash)A; 
                }  
                if (doit) class_poly(lam,Fi2,A,B,C,D,conj); 
            } 
            A+=1; 
        }         
    } 
    return cn;         // class number 
} 
 
// check congruence conditions A14.2.1 
 
BOOL isaD(int d,int pm8,Big k) 
{ 
    int i,dm8; 
    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,int D,Big &W,Big &V) 
{ 
    Big B2,A,B,C,t,X,Y,ld,delta; 
    B=sqrt(p-D,p); 
    A=p; 
    C=(B*B+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 in order is prime) 
// A.14.4 
 
BOOL get_curve(Complex& lam,Flash *Fi2,ofstream& ofile, Big r, Big other_r,Big ord, int D, Big p, Big W) 
{ 
    Poly polly; 
    Big A0,B0,k; 
    BOOL unstable; 
    char c; 
    int i,d,terms,class_number,precision,lh; 
    Flash sigma; 
    BOOL pord=prime(ord); 
 
    k=r/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; 
        cout << "k= " << k << endl; 
    } 
 
    class_number=groups(lam,Fi2,D,FALSE,sigma); 
//  get_mip()->RPOINT=ON; 
//  cout << "sigma= " << sigma << endl; 
//    precision=(int)3.322*((1.364*todouble(sigma)*sqrt((double)D))+class_number/4+5); 
//    if (D%2!=0) 
//    { 
//        lh=0; d=D; while ((d/=2)!=0) lh++; precision=(precision+class_number*lh)/2;          
//    } 
//    else if (D%3!=0) 
//    { 
//        if (D%8==7) {precision/=47; precision+=1;} 
//    } 
//    precision/=MIRACL; 
//    if (precision<32) precision=32; 
     
    cout << "class number= " << class_number << endl; 
 
//    cout << "over(?)-estimated precision= " << precision << 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) 
    { 
        Flash f,rem; 
        T.clear(); 
        T.addterm(1,0);    
        if (!suppress) cout << "constructing polynomial"; 
        groups(lam,Fi2,D,TRUE,sigma); 
        terms=degree(T); 
        unstable=FALSE; 
        for (i=terms;i>=0;i--) 
        { 
            f=T.coeff(i); 
            if (f>0) 
                 f+=Flash(1,10000); 
            else f-=Flash(1,10000); 
            polly.addterm((ZZn)f.trunc(&rem),i); 
            if (fabs(rem)>Flash(1,100))  
            { 
                unstable=TRUE;  
                break;  
            } 
        } 
        T.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; 
    } 
 
    ECn pt,G; 
    Big a,b,x,y; 
    Big w,eps; 
    int at; 
    Poly g; 
 
    forever 
    { 
        if (D!=1 && D!=3) 
        { 
            if (!suppress) cout << "Factoring polynomial of degree " << degree(polly) << " ....." << endl; 
            if (W%2==0) 
            { 
                ZZn V; 
                g=factor(polly,1); 
                V=-g.coeff(0); 
                V=pow(V,24/(igcd(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(polly,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; 
                    }      
                } 
            } 
        } 
 
// 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; 
// 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 ) 
        { 
//            polly=polly/g; 
//            if (degree(polly)>0) 
//            { 
                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; 
        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 # 
 
#define TIMES '*' 
#define RAISE '#' 
 
void eval_power (Big& oldn,Big& n,char op) 
{ 
        int i; 
        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=atol(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; 
    int i,ip,k,D,SD,precision; 
    ofstream ofile; 
 
    mip=mirsys(64,0); 
    Big p,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 " << endl; 
      cout << "OR" << endl; 
      cout << "cm -f " << endl; 
      cout << "e.g. cm -f 2#192-2#64-1" << endl; 
      cout << "To suppress the commentary, use flag -s" << 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 " << 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, use e.g. flag -P64 (default -P32)" << endl; 
      cout << "If program fails, try again with double precision" << endl;   
      cout << "e.g. cm -f 2#224-2#96+1 -k12 -D400000 -P64 -o common.ecs" << endl; 
      cout << "\nFreeware from Shamus Software, 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); 
    precision=32; 
    ip=0; 
    k=256; 
    SD=1; 
    suppress=FALSE; 
    fout=FALSE; 
    dir=FALSE; 
    p=0; 
    while (ip1024) 
    { 
        cout << "Prime is too big - sorry" << endl; 
        return 0; 
    } 
 
    mirexit(); 
 
    if (precision<16) precision=16; 
 
    mip=mirsys(precision,0);     // restart with new precision 
    gprime(100000); 
 
    Big W,V,K,r1,r2,ord,rmin; 
    Complex lam; 
 
    Flash Fi2[7]; 
    Flash pi24; 
     
    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; 
 
    pi24=pi()/(Flash)24;  
    lam=exp(Complex((Flash)0,pi24)); 
 
    Fi2[0]=1; 
    Fi2[2]=pow((Flash)2,Flash(-1,3)); 
    Fi2[3]=pow((Flash)2,Flash(-1,2)); 
    Fi2[6]=Flash(1,2); 
 
    if (!suppress) cout << "finding a curve..." << endl; 
 
    for (D=SD;;D++) 
    { 
        if (!isaD(D,p%8,K)) continue; 
        if (jacobi(p-D,p)==-1) continue; 
        good=TRUE; 
// A.14.2.3 
        for (i=1;;i++) 
        { 
            int 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 (ord==1) ord=r1; 
        if (ord>rmin && (k==0 || prime(ord))) get_curve(lam,Fi2,ofile,r1,r2,ord,D,p,W); 
 
        if (k==0) ord=r2; 
        else      ord=trial_divide(r2); 
        if (ord==1) ord=r2; 
        if (ord>rmin && (k==0 || prime(ord))) get_curve(lam,Fi2,ofile,r2,r1,ord,D,p,W); 
 
        if (D==1) 
        { 
            r1=p+1+V; 
            r2=p+1-V; 
            if (k==0) ord=r1; 
            else      ord=trial_divide(r1); 
            if (ord==1) ord=r1; 
            if (ord>rmin && (k==0 || prime(ord))) get_curve(lam,Fi2,ofile,r1,r2,ord,D,p,W); 
 
            if (k==0) ord=2; 
            else      ord=trial_divide(r2); 
            if (ord==1) ord=r2; 
            if (ord>rmin && (k==0 || prime(ord))) get_curve(lam,Fi2,ofile,r2,r1,ord,D,p,W); 
             
        } 
        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 (ord==1) ord=r1; 
            if (ord>rmin && (k==0 || prime(ord))) get_curve(lam,Fi2,ofile,r1,r2,ord,D,p,W); 
 
            if (k==0) ord=r2; 
            else ord=trial_divide(r2); 
            if (ord==1) ord=r2; 
            if (ord>rmin && (k==0 || prime(ord))) get_curve(lam,Fi2,ofile,r2,r1,ord,D,p,W); 
 
            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 (ord==1) ord=r1; 
            if (ord>rmin && (k==0 || prime(ord))) get_curve(lam,Fi2,ofile,r1,r2,ord,D,p,W); 
 
            if (k==0) ord=r2; 
            else ord=trial_divide(r2); 
            if (ord==1) ord=r2; 
            if (ord>rmin && (k==0 || prime(ord))) get_curve(lam,Fi2,ofile,r2,r1,ord,D,p,W); 
        } 
    } 
    cout << "No satisfactory curve found" << endl; 
    return 0; 
}