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 - F2xqE.c (source / functions) Coverage Total Hit
Test: PARI/GP v2.18.1 lcov report (development 31042-0fbe168e69) Lines: 93.5 % 478 447
Test Date: 2026-07-23 17:04:59 Functions: 93.3 % 60 56
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Copyright (C) 2012  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              : #include "pari.h"
      16              : #include "paripriv.h"
      17              : 
      18              : #define DEBUGLEVEL DEBUGLEVEL_ellcard
      19              : 
      20              : /* Not so fast arithmetic with points over elliptic curves over F_2^n */
      21              : 
      22              : /***********************************************************************/
      23              : /**                                                                   **/
      24              : /**                              F2xqE                                **/
      25              : /**                                                                   **/
      26              : /***********************************************************************/
      27              : /* These functions deal with points over elliptic curves over F_2^n defined
      28              :  * by an equation of the form:
      29              :  *  y^2+x*y = x^3+a_2*x^2+a_6 if the curve is ordinary.
      30              :  *  y^2+a_3*y = x^3+a_4*x+a_6 if the curve is supersingular.
      31              :  * Most of the time a6 is omitted since it can be recovered from any point
      32              :  * on the curve.
      33              :  * For supersingular curves, the parameter a2 is replaced by [a3,a4,a3^-1]. */
      34              : 
      35              : GEN
      36        10360 : RgE_to_F2xqE(GEN x, GEN T)
      37              : {
      38        10360 :   if (ell_is_inf(x)) return x;
      39         9877 :   retmkvec2(Rg_to_F2xq(gel(x,1),T),Rg_to_F2xq(gel(x,2),T));
      40              : }
      41              : 
      42              : GEN
      43       171794 : F2xqE_changepoint(GEN x, GEN ch, GEN T)
      44              : {
      45       171794 :   pari_sp av = avma;
      46              :   GEN p1,z,u,r,s,t,v,v2,v3;
      47       171794 :   if (ell_is_inf(x)) return x;
      48       171794 :   u = gel(ch,1); r = gel(ch,2);
      49       171794 :   s = gel(ch,3); t = gel(ch,4);
      50       171794 :   v = F2xq_inv(u, T); v2 = F2xq_sqr(v, T); v3 = F2xq_mul(v,v2, T);
      51       171794 :   p1 = F2x_add(gel(x,1),r);
      52       171794 :   z = cgetg(3,t_VEC);
      53       171794 :   gel(z,1) = F2xq_mul(v2, p1, T);
      54       171794 :   gel(z,2) = F2xq_mul(v3, F2x_add(gel(x,2), F2x_add(F2xq_mul(s, p1, T),t)), T);
      55       171794 :   return gc_upto(av, z);
      56              : }
      57              : 
      58              : GEN
      59        10360 : F2xqE_changepointinv(GEN x, GEN ch, GEN T)
      60              : {
      61              :   GEN u, r, s, t, X, Y, u2, u3, u2X, z;
      62        10360 :   if (ell_is_inf(x)) return x;
      63         9877 :   X = gel(x,1); Y = gel(x,2);
      64         9877 :   u = gel(ch,1); r = gel(ch,2);
      65         9877 :   s = gel(ch,3); t = gel(ch,4);
      66         9877 :   u2 = F2xq_sqr(u, T); u3 = F2xq_mul(u,u2, T);
      67         9877 :   u2X = F2xq_mul(u2,X, T);
      68         9877 :   z = cgetg(3, t_VEC);
      69         9877 :   gel(z,1) = F2x_add(u2X,r);
      70         9877 :   gel(z,2) = F2x_add(F2xq_mul(u3,Y, T), F2x_add(F2xq_mul(s,u2X, T), t));
      71         9877 :   return z;
      72              : }
      73              : 
      74              : static GEN
      75         3514 : nonzerotrace_F2xq(GEN T)
      76              : {
      77         3514 :   pari_sp av = avma;
      78         3514 :   long n = F2x_degree(T), vs = T[1];
      79              :   GEN a;
      80         3514 :   if (odd(n))
      81         1162 :     return pol1_F2x(vs);
      82              :   do
      83              :   {
      84         4668 :     set_avma(av);
      85         4668 :     a = random_F2x(n, vs);
      86         4668 :   } while (F2xq_trace(a, T)==0);
      87         2352 :   return a;
      88              : }
      89              : 
      90              : void
      91         3514 : F2xq_elltwist(GEN a, GEN a6, GEN T, GEN *pt_a, GEN *pt_a6)
      92              : {
      93         3514 :   pari_sp av = avma;
      94         3514 :   GEN n = nonzerotrace_F2xq(T);
      95         3514 :   if (typ(a)==t_VECSMALL)
      96              :   {
      97         3514 :     *pt_a = gc_leaf(av, F2x_add(n, a));
      98         3514 :     *pt_a6 = vecsmall_copy(a6);
      99              :   } else
     100              :   {
     101            0 :     GEN a6t = F2x_add(a6, F2xq_mul(n, F2xq_sqr(gel(a,1), T), T));
     102            0 :     *pt_a6 = gc_leaf(av, a6t);
     103            0 :     *pt_a = vecsmall_copy(a);
     104              :   }
     105         3514 : }
     106              : 
     107              : static GEN
     108       120660 : F2xqE_dbl_slope(GEN P, GEN a, GEN T, GEN *slope)
     109              : {
     110              :   GEN x, y, Q;
     111       120660 :   if (ell_is_inf(P)) return ellinf();
     112       119723 :   x = gel(P,1); y = gel(P,2);
     113       119723 :   if (typ(a)==t_VECSMALL)
     114              :   {
     115        99661 :     GEN a2 = a;
     116        99661 :     if (!lgpol(gel(P,1))) { *slope = NULL; return ellinf(); }
     117        95747 :     *slope = F2x_add(x, F2xq_div(y, x, T));
     118        95747 :     Q = cgetg(3,t_VEC);
     119        95747 :     gel(Q, 1) = F2x_add(F2xq_sqr(*slope, T), F2x_add(*slope, a2));
     120        95747 :     gel(Q, 2) = F2x_add(F2xq_mul(*slope, F2x_add(x, gel(Q, 1)), T), F2x_add(y, gel(Q, 1)));
     121              :   }
     122              :   else
     123              :   {
     124        20062 :     GEN a3 = gel(a,1), a4 = gel(a,2), a3i = gel(a,3);
     125        20062 :     *slope = F2xq_mul(F2x_add(a4, F2xq_sqr(x, T)), a3i, T);
     126        20062 :     Q = cgetg(3,t_VEC);
     127        20062 :     gel(Q, 1) = F2xq_sqr(*slope, T);
     128        20062 :     gel(Q, 2) = F2x_add(F2xq_mul(*slope, F2x_add(x, gel(Q, 1)), T), F2x_add(y, a3));
     129              :   }
     130       115809 :   return Q;
     131              : }
     132              : 
     133              : GEN
     134       103686 : F2xqE_dbl(GEN P, GEN a, GEN T)
     135              : {
     136       103686 :   pari_sp av = avma;
     137              :   GEN slope;
     138       103686 :   return gc_upto(av, F2xqE_dbl_slope(P, a, T,&slope));
     139              : }
     140              : 
     141              : static GEN
     142        37656 : F2xqE_add_slope(GEN P, GEN Q, GEN a, GEN T, GEN *slope)
     143              : {
     144              :   GEN Px, Py, Qx, Qy, R;
     145        37656 :   if (ell_is_inf(P)) { *slope = NULL; return Q; }
     146        37160 :   if (ell_is_inf(Q)) { *slope = NULL; return P; }
     147        37160 :   Px = gel(P,1); Py = gel(P,2);
     148        37160 :   Qx = gel(Q,1); Qy = gel(Q,2);
     149        37160 :   if (F2x_equal(Px, Qx))
     150              :   {
     151         2108 :     if (F2x_equal(Py, Qy))
     152           77 :       return F2xqE_dbl_slope(P, a, T, slope);
     153              :     else
     154         2031 :       { *slope = NULL; return ellinf(); }
     155              :   }
     156        35052 :   *slope = F2xq_div(F2x_add(Py, Qy), F2x_add(Px, Qx), T);
     157        35052 :   R = cgetg(3,t_VEC);
     158        35052 :   if (typ(a)==t_VECSMALL)
     159              :   {
     160        33687 :     GEN a2 = a;
     161        33687 :     gel(R, 1) = F2x_add(F2x_add(F2x_add(F2x_add(F2xq_sqr(*slope, T), *slope), Px), Qx), a2);
     162        33687 :     gel(R, 2) = F2x_add(F2xq_mul(*slope, F2x_add(Px, gel(R, 1)), T), F2x_add(Py, gel(R, 1)));
     163              :   }
     164              :   else
     165              :   {
     166         1365 :     GEN a3 = gel(a,1);
     167         1365 :     gel(R, 1) = F2x_add(F2x_add(F2xq_sqr(*slope, T), Px), Qx);
     168         1365 :     gel(R, 2) = F2x_add(F2xq_mul(*slope, F2x_add(Px, gel(R, 1)), T), F2x_add(Py, a3));
     169              :   }
     170        35052 :   return R;
     171              : }
     172              : 
     173              : GEN
     174        37621 : F2xqE_add(GEN P, GEN Q, GEN a, GEN T)
     175              : {
     176        37621 :   pari_sp av = avma;
     177              :   GEN slope;
     178        37621 :   return gc_upto(av, F2xqE_add_slope(P, Q, a, T, &slope));
     179              : }
     180              : 
     181              : static GEN
     182            0 : F2xqE_neg_i(GEN P, GEN a)
     183              : {
     184              :   GEN LHS;
     185            0 :   if (ell_is_inf(P)) return P;
     186            0 :   LHS = typ(a)==t_VECSMALL ? gel(P,1): gel(a,1);
     187            0 :   return mkvec2(gel(P,1), F2x_add(LHS, gel(P,2)));
     188              : }
     189              : 
     190              : GEN
     191           84 : F2xqE_neg(GEN P, GEN a, GEN T)
     192              : {
     193              :   GEN LHS;
     194              :   (void) T;
     195           84 :   if (ell_is_inf(P)) return ellinf();
     196           84 :   LHS = typ(a)==t_VECSMALL ? gel(P,1): gel(a,1);
     197           84 :   return mkvec2(gcopy(gel(P,1)), F2x_add(LHS, gel(P,2)));
     198              : }
     199              : 
     200              : GEN
     201            0 : F2xqE_sub(GEN P, GEN Q, GEN a2, GEN T)
     202              : {
     203            0 :   pari_sp av = avma;
     204              :   GEN slope;
     205            0 :   return gc_upto(av, F2xqE_add_slope(P, F2xqE_neg_i(Q, a2), a2, T, &slope));
     206              : }
     207              : 
     208              : struct _F2xqE
     209              : {
     210              :   GEN a2, a6;
     211              :   GEN T;
     212              : };
     213              : 
     214              : static GEN
     215       103686 : _F2xqE_dbl(void *E, GEN P)
     216              : {
     217       103686 :   struct _F2xqE *ell = (struct _F2xqE *) E;
     218       103686 :   return F2xqE_dbl(P, ell->a2, ell->T);
     219              : }
     220              : 
     221              : static GEN
     222        37621 : _F2xqE_add(void *E, GEN P, GEN Q)
     223              : {
     224        37621 :   struct _F2xqE *ell=(struct _F2xqE *) E;
     225        37621 :   return F2xqE_add(P, Q, ell->a2, ell->T);
     226              : }
     227              : 
     228              : static GEN
     229        29520 : _F2xqE_mul(void *E, GEN P, GEN n)
     230              : {
     231        29520 :   pari_sp av = avma;
     232        29520 :   struct _F2xqE *e=(struct _F2xqE *) E;
     233        29520 :   long s = signe(n);
     234        29520 :   if (!s || ell_is_inf(P)) return ellinf();
     235        29499 :   if (s<0) P = F2xqE_neg(P, e->a2, e->T);
     236        29499 :   if (is_pm1(n)) return s>0? gcopy(P): P;
     237        28097 :   return gc_GEN(av, gen_pow_i(P, n, e, &_F2xqE_dbl, &_F2xqE_add));
     238              : }
     239              : 
     240              : GEN
     241            0 : F2xqE_mul(GEN P, GEN n, GEN a2, GEN T)
     242              : {
     243              :   struct _F2xqE E;
     244            0 :   E.a2 = a2; E.T = T;
     245            0 :   return _F2xqE_mul(&E, P, n);
     246              : }
     247              : 
     248              : /* Finds a random nonsingular point on E */
     249              : GEN
     250       181796 : random_F2xqE(GEN a, GEN a6, GEN T)
     251              : {
     252       181796 :   pari_sp ltop = avma;
     253              :   GEN x, y, rhs, u;
     254              :   do
     255              :   {
     256       375121 :     set_avma(ltop);
     257       375121 :     x   = random_F2x(F2x_degree(T),T[1]);
     258       375121 :     if (typ(a) == t_VECSMALL)
     259              :     {
     260        61977 :       GEN a2 = a, x2;
     261        61977 :       if (!lgpol(x))
     262          856 :         { set_avma(ltop); retmkvec2(pol0_Flx(T[1]), F2xq_sqrt(a6,T)); }
     263        61121 :       u = x; x2  = F2xq_sqr(x, T);
     264        61121 :       rhs = F2x_add(F2xq_mul(x2,F2x_add(x,a2),T),a6);
     265        61121 :       rhs = F2xq_div(rhs,x2,T);
     266              :     }
     267              :     else
     268              :     {
     269       313144 :       GEN a3 = gel(a,1), a4 = gel(a,2), a3i = gel(a,3), u2i;
     270       313144 :       u = a3; u2i = F2xq_sqr(a3i,T);
     271       313144 :       rhs = F2x_add(F2xq_mul(x,F2x_add(F2xq_sqr(x,T),a4),T),a6);
     272       313144 :       rhs = F2xq_mul(rhs,u2i,T);
     273              :     }
     274       374265 :   } while (F2xq_trace(rhs,T));
     275       180940 :   y = F2xq_mul(F2xq_Artin_Schreier(rhs, T), u, T);
     276       180940 :   return gc_GEN(ltop, mkvec2(x, y));
     277              : }
     278              : 
     279              : static GEN
     280        13824 : _F2xqE_rand(void *E)
     281              : {
     282        13824 :   struct _F2xqE *ell=(struct _F2xqE *) E;
     283        13824 :   return random_F2xqE(ell->a2, ell->a6, ell->T);
     284              : }
     285              : 
     286              : static const struct bb_group F2xqE_group={_F2xqE_add,_F2xqE_mul,_F2xqE_rand,hash_GEN,zvV_equal,ell_is_inf, NULL};
     287              : 
     288              : const struct bb_group *
     289            0 : get_F2xqE_group(void ** pt_E, GEN a2, GEN a6, GEN T)
     290              : {
     291            0 :   struct _F2xqE *e = (struct _F2xqE *) stack_malloc(sizeof(struct _F2xqE));
     292            0 :   e->a2 = a2; e->a6 = a6; e->T = T;
     293            0 :   *pt_E = (void *) e;
     294            0 :   return &F2xqE_group;
     295              : }
     296              : 
     297              : GEN
     298          280 : F2xqE_order(GEN z, GEN o, GEN a2, GEN T)
     299              : {
     300          280 :   pari_sp av = avma;
     301              :   struct _F2xqE e;
     302          280 :   e.a2=a2; e.T=T;
     303          280 :   return gc_INT(av, gen_order(z, o, (void*)&e, &F2xqE_group));
     304              : }
     305              : 
     306              : GEN
     307           42 : F2xqE_log(GEN a, GEN b, GEN o, GEN a2, GEN T)
     308              : {
     309           42 :   pari_sp av = avma;
     310              :   struct _F2xqE e;
     311           42 :   e.a2=a2; e.T=T;
     312           42 :   return gc_INT(av, gen_PH_log(a, b, o, (void*)&e, &F2xqE_group));
     313              : }
     314              : 
     315              : /***********************************************************************/
     316              : /**                                                                   **/
     317              : /**                            Pairings                               **/
     318              : /**                                                                   **/
     319              : /***********************************************************************/
     320              : 
     321              : /* Derived from APIP from and by Jerome Milan, 2012 */
     322              : 
     323              : static long
     324        19373 : is_2_torsion(GEN Q, GEN a)
     325              : {
     326        19373 :   return (typ(a)==t_VEC || lgpol(gel(Q, 1))) ? 0: 1;
     327              : }
     328              : 
     329              : static GEN
     330        35102 : F2xqE_vert(GEN P, GEN Q, GEN a, GEN T)
     331              : {
     332        35102 :   long vT = T[1];
     333        35102 :   if (ell_is_inf(P))
     334         9085 :     return pol1_F2x(T[1]);
     335        26017 :   if (!F2x_equal(gel(Q, 1), gel(P, 1)))
     336        24255 :     return F2x_add(gel(Q, 1), gel(P, 1));
     337         1762 :   if (is_2_torsion(Q, a))
     338            0 :     return F2xq_inv(gel(Q,2), T);
     339         1762 :   return pol1_F2x(vT);
     340              : }
     341              : 
     342              : static GEN
     343        16932 : F2xqE_Miller_line(GEN R, GEN Q, GEN slope, GEN a, GEN T)
     344              : {
     345        16932 :   long vT = T[1];
     346        16932 :   GEN x = gel(Q, 1), y = gel(Q, 2);
     347        16932 :   GEN tmp1 = F2x_add(x, gel(R, 1));
     348        16932 :   GEN tmp2 = F2x_add(F2xq_mul(tmp1, slope, T), gel(R, 2));
     349              :   GEN s1, s2, ix;
     350        16932 :   if (!F2x_equal(y, tmp2))
     351        16218 :     return F2x_add(y, tmp2);
     352          714 :   if (is_2_torsion(Q, a)) return pol1_F2x(vT);
     353          714 :   if (typ(a)==t_VEC)
     354              :   {
     355          700 :     GEN a4 = gel(a,2), a3i = gel(a,3);
     356          700 :     s1 = F2xq_mul(F2x_add(a4, F2xq_sqr(x, T)), a3i, T);
     357          700 :     if (!F2x_equal(s1, slope))
     358          350 :       return F2x_add(s1, slope);
     359          350 :     s2 = F2xq_mul(F2x_add(x, F2xq_sqr(s1, T)), a3i, T);
     360          350 :     if (lgpol(s2)) return s2;
     361            0 :     return zv_copy(a3i);
     362              :   } else
     363              :   {
     364           14 :     GEN a2 = a ;
     365           14 :     ix = F2xq_inv(x, T);
     366           14 :     s1 = F2x_add(x, F2xq_mul(y, ix, T));
     367           14 :     if (!F2x_equal(s1, slope))
     368            7 :       return F2x_add(s1, slope);
     369            7 :     s2 =F2x_add(a2, F2x_add(F2xq_sqr(s1,T), s1));
     370            7 :     if (!F2x_equal(s2, x))
     371            7 :       return  F2x_add(pol1_F2x(vT), F2xq_mul(s2, ix, T));
     372            0 :     return ix;
     373              :   }
     374              : }
     375              : 
     376              : /* Computes the equation of the line tangent to R and returns its
     377              :    evaluation at the point Q. Also doubles the point R.
     378              :  */
     379              : 
     380              : static GEN
     381        16897 : F2xqE_tangent_update(GEN R, GEN Q, GEN a2, GEN T, GEN *pt_R)
     382              : {
     383        16897 :   if (ell_is_inf(R))
     384              :   {
     385            0 :     *pt_R = ellinf();
     386            0 :     return pol1_F2x(T[1]);
     387              :   }
     388        16897 :   else if (is_2_torsion(R, a2))
     389              :   {
     390            0 :     *pt_R = ellinf();
     391            0 :     return F2xqE_vert(R, Q, a2, T);
     392              :   } else {
     393              :     GEN slope;
     394        16897 :     *pt_R = F2xqE_dbl_slope(R, a2, T, &slope);
     395        16897 :     return F2xqE_Miller_line(R, Q, slope, a2, T);
     396              :   }
     397              : }
     398              : 
     399              : /* Computes the equation of the line through R and P, and returns its
     400              :    evaluation at the point Q. Also adds P to the point R.
     401              :  */
     402              : 
     403              : static GEN
     404         9120 : F2xqE_chord_update(GEN R, GEN P, GEN Q, GEN a2, GEN T, GEN *pt_R)
     405              : {
     406         9120 :   if (ell_is_inf(R))
     407              :   {
     408            0 :     *pt_R = gcopy(P);
     409            0 :     return F2xqE_vert(P, Q, a2, T);
     410              :   }
     411         9120 :   else if (ell_is_inf(P))
     412              :   {
     413            0 :     *pt_R = gcopy(R);
     414            0 :     return F2xqE_vert(R, Q, a2, T);
     415              :   }
     416         9120 :   else if (F2x_equal(gel(P, 1), gel(R, 1)))
     417              :   {
     418         9085 :     if (F2x_equal(gel(P, 2), gel(R, 2)))
     419            0 :       return F2xqE_tangent_update(R, Q, a2, T, pt_R);
     420              :     else
     421              :     {
     422         9085 :       *pt_R = ellinf();
     423         9085 :       return F2xqE_vert(R, Q, a2, T);
     424              :     }
     425              :   } else {
     426              :     GEN slope;
     427           35 :     *pt_R = F2xqE_add_slope(P, R, a2, T, &slope);
     428           35 :     return F2xqE_Miller_line(R, Q, slope, a2, T);
     429              :   }
     430              : }
     431              : 
     432              : struct _F2xqE_miller { GEN T, a2, P; };
     433              : 
     434              : static GEN
     435        16897 : F2xqE_Miller_dbl(void* E, GEN d)
     436              : {
     437        16897 :   struct _F2xqE_miller *m = (struct _F2xqE_miller *)E;
     438        16897 :   GEN T = m->T, a2 = m->a2, P = m->P;
     439        16897 :   GEN v, line, point = gel(d,3);
     440        16897 :   GEN N = F2xq_sqr(gel(d,1), T);
     441        16897 :   GEN D = F2xq_sqr(gel(d,2), T);
     442        16897 :   line = F2xqE_tangent_update(point, P, a2, T, &point);
     443        16897 :   N = F2xq_mul(N, line, T);
     444        16897 :   v = F2xqE_vert(point, P, a2, T);
     445        16897 :   D = F2xq_mul(D, v, T); return mkvec3(N, D, point);
     446              : }
     447              : static GEN
     448         9120 : F2xqE_Miller_add(void* E, GEN va, GEN vb)
     449              : {
     450         9120 :   struct _F2xqE_miller *m = (struct _F2xqE_miller *)E;
     451         9120 :   GEN T = m->T, a2 = m->a2, P = m->P;
     452              :   GEN v, line, point;
     453         9120 :   GEN na = gel(va,1), da = gel(va,2), pa = gel(va,3);
     454         9120 :   GEN nb = gel(vb,1), db = gel(vb,2), pb = gel(vb,3);
     455         9120 :   GEN N = F2xq_mul(na, nb, T);
     456         9120 :   GEN D = F2xq_mul(da, db, T);
     457         9120 :   line = F2xqE_chord_update(pa, pb, P, a2, T, &point);
     458         9120 :   N  = F2xq_mul(N, line, T);
     459         9120 :   v = F2xqE_vert(point, P, a2, T);
     460         9120 :   D = F2xq_mul(D, v, T); return mkvec3(N, D, point);
     461              : }
     462              : /* Returns the Miller function f_{m, Q} evaluated at the point P using
     463              :  * the standard Miller algorithm. */
     464              : static GEN
     465         9120 : F2xqE_Miller(GEN Q, GEN P, GEN m, GEN a2, GEN T)
     466              : {
     467         9120 :   pari_sp av = avma;
     468              :   struct _F2xqE_miller d;
     469              :   GEN v, N, D, g1;
     470              : 
     471         9120 :   d.a2 = a2; d.T = T; d.P = P;
     472         9120 :   g1 = pol1_F2x(T[1]);
     473         9120 :   v = gen_pow_i(mkvec3(g1,g1,Q), m, (void*)&d, F2xqE_Miller_dbl, F2xqE_Miller_add);
     474         9120 :   N = gel(v,1); D = gel(v,2);
     475         9120 :   return gc_upto(av, F2xq_div(N, D, T));
     476              : }
     477              : 
     478              : GEN
     479         5371 : F2xqE_weilpairing(GEN P, GEN Q, GEN m, GEN a2, GEN T)
     480              : {
     481         5371 :   pari_sp av = avma;
     482              :   GEN N, D;
     483         5371 :   if (ell_is_inf(P) || ell_is_inf(Q)
     484         4821 :     || (F2x_equal(gel(P,1),gel(Q,1)) && F2x_equal(gel(P,2),gel(Q,2))))
     485          825 :     return pol1_F2x(T[1]);
     486         4546 :   N    = F2xqE_Miller(P, Q, m, a2, T);
     487         4546 :   D  = F2xqE_Miller(Q, P, m, a2, T);
     488         4546 :   return gc_upto(av, F2xq_div(N, D, T));
     489              : }
     490              : 
     491              : GEN
     492           28 : F2xqE_tatepairing(GEN P, GEN Q, GEN m, GEN a2, GEN T)
     493              : {
     494           28 :   if (ell_is_inf(P) || ell_is_inf(Q))
     495            0 :     return pol1_F2x(T[1]);
     496           28 :   return F2xqE_Miller(P, Q, m, a2, T);
     497              : }
     498              : 
     499              : /***********************************************************************/
     500              : /**                                                                   **/
     501              : /**                          Point counting                           **/
     502              : /**                                                                   **/
     503              : /***********************************************************************/
     504              : 
     505              : static GEN
     506        69228 : Z2x_rshift(GEN y, long x)
     507              : {
     508              :   GEN z;
     509              :   long i, l;
     510        69228 :   if (!x) return pol0_Flx(y[1]);
     511        69228 :   z = cgetg_copy(y, &l); z[1] = y[1];
     512      7719563 :   for(i=2; i<l; i++) z[i] = y[i]>>x;
     513        69228 :   return Flx_renormalize(z, l);
     514              : }
     515              : 
     516              : /* Solve the linear equation approximation in the Newton algorithm */
     517              : 
     518              : static GEN
     519       171575 : gen_Z2x_Dixon(GEN F, GEN V, long N, void *E, GEN lin(void *E, GEN F, GEN d, long N), GEN invl(void *E, GEN d))
     520              : {
     521       171575 :   pari_sp av = avma;
     522              :   long N2, M;
     523              :   GEN VN2, V2, VM, bil;
     524       171575 :   ulong q = 1UL<<N;
     525       171575 :   if (N == 1) return invl(E, V);
     526        69228 :   V = Flx_red(V, q);
     527        69228 :   N2 = (N + 1)>>1; M = N - N2;
     528        69228 :   F = FlxT_red(F, q);
     529        69228 :   VN2 = gen_Z2x_Dixon(F, V, N2, E, lin, invl);
     530        69228 :   bil = lin(E, F, VN2, N);
     531        69228 :   V2 = Z2x_rshift(Flx_sub(V, bil, q), N2);
     532        69228 :   VM = gen_Z2x_Dixon(F, V2, M, E, lin, invl);
     533        69228 :   return gc_upto(av, Flx_add(VN2, Flx_Fl_mul(VM, 1UL<<N2, q), q));
     534              : }
     535              : 
     536              : /* Solve F(X) = V mod 2^N
     537              :    F(Xn) = V [mod 2^n]
     538              :    Vm = (V-F(Xn))/(2^n)
     539              :    F(Xm) = Vm
     540              :    X = Xn + 2^n*Xm
     541              : */
     542              : 
     543              : static GEN
     544        33139 : gen_Z2X_Dixon(GEN F, GEN V, long N, void *E,
     545              :                      GEN lin(void *E, GEN F, GEN d, long N),
     546              :                      GEN lins(void *E, GEN F, GEN d, long N),
     547              :                      GEN invls(void *E, GEN d))
     548              : {
     549        33139 :   pari_sp av = avma;
     550              :   long n, m;
     551              :   GEN Xn, Xm, FXn, Vm;
     552        33139 :   if (N<BITS_IN_LONG)
     553              :   {
     554        33119 :     ulong q = 1UL<<N;
     555        33119 :     return Flx_to_ZX(gen_Z2x_Dixon(ZXT_to_FlxT(F,q), ZX_to_Flx(V,q),N,E,lins,invls));
     556              :   }
     557           20 :   V = ZX_remi2n(V, N);
     558           20 :   n = (N + 1)>>1; m = N - n;
     559           20 :   F = ZXT_remi2n(F, N);
     560           20 :   Xn = gen_Z2X_Dixon(F, V, n, E, lin, lins, invls);
     561           20 :   FXn = lin(E, F, Xn, N);
     562           20 :   Vm = ZX_shifti(ZX_sub(V, FXn), -n);
     563           20 :   Xm = gen_Z2X_Dixon(F, Vm, m, E, lin, lins, invls);
     564           20 :   return gc_upto(av, ZX_remi2n(ZX_add(Xn, ZX_shifti(Xm, n)), N));
     565              : }
     566              : 
     567              : /* H -> H mod 2*/
     568              : 
     569              : static GEN
     570        50918 : _can_invls(void *E, GEN V) {(void) E; return V; }
     571              : 
     572              : /* H -> H-(f0*H0-f1*H1) */
     573              : 
     574              : static GEN
     575           10 : _can_lin(void *E, GEN F, GEN V, long N)
     576              : {
     577           10 :   pari_sp av=avma;
     578              :   GEN d0, d1, z;
     579              :   (void) E;
     580           10 :   RgX_even_odd(V, &d0, &d1);
     581           10 :   z =  ZX_sub(V, ZX_sub(ZX_mul(gel(F,1), d0), ZX_mul(gel(F,2), d1)));
     582           10 :   return gc_upto(av, ZX_remi2n(z, N));
     583              : }
     584              : 
     585              : static GEN
     586        34481 : _can_lins(void *E, GEN F, GEN V, long N)
     587              : {
     588        34481 :   GEN D=Flx_splitting(V, 2), z;
     589        34481 :   ulong q = 1UL<<N;
     590              :   (void) E;
     591        34481 :   z = Flx_sub(Flx_mul(gel(F,1), gel(D,1), q), Flx_mul(gel(F,2), gel(D,2), q), q);
     592        34481 :   return Flx_sub(V, z, q);
     593              : }
     594              : 
     595              : /* P -> P-(P0^2-X*P1^2) */
     596              : 
     597              : static GEN
     598        16427 : _can_iter(void *E, GEN f2, GEN q)
     599              : {
     600              :   GEN f0, f1, z;
     601              :   (void) E;
     602        16427 :   RgX_even_odd(f2, &f0, &f1);
     603        16427 :   z = ZX_add(ZX_sub(f2, FpX_sqr(f0, q)), RgX_shift_shallow(FpX_sqr(f1, q), 1));
     604        16427 :   return mkvec3(z,f0,f1);
     605              : }
     606              : 
     607              : /* H -> H-(2*P0*H0-2*X*P1*H1) */
     608              : 
     609              : static GEN
     610        16427 : _can_invd(void *E, GEN V, GEN v, GEN q, long M)
     611              : {
     612              :   GEN F;
     613              :   (void)E; (void)q;
     614        16427 :   F = mkvec2(ZX_shifti(gel(v,2),1), ZX_shifti(RgX_shift_shallow(gel(v,3),1),1));
     615        16427 :   return gen_Z2X_Dixon(F, V, M, NULL, _can_lin, _can_lins, _can_invls);
     616              : }
     617              : 
     618              : /* Lift P to Q such that Q(x^2)=Q(x)*Q(-x) mod 2^n
     619              :    if Q = Q0(X^2)+X*Q1(X^2), solve Q(X^2) = Q0^2-X*Q1^2
     620              : */
     621              : GEN
     622         7191 : F2x_Teichmuller(GEN P, long n)
     623         7191 : { return gen_ZpX_Newton(F2x_to_ZX(P),gen_2, n, NULL, _can_iter, _can_invd); }
     624              : 
     625              : static GEN
     626        16682 : Z2XQ_frob(GEN x, GEN T, GEN q)
     627              : {
     628        16682 :   return FpX_rem(RgX_inflate(x, 2), T, q);
     629              : }
     630              : 
     631              : static GEN
     632        34747 : Z2xq_frob(GEN x, GEN T, ulong q)
     633              : {
     634        34747 :   return Flx_rem(Flx_inflate(x, 2), T, q);
     635              : }
     636              : 
     637              : struct _frob_lift
     638              : {
     639              :   GEN T, sqx;
     640              : };
     641              : 
     642              : /* H -> S^-1(H) mod 2 */
     643              : 
     644              : static GEN
     645        51429 : _frob_invls(void *E, GEN V)
     646              : {
     647        51429 :   struct _frob_lift *F = (struct _frob_lift*) E;
     648        51429 :   GEN sqx = F->sqx;
     649        51429 :   return F2x_to_Flx(F2xq_sqrt_fast(Flx_to_F2x(V), gel(sqx,1), gel(sqx,2)));
     650              : }
     651              : 
     652              : /* H -> f1*S(H) + f2*H */
     653              : 
     654              : static GEN
     655           10 : _frob_lin(void *E, GEN F, GEN x2, long N)
     656              : {
     657           10 :   GEN T = gel(F,3);
     658           10 :   GEN q = int2n(N);
     659           10 :   GEN y2  = Z2XQ_frob(x2, T, q);
     660           10 :   GEN lin = ZX_add(ZX_mul(gel(F,1), y2), ZX_mul(gel(F,2), x2));
     661              :   (void) E;
     662           10 :   return FpX_rem(ZX_remi2n(lin, N), T, q);
     663              : }
     664              : 
     665              : static GEN
     666        34747 : _frob_lins(void *E, GEN F, GEN x2, long N)
     667              : {
     668        34747 :   GEN T = gel(F,3);
     669        34747 :   ulong q = 1UL<<N;
     670        34747 :   GEN y2  = Z2xq_frob(x2, T, q);
     671        34747 :   GEN lin = Flx_add(Flx_mul(gel(F,1), y2,q), Flx_mul(gel(F,2), x2,q),q);
     672              :   (void) E;
     673        34747 :   return Flx_rem(lin, T, q);
     674              : }
     675              : 
     676              : /* X -> P(X,S(X)) */
     677              : 
     678              : static GEN
     679        16672 : _lift_iter(void *E, GEN x2, GEN q)
     680              : {
     681        16672 :   struct _frob_lift *F = (struct _frob_lift*) E;
     682        16672 :   long N = expi(q);
     683        16672 :   GEN TN = ZXT_remi2n(F->T, N);
     684        16672 :   GEN y2 = Z2XQ_frob(x2, TN, q);
     685        16672 :   GEN x2y2 = FpX_rem(ZX_remi2n(ZX_mul(x2, y2), N), TN, q);
     686        16672 :   GEN s = ZX_add(ZX_add(x2, ZX_shifti(y2, 1)), ZX_shifti(x2y2, 3));
     687        16672 :   GEN V = ZX_add(ZX_add(ZX_sqr(s), y2), ZX_shifti(x2y2, 2));
     688        16672 :   return mkvec4(FpX_rem(ZX_remi2n(V, N), TN, q),x2,y2,s);
     689              : }
     690              : 
     691              : /* H -> Dx*H+Dy*S(H) */
     692              : static GEN
     693        16672 : _lift_invd(void *E, GEN V, GEN v, GEN qM, long M)
     694              : {
     695        16672 :   struct _frob_lift *F = (struct _frob_lift*) E;
     696        16672 :   GEN TM = ZXT_remi2n(F->T, M);
     697        16672 :   GEN x2 = gel(v,2), y2 = gel(v,3), s = gel(v,4), r;
     698        16672 :   GEN Dx = ZX_add(ZX_mul(ZX_Z_add(ZX_shifti(y2, 4), gen_2), s),
     699              :                          ZX_shifti(y2, 2));
     700        16672 :   GEN Dy = ZX_add(ZX_Z_add(ZX_mul(ZX_Z_add(ZX_shifti(x2, 4), utoi(4)), s),
     701              :                            gen_1), ZX_shifti(x2, 2));
     702        16672 :   Dx = FpX_rem(ZX_remi2n(Dx, M), TM, qM);
     703        16672 :   Dy = FpX_rem(ZX_remi2n(Dy, M), TM, qM);
     704        16672 :   r = mkvec3(Dy, Dx, TM);
     705        16672 :   return gen_Z2X_Dixon(r, V, M, E, _frob_lin, _frob_lins, _frob_invls);
     706              : }
     707              : 
     708              : /* Let P(X,Y)=(X+2*Y+8*X*Y)^2+Y+4*X*Y
     709              :  * Solve   P(x,S(x))=0 [mod 2^n,T]
     710              :  * assuming  x = x0    [mod 2,T]
     711              :  *
     712              :  * we set s = X+2*Y+8*X*Y, P = s^2+Y+4*X*Y
     713              :  * Dx = dP/dx = (16*s+4)*x+(4*s+1)
     714              :  * Dy = dP/dy = (16*y+2)*s+4*y */
     715              : static GEN
     716         7422 : solve_AGM_eqn(GEN x0, long n, GEN T, GEN sqx)
     717              : {
     718              :   struct _frob_lift F;
     719         7422 :   F.T=T; F.sqx=sqx;
     720         7422 :   return gen_ZpX_Newton(x0, gen_2, n, &F, _lift_iter, _lift_invd);
     721              : }
     722              : 
     723              : static GEN
     724          238 : Z2XQ_invnorm_pcyc(GEN a, GEN T, long e)
     725              : {
     726          238 :   GEN q = int2n(e);
     727          238 :   GEN z = ZpXQ_norm_pcyc(a, T, q, gen_2);
     728          238 :   return Zp_inv(z, gen_2, e);
     729              : }
     730              : 
     731              : /* Assume a = 1 [4] */
     732              : static GEN
     733         7184 : Z2XQ_invnorm(GEN a, GEN T, long e)
     734              : {
     735              :   pari_timer ti;
     736         7184 :   GEN pe = int2n(e), s;
     737         7184 :   if (degpol(a)==0)
     738           56 :     return Zp_inv(Fp_powu(gel(a,2), get_FpX_degree(T), pe), gen_2, e);
     739         7128 :   if (DEBUGLEVEL>=3) timer_start(&ti);
     740         7128 :   s = ZpXQ_log(a, T, gen_2, e);
     741         7128 :   if (DEBUGLEVEL>=3) timer_printf(&ti,"Z2XQ_log");
     742         7128 :   s = Fp_neg(FpXQ_trace(s, T, pe), pe);
     743         7128 :   if (DEBUGLEVEL>=3) timer_printf(&ti,"FpXQ_trace");
     744         7128 :   s = Qp_exp(cvtop(s, gen_2, e-2));
     745         7128 :   s = modii(padic_u(s), pe);
     746         7128 :   if (DEBUGLEVEL>=3) timer_printf(&ti,"Qp_exp");
     747         7128 :   return s;
     748              : }
     749              : 
     750              : static int
     751         7422 : F2x_is_pcyc(GEN T)
     752              : {
     753              :   long i, n;
     754              :   ulong k;
     755         7422 :   if (!uisprime(F2x_degree(T) + 1)) return 0;
     756         1127 :   n = lg(T)-1;
     757         1136 :   for (i = 2; i < n; i++)
     758           16 :     if (uel(T,i) != ~0UL) return 0;
     759         1120 :   k = uel(T,i); return !(k & (k+1)); /* test if k+1 is a power of 2 */
     760              : }
     761              : 
     762              : /* Assume a2==0, so 4|E(F_p): if t^4 = a6 then (t,t^2) is of order 4
     763              :    8|E(F_p) <=> trace(a6)==0 */
     764              : static GEN
     765         7765 : F2xq_elltrace_Harley(GEN a6, GEN T2)
     766              : {
     767         7765 :   pari_sp ltop = avma;
     768              :   pari_timer ti;
     769              :   GEN T, sqx;
     770              :   GEN x, x2, t;
     771         7765 :   long n = F2x_degree(T2), N = ((n + 1)>>1) + 2;
     772              :   long ispcyc;
     773         7765 :   if (n==1) return gen_m1;
     774         7576 :   if (n==2) return F2x_degree(a6) ? gen_1 : stoi(-3);
     775         7625 :   if (n==3) return F2x_degree(a6) ? (F2xq_trace(a6,T2) ?  stoi(-3): gen_1)
     776          203 :                                   : stoi(5);
     777         7422 :   timer_start(&ti);
     778         7422 :   sqx = mkvec2(F2xq_sqrt(polx_F2x(T2[1]),T2), T2);
     779         7422 :   if (DEBUGLEVEL>1) timer_printf(&ti,"Sqrtx");
     780         7422 :   ispcyc = F2x_is_pcyc(T2);
     781         7422 :   T = ispcyc? F2x_to_ZX(T2): F2x_Teichmuller(T2, N-2);
     782         7422 :   if (DEBUGLEVEL>1) timer_printf(&ti,"Teich");
     783         7422 :   T = FpX_get_red(T, int2n(N));
     784         7422 :   if (DEBUGLEVEL>1) timer_printf(&ti,"Barrett");
     785         7422 :   x = solve_AGM_eqn(F2x_to_ZX(a6), N-2, T, sqx);
     786         7422 :   if (DEBUGLEVEL>1) timer_printf(&ti,"Lift");
     787         7422 :   x2 = ZX_Z_add_shallow(ZX_shifti(x,2), gen_1);
     788         7422 :   t = (ispcyc? Z2XQ_invnorm_pcyc: Z2XQ_invnorm)(x2, T, N);
     789         7422 :   if (DEBUGLEVEL>1) timer_printf(&ti,"Norm");
     790         7422 :   if (cmpii(sqri(t), int2n(n + 2)) > 0)
     791         3501 :     t = subii(t, int2n(N));
     792         7422 :   return gc_INT(ltop, t);
     793              : }
     794              : 
     795              : static GEN
     796        23855 : get_v(GEN u, GEN a, GEN T)
     797              : {
     798        23855 :   GEN a4 = gel(a,2), a3i = gel(a,3);
     799        23855 :   GEN ui2 = F2xq_mul(u, a3i, T), ui4 = F2xq_sqr(ui2, T);
     800        23855 :   return F2xq_mul(a4, ui4, T);
     801              : }
     802              : 
     803              : static GEN
     804        10465 : get_r(GEN w, GEN u, GEN T)
     805              : {
     806        10465 :   return F2xq_sqr(F2xq_mul(F2xq_Artin_Schreier(w, T), u, T), T);
     807              : }
     808              : 
     809              : static GEN
     810        37734 : F2xq_elltracej(GEN a, GEN a6, GEN T, GEN q, long n)
     811              : {
     812        37734 :   GEN a3 = gel(a,1), a4 = gel(a,2), a3i = gel(a,3);
     813              :   GEN r, pi, rhs;
     814        37734 :   long t, s, m = n >> 1;
     815        37734 :   if (odd(n))
     816              :   {
     817              :     GEN u, v, w;
     818        16877 :     u = F2xq_pow(a3,diviuexact(subiu(shifti(q,1), 1), 3),T);
     819        16877 :     v = get_v(u, a, T);
     820        16877 :     if (F2xq_trace(v, T)==0) return gen_0;
     821         8692 :     w = F2xq_Artin_Schreier(F2x_1_add(v), T);
     822         8692 :     if (F2xq_trace(w, T)) w = F2x_1_add(w);
     823         8692 :     r = get_r(w, u, T);
     824         8692 :     pi = int2n(m+1);
     825         8692 :     s = (((m+3)&3L) <= 1) ? -1: 1;
     826              :   }
     827              :   else
     828              :   {
     829        20857 :     if (F2x_degree(F2xq_pow(a3,diviuexact(subiu(q, 1), 3),T))==0)
     830              :     {
     831              :       GEN u, v, w;
     832         6978 :       u = F2xq_sqrtn(a3, utoi(3), T, NULL);
     833         6978 :       v = get_v(u, a, T);
     834         6978 :       if (F2xq_trace(v, T)==1) return gen_0;
     835         3556 :       w = F2xq_Artin_Schreier(v, T);
     836         3556 :       if (F2xq_trace(w, T)==1) return gen_0;
     837         1773 :       r = get_r(w, u, T);
     838         1773 :       pi = int2n(m+1);
     839         1773 :       s = odd(m+1) ? -1: 1;
     840              :     }
     841              :     else
     842              :     {
     843        13879 :       long sv = T[1];
     844        13879 :       GEN P = mkpoln(5, pol1_F2x(sv), pol0_F2x(sv), pol0_F2x(sv), a3, a4);
     845        13879 :       r = F2xq_sqr(gel(F2xqX_roots(P,T), 1), T);
     846        13879 :       pi = int2n(m);
     847        13879 :       s = odd(m) ? -1: 1;
     848              :     }
     849              :   }
     850        24344 :   rhs = F2x_add(F2xq_mul(F2x_add(F2xq_sqr(r, T), a4), r, T), a6);
     851        24344 :   t = F2xq_trace(F2xq_mul(rhs, F2xq_sqr(a3i, T), T), T);
     852        24344 :   return (t==0)^(s==1)? pi: negi(pi);
     853              : }
     854              : 
     855              : GEN
     856        45699 : F2xq_ellcard(GEN a, GEN a6, GEN T)
     857              : {
     858        45699 :   pari_sp av = avma;
     859        45699 :   long n = F2x_degree(T);
     860              :   GEN c;
     861        45699 :   if (typ(a)==t_VECSMALL)
     862              :   {
     863         7765 :     GEN t = F2xq_elltrace_Harley(a6, T);
     864         7765 :     c = addii(int2u(n), F2xq_trace(a,T) ? addui(1,t): subui(1,t));
     865        37934 :   } else if (n==1)
     866              :   {
     867          200 :     long a4i = lgpol(gel(a,2)), a6i = lgpol(a6);
     868          200 :     return utoi(a4i? (a6i? 1: 5): 3);
     869              :   }
     870              :   else
     871              :   {
     872        37734 :     GEN q = int2u(n);
     873        37734 :     c = subii(addiu(q,1), F2xq_elltracej(a, a6, T, q, n));
     874              :   }
     875        45499 :   return gc_INT(av, c);
     876              : }
     877              : 
     878              : /***********************************************************************/
     879              : /**                                                                   **/
     880              : /**                          Group structure                          **/
     881              : /**                                                                   **/
     882              : /***********************************************************************/
     883              : 
     884              : static GEN
     885          401 : _F2xqE_pairorder(void *E, GEN P, GEN Q, GEN m, GEN F)
     886              : {
     887          401 :   struct _F2xqE *e = (struct _F2xqE *) E;
     888          401 :   return  F2xq_order(F2xqE_weilpairing(P,Q,m,e->a2,e->T), F, e->T);
     889              : }
     890              : 
     891              : GEN
     892         3808 : F2xq_ellgroup(GEN a2, GEN a6, GEN N, GEN T, GEN *pt_m)
     893              : {
     894              :   struct _F2xqE e;
     895         3808 :   GEN q = int2u(F2x_degree(T));
     896         3808 :   e.a2=a2; e.a6=a6; e.T=T;
     897         3808 :   return gen_ellgroup(N, subiu(q,1), pt_m, (void*)&e, &F2xqE_group,
     898              :                                                       _F2xqE_pairorder);
     899              : }
     900              : 
     901              : GEN
     902         3738 : F2xq_ellgens(GEN a2, GEN a6, GEN ch, GEN D, GEN m, GEN T)
     903              : {
     904              :   GEN P;
     905         3738 :   pari_sp av = avma;
     906              :   struct _F2xqE e;
     907         3738 :   e.a2=a2; e.a6=a6; e.T=T;
     908         3738 :   switch(lg(D)-1)
     909              :   {
     910           28 :   case 0:
     911           28 :     return cgetg(1,t_VEC);
     912         3598 :   case 1:
     913         3598 :     P = gen_gener(gel(D,1), (void*)&e, &F2xqE_group);
     914         3598 :     P = mkvec(F2xqE_changepoint(P, ch, T));
     915         3598 :     break;
     916          112 :   default:
     917          112 :     P = gen_ellgens(gel(D,1), gel(D,2), m, (void*)&e, &F2xqE_group,
     918              :                                                       _F2xqE_pairorder);
     919          112 :     gel(P,1) = F2xqE_changepoint(gel(P,1), ch, T);
     920          112 :     gel(P,2) = F2xqE_changepoint(gel(P,2), ch, T);
     921          112 :     break;
     922              :   }
     923         3710 :   return gc_GEN(av, P);
     924              : }
     925              : 
     926              : GEN
     927        46168 : ell_to_a4a6_F2xq(GEN E, GEN T)
     928              : {
     929        46168 :   long v = T[1];
     930        46168 :   GEN a1 = Rg_to_F2xq(ell_get_a1(E),T);
     931        46168 :   GEN a2 = Rg_to_F2xq(ell_get_a2(E),T);
     932        46168 :   GEN a3 = Rg_to_F2xq(ell_get_a3(E),T);
     933        46168 :   GEN a4 = Rg_to_F2xq(ell_get_a4(E),T);
     934        46168 :   GEN a6 = Rg_to_F2xq(ell_get_a6(E),T);
     935        46168 :   if (lgpol(a1))
     936              :   {
     937         7961 :     GEN a1i = F2xq_inv(a1,T);
     938         7961 :     GEN a1i2 = F2xq_sqr(a1i,T);
     939         7961 :     GEN a1i3 = F2xq_mul(a1i,a1i2,T);
     940         7961 :     GEN a1i6 = F2xq_sqr(a1i3,T);
     941         7961 :     GEN d  = F2xq_mul(a3,a1i,T);
     942         7961 :     GEN dd = F2xq_mul(d,a1i2,T);
     943         7961 :     GEN e  = F2xq_mul(F2x_add(a4,F2xq_sqr(d,T)),a1i,T);
     944         7961 :     GEN ee = F2xq_mul(e,a1i3,T);
     945         7961 :     GEN da2 = F2x_add(a2,d);
     946         7961 :     GEN d2 = F2xq_mul(da2,a1i2,T);
     947         7961 :     GEN d6 = F2xq_mul(F2x_add(F2x_add(F2xq_mul(F2x_add(F2xq_mul(da2,d,T),a4),d,T),a6),F2xq_sqr(e,T)),a1i6,T);
     948         7961 :     retmkvec3(d2, d6, mkvec4(a1i,dd,pol0_F2x(v),ee));
     949              :   }
     950              :   else
     951              :   { /* allow a1 = a3 = 0: singular curve */
     952        38207 :     GEN d4 = F2x_add(F2xq_sqr(a2,T),a4);
     953        38207 :     GEN d6 = F2x_add(F2xq_mul(a2,a4,T),a6);
     954        38207 :     GEN a3i = lgpol(a3)? F2xq_inv(a3,T): a3;
     955        38207 :     retmkvec3(mkvec3(a3,d4,a3i), d6, mkvec4(pol1_F2x(v),a2,pol0_F2x(T[1]),pol0_F2x(T[1])));
     956              :   }
     957              : }
        

Generated by: LCOV version 2.0-1