Advertisement
Neptunium93

ecmrpn2.1.gp

Jan 1st, 2023 (edited)
852
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PARI/GP 14.73 KB | Source Code | 0 0
  1. /*\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
  2. /*                          ecmrpn2.1.                             */
  3. /*              ECM-Lenstra-Montgomery factorization               */
  4. /*        for numbers of the form 'n = 2^(2m-1)-2^(m-1)+1'         */
  5. /*              including right perfect numbers (RPN)              */
  6. /*                                                                 */
  7. /*  Language: Pari/GP .gp                                          */
  8. /*  Compile (example) for ecmrpn2.1.gp:                            */
  9. /*  gp2c-run -g ecmrpn2.1.gp                                       */
  10. /*                                                                 */
  11. /*  Included functions:                                            */
  12. /*  ===================================                            */
  13. /*  Redc(t, n, n2, ar, br, cr)                                     */
  14. /*  pointAdd(px, pz, qx, qz, rx, rz, n, n2, ar, br, cr)            */
  15. /*  pointDouble(px, pz, n, a24, n2, ar, br, cr)                    */
  16. /*  ScalarMultiply(k, px, pz, n, a24, n2, ar, br, cr)              */
  17. /*  ecm(m, B1, B2=100*B1, c=1, par=0, si=0, fa=[])                 */
  18. /*  addhelp(ecm, "...")                                            */      
  19. /*  ecm_mt(m, B1, B2=100*B1, c=1, par=0, si=0, fa=[], thr=1)       */  
  20. /*  addhelp(ecm_mt, "...")                                         */
  21. /*  ===================================                            */
  22. /*                                                                 */
  23. /*  For help type:                                                 */
  24. /*  ?ecm                                                           */
  25. /*  ?ecm_mt                                                        */
  26. /*                                                                 */
  27. /*  References:                                                    */
  28. /*  https://www.rieselprime.de/ziki/Elliptic_curve_method          */
  29. /*  https://rosettacode.org/wiki/Fermat_numbers#Go                 */
  30. /*  https://www.alpertron.com.ar/ECM.HTM                           */
  31. /*  https://members.loria.fr/PZimmermann/records/ecm/params.html   */
  32. /*                                                                 */
  33. /*  Martin Hopf 2022     mailto: athlontiger@googlemail.com        */
  34. /*                Free for non-commercial use                      */
  35. /*\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
  36. /* changes:                                                        */
  37. /* v.1.2.:  better memory handling for stage 1.                    */
  38. /* v.2.0.:  fast modular reduction for RPN                         */
  39. /* v.2.1.:  'known factors' support                                */
  40. /*\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
  41.  
  42.  
  43. Redc(t, n, n2, ar, br, cr) = {
  44.   \\ this is not Montgomery's Redc core.
  45.   \\ instead it is the modular reduction for RPN and similar numbers.
  46.   my(a, b);
  47.   while( t >= n2,       \\ t = bitand(t, ar) + (t >> cr) << br - t >> cr)
  48.     a = bitand(t, ar);
  49.     b = t >> cr;
  50.     t = b << br;
  51.     t-= b;
  52.     t+= a;
  53.   );
  54.   if( t >= n, t-n, t)
  55. };      \\ end Redc
  56.  
  57.  
  58. pointAdd(px, pz, qx, qz, rx, rz, n, n2, ar, br, cr) = {
  59.   my(t, u, v, upv, umv, x, z);
  60.   t = px-pz;
  61.   if(t < 0, t+= n);
  62.   u = qx+qz;
  63.   if(u > n, u-= n);
  64.   u*= t;
  65.   u = Redc(u, n, n2, ar, br, cr);
  66.   t = px+pz;
  67.   if(t > n, t-= n);
  68.   v = qx-qz;
  69.   if(v < 0, v+= n);
  70.   v*= t;
  71.   v = Redc(v, n, n2, ar, br, cr);
  72.   upv = u+v;
  73.   if(upv > n, upv-= n);
  74.   umv = u-v;
  75.   if(umv < 0, umv+= n);
  76.   x = upv*upv;
  77.   x = Redc(x, n, n2, ar, br, cr);
  78.   x*= rz;
  79.   x = Redc(x, n, n2, ar, br, cr);
  80.   z = umv*umv;
  81.   z = Redc(z, n, n2, ar, br, cr);
  82.   z*= rx;
  83.   z = Redc(z, n, n2, ar, br, cr);
  84.   return([x, z])
  85. };      \\ end pointAdd
  86.  
  87.  
  88. pointDouble(px, pz, n, a24, n2, ar, br, cr) = {
  89.   my(u2, v2, t, x, z);
  90.   u2 = px+pz;
  91.   if(u2 > n, u2-= n);    
  92.   u2*= u2;
  93.   u2 = Redc(u2, n, n2, ar, br, cr);
  94.   v2 = px-pz;
  95.   if(v2 < 0, v2+= n);    
  96.   v2*= v2;
  97.   v2 = Redc(v2, n, n2, ar, br, cr);
  98.   t = u2-v2;
  99.   if(t < 0, t+= n);    
  100.   x = u2*v2;
  101.   x = Redc(x, n, n2, ar, br, cr);
  102.   z = a24*t;
  103.   z = Redc(z, n, n2, ar, br, cr);
  104.   z+= v2;
  105.   if(z > n, z-= n);    
  106.   z*= t;
  107.   z = Redc(z, n, n2, ar, br, cr);
  108.   return([x, z])
  109. };      \\ end pointDouble
  110.  
  111.  
  112. scalarMultiply(k, px, pz, n, a24, n2, ar, br, cr) = {
  113.   my(lk, qx, qz, rx, rz, ik=100, ti=0, ts);
  114.   lk=exponent(k);
  115.   qx=px;
  116.   qz=pz;
  117.   [rx, rz] = pointDouble(px, pz, n, a24, n2, ar, br, cr);
  118.   \\ bittest(k, i=lk) is always 1 - the neutral element of multiplication - so skip it :)
  119.   forstep(i=lk-1, 0, -1,      
  120.     if(bittest(k, i),
  121.       [qx, qz] = pointAdd(rx, rz, qx, qz, px, pz, n, n2, ar, br, cr);
  122.       [rx, rz] = pointDouble(rx, rz, n, a24, n2, ar, br, cr),          
  123.       \\ else
  124.       [rx, rz] = pointAdd(qx, qz, rx, rz, px, pz, n, n2, ar, br, cr);
  125.       [qx, qz] = pointDouble(qx, qz, n, a24, n2, ar, br, cr)
  126.     );
  127.     if(default(debug) > 3,
  128.       if(i%ik,,
  129.         ti+=gettime();
  130.         ts=ti\1000;
  131.         printf("<%.2f%% %dsec.> ", (lk-i-1)/lk*100., ts)
  132.       )
  133.     )
  134.   );
  135.   return([qx, qz])
  136. };      \\ end scalarMultiply
  137.  
  138.  
  139. ecm(m, B1, B2=100*B1, c=1, par=0, si=0, fa=[]) = {
  140.   my(ar, br, cr, n, n2, k, k2, b1, bl, sig=0, u, v, vmu, a, t, a24, px, pz, qx, qz, g=1);
  141.   my(nb, dd, db, dv, beta, b, rx, rz, tx, tz, alpha, delta, step, f, trx, trz, ti, ts, ik=20);
  142.   my(B1now, B1next, B1first, B1step = 100000);  
  143.  
  144.   \\ build RPN out of m.
  145.   n = 2^(2*m-1)-2^(m-1)+1;
  146.   n2= 2*n;
  147.   ar = 2^(2*m-1)-1;
  148.   br = m-1;
  149.   cr = 2*m-1;
  150.  
  151.   \\ stage 1 parameters.
  152.   B1 = floor(B1);
  153.   k = 1;
  154.   b1 = sqrtint(B1);
  155.   bl = log(B1);
  156.  
  157.   \\ stage 2 precomputation.
  158.   B2 = floor(B2);
  159.   nb = exponent(n)+1;      \\ #bits of 'n'.
  160.    if(
  161.     B2 < 3600, dd = 30; db = 4,       \\ elseif...
  162.     B2 < 32400, dd = 90; db = 12,
  163.     B2 < 176400, dd = 210; db = 24,
  164.     B2 < 705600, dd = 420; db = 48,
  165.     B2 < 6350400, dd = 1260; db = 144,
  166.     B2 < 21344400, dd = 2310; db = 240,
  167.     B2 < 42688800, dd = 4620; db = 480,
  168.     B2 < 384199200, dd = 13860; db = 1440,
  169.     B2 < 901800900, dd = 30030; db = 2880,
  170.     B2 < 3607203600, dd = 60060; db = 5760,
  171.     B2 < 16232416200, dd = 180180; db = 17280,
  172.     dd = 510510; db = 46080
  173.   );
  174.    
  175.   dv = vector(db);
  176.   t=0;
  177.   forstep( i = 1, dd/2, 2,
  178.     if( gcd(i, dd) == 1,
  179.       t++;
  180.       dv[t] = i
  181.      
  182.     )
  183.   );
  184.  
  185.   \\ compute a B1-powersmooth integer 'k'
  186.   forprime(p = 2, b1, k*= p^(bl\log(p)));
  187.  
  188.   \\ for memory issues we set B1first = min(B1, B1step).
  189.   B1first = min(B1, B1step);  
  190.   k*= factorback(primes([b1+1, B1first]));
  191.   gettime();
  192.   if(si, c = 1);
  193.  
  194.  
  195.   \\ curve loop
  196.   for(i = 1, c,
  197.     while( sig==0,          \\ iferr then choose another sigma
  198.       if(si,
  199.         sig = si; setrand(si),                       \\else
  200.         sig = random([6,2^32-1])        \\ 5 < sigma < 2^32
  201.       );    
  202.    
  203.       \\ generate a new curve in Montgomery form
  204.  
  205.       if( par == 1,                   \\ 64bit parameterization equals GMP-ECM -sigma 1: ...
  206.         a = 4*sig^2/2^64-2;
  207.         px = 2;
  208.         pz = 1
  209.       );
  210.  
  211.       if( par == 2,                   \\ parameterization used in Alpertron's ECM. sigma 2: ...
  212.         u = 2*sig/(3*sig^2-1);
  213.         a = (-3*u^4-6*u^2+1)/(4*u^3);
  214.         px = 3*u^2+1;
  215.         pz = 4*u
  216.       );
  217.      
  218.       if( par == 3,                   \\ no parameterization: set a24 = sigma. sigma 3: ...
  219.         a = 4*sig-2;
  220.         px = 2;
  221.         pz = 1
  222.       );
  223.  
  224.       if( par < 1 || par > 3,         \\ default Suyama's parameterization equals GMP-ECM -sigma 0: ...
  225.         par = 0;    
  226.         u = sig*sig; u-= 5; v = 4*sig; vmu = v-u; a = vmu*vmu; a*= vmu; t = 3*u;        
  227.         t+= v; a*= t; t = 4*u; t*= u; t*= u; t*= v; a/= t; a-= 2;
  228.         px = u*u; px*= u; t = v*v; t*= v; px/= t; pz = 1
  229.       );
  230.  
  231.       if(default(debug)>2, printf("sigma=%d:%d D=%d\n", par, sig, dd));
  232.  
  233.       \\ Normalizing step done once at the beginning of stage 1.
  234.       \\ As 'px', 'pz' and 'a24' may be rationals at this point, an 'impossible inverse' error
  235.       \\ can occur by mod 'n', usually if 'n' has small factors. Pari/GP's 'iferr' handles
  236.       \\ this and returns a factor before stage 1 begins. This is marked as:
  237.       \\ stage 0 factor found ?
  238.  
  239.       iferr(px%= n, E, sig = 0; si = 0; g = lcm(gcd(lift(component(E,2)),n),g));  \\ inverse mod handling.
  240.       iferr(pz%= n, E, sig = 0; si = 0; g = lcm(gcd(lift(component(E,2)),n),g));  
  241.       a24 = a+2;
  242.       a24/= 4;
  243.       iferr(a24%= n, E, sig = 0; si = 0; g = lcm(gcd(lift(component(E,2)),n),g));
  244.       for(i = 1, #fa, g\= gcd(g, fa[i]));     \\ in case of known factors, remove them.
  245.       if(g > 1 && g < n, return([g, sig, i, 0]))
  246.     );
  247.  
  248.     \\ stage 1 - standard double-add ladder
  249.  
  250.     k2=k;
  251.     B1next = B1first;
  252.     B1now = B1next;
  253.  
  254.     if( B1now == B1,
  255.       [qx, qz] = scalarMultiply(k, px, pz, n, a24, n2, ar, br, cr),     \\ else
  256.      
  257.       \\  for memory issues we split B1 into B1steps.
  258.       while ( B1now < B1,
  259.         [px, pz] = scalarMultiply(k2, px, pz, n, a24, n2, ar, br, cr);
  260.         B1now = B1next;
  261.         B1next = min(B1, B1next + B1step);
  262.         k2 = factorback(primes([B1now+1, B1next]));
  263.       );
  264.       qx = px;
  265.       qz = pz  
  266.     );
  267.  
  268.     g = gcd(n, qz);         \\ factor found stage 1 ?
  269.     if(default(debug) > 3, print);
  270.     if(default(debug) > 1, print("c",i,"s1 <",gettime()," ms.>"));
  271.     for(i = 1, #fa, g\= gcd(g, fa[i]));     \\ in case of known factors, remove them.
  272.     if(g > 1 && g < n, return([g, sig, i, 1]));
  273.  
  274.     \\ stage 2 - advanced standard continuation
  275.    
  276.       g = 1;
  277.       beta = vector(db);
  278.       delta = vector(db);
  279.       b = (B1\dd+1)*dd;     \\ 'b' divisble by 'dd' and next greater 'B1'.  
  280.    
  281.     for(i = 1, db,      \\ create table delta[i], beta[i].
  282.        delta[i] = scalarMultiply(dv[i], qx, qz, n, a24, n2, ar, br, cr);
  283.        beta[i] = delta[i][1]*delta[i][2];
  284.        beta[i] = Redc(beta[i], n, n2, ar, br, cr)
  285.     );
  286.  
  287.     step = scalarMultiply(dd, qx, qz, n, a24, n2, ar, br, cr);
  288.     [rx, rz] = scalarMultiply(b, qx, qz, n, a24, n2, ar, br, cr);
  289.     [tx, tz] = scalarMultiply(b-dd, qx, qz, n, a24, n2, ar, br, cr);
  290.     if(default(debug) > 3, print);
  291.     if(default(debug) > 1, print("c",i,"s2pre <",gettime()," ms.>"));
  292.     \\ step 2 main loop
  293.     forstep(r = b, B2, dd,
  294.       alpha = rx*rz;
  295.       alpha = Redc(alpha, n, n2, ar, br, cr);
  296.       for(i = 1, db,
  297.         \\ do a pseudo primality test only if n is => 1024 bits.  
  298.         if(nb < 1024 || ispseudoprime(r-dv[i]) || ispseudoprime(r+dv[i]),          
  299.           t = rx-delta[i][1];
  300.           if(t < 0, t+= n);
  301.           f = rz+delta[i][2];
  302.           if(f > n, f-= n);
  303.           f*= t;
  304.           f = Redc(f, n, n2, ar, br, cr);
  305.           f-= alpha;
  306.           f+= beta[i];
  307.           if(f > n, f-= n, f < 0, f+= n);
  308.           g*= f;
  309.           g = Redc(g, n, n2, ar, br, cr)
  310.         )
  311.       );
  312.       trx = rx;
  313.       trz = rz;
  314.       [rx, rz] = pointAdd(rx, rz, step[1], step[2], tx, tz, n, n2, ar, br, cr);
  315.       tx = trx;    
  316.       tz = trz;
  317.       if(default(debug) > 3,
  318.         if(r%(dd*ik),,
  319.           ti+=gettime();
  320.           ts=ti\1000;
  321.           printf("<%.2f%% %dsec.> ", (r-b)/B2*100., ts)
  322.         )
  323.       )
  324.     );
  325.    
  326.     g = gcd(n, g);          \\ factor found stage 2 ?
  327.     if(default(debug) > 3, print);
  328.     if(default(debug) > 1, print("c",i,"s2 <",gettime()," ms.>"));
  329.     for(i = 1, #fa, g\= gcd(g, fa[i]));     \\ in case of known factors, remove them.
  330.     if(g > 1 && g < n, return([g, sig, i, 2]));
  331.    
  332.     sig = 0        \\ Stage 2 done. Reset sig for more curves.  
  333.   );
  334. };     \\ end ecm
  335.  
  336.  
  337. addhelp(ecm, "ecm(m, B1, {B2=100*B1}, {c=1}, {par=0}, {si=0}, {fa=[]}) elliptic curve method for numbers of the form \n\t'n = 2^(2*m-1)-2^(m-1)+1' including right perfect numbers (RPN) (V2.1). \n\nInputs are: \n'm' exponent of the number to be factored 'n = 2^(2*m-1)-2^(m-1)+1'. 'n' must be composite. \n'B1' the bound for stage 1. 'B1' <= 10^10 must be even. \nIf specified: \n'B2' {default=100*B1} the bound for stage 2. 'B2' <= 10^14. \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\t3: no parameterization: set a24 = sigma. \n'si' {default=0} sets the sigma-value for one curve, if omitted a pseudo-random value 5 < 'si' < 2^32 is choosen.\n'fa' {default=[]} vector of one or more known factors e.g.: '[<factor1>, <factor2>, <...>]'. \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 entries is returned. \nFrom left to right these entries are: \n\t- a non trivial factor of 'n', \n\t- the generating sigma value, \n\t- the curve and \n\t- the stage where the factor was found. \n\nThe debug level for increased output can be set with '\\g n' command while 'n' ranges from 0 to 20. \n\t'n' >= 2, timings for stage 1 and 2. \n\t'n' >= 3, sigma and stage 2 D-values. \n\t'n' >= 4, more detailed timings (for curves running several hours). \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 4Gbytes in this case. ");
  338.  
  339.  
  340. ecm_mt(m, B1, B2=100*B1, c=1, par=0, si=0, fa=[], thr=1) = {
  341.   my(i=0, R, S);
  342.   forstep(b = 0, c-1, thr,
  343.     S = vector(min(thr, c-b), s, random([6,2^32-1]));
  344.     R = parapply(s -> ecm(m, B1, B2, 1, par, s, fa), S);
  345.     for(t=1, #R,
  346.       i++;
  347.       if(R[t],
  348.         R[t][3] = i;
  349.         return(R[t])        
  350.       )
  351.     );
  352.     if(default(debug) > 0, printf("<c%d/%d> ", i, c))
  353.   )
  354. };      \\ end ecm_mt
  355.  
  356.  
  357. addhelp(ecm_mt, "ecm_mt(m, B1, {B2=100*B1}, {c=1}, {par=0}, {si=0}, {fa=[]}, {thr=1}) framework for ecm to run multi-threaded (if available). \n\n Inputs are the same as for ecm (see ?ecm) except: \n'thr' {default=1} sets the number of curves to run in parallel \n\nFor memory management it is recommended to increase the 'threadsizemax' before running ecm_mt(). \nTo do this, enter for example: 'default(threadsizemax, 1024*1048576)' which sets the max size to 1Gbyte for each thread in this case.");
  358.  
  359.  
  360. export(ecm);        \\ export to the parallel world.
  361. export(scalarMultiply);
  362. export(pointDouble);
  363. export(pointAdd);
  364. export(Redc);
  365.  
  366.  
  367. \\ end ecmrpn2.1.gp
  368.  
Tags: ECM RPN
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement