LCOV - code coverage report
Current view: top level - ecm - torsions.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 781 803 97.3 %
Date: 2022-03-21 11:19:20 Functions: 20 20 100.0 %

          Line data    Source code
       1             : /* torsions.c - ECM with special torsion curves
       2             :    Author: F. Morain
       3             : */
       4             : 
       5             : #include <stdio.h>
       6             : #include <stdlib.h>
       7             : #include <string.h>
       8             : #include <math.h>
       9             : 
      10             : #include <gmp.h> /* GMP header file */
      11             : 
      12             : #include "ecm.h" /* ecm header file */
      13             : #include "ecm-impl.h"
      14             : #include "ecm-ecm.h"
      15             : #include "mpmod.h"
      16             : 
      17             : #include "addlaws.h"
      18             : #include "torsions.h"
      19             : 
      20             : #define DEBUG_TORSION 0
      21             : 
      22             : /* We use three variants of Weierstrass parametrization:
      23             :    CW (complete): y^2+a1*x*y+a3*y=x^3+a2*x^2+a4*x+a6
      24             :    MW (medium)  : y^2=x^3+a2*x^2+a4*x+a6
      25             :    SW (short)   : y^2=x^3+a4*x+a6
      26             : 
      27             :    A Kubert curve is the special case Y^2+(1-c)*X*Y-b*Y = X^3-b*X^2
      28             : 
      29             :    Generally, we build a curve under the SW form, with affine law, meaning
      30             :    that constructed points will be [x, y, 1].
      31             :  */
      32             : 
      33             : /********** utilities **********/
      34             : 
      35             : void
      36         330 : mod_div_2(mpz_t x, mpz_t n)
      37             : {
      38         330 :     if(mpz_tstbit(x, 0)){
      39             :         /* x is odd, x/2 = (x+N)/2 */
      40         220 :         mpz_add(x, x, n);
      41         220 :         mpz_div_2exp(x, x, 1);
      42             :     }
      43             :     else
      44             :         /* x is even, x/2 is easy */
      45         110 :         mpz_div_2exp(x, x, 1);
      46         330 : }
      47             : 
      48             : /* r <- q mod N. 
      49             :    Return value: 1 if den invertible, 0 if factor found; in this case
      50             :    gcd(den(q), N) is put in r.
      51             :  */
      52             : int
      53        2070 : mod_from_rat2(mpz_t r, mpz_t num, mpz_t den, mpz_t N)
      54             : {
      55        2070 :     int ret = 1;
      56             :  
      57        2070 :     if(mpz_invert(r, den, N) == 0){
      58         100 :         mpz_gcd(r, den, N);
      59         100 :         ret = 0;
      60             :     }
      61             :     else{
      62        1970 :         mpz_mul(r, r, num);
      63        1970 :         mpz_mod(r, r, N);
      64             :     }
      65        2070 :     return ret;
      66             : }
      67             : 
      68             : int
      69        1440 : mod_from_rat_str(mpz_t r, char *str, mpz_t N)
      70             : {
      71             :     mpq_t q;
      72             :     int ret;
      73             : 
      74        1440 :     mpq_init(q);
      75        1440 :     mpq_set_str(q, str, 10);
      76        1440 :     ret = mod_from_rat2(r, mpq_numref(q), mpq_denref (q), N);
      77        1440 :     mpq_clear(q);
      78        1440 :     return ret;
      79             : }
      80             : 
      81             : /* From a curve in Kubert form Y^2+(1-c)*X*Y-b*Y = X^3-b*X^2
      82             :    to a Weierstrass form y^2 = X^3 + a2 * X^2 + a4 * X + a6
      83             :    where y = Y+((1-c)*X-b)/2
      84             :    WE:=[0,(1/4*c^2+1/4-1/2*c-b),0,(1/2*c*b-1/2*b),1/4*b^2]);
      85             :    We compute:
      86             :    a2 = 1/4*c^2+1/4-1/2*c-b = ((c-1)/2)^2-b
      87             :    a4 = 1/2*c*b-1/2*b = b*(c-1)/2
      88             :    a6 = (b/2)^2
      89             :    TODO: rewrite this with MediumW, etc.
      90             : */
      91             : void
      92          90 : KW2W246(mpz_t a2, mpz_t a4, mpz_t a6, mpz_t b, mpz_t c, mpz_t n, int compute_a6)
      93             : {
      94             :     /** a4 <- (c-1)/2 **/
      95          90 :     mpz_sub_si(a4, c, 1);
      96          90 :     mod_div_2(a4, n);
      97             :     /** a2 <- a4^2-b **/
      98          90 :     mpz_mul(a2, a4, a4);
      99          90 :     mpz_sub(a2, a2, b);
     100          90 :     mpz_mod(a2, a2, n);
     101             :     /** a4 <- a4*b **/
     102          90 :     mpz_mul(a4, a4, b);
     103          90 :     mpz_mod(a4, a4, n);
     104          90 :     if(compute_a6 != 0){
     105          70 :         mpz_set(a6, b);
     106          70 :         mod_div_2(a6, n);
     107          70 :         mpz_mul(a6, a6, a6);
     108          70 :         mpz_mod(a6, a6, n);
     109             :     }
     110             : #if DEBUG_TORSION >= 2
     111             :     gmp_printf("N:=%Zd;\n", n);
     112             :     gmp_printf("b:=%Zd;\n", b);
     113             :     gmp_printf("c:=%Zd;\n", c);
     114             :     gmp_printf("a2:=%Zd;\n", a2);
     115             :     gmp_printf("a4:=%Zd;\n", a4);
     116             :     printf("a6:=RatMod(b^2/4, N);\n");
     117             :     if(compute_a6 != 0)
     118             :         gmp_printf("a6:=%Zd;\n", a6);
     119             : #endif
     120          90 : }
     121             : 
     122             : static int
     123          70 : check_weierstrass(mpz_t A, mpz_t B, mpz_t X, mpz_t Y, mpz_t tmp1, mpz_t tmp2,
     124             :                   mpz_t n)
     125             : {
     126          70 :     mpz_mul(tmp1, Y, Y);
     127          70 :     mpz_mul(tmp2, X, X);
     128          70 :     mpz_add(tmp2, tmp2, A);
     129          70 :     mpz_mul(tmp2, tmp2, X);
     130          70 :     mpz_add(tmp2, tmp2, B);
     131          70 :     mpz_sub(tmp1, tmp1, tmp2);
     132          70 :     mpz_mod(tmp1, tmp1, n);
     133          70 :     return mpz_sgn(tmp1) == 0;
     134             : }
     135             : 
     136             : /* Weierstrass (a2, a4, a6) to (A, B)
     137             :    A = (a4-1/3*a2^2)
     138             :    B = -1/3*a4*a2 + 2/27*a2^3 + a6
     139             :      = -1/3*a2*(a4-2/9*a2^2) + a6
     140             :    X = x+a2/3
     141             :    Y = y
     142             :    INPUT: if x0 == NULL, we have no point to translate
     143             :           if B == NULL, we do not need and we do not compute B
     144             :    REM: we assume gcd(n, 3) = 1.
     145             : */
     146             : void
     147          70 : MediumWeierstrassToShortWeierstrass(mpz_t A, mpz_t B, mpz_t X, mpz_t Y,
     148             :                                     mpz_t a2, mpz_t a4, mpz_t a6, 
     149             :                                     mpz_t x0, mpz_t y0, mpz_t n)
     150             : {
     151             :     mpz_t tmp1, tmp2, tmp3;
     152             : 
     153          70 :     mpz_init(tmp1);
     154          70 :     mpz_init(tmp2);
     155             :     /* tmp2 <- a2/3 */
     156          70 :     mpz_init_set_si(tmp3, 3);
     157          70 :     mod_from_rat2(tmp2, a2, tmp3, n);
     158          70 :     if(X != NULL && x0 != NULL){
     159             :         /* wx0 = x0 + a2/3 */
     160          70 :         mpz_add(X, tmp2, x0);
     161          70 :         mpz_mod(X, X, n);
     162             :     }
     163          70 :     if(Y != NULL && y0 != NULL){
     164          70 :         mpz_set(Y, y0);
     165          70 :         mpz_mod(Y, Y, n);
     166             :     }
     167             :     /* A = a4-1/3*a2^2 = a4 - a2 * (a2/3) */
     168             :     /** tmp1 <- tmp2*a2 = a2^2/3 */
     169          70 :     mpz_mul(tmp1, a2, tmp2);
     170          70 :     mpz_mod(tmp1, tmp1, n);
     171          70 :     mpz_sub(A, a4, tmp1);
     172          70 :     mpz_mod(A, A, n);
     173          70 :     if(B != NULL){
     174             :         /* B = -1/3*a2*(a4-2/9*a2^2) + a6 */
     175             :         /** B <- 2/9*a2^2 = 2 * (a2^2/3) / 3 **/
     176          70 :         mod_from_rat2(B, tmp1, tmp3, n);
     177          70 :         mpz_mul_si(B, B, 2);
     178          70 :         mpz_sub(B, a4, B);
     179          70 :         mpz_mul(B, B, tmp2);
     180          70 :         mpz_sub(B, a6, B);
     181          70 :         mpz_mod(B, B, n);
     182             :     }
     183             : #if DEBUG_TORSION >= 2
     184             :     gmp_printf("N:=%Zd;\n", n);
     185             :     gmp_printf("a2:=%Zd; a4:=%Zd; a6:=%Zd;\n", a2, a4, a6);
     186             :     gmp_printf("A:=%Zd; B:=%Zd;\n", A, B);
     187             :     if(X != NULL && x0 != NULL){
     188             :         gmp_printf("x:=%Zd;\n", x0);
     189             :         gmp_printf("X:=%Zd;\n", X);
     190             :     }
     191             :     if(Y != NULL && y0 != NULL){
     192             :         gmp_printf("y:=%Zd;\n", Y);
     193             :         printf("(y^2-x^3-a2*x^2-a4*x-a6) mod N;\n");
     194             :         printf("(y^2-X^3-A*X-B) mod N;\n");
     195             :     }
     196             : #endif
     197          70 :     mpz_clear(tmp1);
     198          70 :     mpz_clear(tmp2);
     199          70 :     mpz_clear(tmp3);
     200          70 : }
     201             : 
     202             : /* 
     203             :    The original Kubert curve E(b, c) is y^2+(1-c)*x*y-b*y = x^3-b*x^2
     204             :    The medium Weierstrass form is y^2=x^3+a2*x^2+a4*x+a6 with point (x0, y0);
     205             :    we convert this to short Weierstrass form:
     206             :    E: Y^2 = X^3 + A * X + B
     207             :    and point P=(X, Y) on E.
     208             : */
     209             : void
     210          70 : kubert_to_weierstrass(mpz_t A, mpz_t B, mpz_t X, mpz_t Y, 
     211             :                       mpz_t b, mpz_t c, mpz_t x0, mpz_t y0, mpz_t n)
     212             : {
     213             :     mpz_t a2, a4, a6;
     214             : 
     215          70 :     mpz_init(a2);
     216          70 :     mpz_init(a4);
     217          70 :     mpz_init(a6);
     218          70 :     KW2W246(a2, a4, a6, b, c, n, 1);
     219             :     /* second conversion */
     220          70 :     MediumWeierstrassToShortWeierstrass(A, B, X, Y, a2, a4, a6, x0, y0, n);
     221             : #if DEBUG_TORSION >= 2
     222             :     gmp_printf("a2:=%Zd; a4:=%Zd; a6:=%Zd; A:=%Zd; B:=%Zd;\n", a2, a4, a6,A,B);
     223             :     gmp_printf("X:=%Zd; Y:=%Zd;\n", X, Y);
     224             : #endif
     225          70 :     mpz_clear(a2);
     226          70 :     mpz_clear(a4);
     227          70 :     mpz_clear(a6);
     228          70 : }
     229             : 
     230             : static int
     231         120 : forbidden(char *torsion, int u){
     232         120 :     if(strcmp(torsion, "Z10") == 0)
     233          60 :         return u == 1 || u == 2;
     234          60 :     else if(strcmp(torsion, "Z3xZ3") == 0)
     235          60 :         return u == 2;
     236           0 :     return 0;
     237             : }
     238             : 
     239             : /* Kubert: put b = c. 
     240             :    SIDE EFFECT: tE[0..nE[ and tP[0..nE[ receive a curve of torsion Z5
     241             :                 and a point on it using parameters [smin..smax[.
     242             :    OUTPUT: ECM_NO_FACTOR_FOUND or ECM_FACTOR_FOUND_STEP1 if a factor is found.
     243             : */
     244             : int
     245          20 : build_curves_with_torsion_Z5(mpz_t f, mpmod_t n,
     246             :                              ell_curve_t *tE, ell_point_t *tP,
     247             :                              int smin, int smax, int nE)
     248             : {
     249             :     mpz_t A, B, X, Y;
     250          20 :     int s, ret = ECM_NO_FACTOR_FOUND, nc = 0;
     251             :     mpz_t x0, y0, c, tmp;
     252             : 
     253          20 :     mpz_init(A);
     254          20 :     mpz_init(B);
     255          20 :     mpz_init(X);
     256          20 :     mpz_init(Y);
     257          20 :     mpz_init(x0);
     258          20 :     mpz_init(y0);
     259          20 :     mpz_init(c);
     260          20 :     mpz_init(tmp);
     261          20 :     for(s = smin; s < smax; s++){
     262          20 :         mpz_set_si(x0, s);
     263             :         /* c:=1/2*x0*(4*x0+1)/(3*x0+1); */
     264             :         /* y0 <- 2*(3*x0+1) */
     265          20 :         mpz_mul_si(y0, x0, 3);
     266          20 :         mpz_add_si(y0, y0, 1);
     267             :         /* tmp <- x0*(4*x0+1) */
     268          20 :         mpz_add(tmp, y0, x0);
     269          20 :         mpz_mul(tmp, tmp, x0);
     270          20 :         mpz_add(y0, y0, y0);
     271          20 :         if(mod_from_rat2(c, tmp, y0, n->orig_modulus) == 0){
     272          10 :             printf("factor found during Z5_init\n");
     273          10 :             mpz_gcd(f, c, n->orig_modulus);
     274          10 :             ret = ECM_FACTOR_FOUND_STEP1;
     275          10 :             break;
     276             :         }
     277             :         /* y0:=x0*(x0+1)*(4*x0+1)/4/(3*x0+1) = (x0+1)*c/2 */
     278          10 :         mpz_add_si(y0, x0, 1);
     279          10 :         mpz_mul(y0, y0, c);
     280          10 :         mpz_mod(y0, y0, n->orig_modulus);
     281          10 :         mod_div_2(y0, n->orig_modulus);
     282             : #if DEBUG_TORSION >= 2
     283             :         gmp_printf("x0:=%Zd;\nc:=%Zd;\ny0:=%Zd;\n", x0, c, y0);
     284             :         printf("cr:=1/2*x0*(4*x0+1)/(3*x0+1);\n");
     285             : #endif
     286             :         /* P:=WE![x0, y0, 1]; */
     287          10 :         kubert_to_weierstrass(A, B, X, Y, c, c, x0, y0, n->orig_modulus);
     288          10 :         if(check_weierstrass(A, B, X, Y, tmp, x0, n->orig_modulus) == 0){
     289           0 :             printf("#!# check_weierstrass false\n");
     290           0 :             ret = ECM_ERROR;
     291           0 :             break;
     292             :         }
     293          10 :         ell_curve_init(tE[nc], ECM_EC_TYPE_WEIERSTRASS, ECM_LAW_AFFINE,n);
     294          10 :         mpz_set(tE[nc]->a4, A);
     295          10 :         mpz_set(tE[nc]->a6, B);
     296          10 :         ell_point_init(tP[nc], tE[nc], n);
     297          10 :         mpz_set(tP[nc]->x, X);
     298          10 :         mpz_set(tP[nc]->y, Y);
     299          10 :         nc++;
     300          10 :         if(nc >= nE)
     301          10 :             break;
     302             :     }
     303          20 :     mpz_clear(A);
     304          20 :     mpz_clear(B);
     305          20 :     mpz_clear(X);
     306          20 :     mpz_clear(Y);
     307          20 :     mpz_clear(x0);
     308          20 :     mpz_clear(y0);
     309          20 :     mpz_clear(c);
     310          20 :     mpz_clear(tmp);
     311          20 :     return ret;
     312             : }
     313             : 
     314             : /* 
     315             :      E_aux: T^2 = S^3 + A * S + B
     316             :    => quartic QC: Y^2 = X^4 - 6 * A2 * X^2 + 4 * A1 * X + A0, with
     317             :      X = (T-A1/2)/(S-A2), Y = -X^2 + 2 * S + A2.
     318             :    => quartic y^2 = f(x) = a4*x^4+...+a0, where
     319             :      x = x0+y0/(X-cte), where cte = f'(x0)/4/y0
     320             :      y = Y/y0*(x-x0)^2 = Y*y0/(X-cte)^2
     321             :    INPUT: (s, t) is a point on E_aux; (x0, y0) a point on QC.
     322             :    SIDE EFFECT: x, y contain a point on the elliptic curve.
     323             :    OUTPUT: 1 if no pb occurred,
     324             :            0 if a factor was found and put in f
     325             :  */
     326             : int
     327         100 : cubic_to_quartic(mpz_t f, mpz_t n, mpz_t x, mpz_t y,
     328             :                  mpz_t s, mpz_t t, mpz_t A2, mpz_t A1div2,
     329             :                  mpz_t x0, mpz_t y0, mpz_t cte)
     330             : {
     331             :     mpz_t X, Y;
     332         100 :     int ret = 1;
     333             : 
     334         100 :     mpz_init(X);
     335         100 :     mpz_init(Y);
     336             :     /* X <- (t-A1/2)/(s-A2) */
     337         100 :     mpz_sub(x, t, A1div2);
     338         100 :     mpz_sub(y, s, A2);
     339         100 :     if(mod_from_rat2(X, x, y, n) == 0){
     340          20 :         mpz_set(f, X);
     341          20 :         ret = 0;
     342             :     }
     343             :     else{
     344             :         /* Y <- -X^2 + 2 * s + A2 */
     345          80 :         mpz_mul(Y, X, X);
     346          80 :         mpz_sub(Y, A2, Y);
     347          80 :         mpz_add(Y, Y, s);
     348          80 :         mpz_add(Y, Y, s);
     349          80 :         mpz_mod(Y, Y, n);
     350             :         /* x <- x0+y0/(X-cte) */
     351          80 :         mpz_sub(X, X, cte);
     352          80 :         mpz_mod(X, X, n);
     353          80 :         if(mpz_invert(f, X, n) == 0){
     354          10 :             mpz_gcd(f, X, n);
     355          10 :             ret = 0;
     356             :         }
     357             :         else{
     358             :             /* x <- y0/(X-cte) */
     359          70 :             mpz_mul(x, f, y0);
     360          70 :             mpz_mod(x, x, n);
     361             :             /* y <- x/(X-cte) = y0/(X-cte)^2 */
     362          70 :             mpz_mul(y, x, f);
     363          70 :             mpz_mod(y, y, n);
     364          70 :             mpz_mul(y, y, Y);
     365          70 :             mpz_mod(y, y, n);
     366          70 :             mpz_add(x, x, x0);
     367          70 :             mpz_mod(x, x, n);
     368             :         }
     369             :     }
     370         100 :     mpz_clear(X);
     371         100 :     mpz_clear(Y);
     372         100 :     return ret;
     373             : }
     374             : 
     375             : int
     376         160 : build_curves_with_torsion_aux(ell_curve_t Eaux, ell_point_t Paux,
     377             :                               mpz_t A2, mpz_t A1div2, mpz_t x0, mpz_t y0,
     378             :                               mpz_t cte,
     379             :                               char *sa4, char *sa6, char *sPx, char *sPy,
     380             :                               char *sA2, char *sA1div2, char *sx0, char *sy0,
     381             :                               char *scte, mpmod_t n, mpres_t tmp)
     382             : {
     383             :     mpz_t f;
     384             : 
     385         160 :     mpz_init(f);
     386         160 :     mod_from_rat_str(f, sa4, n->orig_modulus);
     387         160 :     mpres_set_z(tmp, f, n);
     388         160 :     ell_curve_init_set(Eaux, ECM_EC_TYPE_WEIERSTRASS, ECM_LAW_AFFINE, tmp, n);
     389         160 :     mod_from_rat_str(f, sa6, n->orig_modulus);
     390         160 :     mpres_set_z(Eaux->a6, f, n);
     391         160 :     ell_point_init(Paux, Eaux, n);
     392         160 :     mod_from_rat_str(f, sPx, n->orig_modulus);
     393         160 :     mpres_set_z(Paux->x, f, n);
     394         160 :     mod_from_rat_str(f, sPy, n->orig_modulus);
     395         160 :     mpres_set_z(Paux->y, f, n);
     396             : #if DEBUG_TORSION >= 2
     397             :     printf("Paux:=");
     398             :     pt_print(Eaux, Paux, n);
     399             :     printf(";\n");
     400             : #endif
     401         160 :     mod_from_rat_str(A2, sA2, n->orig_modulus);
     402         160 :     mod_from_rat_str(A1div2, sA1div2, n->orig_modulus);
     403         160 :     mod_from_rat_str(x0, sx0, n->orig_modulus);
     404         160 :     mod_from_rat_str(y0, sy0, n->orig_modulus);
     405         160 :     mod_from_rat_str(cte, scte, n->orig_modulus);
     406         160 :     mpz_clear(f);
     407         160 :     return 1;
     408             : }
     409             : 
     410             : /* 
     411             :    SIDE EFFECT: tE[0..nE[ and tP[0..nE[ receive a curve of torsion Z7
     412             :                 and a point on it using parameters [umin..umax[.
     413             :    OUTPUT: ECM_NO_FACTOR_FOUND or ECM_FACTOR_FOUND_STEP1 if a factor is found.
     414             :    tE[i], tP[i] are built in raw modular form, not Montgomery form. 
     415             :    REM: we assume gcd(n, 6).
     416             : */
     417             : int
     418          70 : build_curves_with_torsion_Z7(mpz_t fac, mpmod_t n, 
     419             :                              ell_curve_t *tE, ell_point_t *tP,
     420             :                              int umin, int umax, int nE)
     421             : {
     422          70 :     int u, ret = ECM_NO_FACTOR_FOUND, nc = 0;
     423             :     mpz_t A2, A1div2, x0, y0, cte, d, c, b, kx0, ky0, A, B, X, Y;
     424             :     mpres_t tmp;
     425             :     ell_curve_t E;
     426             :     ell_point_t P, Q;
     427             : 
     428          70 :     mpz_init(A2);
     429          70 :     mpz_init(A1div2);
     430          70 :     mpz_init(cte);
     431          70 :     mpz_init(x0);
     432          70 :     mpz_init(y0);
     433          70 :     mpz_init(A);
     434          70 :     mpz_init(B);
     435          70 :     mpz_init(X);
     436          70 :     mpz_init(Y);
     437             :     /* Eaux = "1295/48", "-1079/864" */
     438             :     /* Paux = "2185/12", "-2458" */
     439             :     /* Y^2 = X^4-1/2*X^2-8*X-1727/16 */
     440          70 :     mpres_init(tmp, n);
     441          70 :     build_curves_with_torsion_aux(E, P, A2, A1div2, x0, y0, cte,
     442             :                                   "1295/48", "-1079/864",
     443             :                                   "2185/12", "-2458",
     444             :                                   "1/12", "-1",
     445             :                                   "-1", "8", "-7/2",
     446             :                                   n, tmp);
     447          70 :     mpz_init(d);
     448          70 :     mpz_init(c);
     449          70 :     mpz_init(b);
     450          70 :     mpz_init(kx0);
     451          70 :     mpz_init(ky0);
     452          70 :     ell_point_init(Q, E, n);
     453          70 :     mpz_set_si(d, umin-1);
     454          70 :     if(ell_point_mul(fac, Q, d, P, E, n) == 0){
     455          10 :         printf("found factor during init of Q in Z7\n");
     456          10 :         ret = ECM_FACTOR_FOUND_STEP1;
     457             :     }
     458          70 :     for(u = umin; (ret != ECM_FACTOR_FOUND_STEP1) && u < umax; u++){
     459             :         /* update Q */
     460          60 :         if(ell_point_add(fac, Q, P, Q, E, n) == 0){
     461          20 :             printf("found factor during update of Q in Z7\n");
     462          20 :             ret = ECM_FACTOR_FOUND_STEP1;
     463          20 :             break;
     464             :         }
     465          40 :         if(ell_point_is_on_curve(Q, E, n) == 0){
     466           0 :             printf("#!# Q=[%d]P is not on E\n", u);
     467             :             //      ell_point_print(Q, E, n); printf("\n");
     468           0 :             ret = ECM_ERROR;
     469           0 :             break;
     470             :         }
     471             :         /* come back to plain (not Montgomery) residues */
     472          40 :         mpres_get_z(b, Q->x, n);
     473          40 :         mpres_get_z(c, Q->y, n);
     474             : #if DEBUG_TORSION >= 2
     475             :         gmp_printf("b:=%Zd; c:=%Zd;\n", b, c);
     476             :         printf("(s, t)[%d]:=", u);
     477             :         pt_print(E, Q, n);
     478             :         printf(";\n");
     479             : #endif
     480          40 :         if(cubic_to_quartic(fac, n->orig_modulus, d, ky0, b, c, 
     481             :                             A2, A1div2, x0, y0, cte) == 0){
     482          10 :             printf("found factor in Z7 (cubic_to_quartic)\n");
     483          10 :             ret = ECM_FACTOR_FOUND_STEP1;
     484          10 :             break;
     485             :         }
     486             :         /* (d, ky0) is a point on y^2 = x^4-18*x^3+13*x^2-28*x+4 */
     487             :         /* d:=x; */
     488             :         /* x0:=-2*d; */
     489          30 :         mpz_mul_si(kx0, d, -2);
     490          30 :         mpz_mod(kx0, kx0, n->orig_modulus);
     491             :         /* y0:=d*y/2; */
     492          30 :         mpz_mul(ky0, ky0, d);
     493          30 :         mpz_mod(ky0, ky0, n->orig_modulus);
     494          30 :         mod_div_2(ky0, n->orig_modulus);
     495             :         /* c:=d^2-d; */
     496          30 :         mpz_mul(c, d, d);
     497          30 :         mpz_sub(c, c, d);
     498          30 :         mpz_mod(c, c, n->orig_modulus);
     499             :         /* b:=c*d; */
     500          30 :         mpz_mul(b, c, d);
     501          30 :         mpz_mod(b, b, n->orig_modulus);
     502             :         /* to short Weierstrass form */
     503          30 :         kubert_to_weierstrass(A, B, X, Y, b, c, kx0, ky0, n->orig_modulus);
     504          30 :         if(check_weierstrass(A, B, X, Y, tmp, x0, n->orig_modulus) == 0){
     505           0 :             ret = ECM_ERROR;
     506           0 :             break;
     507             :         }
     508          30 :         ell_curve_init(tE[nc], ECM_EC_TYPE_WEIERSTRASS, ECM_LAW_AFFINE,n);
     509          30 :         mpz_set(tE[nc]->a4, A);
     510          30 :         mpz_set(tE[nc]->a6, B);
     511          30 :         ell_point_init(tP[nc], tE[nc], n);
     512          30 :         mpz_set(tP[nc]->x, X);
     513          30 :         mpz_set(tP[nc]->y, Y);
     514             : #if DEBUG_TORSION >= 2
     515             :         gmp_printf("E[%d]:=[%Zd];\n", nc, tE[nc]->a4);
     516             :         gmp_printf("P[%d]:=[%Zd, %Zd, %Zd];\n", 
     517             :                    nc, tP[nc]->x, tP[nc]->y, tP[nc]->z);
     518             : #endif
     519          30 :         nc++;
     520          30 :         if(nc >= nE)
     521          30 :             break;
     522             :     }
     523          70 :     mpz_clear(A2);
     524          70 :     mpz_clear(A1div2);
     525          70 :     mpz_clear(x0);
     526          70 :     mpz_clear(y0);
     527          70 :     mpz_clear(cte);
     528          70 :     mpz_clear(A);
     529          70 :     mpz_clear(B);
     530          70 :     mpz_clear(X);
     531          70 :     mpz_clear(Y);
     532          70 :     ell_point_clear(P, E, n);
     533          70 :     ell_point_clear(Q, E, n);
     534          70 :     ell_curve_clear(E, n);
     535          70 :     mpz_clear(d);
     536          70 :     mpz_clear(c);
     537          70 :     mpz_clear(b);
     538          70 :     mpz_clear(kx0);
     539          70 :     mpz_clear(ky0);
     540          70 :     mpres_clear(tmp, n);
     541          70 :     return ret;
     542             : }
     543             : 
     544             : /* 
     545             :    SIDE EFFECT: tE[0..nE[ and tP[0..nE[ receive a curve of torsion Z9
     546             :                 and a point on it using parameters [umin..umax[.
     547             :    OUTPUT: ECM_NO_FACTOR_FOUND or ECM_FACTOR_FOUND_STEP1 if a factor is found.
     548             :    tE[i], tP[i] are built in raw modular form, not Montgomery form. 
     549             :    REM: we assume gcd(n, 6).
     550             : */
     551             : int
     552          40 : build_curves_with_torsion_Z9(mpz_t fac, mpmod_t n, ell_curve_t *tE, 
     553             :                              ell_point_t *tP, int umin, int umax, int nE)
     554             : {
     555          40 :     int u, ret = ECM_NO_FACTOR_FOUND, nc = 0;
     556             :     mpz_t A2, A1div2, x0, y0, cte, d, c, b, kx0, ky0, A, B, X, Y, f;
     557             :     mpres_t tmp;
     558             :     ell_curve_t E;
     559             :     ell_point_t P, Q;
     560             : 
     561          40 :     mpz_init(A2);
     562          40 :     mpz_init(A1div2);
     563          40 :     mpz_init(cte);
     564          40 :     mpz_init(x0);
     565          40 :     mpz_init(y0);
     566          40 :     mpz_init(A);
     567          40 :     mpz_init(B);
     568          40 :     mpz_init(X);
     569          40 :     mpz_init(Y);
     570             :     /* Eaux = [-9, 9] */
     571             :     /* Paux = [1, 1, 1] */
     572             :     /* Y^2 = X^4-24*X-36 */
     573          40 :     mpres_init(tmp, n);
     574          40 :     build_curves_with_torsion_aux(E, P, A2, A1div2, x0, y0, cte,
     575             :                                   "-9", "9", "1", "1", 
     576             :                                   "0", "3", 
     577             :                                   "2", "3", "0",
     578             :                                   n, tmp);
     579          40 :     mpz_init(f);
     580          40 :     mpz_init(d);
     581          40 :     mpz_init(c);
     582          40 :     mpz_init(b);
     583          40 :     mpz_init(kx0);
     584          40 :     mpz_init(ky0);
     585          40 :     ell_point_init(Q, E, n);
     586          40 :     mpz_set_si(d, umin-1);
     587          40 :     if(ell_point_mul(fac, Q, d, P, E, n) == 0){
     588          10 :         printf("found factor during init of Q in Z9\n");
     589          10 :         ret = ECM_FACTOR_FOUND_STEP1;
     590             :     }
     591          40 :     for(u = umin; (ret != ECM_FACTOR_FOUND_STEP1) && u < umax; u++){
     592             :         /* update Q */
     593          30 :         if(ell_point_add(fac, Q, P, Q, E, n) == 0){
     594          10 :             printf("found factor during update of Q in Z9\n");
     595          10 :             ret = ECM_FACTOR_FOUND_STEP1;
     596          10 :             break;
     597             :         }
     598             : #if DEBUG_TORSION >= 2
     599             :         printf("(s, t)[%d]:=", u);
     600             :         pt_print(E, Q, n);
     601             :         printf(";\n");
     602             : #endif
     603          20 :         if(ell_point_is_on_curve(Q, E, n) == 0){
     604           0 :             printf("#!# Q=[%d]P is not on E\n", u);
     605           0 :             ret = ECM_ERROR;
     606           0 :             break;
     607             :         }
     608          20 :         mpres_get_z(b, Q->x, n);
     609          20 :         mpres_get_z(c, Q->y, n);
     610          20 :         if(cubic_to_quartic(fac, n->orig_modulus, f, ky0, b, c, 
     611             :                             A2, A1div2, x0, y0, cte) == 0){
     612          10 :             printf("found factor in Z9 (cubic_2_quartic)\n");
     613          10 :             ret = ECM_FACTOR_FOUND_STEP1;
     614          10 :             break;
     615             :         }
     616             :         /* f:=x; */
     617             :         /* d:=f*(f-1)+1; */
     618          10 :         mpz_sub_si(d, f, 1);
     619          10 :         mpz_mul(d, d, f);
     620          10 :         mpz_add_si(d, d, 1);
     621          10 :         mpz_mod(d, d, n->orig_modulus);
     622             :         /* c:=f*(d-1); */
     623          10 :         mpz_sub_si(c, d, 1);
     624          10 :         mpz_mul(c, c, f);
     625          10 :         mpz_mod(c, c, n->orig_modulus);
     626             :         /* kx0:=(2*f-1)*f^2; */
     627             :         /** b <- f^2 **/
     628          10 :         mpz_mul(b, f, f);
     629          10 :         mpz_mod(b, b, n->orig_modulus);
     630          10 :         mpz_mul_si(kx0, f, 2);
     631          10 :         mpz_sub_si(kx0, kx0, 1);
     632          10 :         mpz_mul(kx0, kx0, b);
     633          10 :         mpz_mod(kx0, kx0, n->orig_modulus);
     634             :         /* ky0:=y*f^4/2; */
     635             :         /** b <- b^2 = f^4 **/
     636          10 :         mpz_mul(b, b, b);
     637          10 :         mpz_mul(ky0, ky0, b);
     638          10 :         mpz_mod(ky0, ky0, n->orig_modulus);
     639          10 :         mod_div_2(ky0, n->orig_modulus);
     640             :         /* b:=c*d; */
     641          10 :         mpz_mul(b, c, d);
     642          10 :         mpz_mod(b, b, n->orig_modulus);
     643             : #if DEBUG_TORSION >= 2
     644             :         gmp_printf("f=%Zd d=%Zd c=%Zd b=%Zd\n", f, d, c, b);
     645             :         gmp_printf("kx0=%Zd ky0=%Zd\n", kx0, ky0);
     646             : #endif
     647             :         /* to short Weierstrass form */
     648          10 :         kubert_to_weierstrass(A, B, X, Y, b, c, kx0, ky0, n->orig_modulus);
     649          10 :         if(check_weierstrass(A, B, X, Y, tmp, x0, n->orig_modulus) == 0){
     650           0 :             ret = ECM_ERROR;
     651           0 :             break;
     652             :         }
     653          10 :         ell_curve_init(tE[nc], ECM_EC_TYPE_WEIERSTRASS, ECM_LAW_AFFINE, n);
     654          10 :         mpz_set(tE[nc]->a4, A);
     655          10 :         mpz_set(tE[nc]->a6, B);
     656          10 :         ell_point_init(tP[nc], tE[nc], n);
     657          10 :         mpz_set(tP[nc]->x, X);
     658          10 :         mpz_set(tP[nc]->y, Y);
     659          10 :         nc++;
     660          10 :         if(nc >= nE)
     661          10 :             break;
     662             :     }
     663          40 :     mpz_clear(A);
     664          40 :     mpz_clear(B);
     665          40 :     mpz_clear(X);
     666          40 :     mpz_clear(Y);
     667          40 :     mpz_clear(A2);
     668          40 :     mpz_clear(A1div2);
     669          40 :     mpz_clear(x0);
     670          40 :     mpz_clear(y0);
     671          40 :     mpz_clear(cte);
     672          40 :     ell_point_clear(P, E, n);
     673          40 :     ell_point_clear(Q, E, n);
     674          40 :     mpz_clear(f);
     675          40 :     mpz_clear(d);
     676          40 :     mpz_clear(c);
     677          40 :     mpz_clear(b);
     678          40 :     mpz_clear(kx0);
     679          40 :     mpz_clear(ky0);
     680          40 :     mpres_clear(tmp, n);
     681          40 :     return ret;
     682             : }
     683             : 
     684             : int
     685          50 : build_curves_with_torsion_Z10(mpz_t fac, mpmod_t n, ell_curve_t *tE, 
     686             :                               ell_point_t *tP, int umin, int umax, int nE)
     687             : {
     688          50 :     int u, ret = ECM_NO_FACTOR_FOUND, nc = 0;
     689             :     mpz_t A2, A1div2, x0, y0, cte, d, c, b, kx0, ky0, A, B, X, Y;
     690             :     mpz_t f;
     691             :     mpres_t tmp;
     692             :     ell_curve_t E;
     693             :     ell_point_t P, Q;
     694             : 
     695          50 :     mpz_init(A2);
     696          50 :     mpz_init(A1div2);
     697          50 :     mpz_init(cte);
     698          50 :     mpz_init(x0);
     699          50 :     mpz_init(y0);
     700          50 :     mpz_init(A);
     701          50 :     mpz_init(B);
     702          50 :     mpz_init(X);
     703          50 :     mpz_init(Y);
     704             :     /* Eaux = [2/3, -53/108] */
     705             :     /* Paux = [2/3, 1/2, 1] */
     706             :     /* Y^2 = X^4-4*X^2-4*X-4 */
     707          50 :     mpres_init(tmp, n);
     708          50 :     build_curves_with_torsion_aux(E, P, A2, A1div2, x0, y0, cte,
     709             :                                   "2/3", "-53/108", "2/3", "1/2",
     710             :                                   "2/3", "-1/2", 
     711             :                                   "0", "1", "-2",
     712             :                                   n, tmp);
     713          50 :     mpz_init(f);
     714          50 :     mpz_init(d);
     715          50 :     mpz_init(c);
     716          50 :     mpz_init(b);
     717          50 :     mpz_init(kx0);
     718          50 :     mpz_init(ky0);
     719          50 :     ell_point_init(Q, E, n);
     720          60 :     for(u = umin; u < umax; u++){
     721          60 :         if(forbidden("Z10", u))
     722          10 :             continue;
     723             :         /* update Qaux */
     724          50 :         mpz_set_si(d, u);
     725          50 :         if(ell_point_mul(fac, Q, d, P, E, n) == 0){
     726          10 :             printf("found factor during update of Q in Z10\n");
     727          10 :             ret = ECM_FACTOR_FOUND_STEP1;
     728          10 :             break;
     729             :         }
     730             : #if DEBUG_TORSION >= 2
     731             :         printf("(s, t)[%d]:=", u);
     732             :         pt_print(E, Q, n);
     733             :         printf(";\n");
     734             : #endif
     735          40 :         if(ell_point_is_on_curve(Q, E, n) == 0){
     736           0 :             printf("#!# Q=[%d]P is not on E\n", u);
     737           0 :             ret = ECM_ERROR;
     738           0 :             break;
     739             :         }
     740          40 :         mpres_get_z(b, Q->x, n);
     741          40 :         mpres_get_z(c, Q->y, n);
     742          40 :         if(cubic_to_quartic(fac, n->orig_modulus, f, ky0, b, c, 
     743             :                             A2, A1div2, x0, y0, cte) == 0){
     744          10 :             printf("found factor in Z10 (cubic_2_quartic)\n");
     745          10 :             ret = ECM_FACTOR_FOUND_STEP1;
     746          10 :             break;
     747             :         }
     748             :         /* f:=x; */
     749             :         /* d:=f^2/(f-(f-1)^2) = -f^2/(f^2-3*f+1) */
     750             :         /** b <- -f^2 **/
     751          30 :         mpz_mul(b, f, f);
     752          30 :         mpz_neg(b, b);
     753          30 :         mpz_mod(b, b, n->orig_modulus);
     754             :         /* c = f^2-3*f+1 = f*(f-3)+1 */
     755          30 :         mpz_sub_si(c, f, 3);
     756          30 :         mpz_mul(c, c, f);
     757          30 :         mpz_add_si(c, c, 1);
     758          30 :         mpz_mod(c, c, n->orig_modulus);
     759          30 :         if(mod_from_rat2(d, b, c, n->orig_modulus) == 0){
     760          10 :             printf("inverse found in Z10 (d)\n");
     761          10 :             mpz_set(fac, d);
     762          10 :             ret = ECM_FACTOR_FOUND_STEP1;
     763          10 :             break;
     764             :         }
     765             :         /* c:=f*(d-1); */
     766          20 :         mpz_sub_si(c, d, 1);
     767          20 :         mpz_mul(c, c, f);
     768          20 :         mpz_mod(c, c, n->orig_modulus);
     769             :         /* ky0:=y*f^4/(f^2-3*f+1)^2/2; = num/den */
     770             :         /* it seems that ky0 = y*d^2/2 */
     771          20 :         mpz_mul(b, ky0, d);
     772          20 :         mpz_mul(b, b, d);
     773          20 :         mpz_mod(b, b, n->orig_modulus);
     774          20 :         mpz_set_si(fac, 2);
     775          20 :         mod_from_rat2(ky0, b, fac, n->orig_modulus);
     776             :         /* kx0:=-f*d; */
     777          20 :         mpz_mul(kx0, f, d);
     778          20 :         mpz_neg(kx0, kx0);
     779          20 :         mpz_mod(kx0, kx0, n->orig_modulus);
     780             :         /* b:=c*d; */
     781          20 :         mpz_mul(b, c, d);
     782          20 :         mpz_mod(b, b, n->orig_modulus);
     783             : #if DEBUG_TORSION >= 2
     784             :         gmp_printf("f:=%Zd; d:=%Zd; c:=%Zd; b:=%Zd;\n", f, d, c, b);
     785             :         gmp_printf("kx0:=%Zd; ky0:=%Zd;\n", kx0, ky0);
     786             : #endif
     787             :         /* to short Weierstrass form */
     788          20 :         kubert_to_weierstrass(A, B, X, Y, b, c, kx0, ky0, n->orig_modulus);
     789          20 :         if(check_weierstrass(A, B, X, Y, tmp, x0, n->orig_modulus) == 0){
     790           0 :             ret = ECM_ERROR;
     791           0 :             break;
     792             :         }
     793          20 :         ell_curve_init(tE[nc], ECM_EC_TYPE_WEIERSTRASS, ECM_LAW_AFFINE, n);
     794          20 :         mpz_set(tE[nc]->a4, A);
     795          20 :         mpz_set(tE[nc]->a6, B);
     796          20 :         ell_point_init(tP[nc], tE[nc], n);
     797          20 :         mpz_set(tP[nc]->x, X);
     798          20 :         mpz_set(tP[nc]->y, Y);
     799          20 :         nc++;
     800          20 :         if(nc >= nE)
     801          20 :             break;
     802             :     }
     803             : #if DEBUG_TORSION >= 2
     804             :     if(ret != ECM_ERROR && nc > 0){
     805             :         printf("Curves built\n");
     806             :         pt_many_print(tE, tP, nE, n);
     807             :     }
     808             : #endif
     809          50 :     mpz_clear(A);
     810          50 :     mpz_clear(B);
     811          50 :     mpz_clear(X);
     812          50 :     mpz_clear(Y);
     813          50 :     mpz_clear(A2);
     814          50 :     mpz_clear(A1div2);
     815          50 :     mpz_clear(x0);
     816          50 :     mpz_clear(y0);
     817          50 :     mpz_clear(cte);
     818          50 :     ell_point_clear(P, E, n);
     819          50 :     ell_point_clear(Q, E, n);
     820          50 :     ell_curve_clear(E, n);
     821          50 :     mpres_clear(tmp, n);
     822          50 :     mpz_clear(d);
     823          50 :     mpz_clear(c);
     824          50 :     mpz_clear(b);
     825          50 :     mpz_clear(kx0);
     826          50 :     mpz_clear(ky0);
     827          50 :     mpz_clear(f);
     828          50 :     return ret;
     829             : }
     830             : 
     831             : /* Warning: b and a have the Montgomery meaning in this function. 
     832             :    All tE[i] will be in Montgomery form: B*Y^2 = X^3 + A * X^2 + X.
     833             : */
     834             : int
     835          80 : build_curves_with_torsion_Z2xZ8(mpz_t fac, mpmod_t n, 
     836             :                                 ell_curve_t *tE, ell_point_t *tP,
     837             :                                 int umin, int umax, int nE)
     838             : {
     839          80 :     int u, nc = 0, ret = ECM_NO_FACTOR_FOUND;
     840             :     mpz_t tmp, a, b, alpha, beta, c, d, kx0, ky0, wx0, mb;
     841             :     mpres_t tmp2;
     842             :     ell_curve_t E;
     843             :     ell_point_t P, Q;
     844             : 
     845          80 :     mpz_init(alpha);
     846          80 :     mpz_init(beta);
     847          80 :     mpz_init(tmp);
     848          80 :     mpz_init(a);
     849          80 :     mpz_init(b);
     850          80 :     mpz_init(c);
     851          80 :     mpz_init(d);
     852          80 :     mpz_init(kx0);
     853          80 :     mpz_init(ky0);
     854          80 :     mpz_init(wx0);
     855          80 :     mpz_init(mb);
     856             : 
     857             :     /* Eaux = [-8, -32] */
     858             :     /* Paux = [12, 40, 1] */
     859          80 :     mpres_init(tmp2, n);
     860          80 :     mpz_set_str(fac, "-8", 10); 
     861          80 :     mpres_set_z(tmp2, fac, n);
     862          80 :     ell_curve_init_set(E, ECM_EC_TYPE_WEIERSTRASS, ECM_LAW_AFFINE, tmp2, n);
     863          80 :     ell_point_init(P, E, n);
     864          80 :     mpz_set_str(fac, "12", 10); 
     865          80 :     mpres_set_z(P->x, fac, n);
     866          80 :     mpz_set_str(fac, "40", 10);
     867          80 :     mpres_set_z(P->y, fac, n);
     868          80 :     mpz_set_ui(P->z, 1);
     869             : 
     870          80 :     ell_point_init(Q, E, n);
     871          80 :     mpz_set_si(d, umin-1);
     872          80 :     if(ell_point_mul(fac, Q, d, P, E, n) == 0){
     873          10 :         printf("found factor during init of Q in Z2xZ8\n");
     874          10 :         ret = ECM_FACTOR_FOUND_STEP1;
     875             :     }
     876          80 :     for(u = umin; (ret != ECM_FACTOR_FOUND_STEP1) && u < umax; u++){
     877             :         /* update Q */
     878          70 :         if(ell_point_add(fac, Q, P, Q, E, n) == 0){
     879          10 :             printf("found factor during update of Q in Z2xZ8\n");
     880          10 :             ret = ECM_FACTOR_FOUND_STEP1;
     881          10 :             break;
     882             :         }
     883             : #if DEBUG_TORSION >= 2
     884             :         printf("(s, t)[%d]:=", u);
     885             :         pt_print(E, Q, n);
     886             :         printf(";\n");
     887             : #endif
     888             :         /* beta <- (y+25)/(x-9) */
     889          60 :         mpres_get_z(a, Q->x, n);
     890          60 :         mpres_get_z(b, Q->y, n);
     891          60 :         mpz_mod(wx0, a, n->orig_modulus);
     892          60 :         mpz_sub_si(a, a, 9);
     893          60 :         mpz_mod(a, a, n->orig_modulus);
     894          60 :         mpz_add_si(b, b, 25);
     895          60 :         mpz_mod(b, b, n->orig_modulus);
     896          60 :         if(mod_from_rat2(beta, b, a, n->orig_modulus) == 0){
     897          10 :             printf("found factor in Z2xZ8 (beta)\n");
     898          10 :             mpz_set(fac, beta);
     899          10 :             ret = ECM_FACTOR_FOUND_STEP1;
     900          10 :             break;
     901             :         }
     902          50 :         mpz_add_si(tmp, beta, 1);
     903          50 :         mpz_mod(tmp, tmp, n->orig_modulus);
     904             :         /* alpha <- 1/(beta+1) */
     905          50 :         if(mpz_invert(alpha, tmp, n->orig_modulus) == 0){
     906          10 :             printf("found factor in Z2xZ8 (alpha)\n");
     907          10 :             mpz_gcd(fac, tmp, n->orig_modulus);
     908          10 :             ret = ECM_FACTOR_FOUND_STEP1;
     909          10 :             break;
     910             :         }
     911             :         /** d <- 8*alpha^2-1; 
     912             :             d = -(beta^2+2*beta-7)/(beta+1)^2
     913             :          **/
     914          40 :         mpz_mul(d, alpha, alpha);
     915          40 :         mpz_mul_si(d, d, 8);
     916          40 :         mpz_sub_si(d, d, 1);
     917          40 :         mpz_mod(d, d, n->orig_modulus);
     918             :         /* d:=2*alpha*(4*alpha+1)/d; */
     919          40 :         mpz_mul_si(c, alpha, 4);
     920          40 :         mpz_add_si(c, c, 1);
     921          40 :         mpz_mul(c, c, alpha);
     922          40 :         mpz_mul_si(c, c, 2);
     923          40 :         mpz_mod(c, c, n->orig_modulus);
     924          40 :         if(mod_from_rat2(fac, c, d, n->orig_modulus) == 0){
     925             :             // the only possibility is d = 0 mod p or 8*alpha^2-1 = 0 mod  p
     926          10 :             printf("found factor in Z2xZ8 (d)\n");
     927          10 :             ret = ECM_FACTOR_FOUND_STEP1;
     928          10 :             break;
     929             :         }
     930          30 :         mpz_set(d, fac);
     931             :         /* c:=(2*d-1)*(d-1)/d;*/
     932          30 :         mpz_sub_si(fac, d, 1);
     933             :         /** kx0 <- 2*d-1 **/
     934          30 :         mpz_mul_si(kx0, d, 2);
     935          30 :         mpz_sub_si(kx0, kx0, 1);
     936          30 :         mpz_mul(fac, fac, kx0);
     937          30 :         mpz_mod(fac, fac, n->orig_modulus);
     938          30 :         if(mod_from_rat2(c, fac, d, n->orig_modulus) == 0){
     939             :             // this is possible only if d = 0 mod p or 
     940             :             // 2*alpha*(4*alpha+1) = 0 mod p
     941          10 :             printf("found factor in Z2xZ8 (d2)\n");
     942          10 :             mpz_set(fac, c);
     943          10 :             ret = ECM_FACTOR_FOUND_STEP1;
     944          10 :             break;
     945             :         }
     946             :         /* b = c*d */
     947          20 :         mpz_mul(b, c, d);
     948          20 :         mpz_mod(b, b, n->orig_modulus);
     949             :         /* kx0:=-(2*d-1)/4;*/
     950          20 :         mod_div_2(kx0, n->orig_modulus);
     951          20 :         mod_div_2(kx0, n->orig_modulus);
     952          20 :         mpz_mul_si(kx0, kx0, -1);
     953          20 :         mpz_mod(kx0, kx0, n->orig_modulus);
     954             :         /* ky0:=(c/8)*(-beta^2+2*uP[1]+9); */
     955          20 :         mpz_mul(fac, beta, beta);
     956          20 :         mpz_set(a, wx0);
     957          20 :         mpz_sub(fac, a, fac);
     958          20 :         mpz_add(fac, fac, a);
     959          20 :         mpz_add_si(fac, fac, 9);
     960          20 :         mpz_mul(fac, fac, c);
     961          20 :         mpz_mod(fac, fac, n->orig_modulus);
     962          20 :         mod_div_2(fac, n->orig_modulus);
     963          20 :         mod_div_2(fac, n->orig_modulus);
     964          20 :         mod_div_2(fac, n->orig_modulus);
     965             :         /* ky0:=ky0/(beta^2+2*beta-7); */
     966          20 :         mpz_add_si(tmp, beta, 2);
     967          20 :         mpz_mul(tmp, tmp, beta);
     968          20 :         mpz_sub_si(tmp, tmp, 7);
     969          20 :         mpz_mod(tmp, tmp, n->orig_modulus);
     970             :         /* as proven above, we cannot have tmp non invertible at that point */
     971          20 :         mod_from_rat2(ky0, fac, tmp, n->orig_modulus);
     972          20 :         KW2W246(fac, a, NULL, b, c, n->orig_modulus, 0);
     973             : #if DEBUG_TORSION >= 2
     974             :         gmp_printf("kwx0:=%Zd;\n", kx0);
     975             :         gmp_printf("kwy0:=%Zd;\n", ky0);
     976             :         printf("(kwy0^2-(kwx0^3+a2*kwx0^2+a4*kwx0+a6)) mod N;\n");
     977             : #endif
     978             :         /* wx0:=kx0+a2/3; */
     979          20 :         mpz_set_si(tmp, 3);
     980          20 :         mod_from_rat2(wx0, fac, tmp, n->orig_modulus);
     981          20 :         mpz_add(wx0, wx0, kx0);
     982          20 :         mpz_mod(wx0, wx0, n->orig_modulus);
     983             :         /* mb:=-1/(d-1)^2; */
     984          20 :         mpz_sub_si(tmp, d, 1);
     985          20 :         mpz_mul(tmp, tmp, tmp);
     986          20 :         mpz_mod(tmp, tmp, n->orig_modulus);
     987          20 :         mpz_neg(tmp, tmp);
     988          20 :         if(mpz_invert(mb, tmp, n->orig_modulus) == 0){
     989          10 :             printf("found factor in Z2xZ8 (mb)\n");
     990          10 :             mpz_gcd(fac, tmp, n->orig_modulus);
     991          10 :             ret = ECM_FACTOR_FOUND_STEP1;
     992          10 :             break;
     993             :         }
     994             :         /* ma:=-1/4*(8*d^4-16*d^3+16*d^2-8*d+1)/(d-1)^2/d^2; 
     995             :              :=mb*(8*d^4-16*d^3+16*d^2-8*d+1)/(4*d^2)
     996             :          */
     997          10 :         mpz_set_si(fac, 8);         /* num */
     998          10 :         mpz_mul(fac, fac, d); mpz_add_si(fac, fac, -16);
     999          10 :         mpz_mul(fac, fac, d); mpz_add_si(fac, fac, 16);
    1000          10 :         mpz_mul(fac, fac, d); mpz_add_si(fac, fac, -8);
    1001          10 :         mpz_mul(fac, fac, d); mpz_add_si(fac, fac, 1);
    1002             : #if 0
    1003             :         mpz_sub_si(tmp, d, 1);    /* den */
    1004             :         mpz_mul(tmp, tmp, d);
    1005             :         mpz_mul(tmp, tmp, tmp);
    1006             :         mpz_mul_si(tmp, tmp, -4);
    1007             :         mpz_mod(tmp, tmp, n->orig_modulus);
    1008             : #else
    1009          10 :         mpz_mul(fac, fac, mb);
    1010             :         /* one day, we could save 1/d computation again */
    1011          10 :         mpz_mul(tmp, d, d);
    1012          10 :         mpz_mul_si(tmp, tmp, 4);
    1013             : #endif
    1014             :         /* to Montgomery form */
    1015          10 :         ell_curve_init(tE[nc], ECM_EC_TYPE_MONTGOMERY, ECM_LAW_HOMOGENEOUS,n);
    1016          10 :         ell_point_init(tP[nc], tE[nc], n);
    1017             :         /* this cannot yield a factor, since d is invertible at that point */
    1018          10 :         mod_from_rat2(tE[nc]->a2, fac, tmp, n->orig_modulus);
    1019             :         /* not really needed, but useful for debug */
    1020          10 :         mpz_set_ui(tE[nc]->a4, 1);
    1021          10 :         mpz_set_ui(tE[nc]->a6, 0);
    1022             :         /* mx:=mb*wx0-ma/3; */
    1023          10 :         mpz_mul(fac, mb, wx0);
    1024          10 :         mpz_set_si(tmp, 3);
    1025          10 :         mod_from_rat2(tP[nc]->x, tE[nc]->a2, tmp, n->orig_modulus);
    1026          10 :         mpz_sub(tP[nc]->x, fac, tP[nc]->x);
    1027          10 :         mpz_mod(tP[nc]->x, tP[nc]->x, n->orig_modulus);
    1028             :         /* my:=mb*ky0; */
    1029             : #if DEBUG_TORSION >= 2
    1030             :         gmp_printf("N:=%Zd;\n", n->orig_modulus);
    1031             :         gmp_printf("ma:=%Zd;\n", tE[nc]->a2);
    1032             :         gmp_printf("mb:=%Zd;\n", mb);
    1033             :         gmp_printf("kx0:=%Zd;\n", kx0);
    1034             :         gmp_printf("ky0:=%Zd;\n", ky0);
    1035             :         gmp_printf("mx0:=%Zd;\n", tP[nc]->x);
    1036             :         mpz_mul(tmp, mb, ky0);
    1037             :         mpz_mod(tmp, tmp, n->orig_modulus);
    1038             :         gmp_printf("my0:=%Zd;\n", tmp);
    1039             :         printf("chk:=(mb*my0^2-mx0^3-ma*mx0^2-mx0) mod N;\n");
    1040             : #endif
    1041          10 :         nc++;
    1042          10 :         if(nc >= nE)
    1043          10 :             break;
    1044             :     }
    1045             : #if DEBUG_TORSION >= 2
    1046             :     printf("Curves built\n");
    1047             :     pt_many_print(tE, tP, nE, n);
    1048             : #endif
    1049          80 :     ell_point_clear(P, E, n);
    1050          80 :     ell_point_clear(Q, E, n);
    1051          80 :     ell_curve_clear(E, n);
    1052          80 :     mpz_clear(mb);
    1053          80 :     mpz_clear(tmp);
    1054          80 :     mpz_clear(a);
    1055          80 :     mpz_clear(b);
    1056          80 :     mpz_clear(c);
    1057          80 :     mpz_clear(d);
    1058          80 :     mpz_clear(alpha);
    1059          80 :     mpz_clear(beta);
    1060          80 :     mpz_init(kx0);
    1061          80 :     mpz_init(ky0);
    1062          80 :     mpz_init(wx0);
    1063          80 :     mpres_clear(tmp2, n);
    1064          80 :     return ret;
    1065             : }
    1066             : 
    1067             : /* Z3xZ3 over Q(sqrt(-3)). Interesting if we know that p | N is s.t.
    1068             :    p = 1 mod 3.
    1069             :    Source: Dujella and Najman, arxiv:1201.0266v1 
    1070             :    A more simpler and more efficient stuff, using Hessian form. */
    1071             : int
    1072          50 : build_curves_with_torsion_Z3xZ3(mpz_t f, mpmod_t n, 
    1073             :                                 ell_curve_t *tE, ell_point_t *tP,
    1074             :                                 int umin, int umax, int nE)
    1075             : {
    1076          50 :     int u, nc = 0, ret = ECM_NO_FACTOR_FOUND;
    1077             :     mpz_t u0, v0, D, num, den;
    1078             : 
    1079          50 :     mpz_init(u0);
    1080          50 :     mpz_init(num);
    1081          50 :     mpz_init(den);
    1082          50 :     mpz_init(D);
    1083          50 :     mpz_init_set_si(v0, umin-1); /* to prevent u0 = v0 */
    1084          60 :     for(u = umin; u < umax; u++){
    1085          60 :         if(forbidden("Z3xZ3", u))
    1086          10 :             continue;
    1087          50 :         mpz_set_si(u0, u);
    1088             :         /* D:=RatMod((u0^3+v0^3+1)/(3*u0*v0), N); */
    1089          50 :         mpz_mul(num, u0, u0);
    1090          50 :         mpz_mul(num, num, u0);
    1091          50 :         mpz_mul(den, v0, v0);
    1092          50 :         mpz_mul(den, den, v0);
    1093          50 :         mpz_add(num, num, den);
    1094          50 :         mpz_add_si(num, num, 1);
    1095          50 :         mpz_mod(num, num, n->orig_modulus);
    1096          50 :         if(mpz_sgn(num) == 0)
    1097           0 :             continue;
    1098             :         
    1099          50 :         mpz_mul(den, u0, v0);
    1100          50 :         mpz_mul_si(den, den, 3);
    1101          50 :         mpz_mod(den, den, n->orig_modulus);
    1102             : 
    1103          50 :         if(mod_from_rat2(D, num, den, n->orig_modulus) == 0){
    1104          10 :             printf("found factor in Z3xZ3 (D)\n");
    1105          10 :             mpz_set(f, D);
    1106          10 :             ret = ECM_FACTOR_FOUND_STEP1;
    1107          10 :             break;
    1108             :         }
    1109          40 :         mpz_mul(num, D, D);
    1110          40 :         mpz_mul(num, num, D);
    1111          40 :         mpz_mod(num, num, n->orig_modulus);
    1112          40 :         if(mpz_cmp_ui(num, 1) == 0){
    1113          10 :             printf("D^3=1 => singluar curve\n");
    1114          10 :             ret = ECM_ERROR;
    1115          10 :             break;
    1116             :         }
    1117          30 :         ell_curve_init_set(tE[nc],ECM_EC_TYPE_HESSIAN,ECM_LAW_HOMOGENEOUS,D,n);
    1118          30 :         ell_point_init(tP[nc], tE[nc], n);
    1119          30 :         mpz_set(tP[nc]->x, u0);
    1120          30 :         mpz_set(tP[nc]->y, v0);
    1121          30 :         mpz_set_ui(tP[nc]->z, 1);
    1122          30 :         nc++;
    1123          30 :         if(nc >= nE)
    1124          30 :             break;
    1125             :     }
    1126          50 :     mpz_clear(u0);
    1127          50 :     mpz_clear(v0);
    1128          50 :     mpz_clear(D);
    1129          50 :     mpz_clear(num);
    1130          50 :     mpz_clear(den);
    1131          50 :     return ret;
    1132             : }
    1133             : 
    1134             : /* For a small price, add a 2-torsion point, also over Q(sqrt(-3)). */
    1135             : int
    1136          30 : build_curves_with_torsion_Z3xZ6(mpz_t f, mpmod_t n, 
    1137             :                                 ell_curve_t *tE, ell_point_t *tP,
    1138             :                                 int umin, int umax, int nE)
    1139             : {
    1140          30 :     int u, nc = 0, ret = ECM_NO_FACTOR_FOUND;
    1141             :     ell_curve_t E;
    1142             :     ell_point_t P, Q;
    1143             :     mpres_t tmp, num, den, tk, sk;
    1144             :     mpz_t t;
    1145             : 
    1146          30 :     mpz_init(t);
    1147          30 :     mpz_init(num);
    1148          30 :     mpz_init(den);
    1149          30 :     mpz_init(tk);
    1150          30 :     mpz_init(sk);
    1151             :     /* Eaux:=EllipticCurve([0, -4]); */
    1152             :     /* Paux:=Eaux![2, 2, 1]; */
    1153          30 :     mpres_init(tmp, n);
    1154          30 :     mpres_set_ui(tmp, 0, n);
    1155          30 :     ell_curve_init_set(E, ECM_EC_TYPE_WEIERSTRASS, ECM_LAW_AFFINE, tmp, n);
    1156          30 :     ell_point_init(P, E, n);
    1157          30 :     mpz_set_str(f, "2", 10);
    1158          30 :     mpres_set_z(P->x, f, n);
    1159          30 :     mpz_set_str(f, "2", 10);
    1160          30 :     mpres_set_z(P->y, f, n);
    1161          30 :     mpz_set_ui(P->z, 1);
    1162             : 
    1163          30 :     ell_point_init(Q, E, n);
    1164          30 :     for(u = umin; u < umax; u++){
    1165             :         /* update Qaux */
    1166          30 :         mpz_set_si(f, u);
    1167          30 :         if(ell_point_mul(f, Q, f, P, E, n) == 0){
    1168          10 :             printf("found factor in Z3xZ6 (update of Q)\n");
    1169          10 :             ret = ECM_FACTOR_FOUND_STEP1;
    1170          10 :             break;
    1171             :         }
    1172             : #if DEBUG_TORSION >= 2
    1173             :         printf("(s, t)[%d]:=", u);
    1174             :         pt_print(E, Q, n);
    1175             :         printf(";\n");
    1176             : #endif
    1177          20 :         mpres_get_z(tk, Q->x, n);
    1178          20 :         mpres_get_z(sk, Q->y, n);
    1179             : #if 0 /* useless in affine form? */
    1180             :         mpres_get_z(t, Q->z, n);
    1181             :         if(mpz_invert(f, t, n->orig_modulus) == 0){
    1182             :             printf("found factor in Z3xZ6 (normalization)\n");
    1183             :             mpz_gcd(f, t, n->orig_modulus);
    1184             :             break;
    1185             :         }
    1186             :         mpz_mul(tk, tk, f);
    1187             :         mpz_mod(tk, tk, n->orig_modulus);
    1188             :         mpz_mul(sk, sk, f);
    1189             :         mpz_mod(sk, sk, n->orig_modulus);
    1190             : #endif
    1191             :         /* t:=RatMod(-tk/2, N); */
    1192          20 :         mpz_mul_si(t, tk, -1);
    1193          20 :         mod_div_2(t, n->orig_modulus);
    1194             :         /* D:=RatMod((2*t^3+1)/3/t^2, N); */
    1195          20 :         mpz_mul(den, t, t);
    1196          20 :         mpz_mod(den, den, n->orig_modulus);
    1197          20 :         mpz_mul(num, den, t);
    1198          20 :         mpz_mul_si(num, num, 2);
    1199          20 :         mpz_add_si(num, num, 1);
    1200          20 :         mpz_mod(num, num, n->orig_modulus);
    1201          20 :         mpz_mul_si(den, den, 3);
    1202          20 :         mpz_mod(den, den, n->orig_modulus);
    1203          20 :         ell_curve_init(tE[nc], ECM_EC_TYPE_HESSIAN, ECM_LAW_HOMOGENEOUS, n);
    1204          20 :         ell_point_init(tP[nc], tE[nc], n);
    1205          20 :         if(mod_from_rat2(tE[nc]->a4, num, den, n->orig_modulus) == 0){
    1206             :             /* only if t = 0, which seems hard */
    1207          10 :             printf("found factor in Z3xZ6 (D)\n");
    1208          10 :             mpz_set(f, tE[nc]->a4);
    1209          10 :             ret = ECM_FACTOR_FOUND_STEP1;
    1210          10 :             break;
    1211             :         }
    1212             : #if DEBUG_TORSION >= 1
    1213             :         gmp_printf("D%d:=%Zd;\n", nc, tE[nc]->a4);
    1214             : #endif
    1215             :         /* u0:=RatMod(sk/tk, N); 
    1216             :            if tk was not invertible, it would have been caught before
    1217             :          */
    1218          10 :         mod_from_rat2(tP[nc]->x, sk, tk, n->orig_modulus);
    1219             :         /* v0:=-1; */
    1220          10 :         mpz_sub_si(tP[nc]->y, n->orig_modulus, 1);
    1221          10 :         mpz_set_ui(tP[nc]->z, 1);
    1222          10 :         nc++;
    1223          10 :         if(nc >= nE)
    1224          10 :             break;
    1225             :     }
    1226          30 :     mpz_clear(t);
    1227          30 :     mpz_clear(num);
    1228          30 :     mpz_clear(den);
    1229          30 :     mpz_clear(sk);
    1230          30 :     mpz_clear(tk);
    1231          30 :     mpres_clear(tmp, n);
    1232          30 :     return ret;
    1233             : }
    1234             : 
    1235             : /* JKL: K = Q(sqrt(-3), sqrt(8*t^3+1), t in Q, t != 0, 1, -1/2;
    1236             :    mu = (2*t^3+1)/(3*t^2) => parameter for Hessian form.
    1237             :    Tors(E) = Z/6xZ/6.
    1238             :    A "specified" point is (0:-1:1), but does it have infinite order?
    1239             :    Also: twisted Hessian is a*X^3+Y^3+Z^3=d*X*Y*Z, d/a=3*mu.
    1240             :    See JKL-ECM in ANTS-XII.
    1241             :  */
    1242             : 
    1243             : /* Original source is Brier + Clavier.
    1244             :    We can build curves in Montgomery form directly... 
    1245             :    Useful if one knows that all p | n are 1 mod 4 (Cunningham, etc.).
    1246             : */
    1247             : int
    1248          30 : build_curves_with_torsion_Z4xZ4(mpz_t f, mpmod_t n, ell_curve_t *tE,
    1249             :                                 ell_point_t *tP,
    1250             :                                 int smin, int smax, int nE)
    1251             : {
    1252             :     mpz_t tau, lambda, nu2, tmp, b, x0;
    1253          30 :     int nu, nc = 0, ret = ECM_NO_FACTOR_FOUND;
    1254             : 
    1255          30 :     mpz_init(tau);
    1256          30 :     mpz_init(lambda);
    1257          30 :     mpz_init(nu2);
    1258          30 :     mpz_init(tmp);
    1259          30 :     mpz_init(b);
    1260          30 :     mpz_init(x0);
    1261          30 :     for(nu = smin; nu < smax; nu++){
    1262          30 :         mpz_set_si(nu2, nu*nu);
    1263             :         /* tau:=(nu^2+3)/2/nu; */
    1264          30 :         mpz_add_si(lambda, nu2, 3);
    1265          30 :         mpz_set_si(tmp, 2*nu);
    1266          30 :         if(mod_from_rat2(tau, lambda, tmp, n->orig_modulus) == 0){
    1267          10 :             printf("Factor found during init of Z4xZ4 (tau)\n");
    1268          10 :             mpz_set(f, tau);
    1269          10 :             ret = ECM_FACTOR_FOUND_STEP1;
    1270          10 :             break;
    1271             :         }
    1272             :         /* lambda:=8*nu^3; */
    1273          20 :         mpz_mul_si(lambda, nu2, 8*nu);
    1274          20 :         mpz_mod(lambda, lambda, n->orig_modulus);
    1275             :         /* A:=-27*lambda^4*(tau^8+14*tau^4+1); */
    1276             :         /* B:=54*lambda^6*(tau^12-33*tau^8-33*tau^4+1); */
    1277             :         /* x0:=3*(3*nu^12+34*nu^10+117*nu^8+316*nu^6+1053*nu^4+2754*nu^2+2187); */
    1278             :         /* y0:=27*(nu^2-3)*(nu^2+1)*(nu^2+9)*(nu^6+5*nu^4+15*nu^2+27)^2; */
    1279             :         /* P = (x0, y0) is a point on Y^2 = X^3+A*X+B */
    1280             : 
    1281             :         /* Montgomery form: there are several possible mb */
    1282             :         /* mb:=1/(9*lambda^2*(tau^4-1));
    1283             :            lambda is invertible iff nu is;
    1284             :            tau^4-1 = (tau-1)(tau+1)(tau^2+1)
    1285             :         */
    1286          20 :         mpz_powm_ui(x0, tau, 4, n->orig_modulus);
    1287          20 :         mpz_sub_si(x0, x0, 1);
    1288          20 :         mpz_mod(x0, x0, n->orig_modulus);
    1289          20 :         mpz_mul(tmp, x0, lambda);
    1290          20 :         mpz_mul(tmp, tmp, lambda);
    1291          20 :         mpz_mul_si(tmp, tmp, 9);
    1292          20 :         if(mpz_invert(b, tmp, n->orig_modulus) == 0){
    1293          10 :             printf("Factor found during init of Z4xZ4 (mb)\n");
    1294          10 :             mpz_gcd(f, tmp, n->orig_modulus);
    1295          10 :             ret = ECM_FACTOR_FOUND_STEP1;
    1296          10 :             break;
    1297             :         }
    1298             :         /* ma:=-2*(tau^4+1)/(tau^4-1); at this point: invertible! */
    1299          10 :         mpz_add_si(tmp, x0, 2);
    1300          10 :         mpz_mul_si(tmp, tmp, -2);
    1301          10 :         mpz_mod(tmp, tmp, n->orig_modulus);
    1302             :         /* to Montgomery form */
    1303          10 :         ell_curve_init(tE[nc], ECM_EC_TYPE_MONTGOMERY, ECM_LAW_HOMOGENEOUS, n);
    1304          10 :         ell_point_init(tP[nc], tE[nc], n);
    1305          10 :         mod_from_rat2(tE[nc]->a4, tmp, x0, n->orig_modulus);
    1306             :         /* now compute real x0 */
    1307             :         /* x0:=3*(3*nu^12+34*nu^10+117*nu^8+316*nu^6+1053*nu^4+2754*nu^2+2187); */
    1308          10 :         mpz_set_si(x0, 3);
    1309          10 :         mpz_mul(x0, x0, nu2); mpz_add_si(x0, x0, 34);
    1310          10 :         mpz_mul(x0, x0, nu2); mpz_add_si(x0, x0, 117);
    1311          10 :         mpz_mul(x0, x0, nu2); mpz_add_si(x0, x0, 316);
    1312          10 :         mpz_mul(x0, x0, nu2); mpz_add_si(x0, x0, 1053);
    1313          10 :         mpz_mul(x0, x0, nu2); mpz_add_si(x0, x0, 2754);
    1314          10 :         mpz_mul(x0, x0, nu2); mpz_add_si(x0, x0, 2187);
    1315          10 :         mpz_mul_si(x0, x0, 3);
    1316          10 :         mpz_mod(x0, x0, n->orig_modulus);
    1317             : #if DEBUG_TORSION >= 2
    1318             :         gmp_printf("N:=%Zd;\n", n);
    1319             :         printf("nu:=%d;\n", nu);
    1320             :         gmp_printf("tau:=%Zd;\n", tau);
    1321             :         gmp_printf("lambda:=%Zd;\n", lambda);
    1322             :         gmp_printf("a:=%Zd;\n", tE[nc]->a4);
    1323             :         gmp_printf("x0:=%Zd;\n", x0);
    1324             : #endif
    1325             :         /* x:=b*x0-a/3; not needed: y:=b*y0 */
    1326          10 :         mpz_set_si(tmp, 3);
    1327          10 :         mod_from_rat2(tP[nc]->x, tE[nc]->a4, tmp, n->orig_modulus);
    1328          10 :         mpz_mul(b, b, x0);
    1329          10 :         mpz_mod(b, b, n->orig_modulus);
    1330          10 :         mpz_sub(tP[nc]->x, b, tP[nc]->x);
    1331          10 :         mpz_mod(tP[nc]->x, tP[nc]->x, n->orig_modulus);
    1332          10 :         nc++;
    1333          10 :         if(nc >= nE)
    1334          10 :             break;
    1335             :     }
    1336          30 :     mpz_clear(tau);
    1337          30 :     mpz_clear(lambda);
    1338          30 :     mpz_clear(nu2);
    1339          30 :     mpz_clear(tmp);
    1340          30 :     mpz_clear(b);
    1341          30 :     mpz_clear(x0);
    1342          30 :     if(ret != ECM_FACTOR_FOUND_STEP1 && nc < nE){
    1343           0 :         printf("Not enough curves generated\n");
    1344           0 :         return ECM_ERROR;
    1345             :     }
    1346          30 :     return ret;
    1347             : }
    1348             : 
    1349             : /* Assuming we can generate curves with given torsion using parameter s
    1350             :    in interval [smin..smax[.
    1351             : */
    1352             : int
    1353         380 : build_curves_with_torsion(mpz_t f, mpmod_t n, ell_curve_t *tE, ell_point_t *tP,
    1354             :                           char *torsion, int smin, int smax, int nE)
    1355             : {
    1356         380 :     int ret = 0;
    1357             : 
    1358             :     /* over Q: see Atkin-Morain, Math. Comp., 1993 */
    1359         380 :     if(strcmp(torsion, "Z5") == 0)
    1360          20 :         return build_curves_with_torsion_Z5(f, n, tE, tP, smin, smax, nE);
    1361         360 :     else if(strcmp(torsion, "Z7") == 0)
    1362          70 :         return build_curves_with_torsion_Z7(f, n, tE, tP, smin, smax, nE);
    1363         290 :     else if(strcmp(torsion, "Z9") == 0)
    1364          40 :         return build_curves_with_torsion_Z9(f, n, tE, tP, smin, smax, nE);
    1365         250 :     else if(strcmp(torsion, "Z10") == 0)
    1366          50 :         return build_curves_with_torsion_Z10(f, n, tE, tP, smin, smax, nE);
    1367         200 :     else if(strcmp(torsion, "Z2xZ8") == 0)
    1368          80 :         return build_curves_with_torsion_Z2xZ8(f, n, tE, tP, smin, smax, nE);
    1369             :     /* no longer over Q */
    1370             :     /** interesting when p = 1 mod 3 **/
    1371         120 :     else if(strcmp(torsion, "Z3xZ3") == 0) /* over Q(sqrt(-3)) */
    1372          50 :         return build_curves_with_torsion_Z3xZ3(f, n, tE, tP, smin, smax, nE);
    1373          70 :     else if(strcmp(torsion, "Z3xZ6") == 0) /* over Q(sqrt(-3)) */
    1374          30 :         return build_curves_with_torsion_Z3xZ6(f, n, tE, tP, smin, smax, nE);
    1375             :     /** interesting when p = 1 mod 4 **/
    1376          40 :     else if(strcmp(torsion, "Z4xZ4") == 0) /* over Q(sqrt(-1)) */
    1377          30 :         return build_curves_with_torsion_Z4xZ4(f, n, tE, tP, smin, smax, nE);
    1378             :     else{
    1379          10 :         printf("Unknown torsion group: %s\n", torsion);
    1380          10 :         ret = ECM_ERROR;
    1381             :     }
    1382          10 :     return ret;
    1383             : }
    1384             : 
    1385             : /* E is a curve with given torsion and (x, y) a point on E mod n.
    1386             :    OUTPUT: ECM_NO_FACTOR_FOUND if everything went ok
    1387             :            ECM_FACTOR_FOUND_STEP1 in case a factor was found when building E.
    1388             :    REM: E is defined over Z, not in mpres_t.
    1389             :  */
    1390             : int
    1391         380 : build_curves_with_torsion2(mpz_t f, mpz_t n, ell_curve_t E, 
    1392             :                            mpz_t x, mpz_t y, char *torsion, 
    1393             :                            mpz_t sigma)
    1394             : {
    1395             :     ell_curve_t tE[1];
    1396             :     ell_point_t tP[1];
    1397             :     mpmod_t modulus;
    1398             :     int ret, smin, smax;
    1399             : 
    1400         380 :     smin = (int)mpz_get_si(sigma);
    1401         380 :     smax = smin+10;
    1402         380 :     mpmod_init(modulus, n, ECM_MOD_DEFAULT);
    1403         380 :     ret = build_curves_with_torsion(f, modulus, tE, tP, torsion, smin, smax,1);
    1404         380 :     if(ret == ECM_NO_FACTOR_FOUND){
    1405         130 :         E->type = tE[0]->type;
    1406         130 :         E->law = tE[0]->law;
    1407         130 :         mpz_set(E->a2, tE[0]->a2);
    1408         130 :         mpz_set(E->a4, tE[0]->a4);
    1409         130 :         mpz_set(E->a6, tE[0]->a6);
    1410         130 :         mpz_set(x, tP[0]->x);
    1411         130 :         mpz_set(y, tP[0]->y);
    1412         130 :         ell_point_clear(tP[0], tE[0], modulus);
    1413         130 :         ell_curve_clear(tE[0], modulus);
    1414             :     }
    1415         380 :     mpmod_clear(modulus);
    1416         380 :     return ret;
    1417             : }

Generated by: LCOV version 1.14