Advertisement
Neptunium93

ecmm.gp

Aug 23rd, 2022 (edited)
1,047
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PARI/GP 9.78 KB | Source Code | 0 0
  1. \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  2. \\            ECM-Lenstra-Montgomery Implementation v.1.1          \\
  3. \\  Language: Pari/GP .gp                                          \\
  4. \\  Compile (example) for ecmm.gp:                                 \\
  5. \\  gp2c-run -g ecmm.gp                                            \\
  6. \\                                                                 \\
  7. \\  Included functions:                                            \\
  8. \\  ===================================                            \\
  9. \\  pointAdd(px, pz, qx, qz, rx, rz, n)                            \\
  10. \\  pointDouble(px, pz, n, a24)                                    \\
  11. \\  scalarMultiply(k, px, pz, n, a24)                              \\
  12. \\  ecm(n, B1, B2=100*B1, c=1, par=0, si=0)                        \\            
  13. \\  addhelp(ecm, "...")                                            \\
  14. \\  factorecm(n, dig=10, par=0)                                    \\
  15. \\  addhelp(factorecm, "...")                                      \\
  16. \\  ===================================                            \\
  17. \\                                                                 \\
  18. \\  For help type:                                                 \\
  19. \\  ?ecm                                                           \\
  20. \\  ?factorecm                                                     \\
  21. \\                                                                 \\
  22. \\  Reference:                                                     \\
  23. \\  https://www.rieselprime.de/ziki/Elliptic_curve_method          \\
  24. \\  https://rosettacode.org/wiki/Fermat_numbers#Go                 \\
  25. \\  https://www.alpertron.com.ar/ECM.HTM                           \\
  26. \\  https://members.loria.fr/PZimmermann/records/ecm/params.html   \\
  27. \\                                                                 \\
  28. \\  Martin Hopf 2022     mailto : athlontiger@googlemail.com       \\
  29. \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  30.  
  31.  
  32. pointAdd(px, pz, qx, qz, rx, rz, n) = { local(t, u, v, upv, umv, x, z);
  33.   t = px-pz;
  34.   u = qx+qz;
  35.   u*= t;
  36.   t = px+pz;
  37.   v = qx-qz;
  38.   v*= t;
  39.   upv = u+v;
  40.   umv = u-v;
  41.   x = upv*upv;
  42.   x*= rz;
  43.   x%= n;
  44.   z = umv*umv;
  45.   z*= rx;
  46.   z%= n;
  47.   return([x, z])
  48. };      \\ end pointAdd
  49.  
  50.  
  51. pointDouble(px, pz, n, a24) = { local(u2, v2, t, x, z);
  52.   u2 = px+pz;
  53.   u2*= u2;
  54.   v2 = px-pz;
  55.   v2*= v2;
  56.   t = u2-v2;
  57.   x = u2*v2;
  58.   x%= n;
  59.   z = a24*t;
  60.   z+= v2;
  61.   z*= t;
  62.   z%= n;
  63.   return([x, z])
  64. };      \\ end pointDouble
  65.  
  66.  
  67. scalarMultiply(k, px, pz, n, a24) = { local(sk, lk, qx, qz, rx, rz);
  68.   sk=binary(k);
  69.   lk=#sk;
  70.   qx=px;
  71.   qz=pz;
  72.   [rx, rz] = pointDouble(px, pz, n, a24);
  73.   for(i=2, lk,      \\ sk[i=1] is always 1 so don't use it :)
  74.     if(sk[i],
  75.       [qx, qz] = pointAdd(rx, rz, qx, qz, px, pz, n);
  76.       [rx, rz] = pointDouble(rx, rz, n, a24),          
  77.       \\ else
  78.       [rx, rz] = pointAdd(qx, qz, rx, rz, px, pz, n);
  79.       [qx, qz] = pointDouble(qx, qz, n, a24)
  80.     )
  81.   );
  82.   return([qx, qz])
  83. };      \\ end scalarMultiply
  84.  
  85.  
  86. ecm(n, B1, B2=100*B1, c=1, par=0, si=0) = {
  87.   local(k, b1, bl, u, v, vmu, a, t, a24, px, pz, qx, qz, g);
  88.   local(dd, beta, s, d, d2, b, tx, tz, step, alpha, limit, f, trx, trz);
  89.  
  90.   k = 1;
  91.   b1 = sqrtint(B1);
  92.   bl = log(B1);
  93.  
  94.   \\ compute a B1-powersmooth integer 'k'
  95.   forprime(p = 2, b1, k*= p^floor(bl/log(p)));
  96.   k*= factorback(primes([b1+1,B1]));
  97.   gettime();
  98.   if(si,c=1);
  99.   for(i = 1, c,
  100.     if(si,sig=si,sig=random([6,2^32-1]));      \\ 5 > sigma > 2^32
  101.     if(default(debug)>2, print("sigma=",sig));
  102.    
  103.     \\ generate a new curve in Montgomery form
  104.      
  105.     if( par == 1,                   \\ 64bit parameterization equals GMP-ECM -sigma 1: ...
  106.       a = 4*sig^2/2^64-2;
  107.       px = 2;
  108.       pz = 1
  109.     );
  110.  
  111.     if( par == 2,                   \\ Alpertron's parameterization -sigma 2: ...
  112.       u = 2*sig/(3*sig^2-1);
  113.       pz = 4*u;
  114.       a = (-3*u^4-6*u^2+1)/(4*u^3);
  115.       a24 = (a+2)/4;
  116.       px = 3*u^2+1
  117.     );
  118.  
  119.     if( par < 1 || par > 2,       \\ default Suyama's parameterization equals GMP-ECM -sigma: 0: ...
  120.       par = 0;    
  121.       u = sig*sig; u-= 5; v = 4*sig; vmu = v-u; a = vmu*vmu; a*= vmu; t = 3*u;        
  122.       t+= v; a*= t; t = 4*u; t*= u; t*= u; t*= v; a/= t; a-= 2;
  123.       px = u*u; px*= u; t = v*v; t*= v; px/= t; pz = 1
  124.     );
  125.      
  126.     \\ stage 1
  127.  
  128.     a24 = a+2;
  129.     a24/= 4;
  130.  
  131.     [qx, qz] = scalarMultiply(k, px, pz, n, a24);
  132.  
  133.     g = gcd(n, qz);
  134.     if(default(debug) > 1, print("c",i,"s1 <",gettime()," ms.>"));
  135.     if(g > 1 && g < n, return([g, sig, i, 1]));
  136.  
  137.     \\ stage 2
  138.     dd = sqrtint(B2);
  139.     beta = vector(dd+1);
  140.     s = vector(2*dd+2);
  141.    
  142.     [s[1], s[2]] = pointDouble(qx, qz, n, a24);
  143.     [s[3], s[4]] = pointDouble(s[1], s[2], n, a24);
  144.     beta[1] = s[1]*s[2];
  145.     beta[1]%= n;
  146.     beta[2] = s[3]*s[4];
  147.     beta[2]%= n;
  148.     for(d = 3, dd,
  149.       d2 = 2*d;  
  150.       [s[d2-1], s[d2]] = pointAdd(s[d2-3], s[d2-2], s[1], s[2], s[d2-5], s[d2-4], n);
  151.       beta[d] = s[d2-1]*s[d2];
  152.       beta[d]%= n
  153.     );    
  154.     g = 1;
  155.     b = B1-1;
  156.     [rx, rz] = scalarMultiply(b, qx, qz, n, a24);
  157.     t = 2*dd;
  158.     t = b-t;
  159.     [tx, tz] = scalarMultiply(t, qx, qz, n, a24);
  160.     step = 2*dd;
  161.     forstep(r = B1-1, B2, step,
  162.       alpha = rx*rz;
  163.       alpha%= n;
  164.       limit = r + step;
  165.       forprime(q = r+1, limit,
  166.         d = (q-r)/2;
  167.         t = rx-s[2*d-1];
  168.         f = rz+s[2*d];
  169.         f*= t;
  170.         f-= alpha;
  171.         f+= beta[d];
  172.         g*= f;  
  173.         g%= n
  174.       );
  175.       trx = rx;
  176.       trz = rz;
  177.       [rx, rz] = pointAdd(rx, rz, s[2*dd-1], s[2*dd], tx, tz, n);
  178.       tx = trx;    
  179.       tz = trz
  180.     );
  181.     g = gcd(n, g);
  182.     if(default(debug) > 1, print("c",i,"s2 <",gettime()," ms.>"));
  183.     if(g > 1 && g < n, return([g, sig, i, 2]))
  184.   );
  185. };     \\ end ecm
  186.  
  187.  
  188. addhelp(ecm, "ecm(n, B1, {B2=100*B1}, {c=1}, {par=0}, {si=0}) performs the elliptic curve method by Lenstra and Montgomery. \n\nInputs are: \n'n' the number to be factored. \n'B1' the bound for stage 1. \nIf specified: \n'B2' {default=100*B1} indicates the bound for stage 2. \n'c' {default=1} indicates the number of curves to run. \n'par' {default=0} sets the parameterization for the curve. Values are: \n\t0: Suyama's parameterization equals GMP-ECM -sigma 0:... . \n\t1: parameterization for 64-bit processors equals GMP-ECM -sigma 1:... . \n\t2: parameterization used in Alpertron's ECM. \n'si' {default=0} sets the sigma-value for one curve, otherwise a pseudo-random value between 5 and 2^32 is choosen. \n\nNote on pseudo-random numbers: if a new Pari/GP-session is started 'random()' will always create the \nsame sequence of pseudo-random numbers. However if you use 'setrand(n)' at the begin of a session \nwith 'n' is a wildly typed number < 2^64, a different sequence of pseudo-random numbers will be created. \n\nIf a factor (not necessarily prime) was found within the specified boundaries, a vector with 4 elements is returned. \nFrom left to right these elements are: \n\t- a non trivial factor of 'n', \n\t- the corresponding sigma value, \n\t- the curve and \n\t- the stage where the factor was found. \n\nThe debug level can be set with '\\g n' command while 'n' ranges from 0 to 20. \n\tIf debug level is set >= 2, timings for stage 1 and 2 are shown. \n\tIf debug level is set >= 3, additionally each sigma-value is shown. \n\nFor memory management it is recommended to increase the 'parisizemax' before running ecm(). \nTo do this, enter for example: 'default(parisizemax, 4096*1048576)' which sets the max size to 4Gbyte in this case. \n\nAvoid 'n' having small factors, as they often result in early 'impossible inverse mod' errors.");  
  189.  
  190.  
  191. factorecm(n, dig=9, par=0) = {
  192.   local(B1, B2, c, M, i, t, d, cd, R, v, bdig, s=10^6, p=2);
  193.   i=2;d = 0;
  194.   bdig = dig*log(10)/log(2);
  195.   printf("\n");
  196.  
  197.   \\ trial-divide to find small factors <= s.
  198.   while( p <= s,
  199.     if( n%p,
  200.       p = nextprime(p+1),       \\ else
  201.       printf("P%d=%d found by trial division.\n", floor(log(p)/log(10))+1, p);
  202.       n/=p;
  203.     )
  204.   );
  205.  
  206.   \\ Parameter-Matrix [bits,B1,curves] for bits[30-200] step 10 bits. See: https://members.loria.fr/PZimmermann/records/ecm/params.html
  207.   M=[30, 1358, 2; 40, 1630, 10; 50, 12322, 9; 60, 21906, 21; 70, 32918, 66; 80, 76620, 119; 90, 183850, 219; 100, 445658, 339; 110, 1305196, 439; 120, 3071166, 649; 130, 4572524, 1507; 140, 9267682, 2399; 150, 22025674, 3159; 160, 35158748 ,6076; 170, 47862548, 14038; 180, 153319098, 12017; 190, 410593604, 13174;  200, 491130496, 29584];
  208.  
  209.   if(bdig < M[1,1],
  210.     i = 1,          \\ else
  211.     if(bdig > M[#M[,1],1],  
  212.       i = #M[,1],   \\ else
  213.       while(bdig > M[i,1], i++)  
  214.     )    
  215.   );
  216.  
  217.   printf("\n");
  218.   while(!ispseudoprime(n) && i <= #M[,1],
  219.     c = M[i,3]-d;
  220.     B1 = M[i,2];
  221.     B2 = M[i,1]*B1;
  222.     cd = floor(log(n)/log(10))+1;
  223.     t = M[i,1]*log(2)/log(10);
  224.     if(c,
  225.       if(c==1,v="",v="s");
  226.       printf("          %d curve%s on C%d with B1=%d and B2=%d (t=%.2f).\n", c, v, cd, B1, B2, t);
  227.     );
  228.     if(c && R=ecm(n, B1, B2, c, par),
  229.         if(ispseudoprime(R[1]),v="P",v="C");
  230.         printf("\n%s%d=%d found @ curve %d stage %d sigma %d:%d\n\n", v, floor(log(R[1])/log(10))+1, R[1], R[3], R[4], par, R[2]);
  231.         n/= R[1];
  232.         d+= R[3],     \\ else
  233.         i++;
  234.         d=0
  235.      
  236.     )
  237.   );
  238.   printf("P%d factoring complete!\n\n",floor(log(n)/log(10))+1)
  239. };    \\ end factorecm
  240.  
  241.  
  242. addhelp(factorecm, "factorecm(n, {dig=9}, {par=0}) factoring routine for ecm() function. \n\nInputs are: \n'n' the number to be factored. \n If specified: \n'dig' {default=9} the (minimum) number of digits that an expected factor of 'n' has. \n'par' {default=0} parameterization value for which ecm() initializes the curves. \n\nFor more details see '?ecm'.");
  243.  
  244. \\ end ecmm.gp
  245.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement