📄 modpol.cpp
字号:
//
// 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
// <modulus>,<prime>,<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
//
// Copyright Shamus Software Ltd., 1999
//
#include <iostream>
#include <fstream>
#include <cstring>
#include <iomanip>
#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 #
//
#define TIMES '*'
#define RAISE '#'
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<L (1. page 3, top), most terms cancel out,
// leaving only every L-th term
//
Ps_ZZn phase(Ps_ZZn &z, int L,int off)
{ // Keep L times every L-th element in the Power Series
Ps_ZZn w;
term_ps_zzn *pos=NULL;
int i,k;
k=off+z.first();
for (i=off;i<psN;i+=L,k+=L)
{
pos=w.addterm(L*z.coeff(k),k,pos);
}
return w;
}
void mueller_pol(int L,int s)
{ // Calculate Modular Polynomial for prime L
// s is smallest int such that s*(L-1)/12 is integer
int i,j,n,v;
Ps_ZZn klein,flt,zlt,x,y,z,f,jlt[500],c[1000],ps[1000];
// First calculate v, and hence psN - number of terms in Power Series
// 2. page 5 1st para
cout << "preliminaries" << flush;
v=s*(L-1)/12;
psN=v+2;
//
// calculate Klein=j(tau) from its definition
// Numerator x...
//
// 1. page 2
//
for (n=1;n<psN;n++)
{
Ps_ZZn a,b,t;
a.addterm((ZZn)n*n*n,n); // a=n^3*x^n
b.addterm((ZZn)1,0);
b.addterm((ZZn)-1,n);
t=a/b;
x+=t;
}
x=(ZZn)240*x;
x.addterm((ZZn)1,0);
x=pow(x,3);
// Denominator y...
y=eta();
y=pow(y,24);
klein=x/y;
cout << "." << flush;
klein.divxn(1); // divides power series by x^parameter
psN*=L;
// cout << "psN= " << psN << endl;
klein=power(klein,L); // this substitutes x^L for x in the power series
cout << "." << flush;
// Find Fl(t), Numerator z= Dedekind eta function
// This has a simple repeating pattern of coefficients, and so costs nothing
// to calculate 1. page 2 bottom
z=eta();
// Denominator y=n(Lt)...
y=power(z,L);
y=(ZZn)1/y; // y has only psN/L terms.
cout << "." << flush;
z*=y; // z has psN terms
flt=pow(z,2*s); // ^2*s - expensive
cout << "." << flush;
flt.divxn(v); // times x^-v
ZZn w=pow((ZZn)L,s);
y=power(flt,L);
cout << "." << flush;
zlt=w/y; // l^s/Fl(lt) - cheap - psN/L terms in power series
cout << "." << endl;
y.clear();
x.clear();
ps[0]=L+1;
//
// Calculate Power Sums. Note that f and flt are very large objects
// with psN terms. Most other power series are in "compressed" form
// with "only" psN/L terms
//
// 1. page 3
//
cout << "Power Sum = " << flush;
z=1;
f=1;
for (i=1;i<=L+1;i++)
{
cout << setw(3) << i << flush;
f*=flt; // expensive. In place multiplication discourages C++
// from moving large objects about
z=z*zlt; // cheap
ps[i]=phase(f,L,(i*v)%L)+z;
cout << "\b\b\b" << flush;
}
cout << setw(3) << L+1 << endl;
f.clear();
z.clear();
flt.clear();
zlt.clear();
cout << "Coefficient = " << flush;
c[0]=1;
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -