LCOV - code coverage report
Current view: top level - ecm - ecm2.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 337 368 91.6 %
Date: 2022-03-21 11:19:20 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /* Elliptic Curve Method implementation: stage 2 routines.
       2             : 
       3             : Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012 Paul Zimmermann,
       4             : Alexander Kruppa, Pierrick Gaudry, Dave Newman.
       5             : 
       6             : This file is part of the ECM Library.
       7             : 
       8             : The ECM Library is free software; you can redistribute it and/or modify
       9             : it under the terms of the GNU Lesser General Public License as published by
      10             : the Free Software Foundation; either version 3 of the License, or (at your
      11             : option) any later version.
      12             : 
      13             : The ECM Library is distributed in the hope that it will be useful, but
      14             : WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      15             : or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
      16             : License for more details.
      17             : 
      18             : You should have received a copy of the GNU Lesser General Public License
      19             : along with the ECM Library; see the file COPYING.LIB.  If not, see
      20             : http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
      21             : 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
      22             : 
      23             : #include <stdlib.h>
      24             : #include <math.h>
      25             : #include "ecm-impl.h"
      26             : 
      27             : /* R_i <- q_i * S, 0 <= i < n, where q_i are large integers, S is a point on
      28             :    an elliptic curve. Uses max(bits in q_i) modular inversions (one less if 
      29             :    max(q_i) is a power of 2). Needs up to n+2 cells in T.
      30             :    Returns whether factor was found or not found, factor goes into p. 
      31             :    No error can occur.
      32             :    We should have n > 0.
      33             : */
      34             : 
      35             : static int
      36        2086 : multiplyW2n (mpz_t p, point *R, curve *S, mpz_t *q, const unsigned int n, 
      37             :               mpmod_t modulus, mpres_t u, mpres_t v, mpres_t *T,
      38             :               unsigned long *tot_muls, unsigned long *tot_gcds)
      39             : {
      40             :   ecm_uint i, maxbit, k; /* k is the number of values to batch invert */
      41        2086 :   ecm_uint l, t, muls = 0, gcds = 0;
      42             : #ifdef WANT_EXPCOST
      43             :   unsigned int hamweight = 0;
      44             : #endif
      45        2086 :   int youpi = ECM_NO_FACTOR_FOUND;
      46             :   mpz_t flag; /* Used as bit field, keeps track of which R[i] contain partial results */
      47             :   point s;    /* 2^t * S */
      48             :   mpz_t signs; /* Used as bit field, i-th bit is set iff q[i]<0 */
      49             : #ifdef WANT_ASSERT
      50             :   mpz_t __dummy; /* used for local computations */
      51             : #endif
      52             : 
      53             :   ASSERT(n > 0);
      54             : 
      55             :   /* We assume the code below works also when S is the neutral element. */
      56             :   
      57        2086 :   mpz_init2 (flag, n);
      58        2086 :   mpz_init2 (signs, n);
      59        2086 :   mpres_init (s.x, modulus);
      60        2086 :   mpres_init (s.y, modulus);
      61        2086 :   mpres_set (s.x, S->x, modulus);
      62        2086 :   mpres_set (s.y, S->y, modulus);
      63             : 
      64             :   /* Set maxbit to index of highest set bit among all the q[i] */
      65             :   /* Index of highest bit of q is sizeinbase(q, 2) - 1 */
      66        2086 :   maxbit = 0;
      67       57324 :   for (i = 0; i < n; i++)
      68             :     {
      69             :       /* We'll first compute positive multiples and change signs later */
      70       55238 :       if (mpz_sgn (q[i]) < 0)
      71             :         {
      72        5292 :           mpz_setbit (signs, i);;
      73        5292 :           mpz_neg (q[i], q[i]);
      74             :         }
      75             : 
      76             :       /* Multiplier == 0? Then set result to neutral element */
      77       55238 :       if (mpz_sgn (q[i]) == 0)
      78             :         {
      79          20 :            mpres_set_ui (R[i].x, 0, modulus);
      80          20 :            mpres_set_ui (R[i].y, 0, modulus);
      81             :         }
      82             : #ifdef WANT_EXPCOST
      83             :       else
      84             :         hamweight += mpz_popcount (q[i]) - 1;
      85             : #endif
      86       55238 :       if ((t = mpz_sizeinbase (q[i], 2) - 1) > maxbit)
      87        4361 :           maxbit = t;
      88             :     }
      89             : 
      90             : #ifdef WANT_EXPCOST
      91             :   outputf (OUTPUT_ALWAYS, "Expecting %d multiplications and %d extgcds\n", 
      92             :           4 * (maxbit) + 6 * hamweight - 3, maxbit + 1);      /* maxbit is floor(log_2(max(q_i))) */
      93             : #endif
      94             : 
      95       40533 :   for (t = 0; t <= maxbit && !youpi; t++)    /* Examine t-th bit of the q[i] */
      96             :     {
      97             :       /* See which values need inverting and put them into T[]. Keep number
      98             :          of those values in k */
      99       38457 :       k = 0;
     100             :       
     101             :       /* Will we have to double s at the end of this pass? If yes,  
     102             :          schedule 2*s.y for inverting */
     103       38457 :       if (t < maxbit)
     104       36381 :         mpres_add (T[k++], s.y, s.y, modulus);
     105             :       
     106     2561943 :       for (i = 0; i < n && !youpi; i++) 
     107     2523486 :         if (ecm_tstbit (q[i], t))       /* If q[i] & (1<<t), we'll add s to R[i] */
     108      920110 :           if (ecm_tstbit (flag, i))     /* Does R[i] contain a partial result yet ? */
     109             :             {                           /* If Yes: need actual point addition so */
     110      864892 :               mpres_sub (T[k], s.x, R[i].x, modulus); /* schedule (s.x-R[i].x) for inverting */
     111      864892 :               if (k > 0)
     112      862816 :                 mpres_mul (T[k], T[k], T[k - 1], modulus);
     113      864892 :               k++;
     114             :             }                           /* If No: we'll simply set R[i] to s later on, nothing tbd here */
     115             :       
     116             :       /* So there are k values in need of inverting, call them v[m], 0 <= m < k. */      
     117             :       /* Here T[m], 0 <= m < k, contains v[0]*...*v[m] */
     118             :       
     119             :       /* Put inverse of the product of all scheduled values in T[k]*/
     120       38457 :       if (k > 0)
     121             :         {
     122       38457 :           muls += 3 * (k - 1);
     123       38457 :           gcds++;
     124       38457 :           if (!mpres_invert (T[k], T[k - 1], modulus))
     125             :             {
     126             :               /* If a factor was found, put factor in p, 
     127             :                  flag success and bail out of loop */
     128          10 :               if (p != NULL)
     129          10 :                 mpres_gcd (p, T[k - 1], modulus);
     130          10 :               youpi = ECM_FACTOR_FOUND_STEP2;
     131          10 :               break;
     132             :             }
     133             :         }
     134             :       
     135             :       /* T[k] now contains 1/(v[0]*...*v[k - 1]), 
     136             :          T[m], 0 <= m < k, still contain v[0]*...*v[m] */
     137             :       
     138       38447 :       l = k - 1;
     139             : 
     140     2561853 :       for (i = n; i-- > 0; ) /* Go through the R[i] again, backwards */
     141     2523406 :         if (ecm_tstbit (q[i], t))
     142             :           {
     143      920079 :             if (ecm_tstbit (flag, i))
     144             :               {
     145             :                 /* T[k] contains 1/(v[0]*...*v[l]) */
     146      864861 :                 if (l > 0) /* need to separate the values */
     147             :                   {
     148             :                     /* T[l - 1] has v[0]*...*v[l-1] */
     149      862785 :                     mpres_mul (T[l], T[l - 1], T[k], modulus); /* So T[l] now has 1/v[l] == 1/(s.x - R[i].x) */
     150      862785 :                     mpres_sub (u, s.x, R[i].x, modulus);
     151      862785 :                     mpres_mul (T[k], T[k], u, modulus);        /* T[k] now has 1/(v[0]*...*v[l - 1]) */
     152             :                   }
     153             :                 else
     154             :                   {
     155             :                     /* T[k] contains 1/v[0] */
     156        2076 :                     mpres_set (T[0], T[k], modulus); 
     157             :                   }
     158             :                 
     159             :                 /* 1/(s.x - R[i].x) is in T[l] */
     160             : #ifdef WANT_ASSERT
     161             :                 mpres_sub (u, s.x, R[i].x, modulus);
     162             :                 mpres_mul (u, u, T[l], modulus);
     163             :                 mpz_init(__dummy);
     164             :                 mpres_get_z (__dummy, u, modulus);
     165             :                 mpz_mod (__dummy, __dummy, modulus->orig_modulus);
     166             :                 if (mpz_cmp_ui (__dummy, 1) != 0) 
     167             :                   outputf (OUTPUT_ERROR, "Error, (s.x - R[%d].x) * T[%d] == "
     168             :                            "%Zd\n", i, l, __dummy);
     169             :                 mpz_clear(__dummy);
     170             : #endif
     171             :                 
     172      864861 :                 mpres_sub (u, s.y, R[i].y, modulus);   /* U    = y2 - y1 */
     173      864861 :                 mpres_mul (T[l], T[l], u, modulus);    /* T[l] = (y2-y1)/(x2-x1) = lambda */
     174      864861 :                 mpres_sqr (u, T[l], modulus);          /* U    = lambda^2 */
     175      864861 :                 mpres_sub (u, u, R[i].x, modulus);     /* U    = lambda^2 - x1 */
     176      864861 :                 mpres_sub (R[i].x, u, s.x, modulus);   /* x3   = lambda^2 - x1 - x2 */
     177      864861 :                 mpres_sub (u, s.x, R[i].x, modulus);   /* U    = x2 - x3 */
     178      864861 :                 mpres_mul (u, u, T[l], modulus);       /* U    = lambda*(x2 - x3) */
     179      864861 :                 mpres_sub (R[i].y, u, s.y, modulus);   /* y3   = lambda*(x2 - x3) - y2 */
     180      864861 :                 muls += 3;
     181      864861 :                 l--;
     182             :               }
     183             :             else /* R[i] does not contain a partial result. */
     184             :               {
     185       55218 :                 mpres_set (R[i].x, s.x, modulus);   /* Just set R[i] to s */
     186       55218 :                 mpres_set (R[i].y, s.y, modulus);
     187       55218 :                 mpz_setbit (flag, i);               /* and flag it as used */
     188             :               }
     189             :           }
     190             :       
     191       38447 :       if (t < maxbit) /* Double s */
     192             :         { 
     193             :           ASSERT(l==0);
     194             : #ifdef WANT_ASSERT
     195             :           mpres_add (u, s.y, s.y, modulus);
     196             :           mpres_mul (u, u, T[k], modulus);
     197             :           mpz_init(__dummy);
     198             :           mpres_get_z (__dummy, u, modulus);
     199             :           mpz_mod (__dummy, __dummy, modulus->orig_modulus);
     200             :           if (mpz_cmp_ui (__dummy, 1) != 0)
     201             :             outputf (OUTPUT_ERROR, "Error, at t==%d, 2*s.y / (2*s.y) == %Zd\n", 
     202             :                      t, __dummy);
     203             :           mpz_clear(__dummy);
     204             : #endif          
     205             : 
     206             :                                                /* 1/(2*s.y) is in T[k] */
     207       36371 :           mpres_sqr (u, s.x, modulus);         /* U = X^2 */
     208       36371 :           mpres_mul_ui (u, u, 3, modulus);     /* U = 3*X^2 */
     209       36371 :           mpres_add (u, u, S->A, modulus);     /* U = 3*X^2 + A */
     210       36371 :           mpres_mul (T[k], T[k], u, modulus);  /* T = (3*X^2 + A) / (2*Y) = lambda */
     211       36371 :           mpres_sqr (u, T[k], modulus);        /* U = lambda^2 */
     212       36371 :           mpres_sub (u, u, s.x, modulus);      /* U = lambda^2 - X */
     213       36371 :           mpres_sub (u, u, s.x, modulus);      /* U = lambda^2 - 2*X = s.x' */
     214       36371 :           mpres_sub (v, s.x, u, modulus);      /* V = s.x - s.x' */
     215       36371 :           mpres_mul (v, v, T[k], modulus);     /* V = lambda*(s.x - s.x') */
     216       36371 :           mpres_sub (s.y, v, s.y, modulus);    /* s.y' = lambda*(s.x - s.x') - s.y */
     217       36371 :           mpres_set (s.x, u, modulus);
     218       36371 :           muls += 4;
     219             :         }
     220             :     }
     221             : 
     222        2086 :   mpres_clear (s.y, modulus);
     223        2086 :   mpres_clear (s.x, modulus);
     224        2086 :   mpz_clear (flag);
     225             : 
     226        2086 :   if (tot_muls != NULL)
     227        2086 :     *tot_muls += muls;
     228        2086 :   if (tot_gcds != NULL)
     229        2086 :     *tot_gcds += gcds;
     230             :   
     231             :   /* Now take inverse points (negative y-coordinate) where q[i] was < 0 */
     232       57324 :   for (i = 0; i < n; i++)
     233       55238 :     if (ecm_tstbit (signs, i))
     234             :       {
     235        5292 :         mpz_neg (R[i].y, R[i].y);
     236        5292 :         mpz_neg (q[i], q[i]);
     237             :       }
     238             : 
     239        2086 :   mpz_clear (signs);
     240        2086 :   return youpi;
     241             : }
     242             : 
     243             : 
     244             : /* Input: Points X[0]..X[(n+1)*m-1]
     245             :    T is used for temporary values and needs to have (n-1)*m+1 entries.
     246             : 
     247             :    Performs the following loop with only one gcdext, using Montgomery's trick:
     248             :    for (i=0;i<m;i++)
     249             :      for (j=0;j<n;j++)
     250             :          (x[j+(n+1)*i] : y[j+(n+1)*i]) += (x[j+1+(n+1)*i] : y[j+1+(n+1)*i])
     251             : 
     252             :    Uses one inversion and 6*n*m-3 multiplications for n*m > 0.
     253             :    Processes neutral (zero), identical and negative points correctly.
     254             : 
     255             :    Return factor found or not (no error can occur here).
     256             : */
     257             : 
     258             : static int
     259      287573 : addWnm (mpz_t p, point *X, curve *S, mpmod_t modulus, unsigned int m, 
     260             :         unsigned int n, mpres_t *T, unsigned long *tot_muls, 
     261             :         unsigned long *tot_gcds)
     262             : {
     263             :   unsigned int k, l;
     264             :   int i, j;
     265             : 
     266      287573 :   if (n == 0 || m == 0)
     267           0 :     return ECM_NO_FACTOR_FOUND;
     268             : 
     269      287573 :   k = 0;
     270     4457640 :   for (i = m - 1; i >= 0; i--)    /* Go through the m different lists */
     271    48235726 :     for (j = n - 1; j >= 0; j--)  /* Go through each list backwards */
     272             :       {                           /* And prepare the values to be inverted */
     273             :         point *X1, *X2;
     274    44065659 :         X1 = X + i * (n + 1) + j;
     275    44065659 :         X2 = X + i * (n + 1) + j + 1;
     276             :         
     277             :         /* If either element is the neutral element, nothing tbd here */
     278    88131289 :         if ((mpres_is_zero (X1->x, modulus) && mpres_is_zero (X1->y, modulus)) ||
     279    44065639 :             (mpres_is_zero (X2->x, modulus) && mpres_is_zero (X2->y, modulus)))
     280          38 :           continue;
     281             :         
     282    44065621 :         mpres_sub (T[k], X2->x, X1->x, modulus); /* Schedule X2.x - X1.x */
     283             : 
     284    44065621 :         if (mpres_is_zero (T[k], modulus))  /* If both x-cordinates are identical */
     285             :           {
     286             :             /* Are the points identical? Compare y coordinates: */
     287          34 :             mpres_sub (T[k], X2->y, X1->y, modulus);
     288          34 :             if (mpres_is_zero (T[k], modulus))
     289             :               {
     290             :                 /* Yes, we need to double. Schedule 2*X[...].y */
     291          25 :                 mpres_add (T[k], X1->y, X1->y, modulus); 
     292             :               }
     293             :             else /* No, they are inverses. Nothing tbd here */
     294             :               {
     295             : #ifdef WANT_ASSERT
     296             :                 /* Check that the y coordinates are mutual negatives */
     297             :                 mpres_add (T[k], X2->y, X1->y, modulus);
     298             :                 ASSERT (mpres_is_zero (T[k], modulus));
     299             : #endif
     300           9 :                 continue; 
     301             :               }
     302             :           }
     303             : 
     304    44065612 :         if (k > 0)
     305    43778059 :           mpres_mul (T[k], T[k], T[k - 1], modulus);
     306    44065612 :         k++;
     307             :       }
     308             : 
     309             :   /* v_m = X[i * (n + 1) + j] - X[i * (n + 1) + j + 1], 0 <= j < n,
     310             :      and m = i * n + j */
     311             :   /* Here T[m] = v_0 * ... * v_m, 0 <= m < k */
     312             : 
     313      287573 :   if (k > 0 && !mpres_invert (T[k], T[k - 1], modulus))
     314             :     {
     315          11 :       if (p != NULL)
     316          11 :         mpres_gcd (p, T[k - 1], modulus);
     317          11 :       if (tot_muls != NULL)
     318          11 :         (*tot_muls) += m * n - 1;
     319          11 :       if (tot_gcds != NULL)
     320          11 :         (*tot_gcds) ++;
     321          11 :       return ECM_FACTOR_FOUND_STEP2;
     322             :     }
     323             : 
     324             :   /* T[k] = 1/(v_0 * ... * v_m), 0 <= m < k */
     325             : 
     326      287562 :   l = k - 1;
     327             : 
     328     4457526 :   for (i = 0; (unsigned) i < m; i++)
     329    48235316 :     for (j = 0; (unsigned) j < n; j++)
     330             :       {
     331             :         point *X1, *X2;
     332    44065352 :         X1 = X + i * (n + 1) + j;
     333    44065352 :         X2 = X + i * (n + 1) + j + 1;
     334             :         
     335             :         /* Is X1 the neutral element? */
     336    44065352 :         if (mpres_is_zero (X1->x, modulus) && mpres_is_zero (X1->y, modulus))
     337             :           {
     338             :             /* Yes, set X1 to X2 */
     339          29 :             mpres_set (X1->x, X2->x, modulus);
     340          29 :             mpres_set (X1->y, X2->y, modulus);
     341          29 :             continue;
     342             :           }
     343             :         
     344             :         /* Is X2 the neutral element? If so, X1 stays the same */
     345    44065323 :         if (mpres_is_zero (X2->x, modulus) && mpres_is_zero (X2->y, modulus))
     346           9 :           continue;
     347             :         
     348             :         /* Are the x-coordinates identical? */
     349    44065314 :         mpres_sub (T[k + 1], X2->x, X1->x, modulus);
     350    44065314 :         if (mpres_is_zero (T[k + 1], modulus))
     351             :           {
     352             :             /* Are the points inverses of each other? */
     353          34 :             mpres_sub (T[k + 1], X2->y, X1->y, modulus);
     354          34 :             if (!mpres_is_zero (T[k + 1], modulus))
     355             :               {
     356             :                 /* Yes. Set X1 to neutral element */
     357           9 :                 mpres_set_ui (X1->x, 0, modulus);
     358           9 :                 mpres_set_ui (X1->y, 0, modulus);
     359           9 :                 continue;
     360             :               }
     361             :             /* No, we need to double. Restore T[k+1] */
     362          25 :             mpres_sub (T[k + 1], X2->x, X1->x, modulus);
     363             :           }
     364             : 
     365    44065305 :         if (l == 0)
     366      287542 :           mpz_set (T[0], T[k]);
     367             :         else
     368    43777763 :           mpres_mul (T[l], T[k], T[l - 1], modulus); 
     369             :           /* T_l = 1/(v_0 * ... * v_l) * (v_0 * ... * v_{l-1}) = 1/v_l */
     370             : 
     371             : 
     372    44065305 :         if (mpres_is_zero (T[k + 1], modulus)) /* Identical points, so double X1 */
     373             :           {
     374          25 :             if (l > 0)
     375             :               {
     376           6 :                 mpres_add (T[k + 1], X1->y, X1->y, modulus); /* T[k+1] = v_{l} */
     377           6 :                 mpres_mul (T[k], T[k], T[k + 1], modulus);
     378             :                 /* T_k = 1/(v_0 * ... * v_l) * v_l = 1/(v_0 * ... * v_{l-1}) */
     379             :               }
     380             :             
     381          25 :             mpres_sqr (T[k + 1], X1->x, modulus);
     382          25 :             mpres_mul_ui (T[k + 1], T[k + 1], 3, modulus);
     383          25 :             mpres_add (T[k + 1], T[k + 1], S->A, modulus);
     384          25 :             mpres_mul (T[l], T[k + 1], T[l], modulus); /* T[l] = lambda */
     385          25 :             mpres_sqr (T[k + 1], T[l], modulus);       /* T1   = lambda^2 */
     386          25 :             mpres_sub (T[k + 1], T[k + 1], X1->x, modulus);  /* T1   = lambda^2 - x1 */
     387          25 :             mpres_sub (X1->x, T[k + 1], X2->x, modulus);     /* X1.x = lambda^2 - x1 - x2 = x3 */
     388          25 :             mpres_sub (T[k + 1], X2->x, X1->x, modulus);     /* T1   = x2 - x3 */
     389          25 :             mpres_mul (T[k + 1], T[k + 1], T[l], modulus);   /* T1   = lambda*(x2 - x3) */
     390          25 :             mpres_sub (X1->y, T[k + 1], X2->y, modulus);     /* Y1   = lambda*(x2 - x3) - y2 = y3 */
     391             :           }
     392             :         else
     393             :           {
     394    44065280 :             if (l > 0)
     395             :               {
     396    43777757 :                 mpres_mul (T[k], T[k], T[k + 1], modulus);
     397             :                 /* T_k = 1/(v_0 * ... * v_l) * v_l = 1/(v_0 * ... * v_{l-1}) */
     398             :               }
     399             : 
     400    44065280 :             mpres_sub (T[k + 1], X2->y, X1->y, modulus);     /* T1   = y2 - y1 */
     401    44065280 :             mpres_mul (T[l], T[l], T[k + 1], modulus);       /* Tl   = (y2 - y1) / (x2 - x1) = lambda */
     402    44065280 :             mpres_sqr (T[k + 1], T[l], modulus);          /* T1   = lambda^2 */
     403    44065280 :             mpres_sub (T[k + 1], T[k + 1], X1->x, modulus);  /* T1   = lambda^2 - x1 */
     404    44065280 :             mpres_sub (X1->x, T[k + 1], X2->x, modulus);     /* X1.x = lambda^2 - x1 - x2 = x3 */
     405    44065280 :             mpres_sub (T[k + 1], X2->x, X1->x, modulus);     /* T1   = x2 - x3 */
     406    44065280 :             mpres_mul (T[k + 1], T[k + 1], T[l], modulus);   /* T1   = lambda*(x2 - x3) */
     407    44065280 :             mpres_sub (X1->y, T[k + 1], X2->y, modulus);     /* Y1   = lambda*(x2 - x3) - y2 = y3 */
     408             :           }
     409             :         
     410    44065305 :         l--;
     411             :       }
     412             : 
     413      287562 :   if (tot_muls != NULL)
     414      287562 :     (*tot_muls) += 6 * m * n - 3;
     415      287562 :   if (tot_gcds != NULL)
     416      287562 :     (*tot_gcds) ++;
     417             : 
     418      287562 :   return ECM_NO_FACTOR_FOUND;
     419             : }
     420             : 
     421             : /* puts in F[0..dF-1] the successive values of 
     422             : 
     423             :    Dickson_{S, a} (j * d2) * s  where s is a point on the elliptic curve
     424             : 
     425             :    for j == 1 mod 6, j and d1 coprime.
     426             :    Returns non-zero iff a factor was found (then stored in f)
     427             :    or an error occurred.
     428             : */
     429             : 
     430             : int
     431        1048 : ecm_rootsF (mpz_t f, listz_t F, root_params_t *root_params, 
     432             :             unsigned long dF, curve *s, mpmod_t modulus)
     433             : {
     434             :   unsigned long i;
     435        1048 :   unsigned long muls = 0, gcds = 0;
     436             :   long st;
     437        1048 :   int youpi = ECM_NO_FACTOR_FOUND;
     438             :   listz_t coeffs;
     439             :   ecm_roots_state_t state;
     440        1048 :   progression_params_t *params = &state.params; /* for less typing */
     441             :   mpz_t t;
     442             :   
     443        1048 :   if (dF == 0)
     444           0 :     return ECM_NO_FACTOR_FOUND;
     445             : 
     446        1048 :   st = cputime ();
     447             : 
     448             :   /* Relative cost of point add during init and computing roots assumed =1 */
     449        1048 :   init_roots_params (params, root_params->S, root_params->d1, root_params->d2, 
     450             :                      1.0);
     451             : 
     452        1048 :   outputf (OUTPUT_DEVVERBOSE, "ecm_rootsF: state: nr = %d, dsieve = %d, "
     453             :            "size_fd = %d, S = %d, dickson_a = %d\n", 
     454             :            params->nr, params->dsieve, params->size_fd, params->S, 
     455             :            params->dickson_a);
     456             : 
     457             :   /* Init finite differences tables */
     458        1048 :   mpz_init (t); /* t = 0 */
     459        1048 :   coeffs = init_progression_coeffs (t, params->dsieve, root_params->d2, 
     460             :                                     1, 6, params->S, params->dickson_a);
     461        1048 :   mpz_clear (t);
     462             : 
     463        1048 :   if (coeffs == NULL) /* error */
     464             :     {
     465           0 :       youpi = ECM_ERROR;
     466           0 :       goto clear;
     467             :     }
     468             : 
     469             :   /* The highest coefficient is the same for all progressions, so set them
     470             :      to one for all but the first progression, later we copy the point.
     471             :      FIXME: can we avoid the multiplication of those points in multiplyW2n()
     472             :      below?
     473             :   */
     474        9646 :   for (i = params->S + 1; i < params->size_fd; i += params->S + 1)
     475        8598 :     mpz_set_ui (coeffs[i + params->S], 1);
     476             : 
     477             :   /* Allocate memory for fd[] and T[] */
     478             : 
     479        1048 :   state.fd = (point *) malloc (params->size_fd * sizeof (point));
     480        1048 :   if (state.fd == NULL)
     481             :     {
     482           0 :       youpi = ECM_ERROR;
     483           0 :       goto exit_ecm_rootsF;
     484             :     }
     485       29550 :   for (i = 0; i < params->size_fd; i++)
     486             :     {
     487       28502 :       outputf (OUTPUT_TRACE, "ecm_rootsF: coeffs[%d] = %Zd\n", i, coeffs[i]);
     488       28502 :       mpres_init (state.fd[i].x, modulus);
     489       28502 :       mpres_init (state.fd[i].y, modulus);
     490             :     }
     491             : 
     492        1048 :   state.T = (mpres_t *) malloc ((params->size_fd + 4) * sizeof (mpres_t));
     493        1048 :   if (state.T == NULL)
     494             :     {
     495           0 :       youpi = ECM_ERROR;
     496           0 :       goto ecm_rootsF_clearfdi;
     497             :     }
     498       33742 :   for (i = 0 ; i < params->size_fd + 4; i++)
     499       32694 :     mpres_init (state.T[i], modulus);
     500             : 
     501             :   /* Multiply fd[] = s * coeffs[] */
     502             : 
     503        1048 :   youpi = multiplyW2n (f, state.fd, s, coeffs, params->size_fd, modulus,
     504        1048 :                        state.T[0], state.T[1], state.T + 2, &muls, &gcds);
     505        1048 :   if (youpi == ECM_FACTOR_FOUND_STEP2)
     506          10 :     outputf (OUTPUT_VERBOSE, "Found factor while computing coeff[] * X\n");  
     507             : 
     508        1048 :   if (youpi == ECM_ERROR)
     509           0 :     goto clear;
     510             : 
     511             :   /* Copy the point corresponding to the highest coefficient of the first 
     512             :      progression to the other progressions */
     513        9646 :   for (i = params->S + 1; i < params->size_fd; i += params->S + 1)
     514             :     {
     515        8598 :       mpres_set (state.fd[i + params->S].x, state.fd[params->S].x, modulus);
     516        8598 :       mpres_set (state.fd[i + params->S].y, state.fd[params->S].y, modulus);
     517             :     }
     518             : 
     519        1048 :   clear_list (coeffs, params->size_fd);
     520        1048 :   coeffs = NULL;
     521             : 
     522        1048 :   if (test_verbose (OUTPUT_VERBOSE))
     523             :     {
     524          57 :       unsigned int st1 = cputime ();
     525          57 :       outputf (OUTPUT_VERBOSE,
     526             :                "Initializing tables of differences for F took %ldms",
     527             :                elltime (st, st1));
     528          57 :       outputf (OUTPUT_DEVVERBOSE, ", %lu muls and %lu extgcds", muls, gcds);
     529          57 :       outputf (OUTPUT_VERBOSE, "\n");
     530          57 :       st = st1;
     531          57 :       muls = 0;
     532          57 :       gcds = 0;
     533             :     }
     534             : 
     535             :   /* Now for the actual calculation of the roots. */
     536             : 
     537     1950491 :   for (i = 0; i < dF && !youpi;)
     538             :     {
     539             :       /* Is this a rsieve value where we computed Dickson(j * d2) * X? */
     540     1949443 :       if (gcd ((unsigned long) params->rsieve, 
     541     1949443 :                (unsigned long) params->dsieve) == 1UL) 
     542             :         {
     543             :           /* Did we use every progression since the last update? */
     544     1357551 :           if (params->next == params->nr)
     545             :             {
     546             :               /* Yes, time to update again */
     547       88697 :               youpi = addWnm (f, state.fd, s, modulus, params->nr, params->S, 
     548             :                               state.T, &muls, &gcds);
     549             :               ASSERT(youpi != ECM_ERROR); /* no error can occur in addWnm */
     550       88697 :               params->next = 0;
     551       88697 :               if (youpi == ECM_FACTOR_FOUND_STEP2)
     552           0 :                 outputf (OUTPUT_VERBOSE,
     553             :                          "Found factor while computing roots of F\n");
     554             :             }
     555             :           
     556             :           /* Is this a j value where we want Dickson(j * d2) * X as a root? */
     557     1357551 :           if (gcd ((unsigned long) params->rsieve, root_params->d1) 
     558             :               == 1UL) 
     559     1135590 :             mpres_get_z (F[i++], 
     560     1135590 :                          state.fd[params->next * (params->S + 1)].x, modulus);
     561             : 
     562     1357551 :           params->next ++;
     563             :         }
     564     1949443 :       params->rsieve += 6;
     565             :     }
     566             : 
     567        1048 :  clear:
     568       33742 :   for (i = 0 ; i < params->size_fd + 4; i++)
     569       32694 :     mpres_clear (state.T[i], modulus);
     570        1048 :   free (state.T);
     571             : 
     572        1048 :  ecm_rootsF_clearfdi:
     573       29550 :   for (i = 0; i < params->size_fd; i++)
     574             :     {
     575       28502 :       mpres_clear (state.fd[i].x, modulus);
     576       28502 :       mpres_clear (state.fd[i].y, modulus);
     577             :     }
     578        1048 :   free (state.fd);
     579             : 
     580        1048 :  exit_ecm_rootsF:
     581        1048 :   if (youpi)
     582          10 :     return youpi; /* error or factor found */
     583             :   
     584        1038 :   outputf (OUTPUT_VERBOSE, "Computing roots of F took %ldms",
     585             :            elltime (st, cputime ()));
     586        1038 :   outputf (OUTPUT_DEVVERBOSE, ", %ld muls and %ld extgcds", muls, gcds);
     587        1038 :   outputf (OUTPUT_VERBOSE, "\n");
     588             : 
     589        1038 :   return ECM_NO_FACTOR_FOUND;
     590             : }
     591             : 
     592             : /* Perform the necessary initialization to allow computation of
     593             :    
     594             :      Dickson_{S, a}(s+n*d) * P , where P is a point on the elliptic curve
     595             :    
     596             :    for successive n, where Dickson_{S, a} is the degree S Dickson
     597             :    polynomial with parameter a. For a == 0, Dickson_{S, a} (x) = x^S.
     598             :    
     599             :    If a factor is found during the initialisation, NULL is returned and the
     600             :    factor in f. If an error occurred, NULL is returned and f is -1.
     601             : */
     602             : 
     603             : ecm_roots_state_t *
     604        1038 : ecm_rootsG_init (mpz_t f, curve *X, root_params_t *root_params, 
     605             :                  unsigned long dF, unsigned long blocks, mpmod_t modulus)
     606             : {
     607             :   unsigned int k, phid2;
     608        1038 :   unsigned long muls = 0, gcds = 0;
     609             :   listz_t coeffs;
     610             :   ecm_roots_state_t *state;
     611             :   progression_params_t *params; /* for less typing */
     612        1038 :   int youpi = 0;
     613             :   unsigned int T_inv;
     614             :   double bestnr;
     615        1038 :   long st = 0;
     616             : 
     617             :   ASSERT (gcd (root_params->d1, root_params->d2) == 1UL);
     618             : 
     619        1038 :   if (test_verbose (OUTPUT_VERBOSE))
     620          57 :     st = cputime ();
     621             :   
     622        1038 :   state = (ecm_roots_state_t *) malloc (sizeof (ecm_roots_state_t));
     623        1038 :   if (state == NULL)
     624             :     {
     625           0 :       mpz_set_si (f, -1);
     626           0 :       return NULL;
     627             :     }
     628        1038 :   params = &(state->params);
     629             : 
     630             :   /* If S < 0, use degree |S| Dickson poly, otherwise use x^S */
     631        1038 :   params->dickson_a = (root_params->S < 0) ? -1 : 0;
     632        1038 :   params->S = abs (root_params->S);
     633             : 
     634             :   /* Estimate the cost of a modular inversion (in unit of time per 
     635             :      modular multiplication) */
     636        1038 :   if (modulus->repr == ECM_MOD_BASE2)
     637          79 :     T_inv = 18;
     638             :   else
     639         959 :     T_inv = 6;
     640             :   
     641             :   /* Guesstimate a value for the number of disjoint progressions to use */
     642        1038 :   bestnr = -(4. + T_inv) + sqrt(12. * (double) dF * (double) blocks * 
     643        1038 :         (T_inv - 3.) * log (2. * root_params->d1) / log (2.) - (4. + T_inv) * 
     644        1038 :         (4. + T_inv));
     645        1038 :   bestnr /= 6. * (double) (params->S) * log (2. * root_params->d1) / log (2.0);
     646             :   
     647        1038 :   outputf (OUTPUT_TRACE, "ecm_rootsG_init: bestnr = %f\n", bestnr);
     648             :   
     649        1038 :   if (bestnr < 1.)
     650          50 :     params->nr = 1;
     651             :   else
     652         988 :     params->nr = (unsigned int) (bestnr + .5);
     653             : 
     654        1038 :   phid2 = eulerphi (root_params->d2);
     655             : 
     656             :   /* Round up params->nr to multiple of eulerphi(d2) */
     657        1038 :   if (phid2 > 1)
     658         963 :     params->nr = ((params->nr + (phid2 - 1)) / phid2) * phid2;
     659             : 
     660        1038 :   params->size_fd = params->nr * (params->S + 1);
     661             : 
     662        1038 :   outputf (OUTPUT_DEVVERBOSE, "ecm_rootsG_init: i0=%Zd, d1=%lu, d2=%lu, "
     663        1038 :            "dF=%lu, blocks=%lu, S=%u, T_inv = %d, nr=%d\n", root_params->i0, 
     664             :            root_params->d1, root_params->d2, dF, blocks, params->S, 
     665             :            T_inv, params->nr);
     666             :   
     667        1038 :   state->X = X;
     668        1038 :   params->next = 0;
     669        1038 :   params->dsieve = 1; /* We only init progressions coprime to d2, 
     670             :                                so nothing to be skipped */
     671        1038 :   params->rsieve = 0;
     672             : 
     673        1038 :   coeffs = init_progression_coeffs (root_params->i0, root_params->d2, 
     674        1038 :                                     root_params->d1, params->nr / phid2, 
     675             :                                     1, params->S, params->dickson_a);
     676             : 
     677        1038 :   if (coeffs == NULL) /* error */
     678             :     {
     679           0 :       free (state);
     680           0 :       mpz_set_si (f, -1);
     681           0 :       return NULL;
     682             :     }
     683             : 
     684        1038 :   state->fd = (point *) malloc (params->size_fd * sizeof (point));
     685        1038 :   if (state->fd == NULL)
     686             :     {
     687           0 :       clear_list (coeffs, params->size_fd);
     688           0 :       free (state);
     689           0 :       mpz_set_si (f, -1);
     690           0 :       return NULL;
     691             :     }
     692       27774 :   for (k = 0; k < params->size_fd; k++)
     693             :     {
     694       26736 :       mpres_init (state->fd[k].x, modulus);
     695       26736 :       mpres_init (state->fd[k].y, modulus);
     696             :     }
     697             :   
     698        1038 :   state->size_T = params->size_fd + 4;
     699        1038 :   state->T = (mpres_t *) malloc (state->size_T * sizeof (mpres_t));
     700        1038 :   if (state->T == NULL)
     701             :     {
     702           0 :       for (k = 0; k < params->size_fd; k++)
     703             :         {
     704           0 :           mpres_clear (state->fd[k].x, modulus);
     705           0 :           mpres_clear (state->fd[k].y, modulus);
     706             :         }
     707           0 :       clear_list (coeffs, params->size_fd);
     708           0 :       free (state);
     709           0 :       mpz_set_si (f, -1);
     710           0 :       return NULL;
     711             :     }
     712       31926 :   for (k = 0; k < state->size_T; k++)
     713       30888 :     mpres_init (state->T[k], modulus);
     714             : 
     715       10918 :   for (k = params->S + 1; k < params->size_fd; k += params->S + 1)
     716        9880 :      mpz_set_ui (coeffs[k + params->S], 1);
     717             : 
     718        1038 :   if (test_verbose (OUTPUT_TRACE))
     719         246 :     for (k = 0; k < params->size_fd; k++)
     720         236 :       outputf (OUTPUT_TRACE, "ecm_rootsG_init: coeffs[%d] == %Zd\n", 
     721         236 :                k, coeffs[k]);
     722             : 
     723        1038 :   youpi = multiplyW2n (f, state->fd, X, coeffs, params->size_fd, modulus, 
     724        1038 :                      state->T[0], state->T[1], state->T + 2, &muls, &gcds);
     725        1038 :   if (youpi == ECM_ERROR)
     726           0 :     mpz_set_si (f, -1); /* fall through */
     727             : 
     728       10918 :   for (k = params->S + 1; k < params->size_fd; k += params->S + 1)
     729             :     {
     730        9880 :       mpres_set (state->fd[k + params->S].x, state->fd[params->S].x, modulus);
     731        9880 :       mpres_set (state->fd[k + params->S].y, state->fd[params->S].y, modulus);
     732             :     }
     733             :   
     734        1038 :   clear_list (coeffs, params->size_fd);
     735        1038 :   coeffs = NULL;
     736             :   
     737        1038 :   if (youpi != ECM_NO_FACTOR_FOUND) /* factor found or error */
     738             :     {
     739           0 :       if (youpi == ECM_FACTOR_FOUND_STEP2)
     740           0 :         outputf (OUTPUT_VERBOSE, "Found factor while computing fd[]\n");
     741             : 
     742           0 :       ecm_rootsG_clear (state, modulus);
     743             :       
     744             :       /* Signal that a factor was found, or an error occurred (f=-1) */
     745           0 :       state = NULL;
     746             :     }
     747             :   else
     748             :     {
     749        1038 :       if (test_verbose (OUTPUT_VERBOSE))
     750             :         {
     751          57 :           st = elltime (st, cputime ());
     752          57 :           outputf (OUTPUT_VERBOSE,
     753             :                    "Initializing table of differences for G took %ldms", st);
     754          57 :           outputf (OUTPUT_DEVVERBOSE, ", %lu muls and %lu extgcds",
     755             :                    muls, gcds);
     756          57 :           outputf (OUTPUT_VERBOSE, "\n");
     757             :         }
     758             :     }
     759             :   
     760        1038 :   return state;
     761             : }
     762             : 
     763             : void 
     764        1038 : ecm_rootsG_clear (ecm_roots_state_t *state, ATTRIBUTE_UNUSED mpmod_t modulus)
     765             : {
     766             :   unsigned int k;
     767             :   
     768       27774 :   for (k = 0; k < state->params.size_fd; k++)
     769             :     {
     770       26736 :       mpres_clear (state->fd[k].x, modulus);
     771       26736 :       mpres_clear (state->fd[k].y, modulus);
     772             :     }
     773        1038 :   free (state->fd);
     774             :   
     775        1038 :   if(state->size_T != 0){
     776       31926 :       for (k = 0; k < state->size_T; k++)
     777       30888 :           mpres_clear (state->T[k], modulus);
     778        1038 :       free (state->T);
     779             :   }
     780             :   
     781        1038 :   free (state);
     782        1038 : }
     783             : 
     784             : /* Puts in G the successive values of
     785             : 
     786             :      Dickson_{S, a}(s+j*k) P
     787             :     
     788             :      where P is a point on the elliptic curve,
     789             :      0<= j <= dF-1, k is the 'd' value from ecm_rootsG_init()
     790             :      and s is the 's' value of ecm_rootsG_init() or where a previous
     791             :      call to ecm_rootsG has left off.
     792             : 
     793             :    Returns non-zero iff a factor was found (then stored in f).
     794             :    Cannot return an error.
     795             : */
     796             : 
     797             : int 
     798        3362 : ecm_rootsG (mpz_t f, listz_t G, unsigned long dF, ecm_roots_state_t *state, 
     799             :             mpmod_t modulus)
     800             : {
     801             :   unsigned long i;
     802        3362 :   unsigned long muls = 0, gcds = 0;
     803        3362 :   int youpi = ECM_NO_FACTOR_FOUND;
     804             :   long st;
     805        3362 :   point *fd = state->fd; /* to save typing */
     806        3362 :   progression_params_t *params = &(state->params); /* for less typing */
     807             :   
     808        3362 :   st = cputime ();
     809             : 
     810        3362 :   outputf (OUTPUT_TRACE, "ecm_rootsG: dF = %lu, state: nr = %u, next = %u, "
     811             :            "S = %u, dsieve = %u, rsieve = %u,\n\tdickson_a = %d\n", 
     812             :            dF, params->nr, params->next, params->S, params->dsieve, 
     813             :            params->rsieve, params->dickson_a);
     814             :   
     815     2830091 :   for (i = 0; i < dF;)
     816             :     {
     817             :       /* Did we use every progression since the last update? */
     818     2826740 :       if (params->next == params->nr)
     819             :         {
     820             :           /* Yes, time to update again */
     821      198876 :           youpi = addWnm (f, fd, state->X, modulus, params->nr, params->S, 
     822             :                           state->T, &muls, &gcds);
     823             :           ASSERT(youpi != ECM_ERROR); /* no error can occur in addWnm */
     824      198876 :           params->next = 0;
     825             :           
     826      198876 :           if (youpi == ECM_FACTOR_FOUND_STEP2)
     827             :             {
     828          11 :               outputf (OUTPUT_VERBOSE, "Found factor while computing G[]\n");
     829          11 :               break;
     830             :             }
     831             :         }
     832             :       
     833             :       /* Is this a root we should skip? (Take only if gcd == 1) */
     834     2826729 :       if (gcd ((unsigned long) params->rsieve,  
     835     2826729 :                (unsigned long) params->dsieve) == 1UL)
     836             :         {
     837     2826729 :           mpres_get_z (G[i++], (fd + params->next * (params->S + 1))->x, 
     838             :                        modulus);
     839     2826729 :           outputf (OUTPUT_TRACE, 
     840             :                    "ecm_rootsG: storing d1*%u*X = %Zd in G[%lu]\n",
     841     2826729 :                    params->rsieve, G[i - 1], i);
     842             :         }
     843             :       
     844     2826729 :       params->next ++;
     845     2826729 :       params->rsieve ++;
     846             :     }
     847             : 
     848        3362 :   outputf (OUTPUT_VERBOSE, "Computing roots of G took %ldms",
     849             :            elltime (st, cputime ()));
     850        3362 :   outputf (OUTPUT_DEVVERBOSE, ", %lu muls and %lu extgcds", muls, gcds);
     851        3362 :   outputf (OUTPUT_VERBOSE, "\n");
     852             :   
     853        3362 :   return youpi;
     854             : }

Generated by: LCOV version 1.14