source: git/Singular/LIB/atkins.lib @ 3d4a5a

spielwiese
Last change on this file since 3d4a5a was 3d4a5a, checked in by Gerhard Pfister <pfister@…>, 17 years ago
eine Zeile in den Hauptprozedur zugefuegtCVS: ---------------------------------------------------------------------- git-svn-id: file:///usr/local/Singular/svn/trunk@9654 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 35.0 KB
Line 
1///////////////////////////////////////////////////////////////////////////////
2version="$Id: atkins.lib,v 1.2 2007-01-09 12:42:22 pfister Exp $";
3category="Teaching";
4info="
5LIBRARY:  atkins.lib     Procedures for teaching cryptography
6AUTHOR:                  Stefan Steidel, Stefan.Steidel@gmx.de
7
8NOTE: The library contains auxiliary procedures to compute the elliptic
9       curve primality test of Atkin and the Atkin's Test itself.
10       The library is intended to be used for teaching purposes but not
11       for serious computations. Sufficiently high printLevel allows to
12       control each step, thus illustrating the algorithms at work.
13
14
15PROCEDURES:
16  new(L,D)                     checks if number D already exists in list L
17  bubblesort(L)                sorts elements of the list L
18  disc(N,k)                    generates a list of negative discriminants
19  Cornacchia(d,p)              computes solution (x,y) for x^2+d*y^2=p
20  CornacchiaModified(D,p)      computes solution (x,y) for x^2+|D|*y^2=4p
21  maximum(L)                   computes the maximal number contained in L
22  cmod(x,y)                    computes x mod y
23  sqr(w,k)                     computes the square root of w
24  e(z,k)                       computes exp(z)
25  jot(t,k)                     computes the j-invariant of t
26  round(r)                     rounds r to the nearest number out of Z
27  HilbertClassPolynomial(D,k)  computes the Hilbert Class Polynomial
28  RootsModp(p,P)               computes roots of the polynomial P modulo p
29  w(D)                         computes the number of units in Q(sqr(D))
30  Atkin(N,K,B)                 tries to prove that N is prime
31
32";
33
34LIB "crypto.lib";
35LIB "general.lib";
36LIB "ntsolve.lib";
37LIB "inout.lib";
38
39///////////////////////////////////////////////////////////////////////////////
40
41proc new(list L, number D)
42"USAGE: new(L,D);
43RETURN:  1, if D does not already exist in L,
44        -1, if D does already exist in L
45EXAMPLE:example new; shows an example
46"
47{
48  number a=1;                // a=1 bedeutet: D noch nicht in L vorhanden
49  int i;
50  for(i=1;i<=size(L);i++)
51  {
52    if(D==L[i])
53    {
54      a=-1;            // a=-1 bedeutet: D bereits in L vorhanden
55      break;
56    }
57  }
58 return(a);
59}
60example
61{ "EXAMPLE:"; echo = 2;
62    ring r = 0,x,dp;
63    list L=8976,-223456,556,-778,3,-55603,45,766677;
64    number D=-55603;
65    new(L,D);
66}
67
68proc bubblesort(list L)
69"USAGE: bubblesort(L);
70RETURN: list L, sort in decreasing order
71EXAMPLE:example bubblesort; shows an example
72"
73{
74  number b;
75  int n,i,j;
76  while(j==0)
77  {
78    i=i+1;
79    j=1;
80    for(n=1;n<=size(L)-i;n++)
81    {
82      if(L[n]<L[n+1])
83      {
84        b=L[n];
85        L[n]=L[n+1];
86        L[n+1]=b;
87        j=0;
88      }
89    }
90  }
91  return(L);
92}
93example
94{ "EXAMPLE:"; echo = 2;
95    ring r = 0,x,dp;
96    list L=-567,-233,446,12,-34,8907;
97    bubblesort(L);
98}
99
100
101
102proc disc(number N, int k)
103"USAGE: disc(N,k);
104RETURN: list L of negative discriminants D, sort in decreasing order
105ASSUME: D<0, D kongruent 0 or 1 modulo 4 and |D|<4N
106NOTE:   D=b^2-4*a, where 0<=b<=k and intPart((b^2)/4)+1<=a<=k for each b
107EXAMPLE:example disc; shows an example
108"
109{
110  list L=-3,-4,-7;
111  number D;
112  number B;
113  int a,b;
114  for(b=0;b<=k;b++)
115  {
116    B=b^2;
117    for(a=int(intPart(B/4))+1;a<=k;a++)
118    {
119      D=-4*a+B;
120      if((D<0)&&((D mod 4)!=2)&&((D mod 4)!=3)&&(absValue(D)<4*N)&&(new(L,D)==1))
121      {
122        L[size(L)+1]=D;
123      }
124    }
125  }
126  L=bubblesort(L);
127  return(L);
128}
129example
130{ "EXAMPLE:"; echo = 2;
131    ring R = 0,x,dp;
132    disc(2003,50);
133}
134
135
136
137proc Cornacchia(number d, number p)
138"USAGE: Cornacchia(d,p);
139RETURN: x,y such that x^2+d*y^2=p with p prime,
140        -1, if the Diophantine equation has no solution,
141         0, if the parameters are wrong selected
142ASSUME: 0<d<p
143EXAMPLE:example Cornacchia; shows an example
144"
145{
146  if((d<0)||(p<d))            // (0)[Test if assumptions well-defined]
147  {
148    return(0);
149    // ERROR("Parameters wrong selected! It has to be 0<d<p!");
150  }
151  else
152  {
153    number k,x(0),a,b,l,r,c,i;
154
155    k=Jacobi(-d,p);          // (1)[Test if residue]
156    if(k==-1)
157    {
158      return(-1);
159      // ERROR("The Diophantine equation has no solution!");
160    }
161    else
162    {
163       x(0)=squareRoot(-d,p);   // (2)[Compute square root]
164       if((p/2>=x(0))||(p<=x(0)))
165       {
166           x(0)=-x(0) mod p;
167       }
168       a=p;
169       b=x(0);
170       l=intRoot(p);
171       while(b>l)       // (3)[Euclidean algorithm]
172       {
173          r=a mod b;
174          a=b;
175          b=r;
176       }
177       c=(p-b^2)/d;     // (4)[Test solution]
178       i=intRoot(c);
179       if((((p-b^2) mod d)!=0)||(c!=i^2))
180       {
181          return(-1);
182       }
183       else
184       {
185          list L=b,i;
186          return(L);
187       }
188    }
189  }
190}
191example
192{ "EXAMPLE:"; echo = 2;
193    ring R = 0,x,dp;
194    Cornacchia(55,9551);
195}
196
197
198
199proc CornacchiaModified(number D, number p)
200"USAGE: CornacchiaModified(D,p);
201RETURN: x,y such that x^2+|D|*y^2=p with p prime,
202        -1, if the Diophantine equation has no solution,
203         0, if the parameters are wrong selected
204ASSUME: D<0, D kongruent 0 or 1 modulo 4 and |D|<4p
205EXAMPLE:example CornacchiaModified; shows an example
206"
207{
208   if((D>=0)||((D mod 4)==2)||((D mod 4)==3)||(absValue(D)>=4*p))
209   {// (0)[Test if assumptions well-defined]
210      return(0);
211      // ERROR("Parameters wrong selected!");
212   }
213   else
214   {
215      if(p==2)                          // (1)[Case p=2]
216      {
217         if((D+8)==intRoot(D+8)^2)
218         {
219            return(intRoot(D+8),1);
220         }
221         else
222         {
223            return(-1);
224            // ERROR("The Diophantine equation has no solution!");
225         }
226      }
227      else
228      {
229         number k,x(0),a,b,l,r,c;
230         k=Jacobi(D,p);                // (2)[Test if residue]
231         if(k==-1)
232         {
233            return(-1);
234            // ERROR("The Diophantine equation has no solution!");
235         }
236         else
237         {
238            x(0)=squareRoot(D,p);    // (3)[Compute square root]
239            if((x(0) mod 2)!=(D mod 2))
240            {
241               x(0)=p-x(0);
242            }
243            a=2*p;
244            b=x(0);
245            l=intRoot(4*p);
246            while(b>l)     // (4)[Euclidean algorithm]
247            {
248               r=a mod b;
249               a=b;
250               b=r;
251            }
252            c=(4*p-b^2)/absValue(D);// (5)[Test solution]
253            if((((4*p-b^2) mod absValue(D))!=0)||(c!=intRoot(c)^2))
254            {
255               return(-1);
256               // ERROR("The Diophantine equation has no solution!");
257            }
258            else
259            {
260               list L=b,intRoot(c);
261               return(L);
262            }
263         }
264      }
265   }
266}
267example
268{ "EXAMPLE:"; echo = 2;
269    ring R = 0,x,dp;
270    CornacchiaModified(-107,1319);
271}
272
273
274
275proc pFactor1(number n,int B, list P)
276"USAGE: pFactor1(n,B,P); n to be factorized, B a bound , P a list of primes
277RETURN: a list of factors of n or the message: no factor found
278NOTE:   Pollard's p-factorization
279        creates the product k of powers of primes (bounded by B)  from
280        the list P with the idea that for a prime divisor p of n p-1|k
281        then p devides gcd(a^k-1,n) for some random a
282EXAMPLE:example pFactor1; shows an example
283"
284{
285      int i;
286      number k=1;
287      number w;
288      while(i<size(P))
289         {
290           i++;
291           w=P[i];
292           if(w>B) {break;}
293           while(w*P[i]<=B)
294              {
295                w=w*P[i];
296              }
297           k=k*w;
298         }
299      number a=random(2,2147483629);
300      number d=gcdN(powerN(a,k,n)-1,n);
301      if((d>1)&&(d<n)){return(d);}
302      return(n);
303}
304example
305{ "EXAMPLE:"; echo = 2;
306   ring R = 0,z,dp;
307   list L=primList(1000);
308   pFactor1(1241143,13,L);
309   number h=10;
310   h=h^30+25;
311   pFactor1(h,20,L);
312}
313
314
315
316proc maximum(list L)
317"USAGE: maximum(list L);
318RETURN: the maximal number contained in list L
319EXAMPLE:example maximum; shows an example
320"
321{
322      number max=L[1];
323
324      int i;
325      for(i=2;i<=size(L);i++)
326         {
327           if(L[i]>max)
328              {
329                max=L[i];
330              }
331         }
332
333      return(max);
334}
335example
336{ "EXAMPLE:"; echo = 2;
337    ring r = 0,x,dp;
338    list L=465,867,1233,4567,776544,233445,2334,556;
339    maximum(L);
340}
341
342
343
344proc cmod(number x, number y)
345"USAGE: cmod(x,y);
346RETURN: x mod y
347ASSUME: x,y out of Z and x,y<=2147483647
348NOTE:   this algorithm is a helping procedure to be able to calculate
349        x mod y with x,y out of Z while working in the complex field
350EXAMPLE:example cmod; shows an example
351"
352{
353      int rest=int(x-y*int(x/y));
354      if(rest<0)
355         {
356           rest=rest+int(y);
357         }
358
359      return(rest);
360}
361example
362{ "EXAMPLE:"; echo = 2;
363    ring r = (complex,30,i),x,dp;
364    number x=-1004456;
365    number y=1233;
366    cmod(x,y);
367}
368
369
370
371proc sqr(number w, int k)
372"USAGE: sqr(w,k);
373RETURN: the square root of w
374ASSUME: w>=0
375NOTE:   k describes the number of decimals being calculated in the real numbers,
376        k, intPart(k/5) are inputs for the procedure "nt_solve"
377EXAMPLE:example sqr; shows an example
378"
379{
380  poly f=var(1)^2-w;
381  def S=basering;
382  ring R=(real,k),var(1),dp;
383  poly f=imap(S,f);
384  ideal I=nt_solve(f,1.1,list(k,int(intPart(k/5))));
385  number c=leadcoef(I[1]);
386  setring S;
387  number c=imap(R,c);
388  return(c);
389}
390example
391{ "EXAMPLE:"; echo = 2;
392    ring R = (real,60),x,dp;
393    number ww=288469650108669535726081;
394    sqr(ww,60);
395}
396
397
398
399proc e(number z, int k)
400"USAGE: e(z,k);
401RETURN: e^z to the order k
402NOTE:   k describes the number of summands being calculated in the exponential power series
403EXAMPLE:example e; shows an example
404"
405{
406  number q=1;
407  number e=1;
408
409  int n;
410  for(n=1;n<=k;n++)
411  {
412    q=q*z/n;
413    e=e+q;
414  }
415  return(e);
416}
417
418example
419{ "EXAMPLE:"; echo = 2;
420    ring r = (real,30),x,dp;
421    number z=40.35;
422    e(z,1000);
423}
424
425
426
427proc jot(number t, int k)
428"USAGE: jot(t,k);
429RETURN: the j-invariant of t
430ASSUME: t is a complex number with positive imaginary part
431NOTE:   k describes the number of summands being calculated in the power series,
432        10*k is input for the procedure "e"
433EXAMPLE:example jot; shows an example
434"
435{
436      number q1,q2,qr1,qi1,tr,ti,m1,m2,f,j;
437
438      number pi=3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989;
439
440      tr=repart(t);
441      ti=impart(t);
442      if(tr==-1/2){qr1=-1;}
443      if(tr==0){qr1=1;}
444      if((tr!=-1/2)&&(tr!=0))
445         {
446           tr=tr-round(tr);
447           qr1=e(2*i*pi*tr,10*k);
448         }
449
450      qi1=e(-pi*ti,10*k);
451      q1=qr1*qi1^2;
452      q2=q1^2;
453
454      int n=1;
455      while(n<=k)
456         {
457           m1=m1+(-1)^n*(q1^(n*(3*n-1)/2)+q1^(n*(3*n+1)/2));
458           m2=m2+(-1)^n*(q2^(n*(3*n-1)/2)+q2^(n*(3*n+1)/2));
459           n=n+1;
460         }
461
462      f=q1*((1+m2)/(1+m1))^24;
463
464      j=(256*f+1)^3/f;
465      return(j);
466}
467
468example
469{ "EXAMPLE:"; echo = 2;
470    ring r = (complex,30,i),x,dp;
471    number t=(-7+i*sqr(7,250))/2;
472    jot(t,50);
473}
474
475
476
477proc round(number r)
478"USAGE: round(r);
479RETURN: the nearest number to r out of Z
480ASSUME: r should be a rational or a real number
481EXAMPLE:example round; shows an example
482"
483{
484  number a=absValue(r);
485  number v=r/a;
486
487  number d=10;
488  int e;
489  while(1)
490  {
491    e=e+1;
492    if(a-d^e<0)
493    {
494      e=e-1;
495      break;
496    }
497  }
498
499  number b=a;
500  int k;
501  for(k=0;k<=e;k++)
502  {
503    while(1)
504    {
505      b=b-d^(e-k);
506      if(b<0)
507      {
508        b=b+d^(e-k);
509        break;
510      }
511    }
512  }
513
514  if(b<1/2)
515  {
516    return(v*(a-b));
517  }
518  else
519  {
520    return(v*(a+1-b));
521  }
522}
523example
524{ "EXAMPLE:"; echo = 2;
525    ring R = (real,50),x,dp;
526    number r=7357683445788723456321.6788643224;
527    round(r);
528}
529
530
531
532proc HilbertClassPolynomial(number D, int k)
533"USAGE: HilbertClassPolynomial(D,k);
534RETURN: the monic polynomial of degree h(D) in Z[X] of which jot((D+sqr(D))/2) is a root
535ASSUME: D is a negative discriminant
536NOTE:   k is input for the procedure "jot",
537        5*k is input for the procedure "sqr",
538        10*k describes the number of decimals being calculated in the complex numbers
539EXAMPLE:example HilbertClassPolynomial; shows an example
540"
541{
542      if(D>=0)                                                         // (0)[Test if assumptions well-defined]
543         {
544           ERROR("Parameter wrong selected!");
545         }
546
547      else
548         {
549           def S=basering;
550           ring R=0,x,dp;
551
552           string s1,s2,s3;
553           number a1,b1,t1,g1;
554           number D=imap(S,D);
555           number B=intRoot(absValue(D)/3);
556
557           ring C=(complex,10*k,i),x,dp;
558           number D=imap(S,D);
559
560           poly P=1;                                                   // (1)[Initialize]
561           number b=cmod(D,2);
562           number B=imap(R,B);
563
564           number t,a,g,tau,j;
565           list L;
566
567           int step=2;
568           while(1)
569              {
570                if(step==2)                                            // (2)[Initialize a]
571                   {
572                     t=(b^2-D)/4;
573                     L=b,1;
574                     a=maximum(L);
575                     step=3;
576                   }
577
578                if(step==3)                                            // (3)[Test]
579                   {
580                     if((cmod(t,a)!=0))
581                        {
582                          step=4;
583                        }
584
585                     else
586                        {
587                          s1=string(a);
588                          s2=string(b);
589                          s3=string(t);
590
591                          setring R;
592                          execute("a1="+s1+";");
593                          execute("b1="+s2+";");
594                          execute("t1="+s3+";");
595                          g1=gcd(gcd(a1,b1),t1/a1);
596                          setring C;
597                          g=imap(R,g1);
598
599                          if(g!=1)
600                             {
601                               step=4;
602                             }
603
604                          else
605                             {
606                               tau=(-b+i*sqr(absValue(D),5*k))/(2*a);
607                               j=jot(tau,k);
608                               if((a==b)||(a^2==t)||(b==0))
609                                  {
610                                    P=P*(var(1)-repart(j));
611                                    step=4;
612                                  }
613
614                               else
615                                  {
616                                    P=P*(var(1)^2-2*repart(j)*var(1)+repart(j)^2+impart(j)^2);
617                                    step=4;
618                                  }
619                             }
620                        }
621                   }
622
623                if(step==4)                                            // (4)[Loop on a]
624                   {
625                     a=a+1;
626                     if(a^2<=t)
627                        {
628                          step=3;
629                          continue;
630                        }
631
632                     else
633                        {
634                          step=5;
635                        }
636                   }
637
638                if(step==5)                                            // (5)[Loop on b]
639                   {
640                     b=b+2;
641                     if(b<=B)
642                        {
643                          step=2;
644                        }
645
646                     else
647                        {
648                          break;
649                        }
650                   }
651              }
652
653           matrix M=coeffs(P,var(1));
654
655           list liste;
656           int n;
657           for(n=1;n<=nrows(M);n++)
658              {
659                liste[n]=round(repart(number(M[n,1])));
660              }
661
662           poly Q;
663           int m;
664           for(m=1;m<=size(liste);m++)
665              {
666                Q=Q+liste[m]*var(1)^(m-1);
667              }
668
669           string s=string(Q);
670           setring S;
671           execute("poly Q="+s+";");
672           return(Q);
673         }
674}
675example
676{ "EXAMPLE:"; echo = 2;
677    ring r = 0,x,dp;
678    number D=-23;
679    HilbertClassPolynomial(D,50);
680}
681
682
683
684proc RootsModp(int p, poly P)
685"USAGE: RootsModp(p,P);
686RETURN: list of roots of the polynomial P modulo p with p prime
687ASSUME: p>=3
688NOTE:   this algorithm will be called recursively, and it is understood
689        that all the operations are done in Z/pZ (excepting sqareRoot(d,p))
690EXAMPLE:example RootsModp; shows an example
691"
692{
693      if(p<3)                                                              // (0)[Test if assumptions well-defined]
694         {
695           ERROR("Parameter wrong selected, since p<3!");
696         }
697
698      else
699         {
700           def S=basering;
701           ring R=p,var(1),dp;
702
703           poly P=imap(S,P);
704           number d;
705           int a;
706           list L;
707
708           poly A=gcd(var(1)^p-var(1),P);                                  // (1)[Isolate roots in Z/pZ]
709           if(subst(A,var(1),0)==0)
710              {
711                L[1]=0;
712                A=A/var(1);
713              }
714
715           if(deg(A)==0)                                                   // (2)[Small degree?]
716              {
717                return(L);
718              }
719
720           if(deg(A)==1)
721              {
722                matrix M=coeffs(A,var(1));
723                L[size(L)+1]=-leadcoef(M[1,1])/leadcoef(M[2,1]);
724                setring S;
725                list L=imap(R,L);
726                return(L);
727              }
728
729           if(deg(A)==2)
730              {
731                matrix M=coeffs(A,var(1));
732                d=leadcoef(M[2,1])^2-4*leadcoef(M[1,1])*leadcoef(M[3,1]);
733
734                ring T=0,var(1),dp;
735                number d=imap(R,d);
736                number e=squareRoot(d,p);
737                setring R;
738                number e=imap(T,e);
739
740                L[size(L)+1]=(-leadcoef(M[2,1])+e)/(2*leadcoef(M[3,1]));
741                L[size(L)+1]=(-leadcoef(M[2,1])-e)/(2*leadcoef(M[3,1]));
742                setring S;
743                list L=imap(R,L);
744                return(L);
745              }
746
747           poly B=1;                                                       // (3)[Random splitting]
748           poly C;
749           while((deg(B)==0)||(deg(B)==deg(A)))
750              {
751                a=random(0,p-1);
752                B=gcd((var(1)+a)^((p-1)/2)-1,A);
753                C=A/B;
754              }
755
756           setring S;                                                      // (4)[Recurse]
757           poly B=imap(R,B);
758           poly C=imap(R,C);
759           list l=L+RootsModp(p,B)+RootsModp(p,C);
760           return(l);
761         }
762}
763example
764{ "EXAMPLE:"; echo = 2;
765    ring r = 0,x,dp;
766    poly f=x4+2x3-5x2+x;
767    RootsModp(7,f);
768    poly g=x5+112x4+655x3+551x2+1129x+831;
769    RootsModp(1223,g);
770}
771
772
773
774proc w(number D)
775"USAGE: w(D);
776RETURN: the number of roots of unity in the quadratic order of discriminant D
777ASSUME: D<0 a discriminant kongruent to 0 or 1 modulo 4
778EXAMPLE:example w; shows an example
779"
780{
781  if((D>=0)||((D mod 4)==2)||((D mod 4)==3))
782  {
783    ERROR("Parameter wrong selected!");
784  }
785  else
786  {
787    if(D<-4) {return(2);}
788    if(D==-4){return(4);}
789    if(D==-3){return(6);}
790  }
791}
792example
793{ "EXAMPLE:"; echo = 2;
794    ring r = 0,x,dp;
795    number D=-3;
796    w(D);
797}
798
799
800
801proc Atkin(number N, int K, int B)
802"USAGE: Atkin(N,K,B);
803RETURN:  1, if N is prime,
804        -1, if N is not prime,
805         0, if the algorithm is not applicable, since there are too little discriminants
806ASSUME: N is coprime to 6 and different from 1
807NOTE:   - K/2 is input for the procedure "disc",
808          K is input for the procedure "HilbertClassPolynomial",
809          B describes the number of recursions being calculated
810        - The basis of the the algorithm is the following theorem:
811          Let N be an integer coprime to 6 and different from 1 and E be an
812          ellipic curve modulo N. Assume that we know an integer m and a
813          point P of E(Z/NZ) satisfying the following conditions.
814           (1) There exists a prime divisor q of m such that q>(4-th root(N)+1)^2.
815           (2) m*P=O(E)=(0:1:0).
816           (3) (m/q)*P=(x:y:t) with t element of (Z/NZ)*.
817          Then N is prime.
818EXAMPLE:example Atkin; shows an example
819"
820{
821  if(N==1)           {return(-1);} // (0)[Test if assumptions well-defined]
822  if((N==2)||(N==3)) {return(1);}
823  if(gcdN(N,6)!=1)
824  {
825    if(printlevel>=1) {"ggT(N,6)="+string(gcdN(N,6));pause();}
826    return(-1);
827  }
828  else
829  {
830    int i;                         // (1)[Initialize]
831    int n(i);
832    number N(i)=N;
833    if(printlevel>=1) {"Setze i=0, n=0 und N(i)=N(0)="+string(N(i))+".";pause();}
834
835    // declarations:
836    int j(0),j(1),j(2),j(3),j(4),k;    // running indices
837    list L;                            // all primes smaller than 1000
838    list H;                            // sequence of negative discriminants
839    number D;                          // discriminant out of H
840    list L1,L2,S,S1,S2,R;              // lists of relevant elements
841    list P,P1,P2;                      // elliptic points on E(Z/N(i)Z)
842    number m,q;                        // m=|E(Z/N(i)Z)| and q|m
843    number a,b,j,c;                    // characterize E(Z/N(i)Z)
844    number g,u;                        // g out of Z/N(i)Z, u=Jacobi(g,N(i))
845    poly T;                            // T=HilbertClassPolynomial(D,K)
846    matrix M;                          // M contains the coefficients of T
847
848    if(printlevel>=1) {"Liste H der moeglichen geeigneten Diskriminanten wird berechnet.";}
849    H=disc(N,K/2);
850    if(printlevel>=1) {"H="+string(H);pause();}
851
852    int step=2;
853    while(1)
854    {
855      if(step==2)                  // (2)[Is N(i) small??]
856      {
857        L=5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997;
858        for(j(0)=1;j(0)<=size(L);j(0)++)
859        {
860          if(N(i)==L[j(0)]){return(1);}
861          if(((N(i) mod L[j(0)])==0)&&(N(i)!=L[j(0)]))
862          {
863            if(printlevel>=1) {"N("+string(i)+")="+string(N(i))+" ist durch "+string(L[j(0)])+" teilbar.";pause();}
864            step=14;
865            break;
866          }
867        }
868        if(step==2)
869        {
870          step=3;
871        }
872      }
873
874      if(step==3)                  // (3)[Choose next discriminant]
875      {
876        n(i)=n(i)+1;
877        if(n(i)==size(H)+1)
878        {
879          if(printlevel>=1) {"Algorithmus nicht anwendbar, da zu wenige geeignete Diskriminanten existieren.";
880                             "Erhoehe den Genauigkeitsparameter K und starte den Algorithmus erneut.";pause();}
881          return(0);
882        }
883        D=H[n(i)];
884        if(printlevel>=1) {"Naechste Diskriminante D wird gewaehlt. D="+string(D)+".";pause();}
885        if(Jacobi(D,N(i))!=1)
886        {
887          if(printlevel>=1) {"Jacobi(D,N("+string(i)+"))="+string(Jacobi(D,N(i)));pause();}
888          continue;
889        }
890        else
891        {
892          L1=CornacchiaModified(D,N(i));
893          if(size(L1)>1)
894          {
895            if(printlevel>=1) {"Die Loesung (x,y) der Gleichung x^2+|D|y^2=4N("+string(i)+") lautet";L1;pause();}
896            step=4;
897          }
898          else
899          {
900            if(L1[1]==-1)
901            {
902              if(printlevel>=1) {"Die Gleichung x^2+|D|y^2=4N("+string(i)+") hat keine Loesung.";pause();}
903              continue;
904            }
905            if(L1[1]==0)
906            {
907              if(printLevel>=1) {"Algorithmus fuer N("+string(i)+")="+string(N(i))+" nicht anwendbar,";
908                                 "da zu wenige geeignete Diskriminanten existieren.";pause();}
909              step=14;
910            }
911          }
912        }
913      }
914
915      if(step==4)                  // (4)[Factor m]
916      {
917        if(printlevel>=1) {"Die Liste L2 der moeglichen m=|E(Z/N("+string(i)+")Z)| wird berechnet.";}
918        if(absValue(L1[1])^2<=4*N(i)) {L2=N(i)+1+L1[1],N(i)+1-L1[1];}
919        if(D==-4)
920        {
921          if(absValue(2*L1[2])^2<=4*N(i)) {L2[size(L2)+1]=N(i)+1+2*L1[2];
922                                           L2[size(L2)+1]=N(i)+1-2*L1[2];}
923        }
924// An dieser Stelle wurde "<=4*N(i)" durch "<=16*N(i)" ersetzt.
925        if(D==-3)
926        {
927          if(absValue(L1[1]+3*L1[2])^2<=16*N(i)) {L2[size(L2)+1]=N(i)+1+(L1[1]+3*L1[2])/2;
928                                                  L2[size(L2)+1]=N(i)+1-(L1[1]+3*L1[2])/2;}
929          if(absValue(L1[1]-3*L1[2])^2<=16*N(i)) {L2[size(L2)+1]=N(i)+1+(L1[1]-3*L1[2])/2;
930                                                  L2[size(L2)+1]=N(i)+1-(L1[1]-3*L1[2])/2;}
931        }
932///////////////////////////////////////////////////////////////
933        if(size(L2)==0)
934        {
935          if(printlevel>=1) {"Nach dem Satz von Hasse wurden keine moeglichen m=|E(Z/N("+string(i)+")Z)|";
936                             "fuer D="+string(D)+" gefunden.";}
937          step=3;
938          continue;
939        }
940        else
941        {
942          if(printlevel>=1) {"L2=";L2;pause();}
943        }
944
945        if(printlevel>=1) {"Die Liste S der Faktoren aller moeglichen m wird berechnet.";}
946        S=list();
947        for(j(1)=1;j(1)<=size(L2);j(1)++)
948        {
949          m=L2[j(1)];
950          if(m!=0)
951          {
952            S1=PollardRho(m,10000,1,L);
953            S2=pFactor(m,100,L);
954            S[size(S)+1]=list(m,S1+S2);
955          }
956        }
957        if(printlevel>=1) {"S=";S;pause();}
958        step=5;
959      }
960
961      if(step==5)                  // (5)[Does a suitable m exist??]
962      {
963        for(j(2)=1;j(2)<=size(S);j(2)++)
964        {
965          m=L2[j(2)];
966          for(j(3)=1;j(3)<=size(S[j(2)][2]);j(3)++)
967          {
968            q=S[j(2)][2][j(3)];
969// sqr(sqr(N(i),50),50) ersetzt intRoot(intRoot(N(i)))
970            if((q>(sqr(sqr(N(i),50),50)+1)^2) && (MillerRabin(q,5)==1))
971            {
972              step=6;
973              break;
974            }
975//////////////////////////////////////////////////////
976          }
977          if(step==6)
978          {
979            if(printlevel>=1) {"Geeignetes Paar (m,q) gefunden, so dass q|m,";
980                               "q>(4-th root(N("+string(i)+"))+1)^2 und q den Miller-Rabin-Test passiert.";
981                               "m="+string(m)+",";"q="+string(q);pause();}
982            break;
983          }
984          else
985          {
986            step=3;
987          }
988        }
989        if(step==3)
990        {
991          if(printlevel>=1) {"Kein geeignetes Paar (m,q), so dass q|m,";
992                             "q>(4-th root(N("+string(i)+"))+1)^2 und q den Miller-Rabin-Test passiert, gefunden.";
993                              pause();}
994          continue;
995        }
996      }
997
998      if(step==6)                  // (6)[Compute elliptic curve]
999      {
1000        if(D==-4)
1001        {
1002          a=-1;
1003          b=0;
1004          if(printlevel>=1) {"Da D=-4, setze a=-1 und b=0.";pause();}
1005        }
1006        if(D==-3)
1007        {
1008          a=0;
1009          b=-1;
1010          if(printlevel>=1) {"Da D=-3, setze a=0 und b=-1.";pause();}
1011        }
1012        if(D<-4)
1013        {
1014          if(printlevel>=1) {"Das Minimalpolynom T von j((D+sqr(D))/2) aus Z[X] fuer D="+string(D)+" wird berechnet.";}
1015          T=HilbertClassPolynomial(D,K);
1016          if(printlevel>=1) {"T="+string(T);pause();}
1017
1018          M=coeffs(T,var(1));
1019          T=0;
1020
1021          for(j(4)=1;j(4)<=nrows(M);j(4)++)
1022          {
1023            M[j(4),1]=leadcoef(M[j(4),1]) mod N(i);
1024            T=T+M[j(4),1]*var(1)^(j(4)-1);
1025          }
1026          if(printlevel>=1) {"Setze T=T mod N("+string(i)+").";"T="+string(T);pause();}
1027
1028          R=RootsModp(int(N(i)),T);
1029          if(deg(T)>size(R))
1030          {
1031            ERROR("Das Polynom T zerfaellt modulo N("+string(i)+") nicht vollstaendig in Linearfaktoren."
1032                  "Erhoehe den Genauigkeitsparameter K und starte den Algorithmus erneut.");
1033          }
1034          if(printlevel>=1) {if(deg(T)>1) {"Die "+string(deg(T))+" Nullstellen von T modulo N("+string(i)+") sind";
1035                                           R;pause();}
1036                             if(deg(T)==1){"Die Nullstelle von T modulo N("+string(i)+") ist";R;pause();}}
1037
1038          j=R[1];
1039          c=j*exgcdN(j-1728,N(i))[1];
1040          a=-3*c mod N(i);
1041          b=2*c mod N(i);
1042          if(printlevel>=1) {"Waehle die Nullstelle j="+string(j)+" aus und setze";"c=j/(j-1728) mod N("+string(i)+"), a=-3c mod N("+string(i)+"), b=2c mod N("+string(i)+").";
1043                             "a="+string(a)+",";"b="+string(b);pause();}
1044        }
1045        step=7;
1046      }
1047
1048      if(step==7)                  // (7)[Find g]
1049      {
1050        if(D==-3)
1051        {
1052          while(1)
1053          {
1054            g=random(1,2147483647) mod N(i);
1055            u=Jacobi(g,N(i));
1056            if((u==-1)&&(powerN(g,(N(i)-1)/3,N(i))!=1))
1057            {
1058              if(printlevel>=1) {"g="+string(g);pause();}
1059              break;
1060            }
1061          }
1062        }
1063        else
1064        {
1065          while(1)
1066          {
1067            g=random(1,2147483647) mod N(i);
1068            u=Jacobi(g,N(i));
1069            if(u==-1)
1070            {
1071              if(printlevel>=1) {"g="+string(g);pause();}
1072              break;
1073            }
1074          }
1075        }
1076        step=8;
1077      }
1078
1079      if(step==8)                  // (8)[Find P]
1080      {
1081        if(printlevel>=1) {"Ein zufaelliger Punkt P auf der Elliptischen Kurve";
1082                           "mit der Gleichung y^2=x^3+ax+b fuer";"N("+string(i)+")="+string(N(i))+",";
1083                           "   a="+string(a)+",";"   b="+string(b);"wird gewaehlt.";}
1084        P=ellipticRandomPoint(N(i),a,b);
1085        if(printlevel>=1) {"P=("+string(P)+")";pause();}
1086
1087        if(size(P)==1)
1088        {
1089          step=14;
1090        }
1091        else
1092        {
1093          step=9;
1094        }
1095      }
1096
1097      if(step==9)                  // (9)[Find right curve]
1098      {
1099        if(printlevel>=1) {"Die Punkte P2=(m/q)*P und P1=q*P2 auf der Kurve werden berechnet.";}
1100        P2=ellipticMult(N(i),a,b,P,m/q);
1101        P1=ellipticMult(N(i),a,b,P2,q);
1102        if(printlevel>=1) {"P1=("+string(P1)+"),";"P2=("+string(P2)+")";pause();}
1103
1104        if((P1[1]==0)&&(P1[2]==1)&&(P1[3]==0))
1105        {
1106          step=12;
1107        }
1108        else
1109        {
1110          if(printlevel>=1) {"Da P1!=(0:1:0), ist fuer die Koeffizienten a="+string(a)+" und b="+string(b)+" m!=|E(Z/N("+string(i)+")Z)|.";
1111                             "Waehle daher neue Koeffizienten a und b.";pause();}
1112          step=10;
1113        }
1114      }
1115
1116      if(step==10)                 // (10)[Change coefficients]
1117      {
1118        k=k+1;
1119        if(k>=w(D))
1120        {
1121          if(printlevel>=1) {"Da k=w(D)="+string(k)+", ist N("+string(i)+")="+string(N(i))+" nicht prim.";pause();}
1122          step=14;
1123        }
1124        else
1125        {
1126          if(D<-4) {a=a*g^2 mod N(i); b=b*g^3 mod N(i);
1127                    if(printlevel>=1) {"Da D<-4, setze a=a*g^2 mod N("+string(i)+") und b=b*g^3 mod N("+string(i)+").";
1128                                       "a="+string(a)+",";"b="+string(b)+",";"k="+string(k);pause();}}
1129          if(D==-4){a=a*g mod N(i);
1130                    if(printlevel>=1) {"Da D=-4, setze a=a*g mod N("+string(i)+").";"a="+string(a)+",";
1131                                       "b="+string(b)+",";"k="+string(k);pause();}}
1132          if(D==-3){b=b*g mod N(i);
1133                    if(printlevel>=1) {"Da D=-3, setze b=b*g mod N("+string(i)+").";"a="+string(a)+",";
1134                                       "b="+string(b)+",";"k="+string(k);pause();}}
1135          step=8;
1136          continue;
1137        }
1138      }
1139
1140      if(step==11)                 // (11)[Find a new P]
1141      {
1142        if(printlevel>=1) {"Ein neuer zufaelliger Punkt P auf der Elliptischen Kurve wird gewaehlt,";
1143                           "da auch P2=(0:1:0).";}
1144        P=ellipticRandomPoint(N(i),a,b);
1145        if(printlevel>=1) {"P=("+string(P)+")";pause();}
1146
1147        if(size(P)==1)
1148        {
1149          step=14;
1150        }
1151        else
1152        {
1153          if(printlevel>=1) {"Die Punkte P2=(m/q)*P und P1=q*P2 auf der Kurve werden berechnet.";}
1154          P2=ellipticMult(N(i),a,b,P,m/q);
1155          P1=ellipticMult(N(i),a,b,P2,q);
1156          if(printlevel>=1) {"P1=("+string(P1)+"),";"P2=("+string(P2)+")";pause();}
1157
1158          if((P1[1]!=0)||(P1[2]!=1)||(P1[3]!=0))
1159          {
1160            if(printlevel>=1) {"Da P1!=(0:1:0), ist, fuer die Koeffizienten a="+string(a)+" und b="+string(b)+", m!=|E(Z/N("+string(i)+")Z)|.";
1161                               "Waehle daher neue Koeffizienten a und b.";pause();}
1162            step=10;
1163            continue;
1164          }
1165          else
1166          {
1167            step=12;
1168          }
1169        }
1170      }
1171
1172      if(step==12)                 // (12)[Check P]
1173      {
1174        if((P2[1]==0)&&(P2[2]==1)&&(P2[3]==0))
1175        {
1176          step=11;
1177          continue;
1178        }
1179        else
1180        {
1181          step=13;
1182        }
1183      }
1184
1185      if(step==13)                 // (13)[Recurse]
1186      {
1187        if(i<B)
1188        {
1189          if(printlevel>=1) {string(i+1)+". Rekursion:";"";
1190                             "N("+string(i)+")="+string(N(i))+" erfuellt die Bedingungen des zugrunde liegenden Satzes,";
1191                             "da P1=(0:1:0) und P2[3] aus (Z/N("+string(i)+")Z)*.";"";
1192                             "Untersuche nun, ob auch der gefundene Faktor q="+string(q)+" diese Bedingungen erfuellt.";
1193                             "Setze dazu i=i+1, N("+string(i+1)+")=q="+string(q)+" und beginne den Algorithmus von vorne.";pause();}
1194          i=i+1;
1195          int n(i);
1196          number N(i)=q;
1197          k=0;
1198          step=2;
1199          continue;
1200        }
1201        else
1202        {
1203          if(printlevel>=1) {"N(B)=N("+string(i)+")="+string(N(i))+" erfuellt die Bedingungen des zugrunde liegenden Satzes,";
1204                             "da P1=(0:1:0) und P2[3] aus (Z/N("+string(i)+")Z)*.";
1205                             "Insbesondere ist N="+string(N)+" prim.";pause();}
1206          return(1);
1207        }
1208      }
1209
1210      if(step==14)                 // (14)[Backtrack]
1211      {
1212        if(i>0)
1213        {
1214          if(printlevel>=1) {"Setze i=i-1 und starte den Algorithmus fuer N("+string(i-1)+")="+string(N(i-1))+" mit";
1215                             "neuer Diskriminanten von vorne.";pause();}
1216          i=i-1;
1217          k=0;
1218          step=3;
1219        }
1220        else
1221        {
1222          if(printlevel>=1) {"N(0)=N="+string(N)+" und daher ist N nicht prim.";pause();}
1223          return(-1);
1224        }
1225      }
1226    }
1227  }
1228}
1229
1230example
1231{ "EXAMPLE:"; echo = 2;
1232    ring R = 0,x,dp;
1233    printlevel=1;
1234    Atkin(7691,100,5);
1235    Atkin(8543,100,4);
1236    Atkin(100019,100,5);
1237    Atkin(10000079,100,2);
1238}
Note: See TracBrowser for help on using the repository browser.