Code coverage tests

This page documents the degree to which the PARI/GP source code is tested by our public test suite, distributed with the source distribution in directory src/test/. This is measured by the gcov utility; we then process gcov output using the lcov frond-end.

We test a few variants depending on Configure flags on the pari.math.u-bordeaux.fr machine (x86_64 architecture), and agregate them in the final report:

The target is to exceed 90% coverage for all mathematical modules (given that branches depending on DEBUGLEVEL or DEBUGMEM are not covered). This script is run to produce the results below.

LCOV - code coverage report
Current view: top level - basemath - elltors.c (source / functions) Coverage Total Hit
Test: PARI/GP v2.18.1 lcov report (development 31041-bd73e9fcdd) Lines: 95.7 % 440 421
Test Date: 2026-07-22 22:45:42 Functions: 92.3 % 26 24
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Copyright (C) 2000  The PARI group.
       2              : 
       3              : This file is part of the PARI/GP package.
       4              : 
       5              : PARI/GP is free software; you can redistribute it and/or modify it under the
       6              : terms of the GNU General Public License as published by the Free Software
       7              : Foundation; either version 2 of the License, or (at your option) any later
       8              : version. It is distributed in the hope that it will be useful, but WITHOUT
       9              : ANY WARRANTY WHATSOEVER.
      10              : 
      11              : Check the License for details. You should have received a copy of it, along
      12              : with the package; see the file 'COPYING'. If not, write to the Free Software
      13              : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      14              : 
      15              : /********************************************************************/
      16              : /**                                                                **/
      17              : /**         TORSION OF ELLIPTIC CURVES over NUMBER FIELDS          **/
      18              : /**                                                                **/
      19              : /********************************************************************/
      20              : #include "pari.h"
      21              : #include "paripriv.h"
      22              : static int
      23          637 : smaller_x(GEN p, GEN q)
      24              : {
      25          637 :   int s = abscmpii(denom_i(p), denom_i(q));
      26          637 :   return (s<0 || (s==0 && abscmpii(numer_i(p),numer_i(q)) < 0));
      27              : }
      28              : 
      29              : /* best generator in cycle of length k */
      30              : static GEN
      31          707 : best_in_cycle(GEN e, GEN p, long k)
      32              : {
      33          707 :   GEN p0 = p,q = p;
      34              :   long i;
      35              : 
      36         1078 :   for (i=2; i+i<k; i++)
      37              :   {
      38          371 :     q = elladd(e,q,p0);
      39          371 :     if (ugcd(i,k)==1 && smaller_x(gel(q,1), gel(p,1))) p = q;
      40              :   }
      41          707 :   return (gsigne(ec_dmFdy_evalQ(e,p)) < 0)? ellneg(e,p): p;
      42              : }
      43              : 
      44              : /* <p,q> = E_tors, possibly NULL (= oo), p,q independent unless NULL
      45              :  * order p = k, order q = 2 unless NULL */
      46              : static GEN
      47         2261 : tors(GEN e, long k, GEN p, GEN q, GEN v)
      48              : {
      49              :   GEN r;
      50         2261 :   if (q)
      51              :   {
      52          287 :     long n = k>>1;
      53          287 :     GEN p1, best = q, np = ellmul(e,p,utoipos(n));
      54          287 :     if (n % 2 && smaller_x(gel(np,1), gel(best,1))) best = np;
      55          287 :     p1 = elladd(e,q,np);
      56          287 :     if (smaller_x(gel(p1,1), gel(best,1))) q = p1;
      57          266 :     else if (best == np) { p = elladd(e,p,q); q = np; }
      58          287 :     p = best_in_cycle(e,p,k);
      59          287 :     if (v)
      60              :     {
      61            0 :       p = ellchangepointinv(p,v);
      62            0 :       q = ellchangepointinv(q,v);
      63              :     }
      64          287 :     r = cgetg(4,t_VEC);
      65          287 :     gel(r,1) = utoipos(2*k);
      66          287 :     gel(r,2) = mkvec2(utoipos(k), gen_2);
      67          287 :     gel(r,3) = mkvec2copy(p, q);
      68              :   }
      69              :   else
      70              :   {
      71         1974 :     if (p)
      72              :     {
      73          420 :       p = best_in_cycle(e,p,k);
      74          420 :       if (v) p = ellchangepointinv(p,v);
      75          420 :       r = cgetg(4,t_VEC);
      76          420 :       gel(r,1) = utoipos(k);
      77          420 :       gel(r,2) = mkvec( gel(r,1) );
      78          420 :       gel(r,3) = mkvec( gcopy(p) );
      79              :     }
      80              :     else
      81              :     {
      82         1554 :       r = cgetg(4,t_VEC);
      83         1554 :       gel(r,1) = gen_1;
      84         1554 :       gel(r,2) = cgetg(1,t_VEC);
      85         1554 :       gel(r,3) = cgetg(1,t_VEC);
      86              :     }
      87              :   }
      88         2261 :   return r;
      89              : }
      90              : 
      91              : /* Finds a multiplicative upper bound for #E_tor (p-Sylow if p != 0);
      92              :  * assume integral model */
      93              : static long
      94         2331 : torsbound(GEN e, ulong p)
      95              : {
      96         2331 :   GEN D = ell_get_disc(e);
      97         2331 :   pari_sp av = avma, av2;
      98         2331 :   long m, b, bold, nb, CM = ellQ_get_CM(e);
      99              :   forprime_t S;
     100         2331 :   nb = expi(D) >> 3; /* number of primes to try ~ 1 prime every 8 bits in D */
     101         2331 :   switch (p)
     102              :   {
     103          378 :     case 0: b = 5040; break;
     104          938 :     case 2: b = 16;   break;
     105           49 :     case 3: b = 9;    break;
     106           84 :     case 5: case 7: b = p; break;
     107          882 :     default: return 1;
     108              :   }
     109         1449 :   bold = b;
     110         1449 :   m = 0;
     111              :   /* p > 2 has good reduction => E(Q) injects in E(Fp) */
     112         1449 :   (void)u_forprime_init(&S, 3, ULONG_MAX);
     113         1449 :   av2 = avma;
     114        24045 :   while (m < nb || (b > 12 && b != 16))
     115              :   {
     116        23191 :     ulong p = u_forprime_next(&S);
     117        23191 :     if (!p) pari_err_BUG("torsbound [ran out of primes]");
     118        23191 :     if (!umodiu(D, p)) continue;
     119              : 
     120        18494 :     b = ugcd(b, p+1 - ellap_CM_fast(e,p,CM));
     121        18494 :     set_avma(av2);
     122        18494 :     if (b == 1) break;
     123        17899 :     if (b == bold) m++; else { bold = b; m = 0; }
     124              :   }
     125         1449 :   return gc_long(av,b);
     126              : }
     127              : 
     128              : /* return a rational point of order pk = p^k on E, or NULL if E(Q)[k] = O.
     129              :  * *fk is either NULL (pk = 4 or prime) or elldivpol(p^(k-1)).
     130              :  * Set *fk to elldivpol(p^k) */
     131              : static GEN
     132          630 : tpoint(GEN E, long pk, GEN *fk)
     133              : {
     134          630 :   GEN f = elldivpol(E,pk,0), g = *fk, v;
     135              :   long i, l;
     136          630 :   *fk = f;
     137          630 :   if (g) f = RgX_div(f, g);
     138          630 :   v = nfrootsQ(f); l = lg(v);
     139          966 :   for (i = 1; i < l; i++)
     140              :   {
     141          791 :     GEN x = gel(v,i);
     142          791 :     GEN y = ellordinate(E,x,0);
     143          791 :     if (lg(y) != 1) return mkvec2(x,gel(y,1));
     144              :   }
     145          175 :   return NULL;
     146              : }
     147              : /* return E(Q)[2] */
     148              : static GEN
     149          672 : t2points(GEN E, GEN *f2)
     150              : {
     151              :   long i, l;
     152              :   GEN v;
     153          672 :   *f2 = ec_bmodel(E,0);
     154          672 :   v = nfrootsQ(*f2); l = lg(v);
     155         1904 :   for (i = 1; i < l; i++)
     156              :   {
     157         1232 :     GEN x = gel(v,i);
     158         1232 :     GEN y = ellordinate(E,x,0);
     159         1232 :     if (lg(y) != 1) gel(v,i) = mkvec2(x,gel(y,1));
     160              :   }
     161          672 :   return v;
     162              : }
     163              : 
     164              : /* psylow = 0 or prime (return p-Sylow subgroup) */
     165              : static GEN
     166         2261 : ellQtors(GEN E, long psylow)
     167              : {
     168         2261 :   GEN T2 = NULL, p, P, Q, v;
     169              :   long v2, r2, B;
     170              : 
     171         2261 :   E = ellintegralmodel_i(E, &v);
     172         2261 :   B = torsbound(E, psylow); /* #E_tor | B */
     173         2261 :   if (B == 1) return tors(E,1,NULL,NULL, v);
     174          784 :   v2 = vals(B); /* bound for v_2(point order) */
     175          784 :   B >>= v2;
     176          784 :   p = const_vec(9, NULL);
     177          784 :   r2 = 0;
     178          784 :   if (v2) {
     179              :     GEN f;
     180          672 :     T2 = t2points(E, &f);
     181          672 :     switch(lg(T2)-1)
     182              :     {
     183           14 :       case 0:  v2 = 0; break;
     184          371 :       case 1:  r2 = 1; if (v2 == 4) v2 = 3; break;
     185          287 :       default: r2 = 2; v2--; break; /* 3 */
     186              :     }
     187          672 :     if (v2) gel(p,2) = gel(T2,1);
     188              :     /* f = f2 */
     189          672 :     if (v2 > 1) { gel(p,4) = tpoint(E,4, &f); if (!gel(p,4)) v2 = 1; }
     190              :     /* if (v2>1) now f = f4 */
     191          672 :     if (v2 > 2) { gel(p,8) = tpoint(E,8, &f); if (!gel(p,8)) v2 = 2; }
     192              :   }
     193          784 :   B <<= v2;
     194          784 :   if (B % 3 == 0) {
     195           91 :     GEN f3 = NULL;
     196           91 :     gel(p,3) = tpoint(E,3,&f3);
     197           91 :     if (!gel(p,3)) B /= (B%9)? 3: 9;
     198           91 :     if (gel(p,3) && B % 9 == 0)
     199              :     {
     200            7 :       gel(p,9) = tpoint(E,9,&f3);
     201            7 :       if (!gel(p,9)) B /= 3;
     202              :     }
     203              :   }
     204          784 :   if (B % 5 == 0) {
     205           63 :     GEN junk = NULL;
     206           63 :     gel(p,5) = tpoint(E,5,&junk);
     207           63 :     if (!gel(p,5)) B /= 5;
     208              :   }
     209          784 :   if (B % 7 == 0) {
     210           35 :     GEN junk = NULL;
     211           35 :     gel(p,7) = tpoint(E,7,&junk);
     212           35 :     if (!gel(p,7)) B /= 7;
     213              :   }
     214              :   /* B is the exponent of E_tors(Q), r2 is the rank of its 2-Sylow,
     215              :    * for i > 1, p[i] is a point of order i if one exists and i is a prime power
     216              :    * and NULL otherwise */
     217          784 :   if (r2 == 2) /* 2 cyclic factors */
     218              :   { /* C2 x C2 */
     219          287 :     if (B == 2) return tors(E,2, gel(T2,1), gel(T2,2), v);
     220          119 :     else if (B == 6)
     221              :     { /* C2 x C6 */
     222           14 :       P = elladd(E, gel(p,3), gel(T2,1));
     223           14 :       Q = gel(T2,2);
     224              :     }
     225              :     else
     226              :     { /* C2 x C4 or C2 x C8 */
     227          105 :       P = gel(p, B);
     228          105 :       Q = gel(T2,2);
     229          105 :       if (gequal(Q, ellmul(E, P, utoipos(B>>1)))) Q = gel(T2,1);
     230              :     }
     231              :   }
     232              :   else /* cyclic */
     233              :   {
     234          497 :     Q = NULL;
     235          497 :     if (v2)
     236              :     {
     237          371 :       if (B>>v2 == 1)
     238          322 :         P = gel(p, B);
     239              :       else
     240           49 :         P = elladd(E, gel(p, B>>v2), gel(p,1<<v2));
     241              :     }
     242          126 :     else P = gel(p, B);
     243              :   }
     244          616 :   return tors(E,B, P, Q, v);
     245              : }
     246              : 
     247              : /* either return one prime of degree 1 above p or NULL (none or expensive) */
     248              : static GEN
     249       227213 : primedec_deg1(GEN K, GEN p)
     250              : {
     251       227213 :   GEN r, T, f = nf_get_index(K);
     252       227213 :   if (dvdii(f,p)) return NULL;
     253       227136 :   T = nf_get_pol(K);
     254       227136 :   r = FpX_oneroot(T, p); if (!r) return NULL;
     255       135387 :   r = deg1pol_shallow(gen_1, Fp_neg(r,p), varn(T));
     256       135387 :   return idealprimedec_kummer(K, r, 1, p);
     257              : }
     258              : 
     259              : /* Bound for the elementary divisors of the torsion group of elliptic curve
     260              :  * (p-Sylow if psylow = p is not 0)
     261              :  * Reduce the curve modulo some small good primes */
     262              : static GEN
     263        29148 : nftorsbound(GEN E, ulong psylow)
     264              : {
     265              :   pari_sp av;
     266        29148 :   long k = 0, g;
     267        29148 :   GEN B1 = gen_0, B2 = gen_0, K = ellnf_get_nf(E);
     268        29148 :   GEN D = ell_get_disc(E), ND = idealnorm(K,D);
     269              :   forprime_t S;
     270        29148 :   if (typ(ND) == t_FRAC) ND = gel(ND,1);
     271        29148 :   ND = mulii(ND, Q_denom(vecslice(E,1,5)));
     272        29148 :   g = maxss(5, expi(ND) >> 3);
     273        29148 :   if (g > 20) g = 20;
     274              :   /* P | p such that e(P/p) < p-1 => E(K) injects in E(k(P)) [otherwise
     275              :    * we may lose some p-torsion]*/
     276        29148 :   (void)u_forprime_init(&S, 3, ULONG_MAX);
     277        29148 :   av = avma;
     278       229096 :   while (k < g) /* k = number of good primes already used */
     279              :   {
     280       225043 :     ulong p = u_forprime_next(&S);
     281              :     GEN P, gp;
     282              :     long j, l;
     283       225043 :     if (!umodiu(ND,p)) continue;
     284       171745 :     gp = utoipos(p);
     285              :     /* primes of degree 1 are easier and give smaller bounds */
     286       171745 :     if (typ(D) != t_POLMOD) /* E/Q */
     287              :     {
     288       169162 :       P = primedec_deg1(K, gp); /* single P|p has all the information */
     289       169162 :       if (!P) continue;
     290       106428 :       P = mkvec(P);
     291              :     }
     292              :     else
     293         2583 :       P = idealprimedec_limit_f(K, utoipos(p), 1);
     294       109011 :     l = lg(P);
     295       192164 :     for (j = 1; j < l; j++,k++)
     296              :     {
     297       108248 :       GEN Q = gel(P,j), EQ, cyc;
     298              :       long n;
     299       108248 :       if ((ulong)pr_get_e(Q) >= p-1) continue;
     300       108248 :       EQ = ellinit(E,zkmodprinit(K,Q),0);
     301       108248 :       cyc = ellgroup(EQ, NULL);
     302       108248 :       n = lg(cyc)-1;
     303       108248 :       if (n == 0) return mkvec2(gen_1,gen_1);
     304       108241 :       B1 = gcdii(B1,gel(cyc,1));
     305       108241 :       B2 = (n == 1)? gen_1: gcdii(B2,gel(cyc,2));
     306       108241 :       obj_free(EQ);
     307              :       /* division by 2 is cheap when it fails, no need to have a sharp bound */
     308       108241 :       if (psylow==0 && Z_ispow2(B1)) return mkvec2(B1,B2);
     309              :     }
     310        83916 :     if ((g & 15) == 0) (void)gc_all(av, 2, &B1, &B2);
     311              :   }
     312         4053 :   if (abscmpiu(B2, 2) > 0)
     313              :   { /* if E(K) has full n-torsion then K contains the n-th roots of 1 */
     314           91 :     GEN n = gel(nfrootsof1(K), 1);
     315           91 :     B2 = gcdii(B2,n);
     316              :   }
     317         4053 :   if (psylow)
     318              :   {
     319            0 :     B1 = powuu(psylow, Z_lval(B1, psylow));
     320            0 :     B2 = powuu(psylow, Z_lval(B2, psylow));
     321              :   }
     322         4053 :   return mkvec2(B1,B2);
     323              : }
     324              : 
     325              : /* Checks whether the point P != oo is divisible by n in E(K), where xn is
     326              :  * [phi_n, psi_n^2]. If so, returns a point Q such that nQ = P or -P.
     327              :  * Else, returns NULL */
     328              : static GEN
     329          364 : ellnfis_divisible_by(GEN E, GEN K, GEN P, GEN xn)
     330              : {
     331          364 :   GEN R = nfroots(K, RgX_sub(RgX_Rg_mul(gel(xn,2), gel(P,1)), gel(xn,1)));
     332          364 :   long i, l = lg(R);
     333          364 :   for (i = 1; i < l; i++)
     334              :   {
     335          252 :     GEN x = gel(R,i), y = ellordinate(E,x,0);
     336          252 :     if (lg(y) != 1) return mkvec2(x, gel(y,1));
     337              :   }
     338          112 :   return NULL;
     339              : }
     340              : 
     341              : /* Q is not the point at infinity; do we have Q = [n]Q' on curve C/K ?
     342              :  * return P such that [n] P = \pm Q or NULL if none exist */
     343              : static GEN
     344           49 : ellnfis_divisible_by_i(GEN C, GEN K, GEN Q, GEN n, long v)
     345              : {
     346              :   GEN xn;
     347           49 :   if (!isprimepower(absi_shallow(n), NULL))
     348              :   {
     349           14 :     GEN f = absZ_factor(n), P = gel(f,1), E = gel(f,2);
     350           14 :     long i, l = lg(P);
     351           14 :     for (i = 1; i < l; i++)
     352              :     {
     353            0 :       GEN q = powii(gel(P,i), gel(E,i));
     354            0 :       xn = ellxn(C, itou(q), v);
     355            0 :       if (!(Q = ellnfis_divisible_by(C, K, Q, xn))) return 0;
     356              :     }
     357           14 :     return Q;
     358              :   }
     359           35 :   xn = ellxn(C, itou(n), v);
     360           35 :   return ellnfis_divisible_by(C, K, Q, xn);
     361              : }
     362              : 
     363              : static GEN ellorder_nf(GEN E, GEN P, GEN B);
     364              : long
     365          273 : ellisdivisible(GEN E, GEN Q, GEN n, GEN *pQ)
     366              : {
     367          273 :   pari_sp av = avma;
     368          273 :   GEN P = NULL, N = NULL, K = NULL;
     369              :   long v;
     370              : 
     371          273 :   checkell(E);
     372          273 :   if (!checkellpt_i(Q)) pari_err_TYPE("ellisdivisible",Q);
     373          273 :   switch(ell_get_type(E))
     374              :   {
     375          252 :     case t_ELL_Q: break;
     376           21 :     case t_ELL_NF: K = ellnf_get_nf(E); break;
     377            0 :     default: pari_err_TYPE("ellisdivisible",E);
     378              :   }
     379          273 :   if (ell_is_inf(Q))
     380              :   {
     381            7 :     if (pQ) *pQ = ellinf();
     382            7 :     return 1;
     383              :   }
     384          266 :   switch(typ(n))
     385              :   {
     386          126 :     case t_INT:
     387          126 :       if (!signe(n)) return 0;
     388          119 :       if (is_bigint(n))
     389              :       { /* only possible if P is torsion */
     390           28 :         GEN x, o, ex = cyc_get_expo(abgrp_get_cyc(elltors(E)));
     391           28 :         if (equali1(ex)) return gc_long(av, 0);
     392           28 :         o = K? ellorder_nf(E, Q, ex): ellorder(E, Q, NULL);
     393           28 :         if (isintzero(o)) return gc_long(av, 0);
     394           21 :         x = Z_ppo(n, o);
     395           21 :         Q = ellmul(E, Q, Fp_inv(x, o));
     396           21 :         n = diviiexact(n, x); /* all primes dividing n divide o = ord(Q) | ex */
     397           21 :         if (!dvdii(diviiexact(ex,o), n)) return gc_long(av, 0);
     398            7 :         if (is_bigint(n)) pari_err_IMPL("ellisdivisible for huge torsion");
     399            7 :         if (!ellisdivisible(E, Q, n, pQ)) return gc_long(av, 0);
     400            7 :         if (!pQ) return gc_long(av, 1);
     401            0 :         *pQ = gc_GEN(av, *pQ); return 1;
     402              :       }
     403           91 :       if (!K)
     404              :       { /* could use elltors instead of a multiple ? */
     405           70 :         ulong nn = itou(n), n2 = u_ppo(nn, torsbound(E, 0));
     406           70 :         if (n2 > 1)
     407              :         { /* n2 coprime to torsion */
     408           42 :           if (!(Q = ellQ_isdivisible(E, Q, n2))) return 0;
     409           28 :           if (signe(n) < 0) Q = ellneg(E, Q);
     410           28 :           if (nn == n2)
     411              :           {
     412           28 :             if (pQ) *pQ = Q;
     413           28 :             return 1;
     414              :           }
     415              :           /* we may have changed n into |n/n2| (and Q in -Q if n < 0) */
     416            0 :           n = utoipos(nn/n2);
     417              :         }
     418              :       }
     419           49 :       v = fetch_var_higher();
     420           49 :       P = ellnfis_divisible_by_i(E, K, Q, n, v);
     421           49 :       delete_var(); N = n; break;
     422          140 :     case t_VEC:
     423          140 :       if (lg(n) == 3 && typ(gel(n,1)) == t_POL && typ(gel(n,2)) == t_POL)
     424              :       { /* ellxn */
     425          140 :         long d, d2 = degpol(gel(n,1));
     426          140 :         if (d2 < 0) return gc_long(av, 0);
     427          140 :         if (!uissquareall(d2,(ulong*)&d)) pari_err_TYPE("ellisdivisible",n);
     428          140 :         P = ellnfis_divisible_by(E, K, Q, n);
     429          140 :         N = utoi(d); break;
     430              :       } /* fall through */
     431              :     default:
     432            0 :       pari_err_TYPE("ellisdivisible",n);
     433            0 :       break;
     434              :   }
     435          189 :   if (!P) return gc_long(av, 0);
     436          154 :   if (!pQ) return gc_long(av, 1);
     437          133 :   if (gequal(Q, ellmul(E, P, N)))
     438           70 :     P = gc_GEN(av, P);
     439              :   else
     440           63 :     P = gc_upto(av, ellneg(E, P));
     441          133 :   *pQ = P; return 1;
     442              : }
     443              : 
     444              : /* 2-torsion point of abscissa x */
     445              : static GEN
     446          126 : tor2(GEN E, GEN x) { return mkvec2(x, gmul2n(gneg(ec_h_evalx(E,x)), -1)); }
     447              : 
     448              : static GEN
     449           35 : ptor0(void)
     450           35 : { return mkvec2(mkvec(gen_1),cgetg(1,t_VEC)); }
     451              : static GEN
     452          126 : ptor1(long p, long n, GEN P)
     453          126 : { return mkvec2(mkvec(powuu(p,n)), mkvec(P)); }
     454              : static GEN
     455           98 : ptor2(long p, long n1, long n2, GEN P1, GEN P2)
     456           98 : { return mkvec2(mkvec2(powuu(p,n1), powuu(p,n2)), mkvec2(P1,P2)); }
     457              : 
     458              : /* Computes the p-primary torsion in E(K). Assume that p is small, should use
     459              :  * Weil pairing otherwise.
     460              :  * N1, N2 = upper bounds on the integers n1 >= n2 such that
     461              :  * E(K)[p^oo] = Z/p^n1 x Z/p^n2
     462              :  * Returns [cyc,gen], where E(K)[p^oo] = sum Z/cyc[i] gen[i] */
     463              : static GEN
     464          259 : ellnftorsprimary(GEN E, long p, long N1, long N2, long v)
     465              : {
     466          259 :   GEN X, P1, P2, Q1, Q2, xp, K = ellnf_get_nf(E);
     467              :   long n1, n2;
     468              : 
     469              :   /* compute E[p] = < P1 > or < P1, P2 > */
     470          259 :   X = nfroots(K, elldivpol(E,p,v));
     471          259 :   if (lg(X) == 1) return ptor0();
     472          231 :   P2 = ellinf();
     473          231 :   if (p==2)
     474              :   {
     475           77 :     P1 = tor2(E, gel(X,1));
     476           77 :     if (lg(X) > 2) P2 = tor2(E, gel(X,2)); /* E[2] = (Z/2Z)^2 */
     477              :   }
     478              :   else
     479              :   {
     480          154 :     long j, l = lg(X), nT, a;
     481          154 :     GEN T = vectrunc_init(l);
     482          539 :     for(j=1; j < l; j++)
     483              :     {
     484          385 :       GEN a = gel(X,j), Y = ellordinate(E,a,0);
     485          385 :       if (lg(Y) != 1) vectrunc_append(T, mkvec2(a,gel(Y,1)));
     486              :     }
     487          154 :     nT = lg(T)-1;
     488          154 :     if (!nT) return ptor0();
     489          147 :     P1 = gel(T,1);
     490          147 :     a = (p-1)/2;
     491          147 :     if (nT != a)
     492              :     { /* E[p] = (Z/pZ)^2 */
     493           49 :       GEN Z = cgetg(a+1,t_VEC), Q1 = P1;
     494              :       long k;
     495           49 :       gel(Z,1) = Q1;
     496           49 :       for (k=2; k <= a; k++) gel(Z,k) = elladd(E,Q1,P1);
     497           49 :       gen_sort_inplace(Z, (void*)&cmp_universal, &cmp_nodata, NULL);
     498           49 :       while (tablesearch(Z, gel(T,k), &cmp_universal)) k++;
     499           49 :       P2 = gel(T,k);
     500              :     }
     501              :   }
     502          224 :   xp = ellxn(E, p, v);
     503              : 
     504          224 :   if (ell_is_inf(P2))
     505              :   { /* E[p^oo] is cyclic, start from P1 and divide by p while possible */
     506          140 :     for (n1 = 1; n1 < N1; n1++)
     507              :     {
     508           14 :       GEN Q = ellnfis_divisible_by(E,K,P1,xp);
     509           14 :       if (!Q) break;
     510           14 :       P1 = Q;
     511              :     }
     512          126 :     return ptor1(p, n1, P1);
     513              :   }
     514              : 
     515              :   /* E[p] = (Z/pZ)^2, compute n2 and E[p^n2] */
     516           98 :   Q1 = NULL;
     517          119 :   for (n2 = 1; n2 < N2; n2++)
     518              :   {
     519           21 :     Q1 = ellnfis_divisible_by(E,K,P1,xp);
     520           21 :     Q2 = ellnfis_divisible_by(E,K,P2,xp);
     521           21 :     if (!Q1 || !Q2) break;
     522           21 :     P1 = Q1;
     523           21 :     P2 = Q2;
     524              :   }
     525              : 
     526              :   /* compute E[p^oo] = < P1, P2 > */
     527           98 :   n1 = n2;
     528           98 :   if (n2 == N2)
     529              :   {
     530           98 :     if (N1 == N2) return ptor2(p, n2,n2, P1,P2);
     531           42 :     Q1 = ellnfis_divisible_by(E,K,P1,xp);
     532              :   }
     533           42 :   if (Q1) { P1 = Q1; n1++; }
     534              :   else
     535              :   {
     536           28 :     Q2 = ellnfis_divisible_by(E,K,P2,xp);
     537           28 :     if (Q2) { P2 = P1; P1 = Q2; n1++; }
     538              :     else
     539              :     {
     540              :       long k;
     541           35 :       for (k = 1; k < p; k++)
     542              :       {
     543           28 :         P1 = elladd(E,P1,P2);
     544           28 :         Q1 = ellnfis_divisible_by(E,K,P1,xp);
     545           28 :         if (Q1) { P1 = Q1; n1++; break; }
     546              :       }
     547           28 :       if (k == p) return ptor2(p, n2,n2, P1,P2);
     548              :     }
     549              :   }
     550              :   /* P1,P2 of order p^n1,p^n2 with n1=n2+1.
     551              :    * Keep trying to divide P1 + k P2 with 0 <= k < p by p */
     552           56 :   while (n1 < N1)
     553              :   {
     554           21 :     Q1 = ellnfis_divisible_by(E,K,P1,xp);
     555           21 :     if (Q1) { P1 = Q1; n1++; }
     556              :     else
     557              :     {
     558              :       long k;
     559           14 :       for (k = 1; k < p; k++)
     560              :       {
     561           14 :         P1 = elladd(E,P1,P2);
     562           14 :         Q1 = ellnfis_divisible_by(E,K,P1,xp);
     563           14 :         if (Q1) { P1 = Q1; n1++; break; }
     564              :       }
     565           14 :       if (k == p) break;
     566              :     }
     567              :   }
     568           35 :   return ptor2(p, n1,n2, P1,P2);
     569              : }
     570              : 
     571              : /* P affine point */
     572              : static GEN
     573          259 : nfpt(GEN e, GEN P)
     574              : {
     575          259 :   GEN T = nf_get_pol(ellnf_get_nf(e));
     576          259 :   GEN x = gel(P,1), y = gel(P,2);
     577          259 :   long tx = typ(x), ty = typ(y);
     578          259 :   if (tx == ty) return P;
     579           98 :   if (tx != t_POLMOD) x = mkpolmod(x,T); else y = mkpolmod(y,T);
     580           98 :   return mkvec2(x,y);
     581              : }
     582              : /* Computes the torsion subgroup of E(K), as [order, cyc, gen] */
     583              : static GEN
     584          189 : ellnftors(GEN e, ulong psylow)
     585              : {
     586          189 :   GEN B = nftorsbound(e, psylow), B1 = gel(B,1), B2 = gel(B,2), d1,d2, P1,P2;
     587          189 :   GEN f = Z_factor(B1), P = gel(f,1), E = gel(f,2);
     588          189 :   long i, l = lg(P), v = fetch_var_higher();
     589              : 
     590          189 :   d1 = d2 = gen_1; P1 = P2 = ellinf();
     591          448 :   for (i=1; i<l; i++)
     592              :   {
     593          259 :     long p = itos(gel(P,i)); /* Compute p-primary torsion */
     594          259 :     long N1 = itos(gel(E,i)); /* >= n1 */
     595          259 :     long N2 = Z_lval(B2,p); /* >= n2 */
     596          259 :     GEN T = ellnftorsprimary(e, p, N1, N2, v), cyc = gel(T,1), gen = gel(T,2);
     597          259 :     if (is_pm1(gel(cyc,1))) continue;
     598              :     /* update generators P1,P2 and their respective orders d1,d2 */
     599          224 :     P1 = elladd(e, P1, gel(gen,1)); d1 = mulii(d1, gel(cyc,1));
     600          224 :     if (lg(cyc) > 2)
     601           98 :     { P2 = elladd(e, P2, gel(gen,2)); d2 = mulii(d2, gel(cyc,2)); }
     602              :   }
     603          189 :   (void)delete_var();
     604          189 :   if (is_pm1(d1)) return mkvec3(gen_1,cgetg(1,t_VEC),cgetg(1,t_VEC));
     605          168 :   if (is_pm1(d2)) return mkvec3(d1, mkvec(d1), mkvec(nfpt(e,P1)));
     606           91 :   return mkvec3(mulii(d1,d2), mkvec2(d1,d2), mkvec2(nfpt(e,P1),nfpt(e,P2)));
     607              : }
     608              : 
     609              : GEN
     610          497 : elltors(GEN e)
     611              : {
     612          497 :   pari_sp av = avma;
     613          497 :   GEN t = NULL;
     614          497 :   checkell(e);
     615          497 :   switch(ell_get_type(e))
     616              :   {
     617          308 :     case t_ELL_Q:  t = ellQtors(e, 0); break;
     618          189 :     case t_ELL_NF: t = ellnftors(e, 0); break;
     619            0 :     case t_ELL_Fp:
     620            0 :     case t_ELL_Fq: return ellgroup0(e,NULL,1);
     621            0 :     default: pari_err_TYPE("elltors",e);
     622              :   }
     623          497 :   return gc_GEN(av, t);
     624              : }
     625              : 
     626              : GEN
     627            0 : elltors0(GEN e, long flag) { (void)flag; return elltors(e); }
     628              : 
     629              : GEN
     630         1953 : elltors_psylow(GEN e, ulong p)
     631              : {
     632         1953 :   pari_sp av = avma;
     633         1953 :   GEN t = NULL;
     634         1953 :   checkell(e);
     635         1953 :   switch(ell_get_type(e))
     636              :   {
     637         1953 :     case t_ELL_Q:  t = ellQtors(e, p); break;
     638            0 :     case t_ELL_NF: t = ellnftors(e, p); break;
     639            0 :     default: pari_err_TYPE("elltors_psylow",e);
     640              :   }
     641         1953 :   return gc_GEN(av, t);
     642              : }
     643              : 
     644              : /********************************************************************/
     645              : /**                                                                **/
     646              : /**                ORDER OF POINTS over NUMBER FIELDS              **/
     647              : /**                                                                **/
     648              : /********************************************************************/
     649              : /* E a t_ELL_Q (use Mazur's theorem) */
     650              : long
     651        52683 : ellorder_Q(GEN E, GEN P)
     652              : {
     653        52683 :   pari_sp av = avma;
     654              :   GEN dx, dy, d4, d6, D, Pp, Q;
     655              :   forprime_t S;
     656              :   ulong a4, p;
     657              :   long k;
     658        52683 :   if (ell_is_inf(P)) return 1;
     659        52683 :   if (gequal(P, ellneg(E,P))) return 2;
     660              : 
     661        52662 :   dx = Q_denom(gel(P,1));
     662        52662 :   dy = Q_denom(gel(P,2));
     663        52662 :   if (ell_is_integral(E)) /* integral model, try Nagell Lutz */
     664        52599 :     if (abscmpiu(dx, 4) > 0 || abscmpiu(dy, 8) > 0) return 0;
     665              : 
     666        35277 :   d4 = Q_denom(ell_get_c4(E));
     667        35277 :   d6 = Q_denom(ell_get_c6(E));
     668        35277 :   D = ell_get_disc (E);
     669              :   /* choose not too small prime p dividing neither a coefficient of the
     670              :      short Weierstrass form nor of P and leading to good reduction */
     671        35277 :   u_forprime_init(&S, 100003, ULONG_MAX);
     672        35277 :   while ( (p = u_forprime_next(&S)) )
     673        35277 :     if (umodiu(d4, p) && umodiu(d6, p) && Rg_to_Fl(D, p)
     674        35277 :      && umodiu(dx, p) && umodiu(dy, p)) break;
     675              : 
     676              :   /* transform E into short Weierstrass form Ep modulo p and P to Pp on Ep,
     677              :    * check whether the order of Pp on Ep is <= 12 */
     678        35277 :   Pp = point_to_a4a6_Fl(E, P, p, &a4);
     679        35277 :   for (Q = Fle_dbl(Pp, a4, p), k = 2;
     680       422708 :        !ell_is_inf(Q) && k <= 12;
     681       387431 :        Q = Fle_add(Q, Pp, a4, p), k++) /* empty */;
     682              : 
     683        35277 :   if (k == 13) k = 0;
     684              :   else
     685              :   { /* check whether [k]P = O over Q. Save potentially costly last elladd */
     686              :     GEN R;
     687           84 :     Q = ellmul(E, P, utoipos(k>>1));
     688           84 :     R = odd(k)? elladd(E, P,Q): Q;
     689           84 :     if (!gequal(Q, ellneg(E,R))) k = 0;
     690              :   }
     691        35277 :   return gc_long(av,k);
     692              : }
     693              : /* E a t_ELL_NF, B a multiplicative bound for exponent(E_tor) or NULL */
     694              : static GEN
     695        28994 : ellorder_nf(GEN E, GEN P, GEN B)
     696              : {
     697        28994 :   GEN K = ellnf_get_nf(E);
     698        28994 :   pari_sp av = avma;
     699              :   GEN dx, dy, d4, d6, D, ND, Ep, Pp, Q, gp, modpr, pr, T, k;
     700              :   forprime_t S;
     701              :   ulong a4, p;
     702        28994 :   if (ell_is_inf(P)) return gen_1;
     703        28994 :   if (gequal(P, ellneg(E,P))) return gen_2;
     704              : 
     705        28959 :   if (!B) B = gel(nftorsbound(E, 0), 1);
     706        28959 :   dx = Q_denom(gel(P,1));
     707        28959 :   dy = Q_denom(gel(P,2));
     708        28959 :   d4 = Q_denom(ell_get_c4(E));
     709        28959 :   d6 = Q_denom(ell_get_c6(E));
     710        28959 :   D = ell_get_disc(E);
     711        28959 :   ND = idealnorm(K,D);
     712        28959 :   if (typ(ND) == t_FRAC) ND = gel(ND,1);
     713              : 
     714              :   /* choose not too small prime p of degree 1 dividing neither a coefficient of
     715              :    * the short Weierstrass form nor of P and leading to good reduction */
     716        28959 :   u_forprime_init(&S, 100003, ULONG_MAX);
     717        58051 :   while ( (p = u_forprime_next(&S)) )
     718              :   {
     719        58051 :     if (!umodiu(d4, p) || !umodiu(d6, p) || !umodiu(ND, p)
     720        58051 :      || !umodiu(dx, p) || !umodiu(dy, p)) continue;
     721        58051 :     gp = utoipos(p);
     722        58051 :     pr = primedec_deg1(K, gp);
     723        58051 :     if (pr) break;
     724              :   }
     725              : 
     726        28959 :   modpr = nf_to_Fq_init(K, &pr,&T,&gp);
     727        28959 :   Ep = ellinit(E, pr, 0);
     728        28959 :   Pp = nfV_to_FqV(P, K, modpr);
     729              : 
     730              :   /* transform E into short Weierstrass form Ep modulo p and P to Pp on Ep,
     731              :    * check whether the order of Pp on Ep divides B */
     732        28959 :   Pp = point_to_a4a6_Fl(Ep, Pp, p, &a4);
     733        28959 :   if (!ell_is_inf(Fle_mul(Pp, B, a4, p))) { set_avma(av); return gen_0; }
     734          147 :   k = Fle_order(Pp, B, a4, p);
     735              :   { /* check whether [k]P = O over K. Save potentially costly last elladd */
     736              :     GEN R;
     737          147 :     Q = ellmul(E, P, shifti(k,-1));
     738          147 :     R = mod2(k)? elladd(E, P,Q): Q;
     739          147 :     if (!gequal(Q, ellneg(E,R))) k = gen_0;
     740              :   }
     741          147 :   return gc_INT(av, k);
     742              : }
     743              : 
     744              : GEN
     745        31591 : ellorder(GEN E, GEN P, GEN o)
     746              : {
     747        31591 :   pari_sp av = avma;
     748        31591 :   GEN fg, r, E0 = E;
     749        31591 :   checkell(E);
     750        31591 :   if (!checkellpt_i(P)) pari_err_TYPE("ellorder",P);
     751        31591 :   if (ell_is_inf(P)) return gen_1;
     752        31577 :   if (ell_get_type(E)==t_ELL_Q)
     753              :   {
     754         1932 :     long tx = typ(gel(P,1)), ty = typ(gel(P,2));
     755         1932 :     GEN p = NULL;
     756         1932 :     if (is_rational_t(tx) && is_rational_t(ty)) return utoi(ellorder_Q(E, P));
     757         1778 :     if (tx == t_INTMOD || tx == t_FFELT) p = gel(P,1);
     758         1778 :     if (!p && (ty == t_INTMOD || ty == t_FFELT)) p = gel(P,2);
     759         1778 :     if (p)
     760              :     {
     761         1778 :       E = ellinit(E,p,0);
     762         1778 :       if (lg(E)==1) pari_err_IMPL("ellorder for curve with singular reduction");
     763              :     }
     764              :   }
     765        31416 :   if (ell_get_type(E)==t_ELL_NF) return ellorder_nf(E, P, NULL);
     766         2422 :   checkell_Fq(E);
     767         2422 :   fg = ellff_get_field(E);
     768         2422 :   if (!o) o = ellff_get_o(E);
     769         2422 :   if (typ(fg)==t_FFELT)
     770         1764 :     r = FF_ellorder(E, P, o);
     771              :   else
     772              :   {
     773          658 :     GEN p = fg, e = ellff_get_a4a6(E);
     774          658 :     GEN Pp = FpE_changepointinv(RgE_to_FpE(P,p), gel(e,3), p);
     775          658 :     r = FpE_order(Pp, o, gel(e,1), p);
     776              :   }
     777         2422 :   if (E != E0) obj_free(E);
     778         2422 :   return gc_INT(av, r);
     779              : }
     780              : 
     781              : GEN
     782            0 : orderell(GEN e, GEN z) { return ellorder(e,z,NULL); }
        

Generated by: LCOV version 2.0-1