source: git/Singular/LIB/AtkinsTest.lib @ c33727

fieker-DuValspielwiese
Last change on this file since c33727 was 370344, checked in by Hans Schönemann <hannes@…>, 17 years ago
*hanne: format git-svn-id: file:///usr/local/Singular/svn/trunk@9589 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 41.2 KB
Line 
1///////////////////////////////////////////////////////////////////////////////
2version="$Id: AtkinsTest.lib,v 1.6 2006-12-14 17:30:46 Singular Exp $";
3category="Teaching";
4info="
5LIBRARY:  AtkinsTest.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 (out of Z) of the list L in decreasing order
18  disc(N,k)       generates a sequence of negative discriminants D with |D|<4N, sort in decreasing order
19  Cornacchia(d,p) computes solution (x,y) for the Diophantine equation x^2+d*y^2=p with p prime and 0<d<p
20  CornacchiaModified(D,p)      computes solution (x,y) for the Diophantine equation x^2+|D|*y^2=4p with p prime
21  pFactor1(n,B,P) Pollard's p-factorization
22  maximum(L)      computes the maximal number contained in list L
23  cmod(x,y)       computes x mod y while working in the complex numbers, e.g. ring C=(complex,30,i),x,dp;
24  sqr(w,k)        computes the square root of w
25  e(z,k)          computes e^z, i.e. the exponential function of z to the order k
26  jot(t,k)        computes the j-invariant of the complex number t
27  round(r)        rounds r to the nearest number out of Z
28  HilbertClassPolynomial(D,k)  computes the monic polynomial of degree h(D) in Z[X] of which jot((D+sqr(D))/2) is a root
29  RootsModp(p,P)  computes roots of the polynomial P modulo p with p prime and p>=3
30  w(D)            computes the number of roots of unity in the quadratic order of discriminant D
31  Atkin(N,K,B)    tries to prove that N is prime
32";
33
34LIB "krypto.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 ellipic curve modulo N.
812          Assume that we know an integer m and a point P of E(Z/NZ) satisfying the following conditions.
813           (1) There exists a prime divisor q of m such that q>(4-th root(N)+1)^2.
814           (2) m*P=O(E)=(0:1:0).
815           (3) (m/q)*P=(x:y:t) with t element of (Z/NZ)*.
816          Then N is prime.
817EXAMPLE:example Atkin; shows an example
818"
819{
820      if(N==1)           {return(-1);}
821      if((N==2)||(N==3)) {return(1);}
822      if(gcdN(N,6)!=1)
823      {
824        if(printlevel>=1)
825        {
826          "ggT(N,6)="+string(gcdN(N,6));
827          pause();
828        }
829        return(-1);
830      }
831      else
832      {
833         int i;                                                             // (1)[Initialize]
834         int n(i);
835         number N(i)=N;
836         if(printlevel>=1)
837         {
838           "Setze i=0, n=0 und N(i)=N(0)="+string(N(i))+".";
839           pause();
840         }
841
842         // declarations:
843         int j(0),j(1),j(2),j(3),j(4),k;                                    // running indices
844         list L;                                                            // all primes smaller than 1000
845         list H;                                                            // sequence of negative discriminants
846         number D;                                                          // discriminant out of H
847         list L1,L2,S,S1,S2,R;                                              // lists of relevant elements
848         list P,P1,P2;                                                      // elliptic points on E(Z/N(i)Z)
849         number m,q;                                                        // m=|E(Z/N(i)Z)| and q|m
850         number a,b,j,c;                                                    // characterize E(Z/N(i)Z)
851         number g,u;                                                        // g out of Z/N(i)Z, u=Jacobi(g,N(i))
852         poly T;                                                            // T=HilbertClassPolynomial(D,K)
853         matrix M;                                                          // M contains the coefficients of T
854
855         if(printlevel>=1)
856         {
857           "Liste H der moeglichen geeigneten Diskriminanten wird berechnet.";
858         }
859         H=disc(N,K/2);
860         if(printlevel>=1) {"H="+string(H);pause();}
861
862         int step=2;
863         while(1)
864            {
865              if(step==2)
866              {
867                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;
868                for(j(0)=1;j(0)<=size(L);j(0)++)                         // (2)[Is N(i) small??]
869                {
870                  if(((N(i) mod L[j(0)])==0)&&(N(i)!=L[j(0)]))
871                  {
872                    if(printlevel>=1)
873                    {
874                      "N("+string(i)+")="+string(N(i))+" ist durch "+string(L[j(0)])+" teilbar.";pause();
875                    }
876                    step=14;
877                    break;
878                  }
879                }
880
881                if(step==2)
882                {
883                  step=3;
884                }
885              }
886
887              if(step==3)                                                   // (3)[Choose next discriminant]
888                 {
889                   n(i)=n(i)+1;
890                   if(n(i)==size(H)+1)
891                   {
892                     if(printlevel>=1)
893                     {
894                       "Algorithmus nicht anwendbar, da zu wenige geeignete Diskriminanten existieren.";
895                       "Erhoehe den Genauigkeitsparameter K und starte den Algorithmus erneut.";pause();
896                     }
897                     return(0);
898                   }
899
900                   D=H[n(i)];
901                   if(printlevel>=1) {"Naechste Diskriminante D wird gewaehlt. D="+string(D)+".";pause();}
902
903                   if(Jacobi(D,N(i))!=1)
904                      {
905                        if(printlevel>=1) {"Jacobi(D,N("+string(i)+"))="+string(Jacobi(D,N(i)));pause();}
906                        continue;
907                      }
908
909                   else
910                   {
911                     L1=CornacchiaModified(D,N(i));
912                     if(size(L1)>1)
913                     {
914                       if(printlevel>=1)
915                       {
916                         "Die Loesung (x,y) der Gleichung x^2+|D|y^2=4N("+string(i)+") lautet";
917                         L1;
918                         pause();
919                       }
920                       step=4;
921                     }
922                     else
923                     {
924                       if(L1[1]==-1)
925                       {
926                         if(printlevel>=1)
927                         {
928                           "Die Gleichung x^2+|D|y^2=4N("+string(i)+") hat keine Loesung.";
929                           pause();
930                         }
931                         continue;
932                       }
933
934                       if(L1[1]==0)
935                       {
936                         if(printLevel>=1)
937                         {
938                           "Algorithmus fuer N("+string(i)+")="+string(N(i))+" nicht anwendbar, da zu wenige geeignete Diskriminanten existieren.";
939                           pause();
940                         }
941                         step=14;
942                       }
943                     }
944                   }
945                 }
946
947              if(step==4)                                                   // (4)[Factor m]
948                 {
949                   if(printlevel>=1) {"Die Liste L2 der moeglichen m=|E(Z/N("+string(i)+")Z)| wird berechnet.";}
950                   if(absValue(L1[1])^2<=4*N(i)) {L2=N(i)+1+L1[1],N(i)+1-L1[1];}
951                   if(D==-4)
952                   {
953                     if(absValue(2*L1[2])^2<=4*N(i))
954                     {
955                       L2[size(L2)+1]=N(i)+1+2*L1[2];
956                       L2[size(L2)+1]=N(i)+1-2*L1[2];
957                     }
958                   }
959
960                   if(D==-3)
961                   {
962                     if(absValue(L1[1]+3*L1[2])^2<=4*N(i))
963                     {
964                       L2[size(L2)+1]=N(i)+1+(L1[1]+3*L1[2])/2;
965                       L2[size(L2)+1]=N(i)+1-(L1[1]+3*L1[2])/2;
966                     }
967                     if(absValue(L1[1]-3*L1[2])^2<=4*N(i))
968                     {
969                       L2[size(L2)+1]=N(i)+1+(L1[1]-3*L1[2])/2;
970                       L2[size(L2)+1]=N(i)+1-(L1[1]-3*L1[2])/2;
971                     }
972                   }
973
974                   if(size(L2)==0)
975                   {
976                     if(printlevel>=1)
977                     {
978                       "Nach dem Satz von Hasse wurden keine moeglichen m=|E(Z/N("+string(i)+")Z)|";
979                       "fuer D="+string(D)+" gefunden.";
980                     }
981                     step=3;
982                     continue;
983                   }
984                   else
985                   {
986                     if(printlevel>=1)
987                     {
988                       "L2=";L2;
989                       pause();
990                     }
991                   }
992
993                   if(printlevel>=1) {"Die Liste S der Faktoren aller moeglichen m wird berechnet.";}
994                   S=list();
995                   for(j(1)=1;j(1)<=size(L2);j(1)++)
996                   {
997                     m=L2[j(1)];
998                     if(m!=0)
999                     {
1000                       S1=PollardRho(m,10000,1,L);
1001                       S2=pFactor1(m,100,L);
1002                       S[size(S)+1]=list(m,S1+S2);
1003                     }
1004                   }
1005                   if(printlevel>=1)
1006                   {
1007                     "S=";S;
1008                     pause();
1009                   }
1010                   step=5;
1011                 }
1012
1013              if(step==5)                                                   // (5)[Does a suitable m exist??]
1014              {
1015                for(j(2)=1;j(2)<=size(S);j(2)++)
1016                {
1017                  m=L2[j(2)];
1018                  for(j(3)=1;j(3)<=size(S[j(2)][2]);j(3)++)
1019                  {
1020                    q=S[j(2)][2][j(3)];
1021                    if((q>(intRoot(intRoot(N(i)))+1)^2) && (MillerRabin(q,5)==1))
1022                    {
1023                      step=6;
1024                      break;
1025                    }
1026                  }
1027
1028                  if(step==6)
1029                  {
1030                    if(printlevel>=1)
1031                    {
1032                      "Geeignetes Paar (m,q) gefunden, so dass q|m,";
1033                      "q>(4-th root(N("+string(i)+"))+1)^2 und q den Miller-Rabin-Test passiert.";
1034                      "m="+string(m)+",";"q="+string(q);
1035                      pause();
1036                    }
1037                    break;
1038                  }
1039                  else
1040                  {
1041                    step=3;
1042                  }
1043                }
1044
1045                if(step==3)
1046                {
1047                  if(printlevel>=1)
1048                  {
1049                    "Kein geeignetes Paar (m,q), so dass q|m,";
1050                    "q>(4-th root(N("+string(i)+"))+1)^2 und q den Miller-Rabin-Test passiert, gefunden.";
1051                    pause();
1052                  }
1053                  continue;
1054                }
1055              }
1056
1057              if(step==6)                                                   // (6)[Compute elliptic curve]
1058                 {
1059                   if(D==-4)
1060                   {
1061                     a=-1;
1062                     b=0;
1063                     if(printlevel>=1)
1064                     {
1065                       "Da D=-4, setze a=-1 und b=0.";
1066                       pause();
1067                     }
1068                   }
1069
1070                   if(D==-3)
1071                   {
1072                     a=0;
1073                     b=-1;
1074                     if(printlevel>=1)
1075                     {
1076                       "Da D=-3, setze a=0 und b=-1.";
1077                       pause();
1078                     }
1079                   }
1080
1081                   if(D<-4)
1082                   {
1083                     if(printlevel>=1)
1084                     {
1085                       "Das Minimalpolynom T von j((D+sqr(D))/2) aus Z[X] fuer D="+string(D)+" wird berechnet.";
1086                     }
1087                     T=HilbertClassPolynomial(D,K);
1088                     if(printlevel>=1)
1089                     {
1090                       "T="+string(T);
1091                       pause();
1092                     }
1093
1094                     M=coeffs(T,var(1));
1095                     T=0;
1096
1097                     for(j(4)=1;j(4)<=nrows(M);j(4)++)
1098                     {
1099                       M[j(4),1]=leadcoef(M[j(4),1]) mod N(i);
1100                       T=T+M[j(4),1]*var(1)^(j(4)-1);
1101                     }
1102                     if(printlevel>=1)
1103                     {
1104                       "Setze T=T mod N("+string(i)+").";"T="+string(T);
1105                       pause();
1106                     }
1107
1108                     R=RootsModp(int(N(i)),T);
1109                     if(deg(T)>size(R))
1110                     {
1111                       ERROR("Das Polynom T zerfaellt modulo N("+string(i)+") nicht vollstaendig in Linearfaktoren."+
1112                             "Erhoehe den Genauigkeitsparameter K und starte den Algorithmus erneut.");
1113                     }
1114                     if(printlevel>=1)
1115                     {
1116                       if(deg(T)>1)
1117                       {
1118                         "Die "+string(deg(T))+" Nullstellen von T modulo N("+string(i)+") sind";
1119                         R;
1120                         pause();
1121                       }
1122                       if(deg(T)==1)
1123                       {
1124                         "Die Nullstelle von T modulo N("+string(i)+") ist";
1125                         R;
1126                         pause();
1127                       }
1128                     }
1129
1130                     j=R[1];
1131                     c=j*exgcdN(j-1728,N(i))[1];
1132                     a=-3*c mod N(i);
1133                     b=2*c mod N(i);
1134                     if(printlevel>=1)
1135                     {
1136                       "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)+").";
1137                       "a="+string(a)+",";"b="+string(b);
1138                       pause();
1139                     }
1140                   }
1141
1142                   step=7;
1143                 }
1144
1145              if(step==7)                                                   // (7)[Find g]
1146              {
1147                if(D==-3)
1148                {
1149                  while(1)
1150                  {
1151                    g=random(1,2147483647) mod N(i);
1152                    u=Jacobi(g,N(i));
1153                    if((u==-1)&&(powerN(g,(N(i)-1)/3,N(i))!=1))
1154                    {
1155                      if(printlevel>=1)
1156                      {
1157                        "g="+string(g);
1158                        pause();
1159                      }
1160                      break;
1161                    }
1162                  }
1163                }
1164                else
1165                {
1166                  while(1)
1167                  {
1168                    g=random(1,2147483647) mod N(i);
1169                    u=Jacobi(g,N(i));
1170                    if(u==-1)
1171                    {
1172                      if(printlevel>=1)
1173                      {
1174                        "g="+string(g);
1175                        pause();
1176                      }
1177                      break;
1178                    }
1179                  }
1180                }
1181
1182                step=8;
1183              }
1184
1185              if(step==8)                                                   // (8)[Find P]
1186              {
1187                if(printlevel>=1)
1188                {
1189                  "Ein zufaelliger Punkt P auf der Elliptischen Kurve";
1190                  "mit der Gleichung y^2=x^3+ax+b fuer";"N("+string(i)+")="+string(N(i))+",";"   a="+string(a)+",";"   b="+string(b);"wird gewaehlt.";
1191                }
1192                P=ellipticRandomPoint(N(i),a,b);
1193                if(printlevel>=1) {"P=("+string(P)+")";pause();}
1194
1195                if(size(P)==1)
1196                {
1197                  step=14;
1198                }
1199                else
1200                {
1201                  step=9;
1202                }
1203              }
1204
1205              if(step==9)                                                   // (9)[Find right curve]
1206                 {
1207                   if(printlevel>=1) {"Die Punkte P2=(m/q)*P und P1=q*P2 auf der Kurve werden berechnet.";}
1208                   P2=ellipticMult(N(i),a,b,P,m/q);
1209                   P1=ellipticMult(N(i),a,b,P2,q);
1210                   if(printlevel>=1) {"P1=("+string(P1)+"),";"P2=("+string(P2)+")";pause();}
1211
1212                   if((P1[1]==0)&&(P1[2]==1)&&(P1[3]==0))
1213                   {
1214                     step=12;
1215                   }
1216                   else
1217                   {
1218                     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)|.";
1219                                           "Waehle daher neue Koeffizienten a und b.";pause();}
1220                     step=10;
1221                   }
1222                 }
1223
1224              if(step==10)
1225                 {
1226                   k=k+1;
1227                   if(k>=w(D))
1228                      {
1229                        if(printlevel>=1) {"Da k=w(D)="+string(k)+", ist N("+string(i)+")="+string(N(i))+" nicht prim.";pause();}
1230                        step=14;
1231                      }
1232
1233                   else
1234                      {
1235                        if(D<-4) {a=a*g^2 mod N(i); b=b*g^3 mod N(i);
1236                                  if(printlevel>=1) {"Da D<-4, setze a=a*g^2 mod N("+string(i)+") und b=b*g^3 mod N("+string(i)+").";"a="+string(a)+",";"b="+string(b)+",";"k="+string(k);pause();}}
1237                        if(D==-4){a=a*g mod N(i);
1238                                  if(printlevel>=1) {"Da D=-4, setze a=a*g mod N("+string(i)+").";"a="+string(a)+",";"b="+string(b)+",";"k="+string(k);pause();}}
1239                        if(D==-3){b=b*g mod N(i);
1240                                  if(printlevel>=1) {"Da D=-3, setze b=b*g mod N("+string(i)+").";"a="+string(a)+",";"b="+string(b)+",";"k="+string(k);pause();}}
1241                        step=8;
1242                        continue;
1243                      }
1244                 }
1245
1246              if(step==11)                                                  // (11)[Find a new P]
1247              {
1248                if(printlevel>=1)
1249                {
1250                  "Ein neuer zufaelliger Punkt P auf der Elliptischen Kurve wird gewaehlt,";
1251                  "da auch P2=(0:1:0).";
1252                }
1253                P=ellipticRandomPoint(N(i),a,b);
1254                if(printlevel>=1)
1255                {
1256                  "P=("+string(P)+")";
1257                  pause();
1258                }
1259
1260                if(size(P)==1)
1261                {
1262                  step=14;
1263                }
1264                else
1265                {
1266                  if(printlevel>=1)
1267                  {
1268                    "Die Punkte P2=(m/q)*P und P1=q*P2 auf der Kurve werden berechnet.";
1269                  }
1270                  P2=ellipticMult(N(i),a,b,P,m/q);
1271                  P1=ellipticMult(N(i),a,b,P2,q);
1272                  if(printlevel>=1)
1273                  {
1274                    "P1=("+string(P1)+"),";"P2=("+string(P2)+")";
1275                    pause();
1276                  }
1277
1278                  if((P1[1]!=0)||(P1[2]!=1)||(P1[3]!=0))
1279                  {
1280                    if(printlevel>=1)
1281                    {
1282                      "Da P1!=(0:1:0), ist, fuer die Koeffizienten a="+string(a)+" und b="+string(b)+", m!=|E(Z/N("+string(i)+")Z)|.";
1283                      "Waehle daher neue Koeffizienten a und b.";
1284                      pause();
1285                    }
1286                    step=10;
1287                    continue;
1288                  }
1289                  else
1290                  {
1291                    step=12;
1292                  }
1293                }
1294              }
1295
1296              if(step==12)                                                  // (12)[Check P]
1297              {
1298                if((P2[1]==0)&&(P2[2]==1)&&(P2[3]==0))
1299                {
1300                  step=11;
1301                  continue;
1302                }
1303                else
1304                {
1305                  step=13;
1306                }
1307              }
1308
1309              if(step==13)                                                  // (13)[Recurse]
1310              {
1311                if(i<B)
1312                {
1313                  if(printlevel>=1)
1314                  {
1315                    string(i+1)+". Rekursion:";"";
1316                    "N("+string(i)+")="+string(N(i))+" erfuellt die Bedingungen des zugrunde liegenden Satzes,";
1317                    "da P1=(0:1:0) und P2[3] aus (Z/N("+string(i)+")Z)*.";"";
1318                    "Untersuche nun, ob auch der gefundene Faktor q="+string(q)+" diese Bedingungen erfuellt.";
1319                    "Setze dazu i=i+1, N("+string(i+1)+")=q="+string(q)+" und beginne den Algorithmus von vorne.";
1320                    pause();
1321                  }
1322                  i=i+1;
1323                  int n(i);
1324                  number N(i)=q;
1325                  k=0;
1326                  step=2;
1327                  continue;
1328                }
1329                else
1330                {
1331                  if(printlevel>=1)
1332                  {
1333                    "N(B)=N("+string(i)+")="+string(N(i))+" erfuellt die Bedingungen des zugrunde liegenden Satzes,";
1334                    "da P1=(0:1:0) und P2[3] aus (Z/N("+string(i)+")Z)*.";
1335                    "Insbesondere ist N="+string(N)+" prim.";
1336                    pause();
1337                  }
1338                  return(1);
1339                }
1340              }
1341
1342              if(step==14)                                                  // (14)[Backtrack]
1343              {
1344                if(i>0)
1345                {
1346                  if(printlevel>=1)
1347                  {
1348                    "Setze i=i-1 und starte den Algorithmus fuer N("+string(i-1)+")="+string(N(i-1))+" mit neuer Diskriminanten von vorne.";
1349                    pause();
1350                  }
1351                  i=i-1;
1352                  k=0;
1353                  step=3;
1354                }
1355                else
1356                {
1357                  if(printlevel>=1)
1358                  {
1359                    "N(0)=N="+string(N)+" und daher ist N nicht prim.";
1360                    pause();
1361                  }
1362                  return(-1);
1363                }
1364              }
1365            }
1366         }
1367}
1368example
1369{ "EXAMPLE:"; echo = 2;
1370    ring R = 0,x,dp;
1371    printlevel=1;
1372    Atkin(7691,100,5);
1373    Atkin(8543,100,4);
1374    Atkin(100019,100,5);
1375    Atkin(10000079,100,2);
1376}
Note: See TracBrowser for help on using the repository browser.