// // Program to generate Modular Polynomials mod p, as required for fast // implementations of the Schoof-Elkies-Atkins algorithm // for counting points on an elliptic curve Y^2=X^3 + A.X + B mod p // // Implemented entirely from the description provided in: // 1. "Distributed Computation of the number of points on an elliptic curve // over a finite prime field", Buchmann, Mueller, & Shoup, SFB 124-TP D5 // Report 03/95, April 1995, Universitat des Saarlandes, and // 2. "Counting the number of points on elliptic curves over finite fields // of characteristic greater than three", Lehmann, Maurer, Mueller & Shoup, // Proc. 1st Algorithmic Number Theory Symposium (ANTS), pp 60-70, 1994 // // Both papers are available on the Web from Volker Mueller's home page // www.informatik.th-darmstadt.de/TI/Mitarbeiter/vmueller.html // // Also strongly recommended is the book // // 3. "Elliptic Curves in Cryptography" // by Blake, Seroussi and Smart, London Mathematical Society Lecture Note // Series 265, Cambridge University Press. ISBN 0 521 65374 6 // // The programs's output for each prime in the range is a bivariate polynomial // in X and Y, which can optionally be stored to disk. Some informative output // is generated just to convince you that it is still working, and to give an // idea of progress. // // This program is a composite of the "mueller" and "process" applications. // It generates the modular polynomials, pre-reduced wrt to a specified prime // modulus. This may be the only feasible way to do it on a small computer // system, for which the "mueller" application is too resource intensive. // // Although less memory intensive than "mueller", problems may still arise. // See mueller.cpp for a description of the -s2, -s3 and -s6 flags // // .pol file format // ,,<1st coef>,<1st power of X>,<1st power of Y>,<2nd coef>... // Each polynomial ends wih zero powers of X and Y. // // For example // modpol -d -f 2#512 0 500 -o test512.pol // // If appending to a file with the -a flag, make sure and use the same // prime modulus as used to create the file originally - no check is made // // generates the test512.pol file directly, given the range 0 to 500 and // using the first prime modulus it can find less than 2^512. This file can // then be used directly with the "sea" application // #include #include #include #include #include "ps_zzn.h" // power series class using namespace std; extern int psN; // power series are modulo x^psN BOOL fout; BOOL append; Miracl precision=20; ofstream mueller; // Code to parse formula in command line // 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 Big tt; static char *ss; 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 (void) { 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 (*ss==' ') ss++; if (*ss=='-') /* Unary minus */ { ss++; minus=1; } else minus=0; while (*ss==' ') ss++; if (*ss=='(' || *ss=='[' || *ss=='{') /* Number is subexpression */ { ss++; eval (); n=tt; } else /* Number is decimal value */ { for (i=0;ss[i]>='0' && ss[i]<='9';i++) ; if (!i) /* No digits found */ { cout << "Error - invalid number" << endl; exit (20); } op=ss[i]; ss[i]=0; n=atoi(ss); ss+=i; *ss=op; } if (minus) n=-n; do op=*ss++; 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]); tt=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; } // // When summing the Zk^n 0<=k " << endl; cout << "OR" << endl; cout << "modpol " << endl; cout << "where the numbers define a range. The program will find the" << endl; cout << "Modular Polynomials for primes in this range wrt the specified modulus" << endl; cout << "To input P in Hex, precede with -h" << endl; cout << "To search downwards for a prime, use flag -d" << endl; cout << "NOTE: Program is both memory and time intensive" << endl; cout << "To skip \"difficult\" primes, use -s2, -s3 or -s6" << endl; cout << "where -s2 skips most and -s6 skips least" << endl; cout << "To output polynomials to a file use flag -o " << endl; #if defined(unix) cout << "e.g. modpol -f 2^192-2^64-1 0 150 -o p192.pol" << endl; #else cout << "e.g. modpol -f 2#192-2#64-1 0 150 -o p192.pol" << endl; #endif cout << "Alternatively to append to a file use flag -a " << endl; cout << "See source code file for details" << endl; cout << "\nFreeware from Certivox, Dublin, Ireland" << endl; cout << "Full C++ source code and MIRACL multiprecision library available" << endl; cout << "email mscott@indigo.ie" << endl; return 0; } if (argc<3) { cout << "Error in command line" << endl; return 0; } ip=0; skip=12; fout=FALSE; dir=gotP=gothi=gotlo=FALSE; append=FALSE; Base=10; while (ipIOBASE=Base; p=argv[ip++]; mip->IOBASE=10; gotP=TRUE; continue; } if (!gotlo) { lo=atoi(argv[ip++]); gotlo=TRUE; continue; } if (!gothi) { hi=atoi(argv[ip++]); gothi=TRUE; continue; } cout << "Error in command line" << endl; return 0; } if (!gothi || !gotlo) { cout << "Error in command line" << endl; return 0; } if (lo>hi || hi>1000) { cout << "Invalid range specified" << endl; return 0; } gprime(1000); // get all primes < 1000 for (i=0;;i++) { sp=mip->PRIMES[i]; primes[i]=sp; if (sp==0) break; } 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; } cout << "P mod 24 = " << p%24 << endl; cout << "P is " << bits(p) << " bits long" << endl; if (fout && !append) mueller << p << endl; modulo(p); // Set prime modulus for ZZn type for (j=0,i=1;;i++) // lets go { sp=primes[i]; if (sp==0) break; if (sphi) break; for (s=1;;s++) if (s*(sp-1)%12==0) break; if (s>=skip) continue; j++; cout << endl; cout << "prime " << j << " = " << sp << " (s=" << s << ")" << endl; mueller_pol(sp,s); } cout << endl; if (j==0) cout << "No primes processed in the specified range" << endl; if (j==1) cout << "One prime processed in the specified range" << endl; if (j>1) cout << j << " primes processed in the specified range" << endl; return 0; }