source: git/Singular/LIB/crypto.lib

spielwiese
Last change on this file was b21369, checked in by Hans Schoenemann <hannes@…>, 3 years ago
remove atkins.lib
  • Property mode set to 100644
File size: 91.7 KB
Line 
1//////////////////////////////////////////////////////////////////////////////
2version="version crypto.lib 4.2.1.0 Jul_2021 "; // $Id$
3category="Teaching";
4info="
5LIBRARY:  crypto.lib     Procedures for teaching cryptography
6AUTHORS:                 Gerhard Pfister, pfister@mathematik.uni-kl.de
7@*                       David Brittinger, dativ@gmx.net
8
9OVERVIEW:
10     The library contains procedures to compute the discrete logarithm,
11      primality-tests, factorization included elliptic curves.
12      The library is intended to be used for teaching purposes but not
13      for serious computations. Sufficiently high printlevel allows to
14      control each step, thus illustrating the algorithms at work.
15
16
17PROCEDURES:
18 round(r);                  rounds r to the nearest number in Z
19 bubblesort(L)              sorts elements of the list L
20 decimal(s);                number corresponding to the hexadecimal number s
21 eexgcdN(L)                 T with sum_i L[i]*T[i]=T[n+1]=gcd(L[1],...,L[n])
22 lcmN(a,b)                  compute lcm(a,b)
23 powerN(m,d,n)              compute m^d mod n
24 chineseRem(T,L)            compute x such that x = T[i] mod L[i]
25 Jacobi(a,n)                the generalized Legendre symbol of a and n
26 primList(n)                the list of all primes <=n
27 primL(q)                   first primes p_1,...,p_r such that q<p_1*...*p_r
28 intPart(x)                 the integral part of a rational number
29 intRoot(m)                 the integral part of the square root of m
30 squareRoot(a,p)            the square root of a in Z/p, p prime
31 solutionsMod2(M)           basis solutions of Mx=0 over Z/2
32 powerX(q,i,I)              q-th power of the i-th variable modulo I
33 babyGiant(b,y,p)           discrete logarithm x: b^x=y mod p
34 rho(b,y,p)                 discrete logarithm x: b^x=y mod p
35 MillerRabin(n,k)           probabilistic primaly-test of Miller-Rabin
36 SolowayStrassen(n,k)       probabilistic primaly-test of Soloway-Strassen
37 PocklingtonLehmer(N,[])    primaly-test of Pocklington-Lehmer
38 PollardRho(n,k,a,[])       Pollard's rho factorization
39 pFactor(n,B,P)             Pollard's p-factorization
40 quadraticSieve(n,c,B,k)    quadratic sieve factorization
41 isOnCurve(N,a,b,P)         P is on the curve y^2z=x^3+a*xz^2+b*z^3  over Z/N
42 ellipticAdd(N,a,b,P,Q)     P+Q, addition on elliptic curves
43 ellipticMult(N,a,b,P,k)    k*P on elliptic curves
44 ellipticRandomCurve(N)     generates y^2z=x^3+a*xz^2+b*z^3  over Z/N randomly
45 ellipticRandomPoint(N,a,b) random point on y^2z=x^3+a*xz^2+b*z^3  over Z/N
46 countPoints(N,a,b)         number of points of y^2=x^3+a*x+b  over Z/N
47 ellipticAllPoints(N,a,b)   points of y^2=x^3+a*x+b  over Z/N
48 ShanksMestre(q,a,b,[])     number of points of y^2=x^3+a*x+b  over Z/N
49 Schoof(N,a,b)              number of points of y^2=x^3+a*x+b  over Z/N
50 generateG(a,b,m)           m-th division polynomial of y^2=x^3+a*x+b  over Z/N
51 factorLenstraECM(N,S,B,[]) Lenstra's factorization
52 ECPP(N)                    primaly-test of Goldwasser-Kilian
53 calculate_ordering(num1, primitive, mod1)    Calculates x so that primitive^x == num1 mod mod1
54  is_primitive_root(primitive, mod1) Checks if primitive is a primitive root modulo mod1
55  find_first_primitive_root(mod1) Returns the first primitive root modulo mod1, starting with 1
56  binary_add(binary_list)         Adds a 1 to a binary encoded list
57  inverse_modulus(num,mod1)       Finds a t so that t*num = 1 mod mod1
58  is_prime(n)                     Checks if n is prime
59  proc find_biggest_index(a)      Returns the index of the biggest element of a
60  find_index(a,e)                 Returns the list index of element e in list a. Returns 0 if e is not in a
61  subset_sum01(list knapsack, int solution)                          solves the subset-sum-knapsack-problem by calculating all subsets and choosing the right solution
62  subset_sum02(list knapsack, int sol)                            solves the subset-sum-knapsack-problem with a naive greedy algorithm
63  unbounded_knapsack(list knapsack, list profit, int capacity)                solves the unbounded_knapsack-problem, needing a list of knapsack weights, a list of profits and a capacity
64  multidimensional_knapsack(matrix m, list capacities, list profits)              solves the multidimensional_knapsack-problem by using the PECH algorithm, needing a weight matrix m, a list of capacities and a list of profits
65  naccache_stern_generation(int key, int primenum)                      generates a hard knapsack for the Naccache-Stern Kryptosystem for given key and prime modulus
66  naccache_stern_encryption(list knapsack, list message, int primenum)            encrypts a message with the Naccache-Stern Kryptosystem, using a hard knapsack, a message encoded as binary list and a prime modulus
67  naccache_stern_decryption(list knapsack, int key, int primenum, int message)        decrypts a message with the Naccache-Stern Kryptosystem, using the easy knapsack, the key, the prime modulus and the message encoded as integer
68  m_merkle_hellman_transformation(list knapsack, int primitive, int mod1)            generates a hard knapsack for the multiplicative Merkle-Hellman Kryptosystem for a given easy knapsack and a primitive root for a modulus mod1
69  m_merkle_hellman_encryption(list knapsack, list message)                  encrypts a message with the multiplicative Merkle-Hellman Kryptosystem, using a hard knapsack and a message encoded as binary list
70  m_merkle_hellman_decryption(list knapsack, bigint primitive, bigint mod1, int message)    decrypts a message with the multiplicative Merkle-Hellman Kryptosystem, using the easy knapsack, the key given by the primitive root, the modulus mod1 and the message encoded as integer
71  merkle_hellman_transformation(list knapsack, int key, int mod1                generates a hard knapsack for the  Merkle-Hellman Kryptosystem for a given easy knapsack , a multiplicator key and a modulus mod1
72  merkle_hellman_encryption(list knapsack, list message)                    encrypts a message with the Merkle-Hellman Kryptosystem, using a hard knapsack and a message encoded as binary list
73  merkle_hellman_decryption(list knapsack, int key, int mod1, int message)          decrypts a message with the multiplicative Merkle-Hellman Kryptosystem, using the hard knapsack, the key, the modulus mod1 and the message encoded as integer
74  super_increasing_knapsack(int ksize)                            Creates the smallest super-increasing knapsack of given size ksize
75  h_increasing_knapsack(int ksize, int h)                            Creates the smallest h-increasing knapsack of given size ksize and h
76  injective_knapsack(int ksize, int kmaxelement)                        Creates all list of all injective knapsacks of given size ksize and maximal element kmaxelement
77  calculate_max_sum(list a)                                  Calculates the maximal sum of a given knapsack a
78  set_is_injective(list a)                                    Checks if knapsack a is injective
79  is_h_injective(list a, int h)                                Checks if knapsack a is h-injective
80  is_fix_injective(list a)                                  Checks if knapsack a is fix-injective
81  three_elements(list out, int iterations)                          Creates the smallest injective knapsack with a given injective_knapsack by using the three-elements-algorithm with a given number of iterations
82
83              [parameters in square brackets are optional]
84";
85
86LIB "polylib.lib";
87
88///////////////////////////////////////////////////////////////////////////////
89
90proc round(number r)
91"USAGE: round(r);
92RETURN: the nearest number to r out of Z
93ASSUME: r should be a rational or a real number
94EXAMPLE:example round; shows an example
95"
96{
97  number a=absValue(r);
98  number v=r/a;
99
100  number d=10;
101  int e;
102  while(1)
103  {
104    e=e+1;
105    if(a-d^e<0)
106    {
107      e=e-1;
108      break;
109    }
110  }
111
112  number b=a;
113  int k;
114  for(k=0;k<=e;k++)
115  {
116    while(1)
117    {
118      b=b-d^(e-k);
119      if(b<0)
120      {
121        b=b+d^(e-k);
122        break;
123      }
124    }
125  }
126
127  if(b<1/2)
128  {
129    return(v*(a-b));
130  }
131  else
132  {
133    return(v*(a+1-b));
134  }
135}
136example
137{ "EXAMPLE:"; echo = 2;
138    ring R = (real,50),x,dp;
139    number r=7357683445788723456321.6788643224;
140    round(r);
141}
142
143
144proc bubblesort(list L)
145"USAGE: bubblesort(L);
146RETURN: list L, sort in decreasing order
147EXAMPLE:example bubblesort; shows an example
148"
149{
150  def b;
151  int n,i,j;
152  while(j==0)
153  {
154    i=i+1;
155    j=1;
156    for(n=1;n<=size(L)-i;n++)
157    {
158      if(L[n]<L[n+1])
159      {
160        b=L[n];
161        L[n]=L[n+1];
162        L[n+1]=b;
163        j=0;
164      }
165    }
166  }
167  return(L);
168}
169example
170{ "EXAMPLE:"; echo = 2;
171    ring r = 0,x,dp;
172    list L=-567,-233,446,12,-34,8907;
173    bubblesort(L);
174}
175
176//=============================================================================
177//=========================== basic prozedures ================================
178//=============================================================================
179
180proc decimal(string s)
181"USAGE:  decimal(s); s = string
182RETURN: the (decimal) number corresponding to the hexadecimal number s
183EXAMPLE:example decimal; shows an example
184"
185{
186   int n=size(s);
187   int i;
188   bigint k;
189   bigint t=16;
190   bigint m=0;
191   for(i=1;i<=n;i++)
192   {
193      k=0;
194      if(s[i]=="1"){k=1;}
195      if(s[i]=="2"){k=2;}
196      if(s[i]=="3"){k=3;}
197      if(s[i]=="4"){k=4;}
198      if(s[i]=="5"){k=5;}
199      if(s[i]=="6"){k=6;}
200      if(s[i]=="7"){k=7;}
201      if(s[i]=="8"){k=8;}
202      if(s[i]=="9"){k=9;}
203      if(s[i]=="a"){k=10;}
204      if(s[i]=="b"){k=11;}
205      if(s[i]=="c"){k=12;}
206      if(s[i]=="d"){k=13;}
207      if(s[i]=="e"){k=14;}
208      if(s[i]=="f"){k=15;}
209      m=m*t+k;
210   }
211   return(m);
212}
213example
214{ "EXAMPLE:"; echo = 2;
215   string s  ="8edfe37dae96cfd2466d77d3884d4196";
216   decimal(s);
217}
218
219proc eexgcdN(list L)
220"USAGE:  eexgcdN(L);
221RETURN: list T such that sum_i L[i]*T[i]=T[n+1]=gcd(L[1],...,L[n])
222EXAMPLE:example eexgcdN; shows an example
223"
224{
225   if(size(L)==2)
226   {
227     list LL=extgcd(L[1],L[2]);return(list(LL[2],LL[3],LL[1]));
228   }
229   bigint p=L[size(L)];
230   L=delete(L,size(L));
231   list T=eexgcdN(L);
232   list S=extgcd(T[size(T)],p);
233   int i;
234   for(i=1;i<=size(T)-1;i++)
235   {
236      T[i]=T[i]*S[2];
237   }
238   p=T[size(T)];
239   T[size(T)]=S[3];
240   T[size(T)+1]=S[1];
241   return(T);
242}
243example
244{ "EXAMPLE:"; echo = 2;
245   eexgcdN(list(24,15,21));
246}
247
248proc lcmN(bigint a, bigint b)
249"USAGE:  lcmN(a,b);
250RETURN: lcm(a,b);
251EXAMPLE:example lcmN; shows an example
252"
253{
254   return (a*b/gcd(a,b));
255}
256example
257{ "EXAMPLE:"; echo = 2;
258   lcmN(24,15);
259}
260
261proc powerN(bigint m, bigint d, bigint n)
262"USAGE:  powerN(m,d,n);
263RETURN: m^d mod n
264EXAMPLE:example powerN; shows an example
265"
266{
267   if(d==0){return(bigint(1));}
268   int i;
269   if(n==0)
270   {
271      for(i=12;i>=2;i--)
272      {
273         if((d mod i)==0){return(powerN(m,d div i,n)^i);}
274      }
275      return(m*powerN(m,d-1,n));
276   }
277   for(i=12;i>=2;i--)
278   {
279      if((d mod i)==0)
280      {
281        bigint rr=powerN(m,d div i,n)^i mod n;
282        if (rr<0) { rr=rr+n;}
283        return(rr);
284      }
285   }
286   return(m*powerN(m,d-1,n) mod n);
287}
288example
289{ "EXAMPLE:"; echo = 2;
290   powerN(24,15,7);
291}
292
293proc chineseRem(list T,list L)
294"USAGE:  chineseRem(T,L);
295RETURN: x such that x = T[i] mod L[i]
296NOTE:   chinese remainder theorem
297EXAMPLE:example chineseRem; shows an example
298"
299{
300   int i;
301   int n=size(L);
302   bigint N=1;
303   for(i=1;i<=n;i++)
304   {
305      N=N*L[i];
306   }
307   list M;
308   for(i=1;i<=n;i++)
309   {
310      M[i]=N div L[i];
311   }
312   list S=eexgcdN(M);
313   bigint x;
314   for(i=1;i<=n;i++)
315   {
316      x=x+S[i]*M[i]*T[i];
317   }
318   x=x mod N;
319   return(x);
320}
321example
322{ "EXAMPLE:"; echo = 2;
323   chineseRem(list(24,15,7),list(2,3,5));
324}
325
326proc Jacobi(bigint a, bigint n)
327"USAGE:  Jacobi(a,n);
328RETURN: the generalized Legendre symbol
329NOTE: if n is an odd prime then Jacobi(a,n)=0,1,-1 if n|a, a=x^2 mod n,else
330EXAMPLE:example Jacobi; shows an example
331"
332{
333   int i;
334   int z=1;
335   bigint t=1;
336   bigint k;
337
338   if((((n-1) div 2) mod 2)!=0){z=-1;}
339   if(a<0){return(z*Jacobi(-a,n));}
340   a=a mod n;
341   if(n==1){return(1);}
342   if(a==0){return(0);}
343
344   while(a!=0)
345   {
346      while((a mod 2)==0)
347      {
348         a=a div 2;
349         if(((n mod 8)==3)||((n mod 8)==5)){t=-t;}
350      }
351      k=a;a=n;n=k;
352      if(((a mod 4)==3)&&((n mod 4)==3)){t=-t;}
353      a=a mod n;
354   }
355   if (n==1){return(t);}
356   return(0);
357}
358example
359{ "EXAMPLE:"; echo = 2;
360   Jacobi(13580555397810650806,5792543);
361}
362
363proc primList(int n)
364"USAGE:  primList(n);
365RETURN: the list of all primes <=n
366EXAMPLE:example primList; shows an example
367"
368{
369   int i,j;
370   list re;
371   re[1]=2;
372   re[2]=3;
373   for(i=5;i<=n;i=i+2)
374   {
375     j=1;
376     while(j<=size(re))
377     {
378        if((i mod re[j])==0){break;}
379        j++;
380     }
381     if(j==size(re)+1){re[size(re)+1]=i;}
382   }
383   return(re);
384}
385example
386{ "EXAMPLE:"; echo = 2;
387   list L=primList(100);
388   size(L);
389   L[size(L)];
390}
391
392proc primL(bigint q)
393"USAGE:  primL(q);
394RETURN: list of the first primes p_1,...,p_r such that q>p_1*...*p_(r-1)
395        and q<p_1*...*p_r
396EXAMPLE:example primL; shows an example
397"
398{
399   int i,j;
400   list re;
401   re[1]=2;
402   re[2]=3;
403   bigint s=6;
404   i=3;
405   while(s<=q)
406   {
407     i=i+2;
408     j=1;
409     while(j<=size(re))
410     {
411        if((i mod re[j])==0){break;}
412        j++;
413     }
414     if(j==size(re)+1)
415     {
416        re[size(re)+1]=i;
417        s=s*i;
418     }
419   }
420   return(re);
421}
422example
423{ "EXAMPLE:"; echo = 2;
424   primL(20);
425}
426
427proc intPart(number x)
428"USAGE:  intPart(x);
429RETURN: the integral part of a rational number
430EXAMPLE:example intPart; shows an example
431"
432{
433  if (x>=0)
434  {
435    return(bigint((numerator(x)-(bigint(numerator(x)) mod bigint(denominator(x)))))
436         div bigint(denominator(x)));
437  }
438  else
439  {
440    return(bigint((numerator(x)-(bigint(numerator(x)) mod bigint(denominator(x)+denominator(x)))))
441         div bigint(denominator(x)));
442  }
443}
444example
445{ "EXAMPLE:"; echo = 2;
446   ring r=0,x,dp;
447   intPart(7/3);
448}
449
450proc intRoot(bigint mm)
451"USAGE:  intRoot(m);
452RETURN: the integral part of the square root of m
453EXAMPLE:example intRoot; shows an example
454"
455{
456   ring R = 0,@x,dp;
457   number m=mm;
458   number x=1;
459   number t=x^2;
460   number s=(x+1)^2;
461   while(((m>t)&&(m>s))||((m<t)&&(m<s)))
462   {
463      if (x==0) { t=0; }
464      else
465      {
466        x=intPart(x/2+m/(2*x));  //Newton step
467        t=x^2;
468      }
469      if(t>m)
470      {
471         s=(x-1)^2;
472      }
473      else
474      {
475         s=(x+1)^2;
476      }
477   }
478   if(t>m){return(bigint(x-1));}
479   if(s==m){return(bigint(x+1));}
480   return(bigint(x));
481}
482example
483{ "EXAMPLE:"; echo = 2;
484   intRoot(20);
485}
486
487proc squareRoot(bigint a, bigint p)
488"USAGE:  squareRoot(a,p);
489RETURN: the square root of a in Z/p, p prime
490NOTE:   assumes the Jacobi symbol is 1 or p=2.
491EXAMPLE:example squareRoot; shows an example
492"
493{
494   if(p==2){return(a);}
495   if((a mod p)==0){return(0);}
496   if (a<0) { a=a+p; }
497   if(powerN(a,p-1,p)!=1)
498   {
499      "p is not prime";
500      return(bigint(-5));
501   }
502   bigint n=random(1,2147483647) mod p;
503   if(n==0){n=n+1;}
504   bigint j=Jacobi(n,p);
505   if(j==0)
506   {
507      "p is not prime";
508      return(bigint(-5));
509   }
510   if(j==1)
511   {
512      return(squareRoot(a,p));
513   }
514   bigint q=p-1;
515   bigint e=0;
516   bigint two=2;
517   bigint z,m,t;
518   while((q mod 2)==0)
519   {
520      e=e+1;
521      q=q div 2;
522   }
523   bigint y=powerN(n,q,p);
524   bigint r=e;
525   bigint x=powerN(a,(q-1) div 2,p);
526   bigint b=a*x^2 mod p;
527   x=a*x mod p;
528
529   while(((b-1) mod p)!=0)
530   {
531      m=0;z=b;
532      while(((z-1) mod p)!=0)
533      {
534         z=z^2 mod p;
535         m=m+1;
536      }
537      t=powerN(y,powerN(two,r-m-1,p),p);
538      y=t^2 mod p;
539      r=m;
540      x=x*t mod p;
541      b=b*y mod p;
542   }
543   return(x);
544}
545example
546{ "EXAMPLE:"; echo = 2;
547   squareRoot(8315890421938608,32003);
548}
549
550
551proc solutionsMod2(bigintmat MM)
552"USAGE:  solutionsMod2(M);
553RETURN: an intmat containing a basis of the vector space of solutions of the
554        linear system of equations defined by M over the prime field of
555        characteristic 2
556EXAMPLE:example solutionsMod2; shows an example
557"
558{
559   ring Rhelp=2,z,(c,dp);
560   int i,j;
561   matrix M[nrows(MM)][ncols(MM)];
562   for(i=1;i<=nrows(MM);i++)
563   {
564      for(j=1;j<=ncols(MM);j++)
565      {
566         M[i,j]=MM[i,j];
567      }
568   }
569   matrix S=syz(M);
570   intmat v[nrows(S)][ncols(S)];
571   for(i=1;i<=nrows(S);i++)
572   {
573      for(j=1;j<=ncols(S);j++)
574      {
575         if(S[i,j]==1){v[i,j]=1;}
576      }
577   }
578   return(v);
579}
580example
581{ "EXAMPLE:"; echo = 2;
582   bigintmat M[3][3]=1,2,3,4,5,6,7,6,5;
583   solutionsMod2(M);
584}
585
586proc powerX(int q, int i, ideal I)
587"USAGE:  powerX(q,i,I);
588RETURN: the q-th power of the i-th variable modulo I
589ASSUME: I is a standard basis
590EXAMPLE:example powerX; shows an example
591"
592{
593   if(q<=181){return(reduce(var(i)^int(q),I));}
594   if((q mod 5)==0){return(reduce(powerX(q div 5,i,I)^5,I));}
595   if((q mod 4)==0){return(reduce(powerX(q div 4,i,I)^4,I));}
596   if((q mod 3)==0){return(reduce(powerX(q div 3,i,I)^3,I));}
597   if((q mod 2)==0){return(reduce(powerX(q div 2,i,I)^2,I));}
598   return(reduce(var(i)*powerX(q-1,i,I),I));
599}
600example
601{ "EXAMPLE:"; echo = 2;
602   ring R = 0,(x,y),dp;
603   powerX(100,2,std(ideal(x3-1,y2-x)));
604}
605
606//======================================================================
607//=========================== Discrete Logarithm =======================
608//======================================================================
609
610//============== Shank's baby step - giant step ========================
611
612proc babyGiant(bigint b, bigint y, bigint p)
613"USAGE:  babyGiant(b,y,p);
614RETURN: the discrete logarithm x: b^x=y mod p
615NOTE:   This procedure works based on Shank's baby step - giant step method.
616EXAMPLE:example babyGiant; shows an example
617"
618{
619   int i,j,m;
620   list l;
621   bigint h=1;
622   bigint x;
623
624//choose m minimal such that m^2>p
625   for(i=1;i<=p;i++){if(i^2>p) break;}
626   m=i;
627
628//baby-step:  compute the table y*b^i for 1<=i<=m
629   for(i=1;i<=m;i++){l[i]=y*b^i mod p;}
630
631//giant-step: compute b^(m+j), 1<=j<=m and search in the baby-step table
632//for an i with y*b^i=b^(m*j). If found then x=m*j-i
633   bigint g=b^m mod p;
634   while(j<m)
635   {
636      j++;
637      h=h*g mod p;
638      for(i=1;i<=m;i++)
639      {
640         if(h==l[i])
641         {
642            x=m*j-i;
643            j=m;
644            break;
645         }
646     }
647   }
648   return(x);
649}
650example
651{ "EXAMPLE:"; echo = 2;
652   bigint b=2;
653   bigint y=10;
654   bigint p=101;
655   babyGiant(b,y,p);
656}
657
658//==============  Pollards rho  =================================
659
660proc rho(bigint b, bigint y, bigint p)
661"USAGE:  rho(b,y,p);
662RETURN: the discrete logarithm x=log_b(y): b^x=y mod p
663NOTE: Pollard's rho:
664       choose random f_0 in 0,...,p-2 ,e_0=0, define x_0=b^f_0, define
665       x_i=y^e_i*b^f_i as below. For i large enough there is i with
666       x_(i/2)=x_i. Let s:=e_(i/2)-e_i mod p-1 and t:=f_i-f_(i/2) mod p-1,
667       d=gcd(s,p-1)=u*s+v*(p-1) then x=tu/d +j*(p-1)/d for some j (to be
668       found by trying)
669EXAMPLE:example rho; shows an example
670"
671{
672   int i=1;
673   int j;
674   bigint s,t;
675   list e,f,x;
676
677   e[1]=0;
678   f[1]=random(0,2147483629) mod (p-1);
679   x[1]=powerN(b,f[1],p);
680   while(i)
681   {
682      if((x[i] mod 3)==1)
683      {
684         x[i+1]=y*x[i] mod p;
685         e[i+1]=e[i]+1 mod (p-1);
686         f[i+1]=f[i];
687      }
688      if((x[i] mod 3)==2)
689      {
690         x[i+1]=x[i]^2 mod p;
691         e[i+1]=e[i]*2 mod (p-1);
692         f[i+1]=f[i]*2 mod (p-1);
693      }
694      if((x[i] mod 3)==0)
695      {
696         x[i+1]=x[i]*b mod p;
697         e[i+1]=e[i];
698         f[i+1]=f[i]+1 mod (p-1);
699      }
700      i++;
701      for(j=i-1;j>=1;j--)
702      {
703         if(x[i]==x[j])
704         {
705            s=(e[j]-e[i]) mod (p-1);
706            t=(f[i]-f[j]) mod (p-1);
707            if(s!=0)
708            {
709               i=0;
710            }
711            else
712            {
713               e[1]=0;
714               f[1]=random(0,2147483629) mod (p-1);
715               x[1]=powerN(b,f[1],p);
716               i=1;
717            }
718            break;
719         }
720      }
721   }
722
723   list w=extgcd(s,p-1);
724   bigint u=w[2];
725   bigint d=w[1];
726
727   bigint a=(t*u div d) mod (p-1);
728
729   bigint pn=powerN(b,a,p);
730   if (pn<0) { pn=pn+p;}
731   while(powerN(b,a,p)!=y)
732   {
733      a=(a+(p-1) div d) mod (p-1);
734      if (a<0) { a=a+p-1; }
735   }
736   return(a);
737}
738example
739{ "EXAMPLE:"; echo = 2;
740   bigint b=2;
741   bigint y=10;
742   bigint p=101;
743   rho(b,y,p);
744}
745//====================================================================
746//====================== Primality Tests =============================
747//====================================================================
748
749//================================= Miller-Rabin =====================
750
751proc MillerRabin(bigint n, int k)
752"USAGE:  MillerRabin(n,k);
753RETURN: 1 if n is prime, 0 else
754NOTE: probabilistic test of Miller-Rabin with k loops to test if n is prime.
755       Using the theorem: If n is prime, n-1=2^s*r, r odd, then
756       powerN(a,r,n)=1 or powerN(a,r*2^i,n)=-1 for some i
757EXAMPLE:example MillerRabin; shows an example
758"
759{
760   if(n<0){n=-n;}
761   if((n==2)||(n==3)){return(1);}
762   if((n mod 2)==0){return(0);}
763
764   int i;
765   bigint a,b,j,r,s;
766   r=n-1;
767   s=0;
768   while((r mod 2)==0)
769   {
770      s=s+1;
771      r=r div 2;
772   }
773   while(i<k)
774   {
775      i++;
776      a=random(2,2147483629) mod n; if(a==0){a=3;}
777      if(gcd(a,n)!=1){return(0);}
778      b=powerN(a,r,n);
779      if(b!=1)
780      {
781         j=0;
782         while(j<s)
783         {
784           if(((b+1) mod n)==0) break;
785           b=powerN(b,2,n);
786           j=j+1;
787         }
788         if(j==s){return(0);}
789      }
790   }
791   return(1);
792}
793example
794{ "EXAMPLE:"; echo = 2;
795   bigint x=2;
796   x=x^787-1;
797   MillerRabin(x,3);
798}
799
800//======================= Soloway-Strassen  ==========================
801
802proc SolowayStrassen(bigint n, int k)
803"USAGE:  SolowayStrassen(n,k);
804RETURN: 1 if n is prime, 0 else
805NOTE: probabilistic test of Soloway-Strassen with k loops to test if n is
806       prime using the theorem: If n is prime then
807       powerN(a,(n-1)/2,n)=Jacobi(a,n) mod n
808EXAMPLE:example SolowayStrassen; shows an example
809"
810{
811   if(n<0){n=-n;}
812   if((n==2)||(n==3)){return(1);}
813   if((n mod 2)==0){return(0);}
814
815   bigint a,pn,jn;
816   int i;
817   while(i<k)
818   {
819      i++;
820      a=random(2,2147483629) mod n; if(a==0){a=3;}
821      if(gcd(a,n)!=1){return(0);}
822      pn=powerN(a,(n-1) div 2,n);
823      if (pn<0) { pn=pn+n;}
824      jn=Jacobi(a,n) mod n;
825      if (jn<0) { jn=jn+n;}
826      if(pn!=jn){return(0);}
827   }
828   return(1);
829}
830example
831{ "EXAMPLE:"; echo = 2;
832   bigint h=10;
833   bigint p=h^100+267;
834   //p=h^100+43723;
835   //p=h^200+632347;
836   SolowayStrassen(h,3);
837}
838
839
840/*
841ring R=0,z,dp;
842number p=398075086424064937397125500550386491199064362342526708406385189575946388957261768583317;
843number q=472772146107435302536223071973048224632914695302097116459852171130520711256363590397527;
844number n=p*q;
845SolowayStrassen(n,3);
846*/
847
848//===================== Pocklington-Lehmer ==============================
849
850proc PocklingtonLehmer(bigint N, list #)
851"USAGE: PocklingtonLehmer(N); optional: PocklingtonLehmer(N,L);
852        L a list of the first k primes
853RETURN:message N is not prime or {A,{p},{a_p}} as certificate for N being prime
854NOTE:assumes that it is possible to factorize N-1=A*B such that gcd(A,B)=1,
855      the factorization of A is completely known and A^2>N .
856      N is prime if and only if for each prime factor p of A we can find
857      a_p such that a_p^(N-1)=1 mod N and gcd(a_p^((N-1)/p)-1,N)=1
858EXAMPLE:example PocklingtonLehmer; shows an example
859"
860{
861   bigint m=intRoot(N);
862   if(size(#)>0)
863   {
864      list S=PollardRho(N-1,10000,1,#);
865   }
866   else
867   {
868      list S=PollardRho(N-1,10000,1);
869   }
870   int i,j;
871   bigint A=1;
872   bigint p,a,g;
873   list PA;
874   list re;
875
876   while(i<size(S))
877   {
878      p=S[i+1];
879      A=A*p;
880      PA[i+1]=p;
881      if(A>m){break;}
882
883      while(1)
884      {
885        p=p*S[i+1];
886        if(((N-1) mod p)==0)
887        {
888           A=A*p;
889        }
890        else
891        {
892           break;
893        }
894      }
895      i++;
896   }
897   if(A<=m)
898   {
899     A=N div A;
900     PA=list(S[size(S)]);
901   }
902   for(i=1;i<=size(PA);i++)
903   {
904      a=1;
905      while(a<N-1)
906      {
907         a=a+1;
908         if(powerN(a,N-1,N)!=1){return("not prime");}
909         g=gcd(powerN(a,(N-1) div PA[i],N),N);
910         if(g==1)
911         {
912           re[size(re)+1]=list(PA[i],a);
913           break;
914         }
915         if(g<N){"not prime";return(g);}
916      }
917   }
918   return(list(A,re));
919}
920example
921{ "EXAMPLE:"; echo = 2;
922   bigint N=105554676553297;
923   PocklingtonLehmer(N);
924   list L=primList(1000);
925   PocklingtonLehmer(N,L);
926}
927
928//=======================================================================
929//======================= Factorization =================================
930//=======================================================================
931
932//======================= Pollards rho  =================================
933
934proc PollardRho(bigint n, int k, int allFactors, list #)
935"USAGE:  PollardRho(n,k,allFactors); optional: PollardRho(n,k,allFactors,L);
936         L a list of the first k primes
937RETURN: a list of factors of n (which could be just n),if allFactors=0@*
938        a list of all factors of n ,if allFactors=1
939NOTE: probabilistic rho-algorithm of Pollard to find a factor of n in k loops.
940      Creates a sequence x_i such that (x_i)^2=(x_2i)^2 mod n for some i,
941      computes gcd(x_i-x_2i,n) to find a divisor. To define the sequence
942      choose x,a and define x_n+1=x_n^2+a mod n, x_1=x.
943      If allFactors is 1, it tries to find recursively all prime factors
944      using the Soloway-Strassen test.
945SEE ALSO: primefactors
946EXAMPLE:example PollardRho; shows an example
947"
948{
949    int i,j;
950    list L=primList(100);
951    list re,se;
952    if(n<0){n=-n;}
953    if(n==1){return(re);}
954
955//this is optional: test whether a prime of the list # divides n
956    if(size(#)>0)
957    {
958       L=#;
959    }
960    for(i=1;i<=size(L);i++)
961    {
962       if((n mod L[i])==0)
963       {
964          re[size(re)+1]=L[i];
965          while((n mod L[i])==0)
966          {
967             n=n div L[i];
968          }
969       }
970       if(n==1){return(re);}
971    }
972    int e=size(re);
973//here the rho-algorithm starts
974    bigint a,d,x,y;
975    while(n>1)
976    {
977       a=random(2,2147483629);
978       x=random(2,2147483629);
979       y=x;
980       d=1;
981       i=0;
982       while(i<k)
983       {
984          i++;
985          x=powerN(x,2,n); x=(x+a) mod n;
986          y=powerN(y,2,n); y=(y+a) mod n;
987          y=powerN(y,2,n); y=(y+a) mod n;
988          d=gcd(x-y,n);
989          if(d>1)
990          {
991             re[size(re)+1]=d;
992             while((n mod d)==0)
993             {
994               n=n div d;
995             }
996             break;
997          }
998          if(i==k)
999          {
1000             re[size(re)+1]=n;
1001             n=1;
1002          }
1003       }
1004    }
1005    if(allFactors)      //want to obtain all prime factors
1006    {
1007       i=e;
1008       while(i<size(re))
1009       {
1010          i++;
1011
1012          if(!SolowayStrassen(re[i],5))
1013          {
1014             se=PollardRho(re[i],2*k,1);
1015             re[i]=se[size(se)];
1016             for(j=1;j<=size(se)-1;j++)
1017             {
1018                re[size(re)+1]=se[j];
1019             }
1020             i--;
1021          }
1022       }
1023    }
1024    return(re);
1025}
1026example
1027{ "EXAMPLE:"; echo = 2;
1028   bigint h=10;
1029   bigint p=h^30+4;
1030   PollardRho(p,5000,0);
1031}
1032
1033//======================== Pollards p-factorization ================
1034proc pFactor(bigint n,int B, list P)
1035"USAGE:  pFactor(n,B,P); n to be factorized, B a bound , P a list of primes
1036RETURN: a list of factors of n or n if no factor found
1037NOTE: Pollard's p-factorization
1038       creates the product k of powers of primes (bounded by B)  from
1039       the list P with the idea that for a prime divisor p of n we have
1040       p-1|k, and then p divides gcd(a^k-1,n) for some random a
1041EXAMPLE:example pFactor; shows an example
1042"
1043{
1044   int i;
1045   bigint k=1;
1046   bigint w;
1047   while(i<size(P))
1048   {
1049      i++;
1050      w=P[i];
1051      if(w>B) break;
1052      while(w*P[i]<=B)
1053      {
1054         w=w*P[i];
1055      }
1056      k=k*w;
1057   }
1058   bigint a=random(2,2147483629);
1059   bigint d=gcd(powerN(a,k,n)-1,n);
1060   if((d>1)&&(d<n)){return(d);}
1061   return(n);
1062}
1063example
1064{ "EXAMPLE:"; echo = 2;
1065   list L=primList(1000);
1066   pFactor(1241143,13,L);
1067   bigint h=10;
1068   h=h^30+25;
1069   pFactor(h,20,L);
1070}
1071
1072//==================== quadratic sieve ==============================
1073
1074proc quadraticSieve(bigint n, int c, list B, int k)
1075"USAGE:  quadraticSieve(n,c,B,k); n to be factorized, [-c,c] the
1076         sieve-intervall, B a list of primes,
1077         k for using the first k elements in B
1078RETURN: a list of factors of n or the message: no divisor found
1079NOTE: The idea being used is to find x,y such that x^2=y^2 mod n then
1080      gcd(x-y,n) can be a proper divisor of n
1081EXAMPLE:example quadraticSieve; shows an example
1082"
1083{
1084   bigint f,d;
1085   int i,j,l,s,p;
1086   list S,tmp;
1087   intvec v;
1088   v[k]=0;
1089
1090//compute the integral part of the square root of n
1091   bigint m=intRoot(n);
1092
1093//consider the function f(X)=(X+m)^2-n and compute for s in [-c,c] the values
1094   while(i<=2*c)
1095   {
1096      f=(i-c+m)^2-n;
1097      tmp[1]=i-c+m;
1098      tmp[2]=f;
1099      tmp[3]=v;
1100      S[i+1]=tmp;
1101      i++;
1102   }
1103
1104//the sieve with p in B
1105//find all s in [-c,c] such that f(s) has all prime divisors in the first
1106//k elements of B and the decomposition of f(s). They are characterized
1107//by 1 or -1 at the second place of S[j]:
1108//S[j]=j-c+m,f(j-c)/p_1^v_1*...*p_k^v_k, v_1,...,v_k maximal
1109   for(i=1;i<=k;i++)
1110   {
1111      p=B[i];
1112      if((p>2)&&(Jacobi(n,p)==-1)){i++;continue;}//n is no quadratic rest mod p
1113      j=1;
1114      while(j<=p)
1115      {
1116         if(j>2*c+1) break;
1117         f=S[j][2];
1118         v=S[j][3];
1119         s=0;
1120         while((f mod p)==0)
1121         {
1122            s++;
1123            f=f div p;
1124         }
1125         if(s)
1126         {
1127           S[j][2]=f;
1128           v[i]=s;
1129           S[j][3]=v;
1130           l=j;
1131           while(l+p<=2*c+1)
1132           {
1133              l=l+p;
1134              f=S[l][2];
1135              v=S[l][3];
1136              s=0;
1137              while((f mod p)==0)
1138              {
1139                s++;
1140                f=f div p;
1141              }
1142              S[l][2]=f;
1143              v[i]=s;
1144              S[l][3]=v;
1145           }
1146         }
1147         j++;
1148      }
1149   }
1150   list T;
1151   for(j=1;j<=2*c+1;j++)
1152   {
1153      if((S[j][2]==1)||(S[j][2]==-1))
1154      {
1155         T[size(T)+1]=S[j];
1156      }
1157   }
1158
1159//the system of equations for the exponents {l_s} for the f(s) such
1160//product f(s)^l_s is a square (l_s are 1 or 0)
1161   bigintmat M[k+1][size(T)];
1162   for(j=1;j<=size(T);j++)
1163   {
1164      if(T[j][2]==-1){M[1,j]=1;}
1165      for(i=1;i<=k;i++)
1166      {
1167         M[i+1,j]=T[j][3][i];
1168      }
1169   }
1170   intmat G=solutionsMod2(M);
1171
1172//construction of x and y such that x^2=y^2 mod n and d=gcd(x-y,n)
1173//y=square root of product f(s)^l_s
1174//x=product s+m
1175   bigint x=1;
1176   bigint y=1;
1177
1178   for(i=1;i<=ncols(G);i++)
1179   {
1180      kill v;
1181      intvec v;
1182      v[k]=0;
1183      for(j=1;j<=size(T);j++)
1184      {
1185         x=x*T[j][1]^G[j,i] mod n;
1186         if((T[j][2]==-1)&&(G[j,i]==1)){y=-y;}
1187         v=v+G[j,i]*T[j][3];
1188
1189      }
1190      for(l=1;l<=k;l++)
1191      {
1192         y=y*B[l]^(v[l] div 2) mod n;
1193      }
1194      d=gcd(x-y,n);
1195      if((d>1)&&(d<n)){return(d);}
1196   }
1197   return("no divisor found");
1198}
1199example
1200{ "EXAMPLE:"; echo = 2;
1201   list L=primList(5000);
1202   quadraticSieve(7429,3,L,4);
1203   quadraticSieve(1241143,100,L,50);
1204}
1205
1206//======================================================================
1207//==================== elliptic curves  ================================
1208//======================================================================
1209
1210//================= elementary operations ==============================
1211
1212proc isOnCurve(bigint N, bigint a, bigint b, list P)
1213"USAGE:  isOnCurve(N,a,b,P);
1214RETURN: 1 or 0 (depending on whether P is on the curve or not)
1215NOTE: checks whether P=(P[1]:P[2]:P[3]) is a point on the elliptic
1216      curve defined by y^2z=x^3+a*xz^2+b*z^3  over Z/N
1217EXAMPLE:example isOnCurve; shows an example
1218"
1219{
1220   if(((P[2]^2*P[3]-P[1]^3-a*P[1]*P[3]^2-b*P[3]^3) mod N)!=0){return(0);}
1221   return(1);
1222}
1223example
1224{ "EXAMPLE:"; echo = 2;
1225   isOnCurve(32003,5,7,list(10,16,1));
1226}
1227
1228proc ellipticAdd(bigint N, bigint a, bigint b, list P, list Q)
1229"USAGE:  ellipticAdd(N,a,b,P,Q);
1230RETURN: list L, representing the point P+Q
1231NOTE: P=(P[1]:P[2]:P[3]), Q=(Q[1]:Q[2]:Q[3]) points on the elliptic curve
1232      defined by y^2z=x^3+a*xz^2+b*z^3  over Z/N
1233EXAMPLE:example ellipticAdd; shows an example
1234"
1235{
1236   if(N==2){ERROR("not implemented for 2");}
1237   int i;
1238   for(i=1;i<=3;i++)
1239   {
1240      P[i]=P[i] mod N; if (P[i]<0) { P[i]=P[i]+N:}
1241      Q[i]=Q[i] mod N; if (Q[i]<0) { Q[i]=Q[i]+N;}
1242   }
1243   list Resu;
1244   Resu[1]=bigint(0);
1245   Resu[2]=bigint(1);
1246   Resu[3]=bigint(0);
1247   list Error;
1248   Error[1]=0;
1249   //test for ellictic curve
1250   bigint D=4*a^3+27*b^2;
1251   bigint g=gcd(D,N);
1252   if(g==N){return(Error);}
1253   if(g!=1)
1254   {
1255      P[4]=g;
1256      return(P);
1257   }
1258   if(((P[1]==0)&&(P[2]==0)&&(P[3]==0))||((Q[1]==0)&&(Q[2]==0)&&(Q[3]==0)))
1259   {
1260      Error[1]=-2;
1261      return(Error);
1262   }
1263   if(!isOnCurve(N,a,b,P)||!isOnCurve(N,a,b,Q))
1264   {
1265      Error[1]=-1;
1266      return(Error);
1267   }
1268   if(P[3]==0){return(Q);}
1269   if(Q[3]==0){return(P);}
1270   list I=extgcd(P[3],N);
1271   if(I[1]!=1)
1272   {
1273      P[4]=I[1];
1274      return(P);
1275   }
1276   P[1]=P[1]*I[2] mod N;
1277   P[2]=P[2]*I[2] mod N;
1278   I=extgcd(Q[3],N);
1279   if(I[1]!=1)
1280   {
1281      P[4]=I[1];
1282      return(P);
1283   }
1284   Q[1]=Q[1]*I[2] mod N;
1285   Q[2]=Q[2]*I[2] mod N;
1286   if((P[1]==Q[1])&&(((P[2]+Q[2]) mod N)==0)){return(Resu);}
1287   bigint L;
1288   if((P[1]==Q[1])&&(P[2]==Q[2]))
1289   {
1290      I=extgcd(2*Q[2],N);
1291      if(I[1]!=1)
1292      {
1293         P[4]=I[1];
1294         return(P);
1295      }
1296      L=I[2]*(3*Q[1]^2+a) mod N;
1297   }
1298   else
1299   {
1300      I=extgcd(Q[1]-P[1],N);
1301      if(I[1]!=1)
1302      {
1303         P[4]=I[1];
1304         return(P);
1305      }
1306      L=(Q[2]-P[2])*I[2] mod N;
1307   }
1308   Resu[1]=(L^2-P[1]-Q[1]) mod N;
1309   if (Resu[1]<0) { Resu[1]=Resu[1]+N; }
1310   Resu[2]=(L*(P[1]-Resu[1])-P[2]) mod N;
1311   if (Resu[2]<0) { Resu[2]=Resu[2]+N; }
1312   Resu[3]=bigint(1);
1313   return(Resu);
1314}
1315example
1316{ "EXAMPLE:"; echo = 2;
1317   bigint N=11;
1318   bigint a=1;
1319   bigint b=6;
1320   list P,Q;
1321   P[1]=2;
1322   P[2]=4;
1323   P[3]=1;
1324   Q[1]=3;
1325   Q[2]=5;
1326   Q[3]=1;
1327   ellipticAdd(N,a,b,P,Q);
1328}
1329
1330proc ellipticMult(bigint N, bigint a, bigint b, list P, bigint k)
1331"USAGE:  ellipticMult(N,a,b,P,k);
1332RETURN: a list L representing the point k*P
1333NOTE:  P=(P[1]:P[2]:P[3]) a point on the elliptic curve defined by
1334       y^2z=x^3+a*xz^2+b*z^3  over Z/N
1335EXAMPLE:example ellipticMult; shows an example
1336"
1337{
1338   if(P[3]==0){return(P);}
1339   list resu;
1340   resu[1]=bigint(0);
1341   resu[2]=bigint(1);
1342   resu[3]=bigint(0);
1343
1344   if(k==0){return(resu);}
1345   if(k==1){return(P);}
1346   if(k==2){return(ellipticAdd(N,a,b,P,P));}
1347   if(k==-1)
1348   {
1349      resu=P;
1350      resu[2]=N-P[2];
1351      return(resu);
1352   }
1353   if(k<0)
1354   {
1355      resu=ellipticMult(N,a,b,P,-k);
1356      return(ellipticMult(N,a,b,resu,-1));
1357   }
1358   if((k mod 2)==0)
1359   {
1360      resu=ellipticMult(N,a,b,P,k div 2);
1361      return(ellipticAdd(N,a,b,resu,resu));
1362   }
1363   resu=ellipticMult(N,a,b,P,k-1);
1364   return(ellipticAdd(N,a,b,resu,P));
1365}
1366example
1367{ "EXAMPLE:"; echo = 2;
1368   bigint N=11;
1369   bigint a=1;
1370   bigint b=6;
1371   list P;
1372   P[1]=2;
1373   P[2]=4;
1374   P[3]=1;
1375   ellipticMult(N,a,b,P,3);
1376}
1377
1378//================== Random for elliptic curves =====================
1379
1380proc ellipticRandomCurve(bigint N)
1381"USAGE:  ellipticRandomCurve(N);
1382RETURN: a list of two random numbers a,b and 4a^3+27b^2 mod N
1383NOTE:   y^2z=x^3+a*xz^2+b^2*z^3 defines an elliptic curve over Z/N
1384EXAMPLE:example ellipticRandomCurve; shows an example
1385"
1386{
1387   int k;
1388   while(k<=10)
1389   {
1390     k++;
1391     bigint a=random(1,2147483647) mod N;
1392     bigint b=random(1,2147483647) mod N;
1393     //test for ellictic curve
1394     bigint D=4*a^3+27*b^4; //the constant term is b^2
1395     bigint g=gcd(D,N);
1396     if(g<N){return(list(a,b,g));}
1397   }
1398   ERROR("no random curve found");
1399}
1400example
1401{ "EXAMPLE:"; echo = 2;
1402   ellipticRandomCurve(32003);
1403}
1404
1405proc ellipticRandomPoint(bigint N, bigint a, bigint b)
1406"USAGE:  ellipticRandomPoint(N,a,b);
1407RETURN: a list representing  a random point (x:y:z) of the elliptic curve
1408        defined by y^2z=x^3+a*xz^2+b*z^3  over Z/N
1409EXAMPLE:example ellipticRandomPoint; shows an example
1410"
1411{
1412   bigint x=random(1,2147483647) mod N;
1413   bigint h=x^3+a*x+b;
1414   h=h mod N;
1415   list resu;
1416   resu[1]=x;
1417   resu[2]=0;
1418   resu[3]=1;
1419   if(h==0){return(resu);}
1420
1421   bigint n=Jacobi(h,N);
1422   if(n==0)
1423   {
1424      resu=-5;
1425      "N is not prime";
1426      return(resu);
1427   }
1428   if(n==1)
1429   {
1430      resu[2]=squareRoot(h,N);
1431      return(resu);
1432   }
1433   return(ellipticRandomPoint(N,a,b));
1434}
1435example
1436{ "EXAMPLE:"; echo = 2;
1437   ellipticRandomPoint(32003,3,181);
1438}
1439
1440
1441
1442//====================================================================
1443//======== counting the points of an elliptic curve  =================
1444//====================================================================
1445
1446//==================   the trivial approaches  =======================
1447proc countPoints(bigint N, bigint a, bigint b)
1448"USAGE:  countPoints(N,a,b);
1449RETURN: the number of points of the elliptic curve defined by
1450        y^2=x^3+a*x+b  over Z/N
1451NOTE: trivial approach
1452EXAMPLE:example countPoints; shows an example
1453"
1454{
1455  bigint x;
1456  bigint r=N+1;
1457  while(x<N)
1458  {
1459     r=r+Jacobi((x^3+a*x+b) mod N,N);
1460     x=x+1;
1461  }
1462  return(r);
1463}
1464example
1465{ "EXAMPLE:"; echo = 2;
1466   countPoints(181,71,150);
1467}
1468
1469proc ellipticAllPoints(bigint N, bigint a, bigint b)
1470"USAGE:  ellipticAllPoints(N,a,b);
1471RETURN: list of points (x:y:z) of the elliptic curve defined by
1472        y^2z=x^3+a*xz^2+b*z^3  over Z/N
1473EXAMPLE:example ellipticAllPoints; shows an example
1474"
1475{
1476   list resu,point;
1477   point[1]=0;
1478   point[2]=1;
1479   point[3]=0;
1480   resu[1]=point;
1481   point[3]=1;
1482   bigint x,h,n;
1483   while(x<N)
1484   {
1485      h=(x^3+a*x+b) mod N;
1486      if(h==0)
1487      {
1488         point[1]=x;
1489         point[2]=0;
1490         resu[size(resu)+1]=point;
1491      }
1492      else
1493      {
1494         n=Jacobi(h,N);
1495         if(n==1)
1496         {
1497            n=squareRoot(h,N);
1498            point[1]=x;
1499            point[2]=n;
1500            resu[size(resu)+1]=point;
1501            point[2]=N-n;
1502            resu[size(resu)+1]=point;
1503         }
1504      }
1505      x=x+1;
1506   }
1507   return(resu);
1508}
1509example
1510{ "EXAMPLE:"; echo = 2;
1511   list L=ellipticAllPoints(181,71,150);
1512   size(L);
1513   L[size(L)];
1514}
1515
1516//================ the algorithm of Shanks and Mestre =================
1517
1518proc ShanksMestre(bigint q, bigint a, bigint b, list #)
1519"USAGE:  ShanksMestre(q,a,b); optional: ShanksMestre(q,a,b,s); s the number
1520         of loops in the algorithm (default s=1)
1521RETURN: the number of points of the elliptic curve defined by
1522         y^2=x^3+a*x+b  over Z/N
1523NOTE: algorithm of Shanks and Mestre (baby-step-giant-step)
1524EXAMPLE:example ShanksMestre; shows an example
1525"
1526{
1527   bigint n=intRoot(4*q);
1528   bigint m=intRoot(intRoot(16*q))+1;
1529   bigint d;
1530   int i,j,k,s;
1531   list B,K,T,P,Q,R,mP;
1532   B[1]=list(0,1,0);
1533   if(size(#)>0)
1534   {
1535      s=#[1];
1536   }
1537   else
1538   {
1539      s=1;
1540   }
1541   while(k<s)
1542   {
1543      P =ellipticRandomPoint(q,a,b);
1544      Q =ellipticMult(q,a,b,P,n+q+1);
1545
1546      while(j<m)
1547      {
1548         j++;
1549         B[j+1]=ellipticAdd(q,a,b,P,B[j]);  //baby-step list
1550      }
1551      mP=ellipticAdd(q,a,b,P,B[j]);
1552      mP[2]=q-mP[2];
1553      while(i<m)                            //giant-step
1554      {
1555         j=0;
1556         while(j<m)
1557         {
1558            j++;
1559            if((Q[1]==B[j][1])&&(Q[2]==B[j][2])&&(Q[3]==B[j][3]))
1560            {
1561               T[1]=P;
1562               T[2]=q+1+n-(i*m+j-1);
1563               K[size(K)+1]=T;
1564               if(size(K)>1)
1565               {
1566                  if(K[size(K)][2]!=K[size(K)-1][2])
1567                  {
1568                     d=gcd(K[size(K)][2],K[size(K)-1][2]);
1569                     if(ellipticMult(q,a,b,K[size(K)],d)[3]==0)
1570                     {
1571                       K[size(K)][2]=K[size(K)-1][2];
1572                     }
1573                  }
1574               }
1575               i=int(m);
1576               break;
1577            }
1578         }
1579         i=i+1;
1580         Q=ellipticAdd(q,a,b,mP,Q);
1581      }
1582      k++;
1583   }
1584   if(size(K)>0)
1585   {
1586      int te=1;
1587      for(i=1;i<=size(K)-1;i++)
1588      {
1589         if(K[size(K)][2]!=K[i][2])
1590         {
1591           if(ellipticMult(q,a,b,K[i],K[size(K)][2])[3]!=0)
1592           {
1593             te=0;
1594             break;
1595           }
1596         }
1597      }
1598      if(te)
1599      {
1600         return(K[size(K)][2]);
1601      }
1602   }
1603   return(ShanksMestre(q,a,b,s));
1604}
1605example
1606{ "EXAMPLE:"; echo = 2;
1607   ShanksMestre(32003,71,602);
1608}
1609
1610//==================== Schoof's algorithm =============================
1611
1612proc Schoof(bigint N,bigint a, bigint b)
1613"USAGE:  Schoof(N,a,b);
1614RETURN: the number of points of the elliptic curve defined by
1615        y^2=x^3+a*x+b  over Z/N
1616NOTE:  algorithm of Schoof
1617EXAMPLE:example Schoof; shows an example
1618"
1619{
1620   int pr=printlevel;
1621//test for ellictic curve
1622   bigint D=4*a^3+27*b^2;
1623   bigint G=gcd(D,N);
1624   if(G==N){ERROR("not an elliptic curve");}
1625   if(G!=1){ERROR("not a prime");}
1626
1627//=== small N
1628  // if((N<=500)&&(pr<5)){return(countPoints(int(N),a,b));}
1629
1630//=== the general case
1631   bigint q=intRoot(4*N);
1632   list L=primL(2*q);
1633   int r=size(L);
1634   list T;
1635   int i,j;
1636   for(j=1;j<=r;j++)
1637   {
1638      T[j]=(testElliptic(int(N),a,b,L[j])+int(q)) mod L[j];
1639   }
1640   if(pr>=5)
1641   {
1642      "===================================================================";
1643      "Chinese remainder :";
1644      for(i=1;i<=size(T);i++)
1645      {
1646         " x =",T[i]," mod ",L[i];
1647      }
1648      "gives t+ integral part of the square root of q (to be positive)";
1649      chineseRem(T,L);
1650      "we obtain t = ",chineseRem(T,L)-q;
1651      "===================================================================";
1652   }
1653   bigint t=chineseRem(T,L)-q;
1654   return(N+1-t);
1655}
1656example
1657{ "EXAMPLE:"; echo = 2;
1658   Schoof(32003,71,602);
1659}
1660
1661/*
1662needs 518 sec
1663Schoof(2147483629,17,3567);
16642147168895
1665*/
1666
1667
1668proc generateG(number a,number b, int m)
1669"USAGE:  generateG(a,b,m);
1670RETURN: m-th division polynomial
1671NOTE: generate the so-called division polynomials, i.e., the recursively defined
1672polynomials p_m=generateG(a,b,m) in Z[x, y] such that, for a point (x:y:1) on the
1673elliptic curve defined by y^2=x^3+a*x+b  over Z/N the point@*
1674m*P=(x-(p_(m-1)*p_(m+1))/p_m^2 :(p_(m+2)*p_(m-1)^2-p_(m-2)*p_(m+1)^2)/4y*p_m^3 :1)
1675and m*P=0 if and only if p_m(P)=0
1676EXAMPLE:example generateG; shows an example
1677"
1678{
1679   if(m==0){return(poly(0));}
1680   if(m==1){return(poly(1));}
1681   if(m==2){return(2*var(1));}
1682   if(m==3){return(3*var(2)^4+6*a*var(2)^2+12*b*var(2)-a^2);}
1683   if(m==4)
1684   {
1685      return(4*var(1)*(var(2)^6+5*a*var(2)^4+20*b*var(2)^3-5*a^2*var(2)^2
1686        -4*a*b*var(2)-8*b^2-a^3));
1687   }
1688   if((m mod 2)==0)
1689   {
1690      return((generateG(a,b,m div 2+2)*generateG(a,b,m div 2-1)^2
1691        -generateG(a,b,m div 2-2)*generateG(a,b,m div 2+1)^2)
1692        *generateG(a,b,m div 2)/(2*var(1)));
1693   }
1694   return(generateG(a,b,(m-1) div 2+2)*generateG(a,b,(m-1) div 2)^3
1695     -generateG(a,b,(m-1) div 2-1)*generateG(a,b,(m-1) div 2+1)^3);
1696}
1697example
1698{ "EXAMPLE:"; echo = 2;
1699   ring R = 0,(x,y),dp;
1700   generateG(7,15,4);
1701}
1702
1703
1704static proc testElliptic(int q,bigint aa,bigint bb,int l)
1705"USAGE:  testElliptic(q,a,b,l);
1706RETURN: an integer t, the trace of the Frobenius
1707NOTE: the kernel for the Schoof algorithm: looks for the t such that for all
1708      points (x:y:1) in C[l]={P in C | l*P=0},C the elliptic curve defined by
1709      y^2=x^3+a*x+b  over Z/q with group structure induced by 0=(0:1:0),
1710      (x:y:1)^(q^2)-t*(x:y:1)^q -ql*(x:y:1)=(0:1:0), ql= q mod l, trace of
1711      Frobenius.
1712EXAMPLE:example testElliptic; shows an example
1713"
1714{
1715   int pr=printlevel;
1716   ring S=q,(y,x),(L(100000),lp);
1717   number a=aa;
1718   number b=bb;
1719   poly F=y2-x3-a*x-b;       // the curve C
1720   poly G=generateG(a,b,l);
1721   ideal I=std(ideal(F,G));  // the points C[l]
1722   poly xq=powerX(q,2,I);
1723   poly yq=powerX(q,1,I);
1724   poly xq2=reduce(subst(xq,x,xq,y,yq),I);
1725   poly yq2=reduce(subst(yq,x,xq,y,yq),I);
1726   ideal J;
1727   int ql=q mod l;
1728   if(ql==0){ERROR("q is not prime");}
1729   int t;
1730   poly F1,F2,G1,G2,P1,P2,Q1,Q2,H1,H2,L1,L2;
1731
1732   if(pr>=5)
1733   {
1734      "===================================================================";
1735      "q=",q;
1736      "l=",l;
1737      "q mod l=",ql;
1738      "the Groebner basis for C[l]:";I;
1739      "x^q mod I = ",xq;
1740      "x^(q^2) mod I = ",xq2;
1741      "y^q mod I = ",yq;
1742      "y^(q^2) mod I = ",yq2;
1743      pause();
1744   }
1745   //==== l=2 =============================================================
1746   if(l==2)
1747   {
1748      xq=powerX(q,2,std(x3+a*x+b));
1749      J=std(ideal(xq-x,x3+a*x+b));
1750      if(deg(J[1])==0){t=1;}
1751      if(pr>=5)
1752      {
1753         "===================================================================";
1754         "the case l=2";
1755         "the gcd(x^q-x,x^3+ax+b)=",J[1];
1756         pause();
1757      }
1758      return(t);
1759   }
1760   //=== (F1/G1,F2/G2)=[ql](x,y) ==========================================
1761   if(ql==1)
1762   {
1763      F1=x;G1=1;F2=y;G2=1;
1764   }
1765   else
1766   {
1767      G1=reduce(generateG(a,b,ql)^2,I);
1768      F1=reduce(x*G1-generateG(a,b,ql-1)*generateG(a,b,ql+1),I);
1769      G2=reduce(4*y*generateG(a,b,ql)^3,I);
1770      F2=reduce(generateG(a,b,ql+2)*generateG(a,b,ql-1)^2
1771               -generateG(a,b,ql-2)*generateG(a,b,ql+1)^2,I);
1772
1773   }
1774   if(pr>=5)
1775   {
1776      "===================================================================";
1777      "the point ql*(x,y)=(F1/G1,F2/G2)";
1778      "F1=",F1;
1779      "G1=",G1;
1780      "F2=",F2;
1781      "G2=",G2;
1782      pause();
1783   }
1784   //==== the case t=0 :  the equations for (x,y)^(q^2)=-[ql](x,y) ===
1785   J[1]=xq2*G1-F1;
1786   J[2]=yq2*G2+F2;
1787   if(pr>=5)
1788   {
1789      "===================================================================";
1790      "the case t=0 mod l";
1791      "the equations for (x,y)^(q^2)=-[ql](x,y) :";
1792      J;
1793      "the test, if they vanish for all points in C[l]:";
1794      reduce(J,I);
1795      pause();
1796   }
1797   //=== test if all points of C[l] satisfy  (x,y)^(q^2)=-[ql](x,y)
1798   //=== if so: t mod l =0 is returned
1799   if(size(reduce(J,I,5))==0){return(0);}
1800
1801   //==== test for (x,y)^(q^2)=[ql](x,y) for some point
1802
1803   J=xq2*G1-F1,yq2*G2-F2;
1804   J=std(J+I);
1805   if(pr>=5)
1806   {
1807      "===================================================================";
1808      "test if (x,y)^(q^2)=[ql](x,y) for one point";
1809      "if so, the Frobenius has an eigenvalue 2ql/t: (x,y)^q=(2ql/t)*(x,y)";
1810      "it follows that t^2=4q mod l";
1811      "if w is one square root of q mod l";
1812      "t =2w mod l or -2w mod l ";
1813      "-------------------------------------------------------------------";
1814      "the equations for (x,y)^(q^2)=[ql](x,y) :";
1815      xq2*G1-F1,yq2*G2-F2;
1816      "the test if one point satisfies them";
1817      J;
1818      pause();
1819   }
1820   if(deg(J[1])>0)
1821   {
1822      int w=int(squareRoot(q,l));
1823      //=== +/-2w mod l zurueckgeben, wenn (x,y)^q=+/-[w](x,y)
1824      //==== the case t>0 :  (Q1/P1,Q2/P2)=[w](x,y) ==============
1825      if(w==1)
1826      {
1827         Q1=x;P1=1;Q2=y;P2=1;
1828      }
1829      else
1830      {
1831         P1=reduce(generateG(a,b,w)^2,I);
1832         Q1=reduce(x*G1-generateG(a,b,w-1)*generateG(a,b,w+1),I);
1833         P2=reduce(4*y*generateG(a,b,w)^3,I);
1834         Q2=reduce(generateG(a,b,w+2)*generateG(a,b,w-1)^2
1835               -generateG(a,b,w-2)*generateG(a,b,w+1)^2,I);
1836      }
1837      J=xq*P1-Q1,yq*P2-Q2;
1838      J=std(I+J);
1839      if(pr>=5)
1840      {
1841      "===================================================================";
1842      "the Frobenius has an eigenvalue, one of the roots of  w^2=q mod l:";
1843      "one root is:";w;
1844      "test, if it is the eigenvalue (if not it must be -w):";
1845      "the equations for (x,y)^q=w*(x,y)";I;xq*P1-Q1,yq*P2-Q2;
1846      "the Groebner basis";
1847       J;
1848         pause();
1849      }
1850      if(deg(J[1])>0){return(2*w mod l);}
1851      return(-2*w mod l);
1852   }
1853
1854   //==== the case t>0 :  (Q1/P1,Q2/P2)=(x,y)^(q^2)+[ql](x,y) =====
1855   P1=reduce(G1*G2^2*(F1-xq2*G1)^2,I);
1856   Q1=reduce((F2-yq2*G2)^2*G1^3-F1*G2^2*(F1-xq2*G1)^2-xq2*P1,I);
1857   P2=reduce(P1*G2*(F1-xq2*G1),I);
1858   Q2=reduce((xq2*P1-Q1)*(F2-yq2*G2)*G1-yq2*P2,I);
1859
1860   if(pr>=5)
1861   {
1862      "we are in the general case:";
1863      "(x,y)^(q^2)!=ql*(x,y) and (x,y)^(q^2)!=-ql*(x,y) ";
1864      "the point (Q1/P1,Q2/P2)=(x,y)^(q^2)+[ql](x,y)";
1865      "Q1=",Q1;
1866      "P1=",P1;
1867      "Q2=",Q2;
1868      "P2=",P2;
1869      pause();
1870   }
1871   while(t<(l-1) div 2)
1872   {
1873      t++;
1874      //====  (H1/L1,H2/L2)=[t](x,y)^q ===============================
1875      if(t==1)
1876      {
1877         H1=xq;L1=1;
1878         H2=yq;L2=1;
1879      }
1880      else
1881      {
1882         H1=x*generateG(a,b,t)^2-generateG(a,b,t-1)*generateG(a,b,t+1);
1883         H1=subst(H1,x,xq,y,yq);
1884         H1=reduce(H1,I);
1885         L1=generateG(a,b,t)^2;
1886         L1=subst(L1,x,xq,y,yq);
1887         L1=reduce(L1,I);
1888         H2=generateG(a,b,t+2)*generateG(a,b,t-1)^2
1889           -generateG(a,b,t-2)*generateG(a,b,t+1)^2;
1890         H2=subst(H2,x,xq,y,yq);
1891         H2=reduce(H2,I);
1892         L2=4*y*generateG(a,b,t)^3;
1893         L2=subst(L2,x,xq,y,yq);
1894         L2=reduce(L2,I);
1895      }
1896      J=Q1*L1-P1*H1,Q2*L2-P2*H2;
1897      if(pr>=5)
1898      {
1899      "we test now the different t, 0<t<=(l-1)/2:";
1900      "the point (H1/L1,H2/L2)=[t](x,y)^q :";
1901      "H1=",H1;
1902      "L1=",L1;
1903      "H2=",H2;
1904      "L2=",L2;
1905      "the equations for (x,y)^(q^2)+[ql](x,y)=[t](x,y)^q :";J;
1906      "the test";reduce(J,I);
1907      "the test for l-t (the x-cordinate is the same):";
1908       Q1*L1-P1*H1,Q2*L2+P2*H2;
1909       reduce(ideal(Q1*L1-P1*H1,Q2*L2+P2*H2),I);
1910         pause();
1911      }
1912      if(size(reduce(J,I,5))==0){return(t);}
1913      J=Q1*L1-P1*H1,Q2*L2+P2*H2;
1914      if(size(reduce(J,I,5))==0){return(l-t);}
1915   }
1916   ERROR("something is wrong in testElliptic");
1917}
1918example
1919{ "EXAMPLE:"; echo = 2;
1920   testElliptic(1267985441,338474977,64740730,3);
1921}
1922
1923//============================================================================
1924//================== Factorization and Primality Test ========================
1925//============================================================================
1926
1927//============= Lenstra's ECM Factorization ==================================
1928
1929proc factorLenstraECM(bigint N, list S, int B, list #)
1930"USAGE:  factorLenstraECM(N,S,B); optional: factorLenstraECM(N,S,B,d);
1931         d+1 the number of loops in the algorithm (default d=0)
1932RETURN: a factor of N or the message no factor found
1933NOTE: - computes a factor of N using Lenstra's ECM factorization@*
1934      - the idea is that the fact that N is not prime is detected using
1935        the operations on the elliptic curve
1936      - is similarly to Pollard's p-1-factorization
1937EXAMPLE:example factorLenstraECM; shows an example
1938"
1939{
1940   list L,P;
1941   bigint g,M,w;
1942   int i,j,k,d;
1943   int l=size(S);
1944   if(size(#)>0)
1945   {
1946      d=#[1];
1947   }
1948
1949   while(i<=d)
1950   {
1951      L=ellipticRandomCurve(N);
1952      if(L[3]>1){return(L[3]);} //the discriminant was not invertible
1953      P=list(0,L[2],1);
1954      j=0;
1955      M=1;
1956      while(j<l)
1957      {
1958         j++;
1959         w=S[j];
1960         if(w>B) break;
1961         while(w*S[j]<B)
1962         {
1963           w=w*S[j];
1964         }
1965         M=M*w;
1966         P=ellipticMult(N,L[1],L[2]^2,P,w);
1967         if(size(P)==4){return(P[4]);}  //some inverse did not exist
1968         if(P[3]==0){break;}            //the case M*P=0
1969      }
1970      i++;
1971   }
1972   return("no factor found");
1973}
1974example
1975{ "EXAMPLE:"; echo = 2;
1976   list L=primList(1000);
1977   factorLenstraECM(181*32003,L,10,5);
1978   bigint h=10;
1979   h=h^30+25;
1980   factorLenstraECM(h,L,4,3);
1981}
1982
1983//================= ECPP (Goldwasser-Kilian) a primaly-test =============
1984
1985proc ECPP(bigint N)
1986"USAGE:  ECPP(N);
1987RETURN: message:N is not prime or {L,P,m,q} as certificate for N being prime@*
1988         L a list (y^2=x^3+L[1]*x+L[2] defines an elliptic curve C)@*
1989         P a list ((P[1]:P[2]:P[3]) is a point of C)@*
1990         m,q integers
1991ASSUME: gcd(N,6)=1
1992NOTE:   The basis of the algorithm is the following theorem:
1993         Given C, an elliptic curve over Z/N, P a point of C(Z/N),
1994         m an integer, q a prime with the following properties:
1995         - q|m
1996         - q>(4-th root(N) +1)^2
1997         - m*P=0=(0:1:0)
1998         - (m/q)*P=(x:y:z) and z a unit in Z/N
1999         Then N is prime.
2000EXAMPLE:example ECPP; shows an example
2001"
2002{
2003   list L,S,P;
2004   bigint m,q;
2005   int i;
2006
2007   bigint n=intRoot(intRoot(N));
2008   n=(n+1)^2;                         //lower bound for q
2009   while(1)
2010   {
2011      L=ellipticRandomCurve(N);       //a random elliptic curve C
2012      m=ShanksMestre(N,L[1],L[2],3);  //number of points of the curve C
2013      S=PollardRho(m,10000,1);        //factorization of m
2014      for(i=1;i<=size(S);i++)         //search for q between the primes
2015      {
2016         q=S[i];
2017         if(n<q){break;}
2018      }
2019      if(n<q){break;}
2020   }
2021   bigint u=m/q;
2022   while(1)
2023   {
2024      P=ellipticRandomPoint(N,L[1],L[2]);  //a random point on C
2025      "P=",P;
2026      if(ellipticMult(N,L[1],L[2],P,m)[3]!=0){"N is not prime";return(-5);}
2027      if(ellipticMult(N,L[1],L[2],P,u)[3]!=0)
2028      {
2029         L=delete(L,3);
2030         return(list(L,P,m,q));
2031      }
2032   }
2033}
2034example
2035{ "EXAMPLE:"; echo = 2;
2036   bigint N=1267985441;
2037   ECPP(N);
2038}
2039
2040static proc wordToNumber(string s)
2041{
2042   int i;
2043   intvec v;
2044   bigint n;
2045   bigint t=27;
2046   for(i=size(s);i>0;i--)
2047   {
2048      if(s[i]=="a"){v[i]=0;}
2049      if(s[i]=="b"){v[i]=1;}
2050      if(s[i]=="c"){v[i]=2;}
2051      if(s[i]=="d"){v[i]=3;}
2052      if(s[i]=="e"){v[i]=4;}
2053      if(s[i]=="f"){v[i]=5;}
2054      if(s[i]=="g"){v[i]=6;}
2055      if(s[i]=="h"){v[i]=7;}
2056      if(s[i]=="i"){v[i]=8;}
2057      if(s[i]=="j"){v[i]=9;}
2058      if(s[i]=="k"){v[i]=10;}
2059      if(s[i]=="l"){v[i]=11;}
2060      if(s[i]=="m"){v[i]=12;}
2061      if(s[i]=="n"){v[i]=13;}
2062      if(s[i]=="o"){v[i]=14;}
2063      if(s[i]=="p"){v[i]=15;}
2064      if(s[i]=="q"){v[i]=16;}
2065      if(s[i]=="r"){v[i]=17;}
2066      if(s[i]=="s"){v[i]=18;}
2067      if(s[i]=="t"){v[i]=19;}
2068      if(s[i]=="u"){v[i]=20;}
2069      if(s[i]=="v"){v[i]=21;}
2070      if(s[i]=="w"){v[i]=22;}
2071      if(s[i]=="x"){v[i]=23;}
2072      if(s[i]=="y"){v[i]=24;}
2073      if(s[i]=="z"){v[i]=25;}
2074      if(s[i]==" "){v[i]=26;}
2075   }
2076   for(i=1;i<=size(s);i++)
2077   {
2078      n=n+v[i]*t^(i-1);
2079   }
2080   return(n);
2081}
2082
2083static proc numberToWord(bigint n)
2084{
2085   int i,j;
2086   string v;
2087   list s;
2088   bigint t=27;
2089   bigint mm;
2090   bigint nn=n;
2091   while(nn>t)
2092   {
2093      j++;
2094      mm=nn mod t;
2095      s[j]=mm;
2096      nn=(nn-mm) div t;
2097   }
2098   j++;
2099   s[j]=nn;
2100   for(i=1;i<=j;i++)
2101   {
2102      if(s[i]==0){v=v+"a";}
2103      if(s[i]==1){v=v+"b";}
2104      if(s[i]==2){v=v+"c";}
2105      if(s[i]==3){v=v+"d";}
2106      if(s[i]==4){v=v+"e";}
2107      if(s[i]==5){v=v+"f";}
2108      if(s[i]==6){v=v+"g";}
2109      if(s[i]==7){v=v+"h";}
2110      if(s[i]==8){v=v+"i";}
2111      if(s[i]==9){v=v+"j";}
2112      if(s[i]==10){v=v+"k";}
2113      if(s[i]==11){v=v+"l";}
2114      if(s[i]==12){v=v+"m";}
2115      if(s[i]==13){v=v+"n";}
2116      if(s[i]==14){v=v+"o";}
2117      if(s[i]==15){v=v+"p";}
2118      if(s[i]==16){v=v+"q";}
2119      if(s[i]==17){v=v+"r";}
2120      if(s[i]==18){v=v+"s";}
2121      if(s[i]==19){v=v+"t";}
2122      if(s[i]==20){v=v+"u";}
2123      if(s[i]==21){v=v+"v";}
2124      if(s[i]==22){v=v+"w";}
2125      if(s[i]==23){v=v+"x";}
2126      if(s[i]==24){v=v+"y";}
2127      if(s[i]==25){v=v+"z";}
2128      if(s[i]==26){v=v+" ";}
2129   }
2130   return(v);
2131}
2132
2133proc code(string s)
2134"USAGE:  code(s); s a string
2135ASSUME:  s contains only small letters and space
2136COMPUTE: a bigint, RSA-coding of the string s
2137RETURN:  return RSA-coding of the string s as string
2138EXAMPLE: code;  shows an example
2139"
2140{
2141   ring r=0,x,dp;
2142   bigint
2143p=398075086424064937397125500550386491199064362342526708406385189575946388957261768583317;
2144   bigint
2145q=472772146107435302536223071973048224632914695302097116459852171130520711256363590397527;
2146   bigint n=p*q;
2147   bigint phi=(p-1)*(q-1);
2148   bigint e=1234567891;
2149   //bigint d=extgcd(e,phi)[2];
2150   bigint m=wordToNumber(s);
2151   bigint c=powerN(m,e,n);
2152   string cc=string(c);
2153   return(cc);
2154}
2155example
2156{"EXAMPLE:";  echo = 2;
2157  string s="i go to school";
2158  code(s);
2159}
2160
2161proc decodeString(string g)
2162"USAGE:  decodeString(s); s a string
2163ASSUME:  s is a string of a bigint, the output of code
2164COMPUTE: a string, RSA-decoding of the string s
2165RETURN:  return RSA-decoding of the string s as string
2166EXAMPLE: decodeString;  shows an example
2167"
2168{
2169   bigint
2170p=398075086424064937397125500550386491199064362342526708406385189575946388957261768583317;
2171   bigint
2172q=472772146107435302536223071973048224632914695302097116459852171130520711256363590397527;
2173   bigint n=p*q;
2174   bigint phi=(p-1)*(q-1);
2175   bigint e=1234567891;
2176   bigint d=extgcd(e,phi)[2];
2177   execute("bigint c="+g+";");
2178   bigint f=powerN(c,d,n);
2179   string s=numberToWord(f);
2180   return(s);
2181}
2182example
2183{"EXAMPLE:";  echo = 2;
2184  string
2185s="78638618599886548153321853785991541374544958648147340831959482696082179852616053583234149080198937632782579537867262780982185252913122030800897193851413140758915381848932565";
2186  string t=decodeString(s);
2187  t;
2188}
2189/*----------------------------------------------------------------------------
2190 * set stuff
2191 * -------------------------------------------------------------------------*/
2192static proc set_multiply_list_content(list h)
2193"USAGE:   set_multiply_list_content(h)
2194RETURN:  An integer c als product of all elements in h
2195EXAMPLE: example set_multiply_list_content; shows an example;
2196"
2197{
2198  int c = 1;
2199  for (int i=1;i<=size(h);i++)
2200  {
2201    c = c*h[i];
2202  }
2203  return(c);
2204}
2205example
2206{
2207  "EXAMPLE:"; echo = 2;
2208  list h=2,4,5;
2209  set_multiply_list_content(h);
2210}
2211
2212static proc set_delete_certain_element(list a, int e)
2213"USAGE:   set_delete_certain_element(a,e)
2214RETURN:  A list a without element e. If e was not in the list before, a will not be changed
2215EXAMPLE: example set_delete_certain_element; shows an example.
2216"
2217{
2218  list output_list = a;
2219  for (int i=1;i<=size(a);i++)
2220  {
2221    if (a[i]==e)
2222    {
2223      output_list = delete(output_list,i);
2224    }
2225  }
2226  return(output_list);
2227}
2228example
2229{
2230  "EXAMPLE:"; echo = 2;
2231  list h=2,4,5;
2232  set_delete_certain_element(h,4);
2233  set_delete_certain_element(h,10);
2234}
2235
2236static proc set_bubblesort_int(list output_list)
2237"USAGE:   set_bubblesort_int(output_list)
2238RETURN:  An ascending sorted list with integer values.
2239EXAMPLE: set_bubblesort_int; shows an example.
2240"
2241{
2242  output_list = bubblesort(output_list);
2243  //Cast every value into an integer
2244  for (int i=1; i<=size(output_list);i++)
2245  {
2246    output_list[i] = int(output_list[i]);
2247  }
2248  return(output_list);
2249}
2250example
2251{
2252  "EXAMPLE:"; echo = 2;
2253  list output_list=10,4,5,24,9;
2254  set_bubblesort_int(output_list);
2255}
2256
2257static proc set_is_set(list a)
2258"USAGE:   set_is_set(a)
2259RETURN:  1 if the list is a set, 0 the list contains any duplicated elements
2260EXAMPLE: set_is_set; shows an example.
2261"
2262{
2263  int i,v;
2264  for (v=1; v<=size(a); v++)
2265  {
2266    for (i=v+1; i<=size(a); i++)
2267    {
2268      if (a[i]==a[v])
2269      {
2270        return(0);
2271      }
2272    }
2273  }
2274  return(1);
2275}
2276example
2277{
2278  "EXAMPLE:"; echo = 2;
2279  list set = 1,5,10,2;
2280  list noset = 1,5,10,2,5;
2281  set_is_set(set);
2282  set_is_set(noset);
2283}
2284
2285static proc set_contains(list a, int e)
2286"USAGE:   set_contains(a,e)
2287RETURN:  1 if the list contains e, 0 otherwise
2288EXAMPLE: set_contains; shows an example.
2289"
2290{
2291  for (int v=1; v<=size(a); v++)
2292  {
2293    if (a[v]==e)
2294    {
2295      return(1);
2296    }
2297  }
2298  return(0);
2299}
2300example
2301{
2302  "EXAMPLE:"; echo = 2;
2303  list set = 1,5,10,2;
2304  set_contains(set,5);
2305  set_contains(set,40);
2306}
2307
2308static proc set_delete_duplicates(list a)
2309"USAGE:   set_delete_duplicates(a)
2310RETURN:  a list a without any duplicated elements
2311EXAMPLE: set_delete_duplicates; shows an example.
2312"
2313{
2314  int i;
2315  list output_list = a[1];
2316  for (i=1; i<=size(a); i++)
2317  {
2318    if (set_contains(output_list,a[i])==0)
2319    {
2320      output_list = insert(output_list,a[i]);
2321    }
2322  }
2323  return(output_list);
2324}
2325example
2326{
2327  "EXAMPLE:"; echo = 2;
2328  list set = 1,5,10,2,10,5;
2329  set_delete_duplicates(set);
2330}
2331
2332static proc set_equals(list a,list b)
2333"USAGE:   set_equals(a, b)
2334RETURN:  1 if the lists are equal from a set-structure standpoint, 0 otherwise
2335EXAMPLE: set_equals; shows an example.
2336"
2337{
2338  //Checks if the lists have the same length
2339  if (size(a)!=size(b))
2340  {
2341    return(0);
2342  }
2343
2344  //Sorts the lists
2345  a = set_bubblesort_int(a);
2346  b = set_bubblesort_int(b);
2347
2348  //Checks every single element of both lists
2349  for (int i=1; i<=size(a); i++)
2350  {
2351    if (a[i]!=b[i])
2352    {
2353      return(0);
2354    }
2355  }
2356  return(1);
2357}
2358example
2359{
2360  "EXAMPLE:"; echo = 2;
2361  list set1 = 1,5,10,2;
2362  list set2 = 10,2,5,1;
2363  list set3 = 1,5,9,2;
2364  set_equals(set1,set2);
2365  set_equals(set1,set3);
2366}
2367
2368static proc set_insert(list a, int e)
2369"USAGE:   set_insert(a,e)
2370RETURN:  list a containing element e
2371EXAMPLE: set_insert; shows an example.
2372"
2373{
2374  if(set_contains(a,e))
2375  {
2376    return(a);
2377  }
2378  else
2379  {
2380    a=insert(a,e);
2381    return(a);
2382  }
2383}
2384example
2385{
2386  "EXAMPLE:"; echo = 2;
2387  list set = 1,5,10,2;
2388  set_insert(set,5);
2389  set_insert(set,22);
2390}
2391
2392static proc set_union(list a, list b)
2393"USAGE:   set_union(a, b)
2394RETURN:  list a as union of a and b
2395EXAMPLE: set_union; shows an example.
2396"
2397{
2398  for (int i=1; i<=size(b); i++)
2399  {
2400    if (set_contains(a,b[i])==0)
2401    {
2402      a = insert(a,b[i]);
2403    }
2404  }
2405  return(a);
2406}
2407example
2408{
2409  "EXAMPLE:"; echo = 2;
2410  list set1 = 1,5,10,2;
2411  list set2 = 5,10,93,58,29;
2412  set_union(set1,set2);
2413}
2414
2415static proc set_section(list a, list b)
2416"USAGE:   set_section(a, b)
2417RETURN:  list output_list as intersection of a and b
2418EXAMPLE: set_section; shows an example.
2419"
2420{
2421  list output_list;
2422  for (int i=1; i<=size(a); i++)
2423  {
2424    if (set_contains(b,a[i])==1)
2425    {
2426      output_list = insert(output_list,a[i]);
2427    }
2428  }
2429  return(output_list);
2430}
2431example
2432{
2433  "EXAMPLE:"; echo = 2;
2434  list set1 = 1,5,10,2;
2435  list set2 = 5,10,93,58,29;
2436  set_section(set1,set2);
2437}
2438
2439static proc set_list_delete_duplicates(list a)
2440"USAGE:   set_list_delete_duplicates(a)
2441RETURN:  list output_list with no duplicated lists
2442EXAMPLE: set_list_delete_duplicates; shows an example.
2443"
2444{
2445  int v;
2446  int i;
2447  int counter;
2448  int out_size;
2449  list output_list=insert(output_list,a[1]);
2450  //Create a new list and try to insert every list element from a into that list. If a list is already inserted into the
2451  //new list, do nothing.
2452  for (i=2; i<=size(a); i++)
2453  {
2454    out_size = size(output_list);
2455    counter = 0;
2456
2457    for (v=1; v<=out_size; v++)
2458    {
2459      if (set_equals(output_list[v],a[i])==1)
2460      {
2461        counter++;
2462      }
2463    }
2464    if (counter==0)
2465    {
2466      output_list = insert(output_list,a[i]);
2467    }
2468  }
2469  return(output_list);
2470}
2471example
2472{
2473  "EXAMPLE:"; echo = 2;
2474  list set1 = 1,5,10,2;
2475  list set2 = 1,10,2,5;
2476  list set3 = 1,2,3;
2477  list superset = set1,set2,set3;
2478  set_list_delete_duplicates(superset);
2479}
2480
2481static proc set_construct_increasing_set(int maxelement)
2482"USAGE:   set_construct_increasing_set(maxelement)
2483RETURN:  list output_list with increasing elements from 1 to maxelement
2484EXAMPLE: set_construct_increasing_set; shows an example.
2485"
2486{
2487  list output_list;
2488  for (int i=1; i<=maxelement; i++)
2489  {
2490    output_list = insert(output_list, i);
2491  }
2492  return(output_list);
2493}
2494example
2495{
2496  "EXAMPLE:"; echo = 2;
2497  set_construct_increasing_set(10);
2498}
2499
2500static proc set_addtoall(list a, int element)
2501"USAGE:   set_addtoall(a,alement)
2502RETURN:  Transformed list with e_i+element for every element e_i in list a
2503EXAMPLE: set_addtoall; shows an example.
2504"
2505{
2506  list output_list;
2507  int c;
2508  for (int i=1; i<=size(a); i++)
2509  {
2510    c = a[i]+element;
2511    output_list = insert(output_list,c);
2512  }
2513  return(set_turn(output_list));
2514}
2515example
2516{
2517  "EXAMPLE:"; echo = 2;
2518  list set = 1,5,10,2;
2519  set_addtoall(set,5);
2520}
2521
2522static proc set_turn(list a)
2523"USAGE:   set_turn(a)
2524RETURN:  Turned list a
2525EXAMPLE: set_turn; shows an example.
2526"
2527{
2528  list output_list;
2529  for (int i=1; i<=size(a); i++)
2530  {
2531    output_list[size(a)+1-i] = a[i];
2532  }
2533  return(output_list);
2534}
2535example
2536{
2537  "EXAMPLE:"; echo = 2;
2538  list set = 1,5,10;
2539  set_turn(set);
2540}
2541
2542static proc set_subset_set(list a)
2543"USAGE:   set_subset_set(a)
2544RETURN:  Set of subsets
2545EXAMPLE: set_subset_set; shows an example.
2546"
2547{
2548  int v;
2549  int choice;
2550  list output_list;
2551  list start = a[1];
2552  list insertion_list;
2553  int output_length;
2554  output_list = insert(output_list,start);
2555
2556  for (int i=2; i<=size(a); i++)
2557  {
2558    choice = 0;
2559    start = a[i];
2560    output_list = insert(output_list,start);
2561    output_length = size(output_list);
2562    for (v=2; v<=output_length; v++)
2563    {
2564      insertion_list = set_insert(output_list[v],a[i]);
2565      output_list = insert(output_list, insertion_list,size(output_list));
2566    }
2567  }
2568  return(output_list);
2569}
2570example
2571{
2572  "EXAMPLE:"; echo = 2;
2573  list set = 1,5,10;
2574  set_subset_set(set);
2575}
2576/* -----------------------------------------------------------------
2577 * knapsack_utilities: Utility functions needed for knapsack
2578 * -----------------------------------------------------------------*/
2579proc calculate_ordering(bigint num1, bigint primitive, bigint mod1)
2580"USAGE:   calculate_ordering(num1, primitive, mod1)
2581RETURN:  x so that primitive^x == num1 mod mod1
2582EXAMPLE: example calculate_ordering; shows an example;
2583"
2584{
2585  for (int i=1;i<=int((mod1-2));i++)
2586  {
2587    if ((primitive^i%mod1)==num1)
2588    {
2589      return(i);
2590    }
2591  }
2592  return(0);
2593}
2594example
2595{
2596  "EXAMPLE:"; echo = 2;
2597  bigint mod1 = 33;
2598  bigint primitive = 14;
2599  bigint num1 = 5;
2600  calculate_ordering(num1,primitive,mod1);
2601}
2602
2603proc is_primitive_root(bigint primitive, bigint mod1)
2604"USAGE:   is_primitive_root(primitive, mod1)
2605RETURN:  1 if primitive is a primitive root modulo mod1, 0 otherwise
2606EXAMPLE: example is_primitive_root; shows an example;
2607"
2608{
2609  list output_list;
2610  for (int i=1;i<=int((mod1-1));i++)
2611  {
2612    output_list = set_insert(output_list,int((primitive^i%mod1)));
2613  }
2614  if (bigint(size(output_list))==bigint(mod1-1))
2615  {
2616    return(1);
2617  }
2618  else
2619  {
2620    return(0);
2621  }
2622}
2623example
2624{
2625  "EXAMPLE:"; echo = 2;
2626  is_primitive_root(3,7);
2627  is_primitive_root(2,7);
2628}
2629
2630proc find_first_primitive_root(bigint mod1)
2631"USAGE:   find_first_primitive_root(mod1)
2632RETURN:  First primitive root modulo mod1, 0 if no root can be found.
2633EXAMPLE: example find_first_primitive_root; shows an example;
2634"
2635{
2636  for (int i=0;i<=int(mod1-1);i++)
2637  {
2638    if (is_primitive_root(bigint(i),mod1)==1)
2639    {
2640      return(i);
2641    }
2642  }
2643  return(0);
2644}
2645example
2646{
2647  "EXAMPLE:"; echo = 2;
2648  ring r = 0,x,lp;
2649  find_first_primitive_root(7);
2650  find_first_primitive_root(557);
2651}
2652
2653proc binary_add(list binary_list)
2654"USAGE:   binary_add(binary_list)
2655RETURN:  binary encoded list, increased by 1
2656EXAMPLE: example binary_add; shows an example;
2657"
2658{
2659  int residual=1;
2660  int position = size(binary_list);
2661  while((residual==1)&&(position!=0))
2662  {
2663    if(binary_list[position]==0)
2664    {
2665      binary_list[position]=1;
2666      residual=0;
2667    }
2668    else
2669    {
2670      binary_list[position]=0;
2671      position--;
2672    }
2673  }
2674  if (position==0)
2675  {
2676    binary_list = insert(binary_list,1);
2677  }
2678  return(binary_list);
2679}
2680example
2681{
2682  "EXAMPLE:"; echo = 2;
2683  ring r = 0,x,lp;
2684  list binary_list = 1,0,1,1,1;
2685  binary_add(binary_list);
2686}
2687
2688proc inverse_modulus(int num, int mod1)
2689"USAGE:   inverse_modulus(num, mod1)
2690RETURN:  inverse element of num modulo mod1
2691EXAMPLE: example inverse_modulus; shows an example;
2692"
2693{
2694  if (num>=mod1)
2695  {
2696    return(0);
2697  }
2698  else
2699  {
2700    for (int i=1;i<mod1;i++)
2701    {
2702      if ((i*num%mod1)==1)
2703      {
2704        return(i);
2705      }
2706    }
2707  }
2708}
2709example
2710{
2711  "EXAMPLE:"; echo = 2;
2712  ring r = 0,x,lp;
2713  int mod1 = 13;
2714  int num = 5;
2715  inverse_modulus(num,mod1);
2716}
2717
2718proc is_prime(int n)
2719"USAGE:   is_prime(n)
2720RETURN:  1 if n is prime, 0 otherwise
2721EXAMPLE: example is_prime; shows an example;
2722"
2723{
2724  int prime1 = 1;
2725  for (int i=n-1;i>1;i--)
2726  {
2727    if(n%i==0)
2728    {
2729        prime1 = 0;
2730    }
2731  }
2732  return(prime1);
2733}
2734example
2735{
2736  "EXAMPLE:"; echo = 2;
2737  ring r = 0,x,lp;
2738  is_prime(10);
2739  is_prime(7);
2740}
2741
2742proc find_biggest_index(list a)
2743"USAGE:   find_biggest_index( a)
2744RETURN:  Returns the index of the biggest element of a
2745EXAMPLE: example find_biggest_index; shows an example;
2746"
2747{
2748  list sortedlist = bubblesort(a);
2749  return(find_index(a,sortedlist[1]));
2750}
2751
2752proc find_index(list a, bigint e)
2753"USAGE:   find_index(a, e)
2754RETURN:  Returns the list index of element e in list a. Returns 0 if e is not in a
2755EXAMPLE: example find_index; shows an example;
2756"
2757{
2758  for(int i=1;i<=size(a);i++)
2759  {
2760    if (bigint(a[i])==e)
2761    {
2762      return(i);
2763    }
2764  }
2765  return(0);
2766}
2767example
2768{
2769  "EXAMPLE:"; echo = 2;
2770  list a = 1,5,20,6,37;
2771  find_index(a,20);
2772  find_index(a,6);
2773  find_index(a,100);
2774}
2775/* ------------------------------------------------------------------
2776 * Knapsack Algorithmus such as solving several knapsack problems,
2777 * kryptographic algorithms and algorithms for creatings suitable knapsacks
2778 * ---------------------------------------------------------------- */
2779proc subset_sum01(list knapsack, int solution)
2780"USAGE:   subset_sum01(knapsack,solution)
2781RETURN:  binary list of the positions of the elements included in the subset sum or 0 if no solution exists
2782NOTE: This will return the first solution of the ssk-problem, given be the smallest binary encoding. It wont return several solutions if they exist
2783EXAMPLE: example subset_sum01; shows an example;
2784"
2785{
2786  int i;
2787  int v;
2788  int comparable;
2789  //Check if the knapsack is a set
2790  if (set_is_set(knapsack)==1)
2791  {
2792    //Create a binary list full of zeroes
2793    list binary_list;
2794    for (i=1;i<=size(knapsack);i++)
2795    {
2796      binary_list = insert(binary_list,0);
2797    }
2798    binary_list = binary_add(binary_list);
2799
2800    for(i=1;i<=2^(size(knapsack));i++)
2801    {
2802      comparable = 0;
2803      //Create the Subset-Sum for the actual binary coding of binary_list
2804      for (v=1;v<=size(knapsack);v++)
2805      {
2806        comparable = comparable+knapsack[v]*binary_list[v];
2807      }
2808      //Check if the sum equals the solution
2809      if (comparable==solution)
2810      {
2811        return(binary_list);
2812      }
2813      else
2814      {
2815        binary_list = binary_add(binary_list);
2816      }
2817    }
2818    return(0);
2819  }
2820  else
2821  {
2822    return(0);
2823  }
2824}
2825example
2826{
2827  "EXAMPLE:"; echo = 2;
2828  list h=1,4,7,32;
2829  subset_sum01(h,20);
2830  subset_sum01(h,11);
2831  subset_sum01(h,33);
2832}
2833
2834proc subset_sum02(list knapsack, int sol)
2835"USAGE:   subset_sum02(knapsack,sol)
2836RETURN:  binary list of the positions of the elements included in the subset sum or 0 if no solution exists
2837EXAMPLE: example subset_sum02; shows an example;
2838"
2839{
2840  list summands;
2841  int calcu;
2842  int i;
2843  //Create a sorted copy of the knapsack, calling it worksack
2844  list worksack = set_bubblesort_int(knapsack);
2845  int counter = 1;
2846  while((counter<=size(worksack))&&(sol>0))
2847  {
2848    //Try to subtract an element of the knapsack from the capacity. Create a list with all the summands used
2849    calcu = sol-worksack[counter];
2850    if (calcu>=0)
2851    {
2852      sol = sol-worksack[counter];
2853      summands = insert(summands,int(worksack[counter]));
2854    }
2855    counter++;
2856  }
2857  if(sol>0)
2858  {
2859    return(0);
2860  }
2861
2862  //Get the index of the summands of the original knapsack and change the bits in the binary list which will be the solution
2863  list binary_list;
2864  for (i=1;i<=size(knapsack);i++)
2865  {
2866    binary_list = insert(binary_list,0);
2867  }
2868
2869  for (i=1; i<=size(knapsack);i++)
2870  {
2871    if (set_contains(summands,knapsack[i])==1)
2872    {
2873      binary_list[i]=1;
2874    }
2875  }
2876  return(binary_list);
2877}
2878example
2879{
2880  "EXAMPLE:"; echo = 2;
2881  list h=1,4,7,32;
2882  subset_sum02(h,20);
2883  subset_sum02(h,11);
2884  subset_sum02(h,33);
2885}
2886
2887proc unbounded_knapsack(list knapsack, list profit, int capacity)
2888"USAGE:   unbounded_knapsack(knapsack,profit,capacity)
2889RETURN:  list of maximum profit of each iteration. For example, output_list[2] contains the maximum profit that can be achieved if the knapsack has capacity 2.
2890EXAMPLE: unbounded_knapsack; shows an example;
2891"
2892{
2893  int i;
2894  int v;
2895  list output_list;
2896  for (i=1;i<=capacity+1;i++)
2897  {
2898    output_list = insert(output_list,0);
2899  }
2900  for (i=1;i<=capacity+1;i++)
2901  {
2902    for(v=1;v<=size(knapsack);v++)
2903    {
2904      if (knapsack[v]<i)
2905      {
2906        if(output_list[i]<(output_list[i-knapsack[v]]+profit[v]))
2907        {
2908          output_list[i] = output_list[i-knapsack[v]]+profit[v];
2909        }
2910      }
2911    }
2912  }
2913  return(output_list);
2914}
2915example
2916{
2917  "EXAMPLE:"; echo = 2;
2918  list h=1,4,7,32;
2919  list knapsack = 5,2;
2920  list profit = 10,3;
2921  int capacity = 5;
2922  unbounded_knapsack(knapsack,profit,capacity);
2923}
2924
2925proc multidimensional_knapsack(matrix m, list capacities, list profits)
2926"USAGE:   multidimensional_knapsack(m,capacities,profits)
2927RETURN:  binary list of the positions of the elements included in the optimal selection
2928EXAMPLE: example multidimensional_knapsack; shows an example;
2929"
2930{
2931  int index;
2932  list output_list;
2933  list nolist;
2934  list y_list;
2935  list minmax_list;
2936  int i;
2937  int v;
2938  int checkint;
2939  //create the output_list full of zeroes with the length of all given selections
2940  for (i=1;i<=size(profits);i++)
2941  {
2942    output_list = insert(output_list,0);
2943  }
2944
2945  //Create the List E with all indices of the output_list that haven't been used yet.
2946  list E = set_turn(set_construct_increasing_set(size(profits)));
2947
2948  //Repeat till every index in E is used.
2949  while(size(E)>0)
2950  {
2951    y_list = nolist;
2952    for (i=1;i<=size(E);i++)
2953    {
2954      //Create all possible elements of y_i (y_list). minimax_list will be replaced of an empty list in each iteration
2955      minmax_list = nolist;
2956      for (v=1; v<=size(capacities);v++)
2957      {
2958        if (set_contains(E,v)==1)
2959        {
2960        minmax_list = insert(minmax_list, bigint(capacities[v])/bigint(m[v,E[i]]));
2961        }
2962      }
2963      //Sort the elements so that it is easy to pick the smallest one
2964      minmax_list = bubblesort(minmax_list);
2965
2966      //insert Element y_i into y_list, which is the smallest of (b_i/w_ij) like in the PECH algorithm description.
2967      y_list = insert(y_list,minmax_list[size(minmax_list)],size(y_list));
2968
2969
2970    }
2971
2972    //Check if all y_i in y_list are smaller than 1. If so, every additional selection will exceed the capacity and the algorithm stops.
2973    checkint=0;
2974    for(i=1;i<=size(y_list);i++)
2975    {
2976      if (y_list[i]>=1)
2977      {
2978        checkint=1;
2979      }
2980    }
2981    if (checkint==0)
2982    {
2983      return(output_list);
2984    }
2985
2986
2987    //Find the index of the selection and update the binary output_list
2988    minmax_list = nolist;
2989    for (i=1;i<=size(E);i++)
2990    {
2991      minmax_list = insert(minmax_list, profits[E[i]]*y_list[i],size(minmax_list));
2992    }
2993    index = find_biggest_index(minmax_list);
2994
2995    output_list[E[index]]=1;
2996
2997    //Update the capacities by subtracting the weights of the selection
2998    for (i=1;i<=size(capacities);i++)
2999    {
3000      capacities[i] = capacities[i]- m[i,E[index]];
3001    }
3002    E = set_delete_certain_element(E,index);
3003
3004  }
3005  return(output_list);
3006}
3007example
3008{
3009  "EXAMPLE:"; echo = 2;
3010  ring r = 0,x,lp;
3011  matrix m[3][3] = 1,4,10,7,8,3,1,9,7;
3012  list c = 12,17,10;
3013  list p = 3,2,5;
3014  multidimensional_knapsack(m,c,p);
3015}
3016
3017proc naccache_stern_generation(int key, int primenum)
3018"USAGE:   naccache_stern_generation(key, primenum)
3019RETURN:  a hard knapsack list
3020EXAMPLE: example naccache_stern_generation; shows an example;
3021"
3022{
3023  //Check if primenum is a prime and the gcd-Condition holds
3024  if ((is_prime(primenum)==0)||(gcd(key,(primenum-1))!=1))
3025  {
3026    return(0);
3027  }
3028  else
3029  {
3030    int i;
3031    int p;
3032    list primelist;
3033    int primecounter=2;
3034    //Generate the knapsack containing the smallest prime numbers so that primenum exceeds the product of all of them
3035    while(set_multiply_list_content(primelist)<primenum)
3036    {
3037      if (is_prime(primecounter)==1)
3038      {
3039      primelist = insert(primelist,primecounter);
3040      }
3041      primecounter++;
3042    }
3043    primelist = delete(primelist,1);
3044
3045
3046    //Generate the hard knapsack of the length of the prime numbers containing zeroes.
3047    list hardknapsack;
3048    for (i=1;i<=size(primelist);i++)
3049    {
3050      hardknapsack = insert(hardknapsack,0);
3051    }
3052
3053    //Create the elements of the hard knapsack
3054    primecounter = 1;
3055    bigint calcu;
3056    i=0;
3057    while (i<size(primelist))
3058    {
3059      //Create some v_i^key%primenum and store it in calcu
3060      calcu = bigint(primecounter)^key%bigint(primenum);
3061
3062      //If calcu is one of the prime numbers in the knapsack, find the index and insert v_i in the hard knapsack at that given index
3063      if(set_contains(primelist,int(calcu))==1)
3064      {
3065        p=find_index(primelist,int(calcu));
3066        hardknapsack[p] = primecounter;
3067        i++;
3068      }
3069      primecounter++;
3070    }
3071  return(hardknapsack);
3072  }
3073}
3074example
3075{
3076  "EXAMPLE:"; echo = 2;
3077  naccache_stern_generation(5,292);
3078  naccache_stern_generation(5,293);
3079}
3080
3081proc naccache_stern_encryption(list knapsack, list message, int primenum)
3082"USAGE:   naccache_stern_encryption(knapsack, message, primenum)
3083RETURN:  an encrypted message as integer
3084EXAMPLE: example naccache_stern_encryption; shows an example;
3085"
3086{
3087  bigint solution = 1;
3088  if (size(knapsack)==size(message))
3089  {
3090    for(int i=1;i<=size(knapsack);i++)
3091    {
3092      solution = solution*((bigint(knapsack[i])^message[i])%bigint(primenum));
3093    }
3094    return(solution);
3095  }
3096  else
3097  {
3098    return(0);
3099  }
3100
3101}
3102example
3103{
3104  "EXAMPLE:"; echo = 2;
3105  //Please note that the values for primenum and hardknapsack have been obtained from the example of naccache_stern_generation!
3106  list hardknapsack = 85,164,117,44;
3107  int primenum = 293;
3108  list message = 1,0,1,0;
3109  naccache_stern_encryption(hardknapsack,message,primenum);
3110}
3111
3112proc naccache_stern_decryption(list knapsack, int key, int primenum, int message)
3113"USAGE:   naccache_stern_decryption(knapsack, key, primenum, message)
3114RETURN:  decrypted binary list
3115EXAMPLE: example naccache_stern_decryption; shows an example;
3116"
3117{
3118  //create a binary list with the length of the knapsack containing zeros
3119  int k = int(bigint(message)^key%bigint(primenum));
3120  int i;
3121  list binary_list;
3122  for (i=1;i<=size(knapsack);i++)
3123  {
3124    binary_list = insert(binary_list,0);
3125  }
3126
3127  //create primelist like in int naccache_stern_generation process
3128  list primelist;
3129  int primecounter=2;
3130  while(size(primelist)<size(knapsack))
3131  {
3132    if (is_prime(primecounter)==1)
3133    {
3134      primelist = insert(primelist,primecounter);
3135    }
3136      primecounter++;
3137  }
3138
3139  //find divisors of k and update the binarylist in a way that the positions of the divisors in primelist are marked
3140  for (i=1;i<=size(primelist);i++)
3141  {
3142    if(k%primelist[i]==0)
3143    {
3144      binary_list[i]=1;
3145    }
3146  }
3147  return(binary_list);
3148
3149}
3150example
3151{
3152  "EXAMPLE:"; echo = 2;
3153  //Please note that the values have been obtained from the example of naccache_stern_generation and naccache_stern_encryption!
3154  int primenum = 293;
3155  int message = 9945;
3156  int key = 5;
3157  list hardknapsack = 85,164,117,44;
3158  naccache_stern_decryption(hardknapsack,key,primenum,message);
3159}
3160
3161proc m_merkle_hellman_transformation(list knapsack, int primitive, int mod1)
3162"USAGE:   m_merkle_hellman_transformation(knapsack, primitive, mod1)
3163RETURN:  list containing a hard knapsack
3164EXAMPLE: example m_merkle_hellman_transformation; shows an example;
3165"
3166{
3167  bigint new_element;
3168  list output_list;
3169  //calculate the primitiv root of every element in knapsack and insert it into a new knapsack
3170  for (int i=size(knapsack);i>=1;i--)
3171  {
3172    new_element = calculate_ordering(knapsack[i],primitive,mod1);
3173    output_list = insert(output_list,int(new_element));
3174  }
3175  return(output_list);
3176}
3177example
3178{
3179  "EXAMPLE:"; echo = 2;
3180  //Please note that the values for primenum and hardknapsack have been obtained from the example of naccache_stern_generation and naccache_stern_encryption!
3181  list knapsack = 2,3,5,7;
3182  int mod1 = 211;
3183  int primitive = 2;
3184  m_merkle_hellman_transformation(knapsack,primitive,mod1);
3185}
3186
3187proc m_merkle_hellman_encryption(list knapsack, list message)
3188"USAGE:    m_merkle_hellman_encryption(knapsack, message)
3189RETURN:  an encrypted message as integer
3190NOTE: This works in the same way as merkle_hellman_encryption. The additional function is created to keep consistency with the needed functions for every kryptosystem.
3191EXAMPLE: example m_merkle_hellman_encryption; shows an example;
3192"
3193{
3194  return(merkle_hellman_encryption(knapsack,message));
3195}
3196example
3197{
3198  "EXAMPLE:"; echo = 2;
3199  //Please note that the values for primenum and hardknapsack have been obtained from the example of m_merkle_hellman_transformation!
3200  list knapsack = 1,43,132,139;
3201  list message = 1,0,0,1;
3202  m_merkle_hellman_encryption(knapsack,message);
3203}
3204
3205proc m_merkle_hellman_decryption(list knapsack, bigint primitive, bigint mod1, int message)
3206"USAGE:  m_merkle_hellman_decryption(knapsack, primitive, mod1, message)
3207RETURN:  decrypted binary list
3208EXAMPLE: example merkle_hellman_decryption; shows an example;
3209"
3210{
3211  //Convert message
3212  int factorizing = int((primitive^message)%mod1);
3213  int i;
3214
3215  //Create binary list of length of the knapsack, containing zeroes.
3216  list binary_list;
3217  for (i=1;i<=size(knapsack);i++)
3218  {
3219    binary_list = insert(binary_list,0);
3220  }
3221
3222  //factorize the converted message, mark the factor positions in knapsack as bits in binary_list
3223  for (i=1;i<=size(knapsack);i++)
3224  {
3225    if(factorizing%knapsack[i]==0)
3226    {
3227      binary_list[i]=1;
3228    }
3229  }
3230  return(binary_list);
3231}
3232example
3233{
3234  "EXAMPLE:"; echo = 2;
3235  //Please note that the values  have been obtained from the example of m_merkle_hellman_encryption and m_merkle_hellman_transformation!
3236  list knapsack = 2,3,5,7;
3237  int message = 140;
3238  bigint primitive = 2;
3239  bigint mod1 = 211;
3240  m_merkle_hellman_decryption(knapsack,primitive,mod1,message);
3241}
3242
3243proc merkle_hellman_transformation(list knapsack, int key, int mod1)
3244"USAGE:   merkle_hellman_transformation(knapsack, key, mod1)
3245RETURN:  hard knapsack
3246EXAMPLE: example merkle_hellman_transformation; shows an example;
3247"
3248{
3249  list output_list;
3250  int new_element;
3251  //transform every element in the knapsack with normal strong modular multiplication
3252  for (int i=size(knapsack);i>=1;i--)
3253  {
3254    new_element=knapsack[i]*key%mod1;
3255    output_list = insert(output_list,new_element);
3256  }
3257  return(output_list);
3258}
3259example
3260{
3261  "EXAMPLE:"; echo = 2;
3262  list knapsack = 1,3,5,12;
3263  int key = 3;
3264  int mod1 = 23;
3265  merkle_hellman_transformation(knapsack,key,mod1);
3266}
3267
3268proc merkle_hellman_encryption(list knapsack, list message)
3269"USAGE:   merkle_hellman_encryption(knapsack, message)
3270RETURN:  encrypted integer
3271EXAMPLE: example merkle_hellman_encryption; shows an example;
3272"
3273{
3274  int solution = 0;
3275  if (size(knapsack)!=size(message)||(set_is_set(knapsack)==0))
3276  {
3277    return(0);
3278  }
3279  else
3280  {
3281    for (int i=1;i<=size(knapsack);i++)
3282    {
3283      solution = solution+knapsack[i]*message[i];
3284    }
3285    return(solution);
3286  }
3287}
3288example
3289{
3290  "EXAMPLE:"; echo = 2;
3291  //Please note that the values  have been obtained from the example of merkle_hellman_transformation!
3292  list hardknapsack =3,9,15,13;
3293  list message = 0,1,0,1;
3294  merkle_hellman_encryption(hardknapsack,message);
3295}
3296
3297proc merkle_hellman_decryption(list knapsack, int key, int mod1, int message)
3298"USAGE:   merkle_hellman_decryption(knapsack, key, mod1, message)
3299RETURN:  decrypted binary list
3300EXAMPLE: example merkle_hellman_decryption; shows an example;
3301"
3302{
3303  int new_element;
3304  int t = inverse_modulus(key,mod1);
3305  int transformed_message;
3306  list binary_list;
3307  if ((set_is_set(knapsack)==1)&&(key<mod1))
3308  {
3309    //reconstruct easy knapsack be multiplying with the inverse modulus t
3310    list easy_knapsack;
3311    for (int i=size(knapsack);i>=1;i--)
3312    {
3313      new_element=knapsack[i]*t%mod1;
3314      easy_knapsack = insert(easy_knapsack,new_element);
3315    }
3316
3317    //solve the easy knapsack problem with subset_sum01 or subset_sum02
3318    transformed_message = (message*t)%mod1;
3319    transformed_message;
3320    binary_list = subset_sum01(easy_knapsack,transformed_message);
3321    return(binary_list)
3322  }
3323  else
3324  {
3325    return(0)
3326  }
3327}
3328example
3329{
3330  "EXAMPLE:"; echo = 2;
3331  //Please note that the values  have been obtained from the example of merkle_hellman_decryption and merkle_hellman_transformation!
3332  list hardknapsack =3,9,15,13;
3333  int key = 3;
3334  int message = 22;
3335  int mod1 = 23;
3336  merkle_hellman_decryption(hardknapsack, key, mod1, message);
3337}
3338
3339proc super_increasing_knapsack(int ksize)
3340"USAGE:   super_increasing_knapsack(ksize)
3341RETURN:  super-increasing knapsack list
3342EXAMPLE: super_increasing_knapsack; shows an example;
3343"
3344{
3345  list output_list = insert(output_list,1);
3346  int next_element;
3347
3348  for (int i=2; i<=ksize; i++)
3349  {
3350    next_element = calculate_max_sum(output_list)+1;
3351    output_list = insert(output_list,next_element);
3352  }
3353  return(output_list);
3354}
3355example
3356{
3357  "EXAMPLE:"; echo = 2;
3358  super_increasing_knapsack(10);
3359}
3360
3361proc h_increasing_knapsack(int ksize, int h)
3362"USAGE:   h_increasing_knapsack(ksize, h)
3363RETURN:  h-increasing knapsack list
3364EXAMPLE: h_increasing_knapsack; shows an example;
3365"
3366{
3367  int v;
3368  if (ksize<=h+1)
3369  {
3370    return(set_turn(super_increasing_knapsack(ksize)))
3371  }
3372  else
3373  {
3374    list out = set_turn(super_increasing_knapsack(h+1));
3375    int next_element;
3376    for (int i=h+2; i<=ksize; i++)
3377    {
3378      next_element = 0;
3379      for (v=i-h; v<=i-1; v++)
3380      {
3381        next_element = next_element+out[v];
3382      }
3383      next_element++;
3384      out = insert(out,next_element,size(out));
3385    }
3386    return(out);
3387  }
3388}
3389example
3390{
3391  "EXAMPLE:"; echo = 2;
3392  h_increasing_knapsack(10,5);
3393}
3394
3395proc injective_knapsack(int ksize, int kmaxelement)
3396"USAGE:   injective_knapsack(ksize, kmaxelement)
3397RETURN:  list of injective knapsacks with maximal element kmaxelement and size ksize
3398EXAMPLE: injective_knapsack; shows an example;
3399"
3400{
3401  //Create a List of size ksize with the greatest possible elements keeping the set structure
3402  list list_of_lists;
3403  list A = insert(A,kmaxelement);
3404  int i;
3405  for (i=2;i<=ksize;i++)
3406  {
3407    A = insert(A,kmaxelement-(i-1));
3408  }
3409  A = set_turn(A);
3410  list_of_lists = insert(list_of_lists,A);
3411
3412  //Create all possible sets containing the possible elements of A
3413  int residual;
3414  int position;
3415  while(A[1]==kmaxelement)
3416  {
3417    residual=3;
3418    position = ksize;
3419    while((residual!=0))
3420    {
3421      if(A[position]==1)
3422      {
3423        A[position]=kmaxelement-position+1;
3424        residual=1;
3425        position--;
3426      }
3427      else
3428      {
3429        A[position]=A[position]-1;
3430        residual=0;
3431      }
3432    }
3433    //Insert the list into the overall list if its a set
3434    if (set_is_set(A)==1)
3435    {
3436      list_of_lists = insert(list_of_lists,A);
3437    }
3438  }
3439  //delete the first element since it is smaller than kmaxelement
3440  list_of_lists = delete(list_of_lists,1);
3441  //delete duplicates
3442  list_of_lists = set_list_delete_duplicates(list_of_lists);
3443
3444  //Check if the remaining knapsacks are injective
3445  list output_list;
3446  for(i=1;i<=size(list_of_lists);i++)
3447  {
3448    if (set_is_injective(list_of_lists[i])==1)
3449    {
3450      output_list=insert(output_list,list_of_lists[i]);
3451    }
3452  }
3453  return(output_list);
3454}
3455example
3456{
3457  "EXAMPLE:"; echo = 2;
3458  injective_knapsack(3,9);
3459}
3460
3461proc calculate_max_sum(list a)
3462"USAGE:   calculate_max_sum(a)
3463RETURN:  sum of all elements in a
3464EXAMPLE: calculate_max_sum; shows an example;
3465"
3466{
3467  int sum = a[1];
3468  for (int i=2; i<=size(a);i++)
3469  {
3470    sum = sum+a[i];
3471  }
3472  return(sum);
3473}
3474example
3475{
3476  "EXAMPLE:"; echo = 2;
3477  list a = 1,5,3,2,12;
3478  calculate_max_sum(a);
3479}
3480
3481proc set_is_injective(list a)
3482"USAGE:   set_is_injective(a)
3483RETURN:  1 if a is injective, 0 otherwise
3484EXAMPLE: set_is_injective; shows an example;
3485"
3486{
3487  //Create all subsets of the set a
3488  list subsum = set_subset_set(a);
3489  list checklist=calculate_max_sum(subsum[1]);
3490  int calculator;
3491  for (int i=2; i<=size(subsum);i++)
3492  {
3493    //calculate the maximal subset_sum for every subset. Check if there are duplicated subset_sums. If so, a is not injective
3494    calculator = calculate_max_sum(subsum[i]);
3495    if (set_contains(checklist, calculator))
3496    {
3497      return(0);
3498    }
3499    else
3500    {
3501      checklist = insert(checklist,calculator);
3502    }
3503  }
3504  return(1);
3505}
3506example
3507{
3508  "EXAMPLE:"; echo = 2;
3509  list inj = 1,5,7,41;
3510  list non_inj = 1,2,3,4;
3511  set_is_injective(inj);
3512  set_is_injective(non_inj);
3513}
3514
3515proc is_h_injective(list a, int h)
3516"USAGE:   is_h_injective(a, h)
3517RETURN:  1 if a is h-injective, 0 otherwise
3518EXAMPLE: is_h_injective; shows an example;
3519"
3520{
3521  //Create all sets of subsets
3522  list subsetlist = set_subset_set(a);
3523  list h_subsetlist;
3524  //delete every list with elements more than h+1 since they are not needed to check h-injectivity
3525  for (int i=1; i<=size(subsetlist); i++)
3526  {
3527    if(size(subsetlist[i])<=h)
3528    {
3529      h_subsetlist = insert(h_subsetlist,subsetlist[i]);
3530    }
3531  }
3532
3533  //Check if the remaining max_sums do not occure more than once
3534  list checklist=calculate_max_sum(h_subsetlist[1]);
3535  int calculator;
3536  for (i=2; i<=size(h_subsetlist);i++)
3537  {
3538    calculator = calculate_max_sum(h_subsetlist[i]);
3539    if (set_contains(checklist, calculator)==1)
3540    {
3541      return(0);
3542    }
3543    else
3544    {
3545      checklist = insert(checklist,calculator);
3546    }
3547  }
3548  return(1);
3549
3550}
3551example
3552{
3553  "EXAMPLE:"; echo = 2;
3554  list h_inj = 1,2,4,10,17;
3555  is_h_injective(h_inj,3);
3556  //1+2+4+10=17
3557  is_h_injective(h_inj,4);
3558}
3559
3560proc is_fix_injective(list a)
3561"USAGE:   is_fix_injective(a)
3562RETURN:  1 if a is fix-injective, 0 otherwise
3563EXAMPLE: is_fix_injective; shows an example;
3564"
3565{
3566  //Generation of the list-list-list
3567  list subsetlist = set_subset_set(a);
3568  list alreadycreatedlist;
3569  list listoflists;
3570  list emptylist1;
3571  list worklist;
3572  int i;
3573  int v;
3574  list checklist;
3575  int calculator;
3576
3577  int set_destination;
3578
3579  //create list of lists which contain the lists of a certain length as elements
3580  for (i = 1; i<= size(subsetlist); i++)
3581  {
3582    //Determine the size of the actual list to choose where to insert it in the listoflists
3583    set_destination = size(subsetlist[i]);
3584    if (set_contains(alreadycreatedlist,set_destination)==1)
3585    {
3586      //There is already an element with the same set size, so just insert it
3587      listoflists[set_destination] = insert(listoflists[set_destination],subsetlist[i]);
3588    }
3589    else
3590    {
3591      //There is not yet an element with the same set size, so create a new one
3592      listoflists[set_destination] = insert(emptylist1,subsetlist[i]);
3593      alreadycreatedlist = set_insert(alreadycreatedlist,set_destination );
3594    }
3595  }
3596
3597  //Check for injectivity of each separate list. Works as in injectivity or h-injectivity
3598  for (v=1; v<=size(listoflists); v++)
3599  {
3600    worklist = listoflists[v];
3601
3602    checklist=calculate_max_sum(worklist[1]);
3603    for (i=2; i<=size(worklist); i++)
3604    {
3605      calculator = calculate_max_sum(worklist[i]);
3606      if (set_contains(checklist, calculator)==1)
3607      {
3608        return(0);
3609      }
3610      else
3611      {
3612        checklist = insert(checklist,calculator);
3613      }
3614    }
3615  }
3616  return(1);
3617}
3618example
3619{
3620  "EXAMPLE:"; echo = 2;
3621  //this is fix-injective because 17=10+2+4+1 with different numbers of addens.
3622  list fix_inj = 1,2,4,10,17;
3623  //this is not fix-injective because 4+1=2+3.
3624  list not_fix_inj = 1,2,3,4;
3625  is_fix_injective(fix_inj);
3626  is_fix_injective(not_fix_inj);
3627}
3628
3629proc three_elements(list out, int iterations)
3630"USAGE:   three_elements(out, iterations)
3631RETURN:  Injective_knapsack created with the three elements method
3632EXAMPLE: three_elements; shows an example;
3633"
3634{
3635  int a;
3636  int b;
3637  int c;
3638  int subsum;
3639  int adden = 1;
3640  int condition = 0;
3641  out = set_turn(out);
3642  if (set_is_injective(out)==0)
3643  {
3644    return(0);
3645  }
3646  else
3647  {
3648    for (int i=1; i<=iterations; i++)
3649    {
3650      while(condition==0)
3651      {
3652        subsum = calculate_max_sum(out);
3653        a = 2*subsum+adden;
3654        b = a+subsum+adden;
3655        c = b+subsum+1;
3656        if ((a+b)>(c+subsum))
3657        {
3658          condition=1;
3659        }
3660        else
3661        {
3662          adden++;
3663        }
3664      }
3665      adden =1;
3666      condition=0;
3667      out=set_insert(out, a);
3668      out=set_insert(out, b);
3669      out=set_insert(out, c);
3670    }
3671    return(out);
3672  }
3673}
3674example
3675{
3676  "EXAMPLE:"; echo = 2;
3677  //this is fix-injective because 17=10+2+4+1 with different numbers of addens.
3678  list super_increasing = 1,2,4,10,20;
3679  list a = three_elements(super_increasing,2);
3680  a;
3681  set_is_injective(a);
3682}
3683/*
3684//===============================================================
3685//=======  Example for DSA  =====================================
3686//===============================================================
3687Suppose a file test is given.It contains "Oscar".
3688
3689//Hash-function MD5 under Linux
3690
3691md5sum test           8edfe37dae96cfd2466d77d3884d4196
3692
3693//================================================================
3694
3695ring R=0,x,dp;
3696
3697number q=2^19+21;          //524309
3698number o=2*3*23*number(7883)*number(16170811);
3699
3700number p=o*q+1;            //9223372036869000547
3701number b=2;
3702number g=power(2,o,p);     //8308467587808723131
3703
3704number a=111111;
3705number A=power(g,a,p);     //8566038811843553785
3706
3707number h =decimal("8edfe37dae96cfd2466d77d3884d4196");
3708
3709                           //189912871665444375716340628395668619670
3710h= h mod q;                //259847
3711
3712number k=123456;
3713
3714number ki=exgcd(k,q)[1];    //50804
3715                            //inverse von k mod q
3716
3717number r= power(g,k,p) mod q;    //76646
3718
3719number s=ki*(h+a*r) mod q;       //2065
3720
3721//========== signature is (r,s)=(76646,2065) ====================
3722//==================== verification  ============================
3723
3724number si=exgcd(s,q)[1];  //inverse von s mod q
3725number e1=si*h mod q;
3726number e2=si*r mod q;
3727number rr=((power(g,e1,p)*power(A,e2,p)) mod p) mod q;    //76646
3728
3729//===============================================================
3730//=======  Example for knapsack  ================================
3731//===============================================================
3732ring R=(5^5,t),x,dp;
3733R;
3734//   # ground field : 3125
3735//   primitive element : t
3736//   minpoly        : 1*t^5+4*t^1+2*t^0
3737//   number of vars : 1
3738//        block   1 : ordering dp
3739//                  : names    x
3740//        block   2 : ordering C
3741
3742proc findEx(number n, number g)
3743{
3744   int i;
3745   for(i=0;i<=size(basering)-1;i++)
3746   {
3747      if(g^i==n){return(i);}
3748   }
3749}
3750
3751number g=t^3;                       //choice of the primitive root
3752
3753findEx(t+1,g);
3754//2091
3755findEx(t+2,g);
3756//2291
3757findEx(t+3,g);
3758//1043
3759
3760intvec b=1,2091,2291,1043;          // k=4
3761int z=199;
3762intvec v=1043+z,1+z,2091+z,2291+z;  //permutation   pi=(0123)
3763v;
37641242,200,2290,2490
3765
3766//(1101)=(e_3,e_2,e_1,e_0)
3767//encoding 2490+2290+1242=6022 und 1+1+0+1=3
3768
3769//(6022,3) decoding: c-z*c'=6022-199*3=5425
3770
3771ring S=5,x,dp;
3772poly F=x5+4x+2;
3773poly G=reduce((x^3)^5425,std(F));
3774G;
3775//x3+x2+x+1
3776
3777factorize(G);
3778//[1]:
3779//   _[1]=1
3780//   _[2]=x+1
3781//   _[3]=x-2
3782//   _[4]=x+2
3783//[2]:
3784//   1,1,1,1
3785
3786//factors x+1,x+2,x+3, i.e.  (1110)=(e_pi(3),e_pi(2),e_pi(1),e_pi(0))
3787
3788//pi(0)=1,pi(1)=2,pi(2)=3,pi(3)=0 gives:  (1101)
3789
3790*/
3791
Note: See TracBrowser for help on using the repository browser.