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 - Fle.c (source / functions) Hit Total Coverage
Test: PARI/GP v2.14.0 lcov report (development 27775-aca467eab2) Lines: 439 470 93.4 %
Date: 2022-07-03 07:33:15 Functions: 57 64 89.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 2014  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             : /* Not so fast arithmetic with points over elliptic curves over Fl */
      19             : 
      20             : /***********************************************************************/
      21             : /**                                                                   **/
      22             : /**                              Flj                                  **/
      23             : /**                                                                   **/
      24             : /***********************************************************************/
      25             : 
      26             : /* Arithmetic is implemented using Jacobian coordinates, representing
      27             :  * a projective point (x : y : z) on E by [z*x , z^2*y , z].  This is
      28             :  * probably not the fastest representation available for the given
      29             :  * problem, but they're easy to implement and up to 60% faster than
      30             :  * the school-book method. */
      31             : 
      32             : /* Cost: 1M + 8S + 1*a + 10add + 1*8 + 2*2 + 1*3.
      33             :  * http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl */
      34             : INLINE void
      35    23678220 : Flj_dbl_indir_pre(GEN P, GEN Q, ulong a4, ulong p, ulong pi)
      36             : {
      37             :   ulong X1, Y1, Z1;
      38             :   ulong XX, YY, YYYY, ZZ, S, M, T;
      39             : 
      40    23678220 :   X1 = P[1]; Y1 = P[2]; Z1 = P[3];
      41             : 
      42    23678220 :   if (Z1 == 0) { Q[1] = X1; Q[2] = Y1; Q[3] = Z1; return; }
      43             : 
      44    23517642 :   XX = Fl_sqr_pre(X1, p, pi);
      45    23519681 :   YY = Fl_sqr_pre(Y1, p, pi);
      46    23516032 :   YYYY = Fl_sqr_pre(YY, p, pi);
      47    23515119 :   ZZ = Fl_sqr_pre(Z1, p, pi);
      48    23514069 :   S = Fl_double(Fl_sub(Fl_sqr_pre(Fl_add(X1, YY, p), p, pi),
      49             :                        Fl_add(XX, YYYY, p), p), p);
      50    23509309 :   M = Fl_addmul_pre(Fl_triple(XX, p), a4, Fl_sqr_pre(ZZ, p, pi), p, pi);
      51    23519101 :   T = Fl_sub(Fl_sqr_pre(M, p, pi), Fl_double(S, p), p);
      52    23514853 :   Q[1] = T;
      53    23514853 :   Q[2] = Fl_sub(Fl_mul_pre(M, Fl_sub(S, T, p), p, pi),
      54             :                 Fl_double(Fl_double(Fl_double(YYYY, p), p), p), p);
      55    23510805 :   Q[3] = Fl_sub(Fl_sqr_pre(Fl_add(Y1, Z1, p), p, pi),
      56             :                 Fl_add(YY, ZZ, p), p);
      57             : }
      58             : 
      59             : INLINE void
      60    20044061 : Flj_dbl_pre_inplace(GEN P, ulong a4, ulong p, ulong pi)
      61             : {
      62    20044061 :   Flj_dbl_indir_pre(P, P, a4, p, pi);
      63    20044303 : }
      64             : 
      65             : GEN
      66     3630341 : Flj_dbl_pre(GEN P, ulong a4, ulong p, ulong pi)
      67             : {
      68     3630341 :   GEN Q = cgetg(4, t_VECSMALL);
      69     3630008 :   Flj_dbl_indir_pre(P, Q, a4, p, pi);
      70     3629905 :   return Q;
      71             : }
      72             : 
      73             : /* Cost: 11M + 5S + 9add + 4*2.
      74             :  * http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-add-2007-bl */
      75             : INLINE void
      76     7190557 : Flj_add_indir_pre(GEN P, GEN Q, GEN R, ulong a4, ulong p, ulong pi)
      77             : {
      78             :   ulong X1, Y1, Z1, X2, Y2, Z2;
      79             :   ulong Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V, W;
      80     7190557 :   X1 = P[1]; Y1 = P[2]; Z1 = P[3];
      81     7190557 :   X2 = Q[1]; Y2 = Q[2]; Z2 = Q[3];
      82             : 
      83     7190557 :   if (Z2 == 0) { R[1] = X1; R[2] = Y1; R[3] = Z1; return; }
      84     7190382 :   if (Z1 == 0) { R[1] = X2; R[2] = Y2; R[3] = Z2; return; }
      85             : 
      86     7177847 :   Z1Z1 = Fl_sqr_pre(Z1, p, pi);
      87     7177984 :   Z2Z2 = Fl_sqr_pre(Z2, p, pi);
      88     7177561 :   U1 = Fl_mul_pre(X1, Z2Z2, p, pi);
      89     7177599 :   U2 = Fl_mul_pre(X2, Z1Z1, p, pi);
      90     7177705 :   S1 = Fl_mul_pre(Y1, Fl_mul_pre(Z2, Z2Z2, p, pi), p, pi);
      91     7177749 :   S2 = Fl_mul_pre(Y2, Fl_mul_pre(Z1, Z1Z1, p, pi), p, pi);
      92     7177912 :   H = Fl_sub(U2, U1, p);
      93     7177546 :   r = Fl_double(Fl_sub(S2, S1, p), p);
      94             : 
      95     7177454 :   if (H == 0) {
      96      545923 :     if (r == 0) Flj_dbl_indir_pre(P, R, a4, p, pi); /* P = Q */
      97      541261 :     else { R[1] = R[2] = 1; R[3] = 0; } /* P = -Q */
      98      545923 :     return;
      99             :   }
     100     6631531 :   I = Fl_sqr_pre(Fl_double(H, p), p, pi);
     101     6632112 :   J = Fl_mul_pre(H, I, p, pi);
     102     6632020 :   V = Fl_mul_pre(U1, I, p, pi);
     103     6632115 :   W = Fl_sub(Fl_sqr_pre(r, p, pi), Fl_add(J, Fl_double(V, p), p), p);
     104     6631847 :   R[1] = W;
     105     6631847 :   R[2] = Fl_sub(Fl_mul_pre(r, Fl_sub(V, W, p), p, pi),
     106             :                 Fl_double(Fl_mul_pre(S1, J, p, pi), p), p);
     107     6632073 :   R[3] = Fl_mul_pre(Fl_sub(Fl_sqr_pre(Fl_add(Z1, Z2, p), p, pi),
     108             :                            Fl_add(Z1Z1, Z2Z2, p), p), H, p, pi);
     109             : }
     110             : 
     111             : INLINE void
     112     7100255 : Flj_add_pre_inplace(GEN P, GEN Q, ulong a4, ulong p, ulong pi)
     113     7100255 : { Flj_add_indir_pre(P, Q, P, a4, p, pi); }
     114             : 
     115             : GEN
     116       89508 : Flj_add_pre(GEN P, GEN Q, ulong a4, ulong p, ulong pi)
     117             : {
     118       89508 :   GEN R = cgetg(4, t_VECSMALL);
     119       89500 :   Flj_add_indir_pre(P, Q, R, a4, p, pi);
     120       89504 :   return R;
     121             : }
     122             : 
     123             : GEN
     124     2297678 : Flj_neg(GEN Q, ulong p)
     125     2297678 : { return mkvecsmall3(Q[1], Fl_neg(Q[2], p), Q[3]); }
     126             : 
     127             : typedef struct {
     128             :   ulong pbits, nbits;  /* Positive bits and negative bits */
     129             :   ulong lnzb; /* Leading nonzero bit */
     130             : } naf_t;
     131             : 
     132             : /* Return the signed binary representation (i.e. the Non-Adjacent Form
     133             :  * in base 2) of a; a = x.pbits - x.nbits (+ 2^BILif < 0; this
     134             :  * exceptional case can happen if a > 2^(BIL-1)) */
     135             : static void
     136     3952815 : naf_repr(naf_t *x, ulong a)
     137             : {
     138     3952815 :   ulong pbits = 0, nbits = 0, c0 = 0, c1, a0;
     139             :   long t, i;
     140             : 
     141    38542469 :   for (i = 0; a; a >>= 1, ++i) {
     142    34589654 :     a0 = a & 1;
     143    34589654 :     c1 = (c0 + a0 + ((a & 2) >> 1)) >> 1;
     144    34589654 :     t = c0 + a0 - (c1 << 1);
     145    34589654 :     if (t < 0)
     146     5359880 :       nbits |= (1UL << i);
     147    29229774 :     else if (t > 0)
     148     6189075 :       pbits |= (1UL << i);
     149    34589654 :     c0 = c1;
     150             :   }
     151     3952815 :   c1 = c0 >> 1;
     152     3952815 :   t = c0 - (c1 << 1);
     153             :   /* since a >= 0, we have t >= 0; if i = BIL, pbits (virtually) overflows;
     154             :    * that leading overflowed bit is implied and not recorded in pbits */
     155     3952815 :   if (t > 0 && i != BITS_IN_LONG) pbits |= (1UL << i);
     156     3952815 :   x->pbits = pbits;
     157     3952815 :   x->nbits = nbits;
     158     3952815 :   x->lnzb = t? i-2: i-3;
     159     3952815 : }
     160             : 
     161             : /* Standard left-to-right signed double-and-add to compute [n]P. */
     162             : static GEN
     163     3697429 : Flj_mulu_pre_naf(GEN P, ulong n, ulong a4, ulong p, ulong pi, const naf_t *x)
     164             : {
     165             :   GEN R, Pi;
     166             :   ulong pbits, nbits;
     167             :   ulong m;
     168             : 
     169     3697429 :   if (n == 0) return mkvecsmall3(1, 1, 0);
     170     3697372 :   if (n == 1) return Flv_copy(P);
     171             : 
     172     3630379 :   R = Flj_dbl_pre(P, a4, p, pi);
     173     3629860 :   if (n == 2) return R;
     174             : 
     175     2888393 :   pbits = x->pbits;
     176     2888393 :   nbits = x->nbits;
     177     2888393 :   Pi = nbits? Flj_neg(P, p): NULL;
     178     2888298 :   m = (1UL << x->lnzb);
     179    22933498 :   for ( ; m; m >>= 1) {
     180    20044992 :     Flj_dbl_pre_inplace(R, a4, p, pi);
     181    20043675 :     if (m & pbits)
     182     3126374 :       Flj_add_pre_inplace(R, P, a4, p, pi);
     183    16917301 :     else if (m & nbits)
     184     3976003 :       Flj_add_pre_inplace(R, Pi, a4, p, pi);
     185             :   }
     186     2888506 :   return gc_const((pari_sp)R, R);
     187             : }
     188             : 
     189             : GEN
     190     2604862 : Flj_mulu_pre(GEN P, ulong n, ulong a4, ulong p, ulong pi)
     191             : {
     192     2604862 :   naf_t x; naf_repr(&x, n);
     193     2605293 :   return Flj_mulu_pre_naf(P, n, a4, p, pi, &x);
     194             : }
     195             : 
     196             : struct _Flj { ulong a4, p, pi; };
     197             : 
     198             : static GEN
     199       89509 : _Flj_add(void *E, GEN P, GEN Q)
     200             : {
     201       89509 :   struct _Flj *ell=(struct _Flj *) E;
     202       89509 :   return Flj_add_pre(P, Q, ell->a4, ell->p, ell->pi);
     203             : }
     204             : 
     205             : static GEN
     206      104619 : _Flj_mul(void *E, GEN P, GEN n)
     207             : {
     208      104619 :   struct _Flj *ell = (struct _Flj *) E;
     209      104619 :   long s = signe(n);
     210             :   GEN Q;
     211      104619 :   if (s==0) return mkvecsmall3(1, 1, 0);
     212      104619 :   Q = Flj_mulu_pre(P, itou(n), ell->a4, ell->p, ell->pi);
     213      104633 :   return s>0 ? Q : Flj_neg(Q, ell->p);
     214             : }
     215             : static GEN
     216           0 : _Flj_one(void *E)
     217           0 : { (void) E; return mkvecsmall3(1, 1, 0); }
     218             : 
     219             : GEN
     220       15087 : FljV_factorback_pre(GEN P, GEN L, ulong a4, ulong p, ulong pi)
     221             : {
     222             :   struct _Flj E;
     223       15087 :   E.a4 = a4; E.p = p; E.pi = pi;
     224       15087 :   return gen_factorback(P, L, (void*)&E, &_Flj_add, &_Flj_mul, &_Flj_one);
     225             : }
     226             : 
     227             : ulong
     228      253556 : Flj_order_ufact(GEN P, ulong n, GEN F, ulong a4, ulong p, ulong pi)
     229             : {
     230      253556 :   pari_sp av = avma;
     231      253556 :   ulong res = 1;
     232             :   long i, nfactors;
     233             :   GEN primes, exps;
     234             : 
     235      253556 :   primes = gel(F, 1);
     236      253556 :   nfactors = lg(primes);
     237      253556 :   exps = gel(F, 2);
     238             : 
     239      721484 :   for (i = 1; i < nfactors; ++i) {
     240      577384 :     ulong q, pp = primes[i];
     241      577384 :     long j, k, ei = exps[i];
     242             :     naf_t x;
     243             :     GEN b;
     244             : 
     245     1369951 :     for (q = pp, j = 1; j < ei; ++j) q *= pp;
     246      577384 :     b = Flj_mulu_pre(P, n / q, a4, p, pi);
     247             : 
     248      577384 :     naf_repr(&x, pp);
     249     1669517 :     for (j = 0; j < ei && b[3]; ++j)
     250     1092133 :       b = Flj_mulu_pre_naf(b, pp, a4, p, pi, &x);
     251      577384 :     if (b[3]) return 0;
     252     1158076 :     for (k = 0; k < j; ++k) res *= pp;
     253      467928 :     set_avma(av);
     254             :   }
     255      144100 :   return res;
     256             : }
     257             : 
     258             : GEN
     259     1549125 : Fle_to_Flj(GEN P)
     260     3098046 : { return ell_is_inf(P) ? mkvecsmall3(1UL, 1UL, 0UL):
     261     1549062 :                          mkvecsmall3(P[1], P[2], 1UL);
     262             : }
     263             : 
     264             : GEN
     265       61600 : Flj_to_Fle(GEN P, ulong p)
     266             : {
     267       61600 :   if (P[3] == 0) return ellinf();
     268             :   else
     269             :   {
     270       60942 :     ulong Z = Fl_inv(P[3], p);
     271       60942 :     ulong Z2 = Fl_sqr(Z, p);
     272       60942 :     ulong X3 = Fl_mul(P[1], Z2, p);
     273       60942 :     ulong Y3 = Fl_mul(P[2], Fl_mul(Z, Z2, p), p);
     274       60942 :     return mkvecsmall2(X3, Y3);
     275             :   }
     276             : }
     277             : 
     278             : GEN
     279     1563902 : Flj_to_Fle_pre(GEN P, ulong p, ulong pi)
     280             : {
     281     1563902 :   if (P[3] == 0) return ellinf();
     282             :   else
     283             :   {
     284     1382563 :     ulong Z = Fl_inv(P[3], p);
     285     1383034 :     ulong Z2 = Fl_sqr_pre(Z, p, pi);
     286     1382786 :     ulong X3 = Fl_mul_pre(P[1], Z2, p, pi);
     287     1382784 :     ulong Y3 = Fl_mul_pre(P[2], Fl_mul_pre(Z, Z2, p, pi), p, pi);
     288     1382824 :     return mkvecsmall2(X3, Y3);
     289             :   }
     290             : }
     291             : 
     292             : INLINE void
     293     6655815 : random_Fle_pre_indir(ulong a4, ulong a6, ulong p, ulong pi,
     294             :                      ulong *pt_x, ulong *pt_y)
     295             : {
     296             :   ulong x, x2, y, rhs;
     297             :   do
     298             :   {
     299     6655815 :     x   = random_Fl(p); /*  x^3+a4*x+a6 = x*(x^2+a4)+a6  */
     300     6655898 :     x2  = Fl_sqr_pre(x, p, pi);
     301     6655877 :     rhs = Fl_addmul_pre(a6, x, Fl_add(x2, a4, p), p, pi);
     302     6655889 :   } while ((!rhs && !Fl_add(Fl_triple(x2,p),a4,p)) || krouu(rhs, p) < 0);
     303     3338093 :   y = Fl_sqrt_pre(rhs, p, pi);
     304     3338090 :   *pt_x = x; *pt_y = y;
     305     3338090 : }
     306             : 
     307             : GEN
     308      432888 : random_Flj_pre(ulong a4, ulong a6, ulong p, ulong pi)
     309             : {
     310             :   ulong x, y;
     311      432888 :   random_Fle_pre_indir(a4, a6, p, pi, &x, &y);
     312      432869 :   return mkvecsmall3(x, y, 1);
     313             : }
     314             : 
     315             : GEN
     316      156218 : Flj_changepointinv_pre(GEN P, GEN ch, ulong p, ulong pi)
     317             : {
     318             :   ulong c, u, r, s, t, u2, u3, z2;
     319      156218 :   ulong x  = uel(P,1), y = uel(P,2), z = uel(P,3);
     320             :   GEN w;
     321      156218 :   if (z == 0) return Flv_copy(P);
     322      156218 :   u = ch[1]; r = ch[2];
     323      156218 :   s = ch[3]; t = ch[4];
     324      156218 :   u2 = Fl_sqr_pre(u, p, pi); u3 = Fl_mul_pre(u, u2, p, pi);
     325      156222 :   c = Fl_mul_pre(u2, x, p, pi);
     326      156209 :   z2 = Fl_sqr_pre(z, p, pi);
     327      156210 :   w = cgetg(4, t_VECSMALL);
     328      156200 :   uel(w,1) = Fl_add(c, Fl_mul_pre(r, z2, p, pi), p);
     329      156206 :   uel(w,2) = Fl_add(Fl_mul_pre(u3 ,y, p, pi),
     330             :                     Fl_mul_pre(z, Fl_add(Fl_mul_pre(s,c,p,pi),
     331             :                                          Fl_mul_pre(z2,t,p,pi), p), p, pi), p);
     332      156214 :   uel(w,3) = z;
     333      156214 :   return w;
     334             : }
     335             : 
     336             : /***********************************************************************/
     337             : /**                                                                   **/
     338             : /**                              Fle                                  **/
     339             : /**                                                                   **/
     340             : /***********************************************************************/
     341             : GEN
     342       15807 : Fle_changepoint(GEN P, GEN ch, ulong p)
     343             : {
     344             :   ulong c, u, r, s, t, v, v2, v3;
     345             :   GEN z;
     346       15807 :   if (ell_is_inf(P)) return ellinf();
     347       15807 :   u = ch[1]; r = ch[2];
     348       15807 :   s = ch[3]; t = ch[4];
     349       15807 :   v = Fl_inv(u, p); v2 = Fl_sqr(v,p); v3 = Fl_mul(v,v2,p);
     350       15807 :   c = Fl_sub(uel(P,1),r,p);
     351       15807 :   z = cgetg(3,t_VECSMALL);
     352       15807 :   z[1] = Fl_mul(v2, c, p);
     353       15807 :   z[2] = Fl_mul(v3, Fl_sub(uel(P,2), Fl_add(Fl_mul(s,c, p),t, p),p),p);
     354       15807 :   return z;
     355             : }
     356             : 
     357             : GEN
     358       70681 : Fle_changepointinv(GEN P, GEN ch, ulong p)
     359             : {
     360             :   ulong c, u, r, s, t, u2, u3;
     361             :   GEN z;
     362       70681 :   if (ell_is_inf(P)) return ellinf();
     363       70023 :   u = ch[1]; r = ch[2];
     364       70023 :   s = ch[3]; t = ch[4];
     365       70023 :   u2 = Fl_sqr(u, p); u3 = Fl_mul(u,u2,p);
     366       70023 :   c = Fl_mul(u2,uel(P,1), p);
     367       70023 :   z = cgetg(3, t_VECSMALL);
     368       70023 :   z[1] = Fl_add(c,r,p);
     369       70023 :   z[2] = Fl_add(Fl_mul(u3,uel(P,2),p), Fl_add(Fl_mul(s,c,p), t, p), p);
     370       70023 :   return z;
     371             : }
     372             : static GEN
     373      572784 : Fle_dbl_slope(GEN P, ulong a4, ulong p, ulong *slope)
     374             : {
     375             :   ulong x, y, Qx, Qy;
     376      572784 :   if (ell_is_inf(P) || !P[2]) return ellinf();
     377      503317 :   x = P[1]; y = P[2];
     378      503317 :   *slope = Fl_div(Fl_add(Fl_triple(Fl_sqr(x,p), p), a4, p),
     379             :                   Fl_double(y, p), p);
     380      503323 :   Qx = Fl_sub(Fl_sqr(*slope, p), Fl_double(x, p), p);
     381      503310 :   Qy = Fl_sub(Fl_mul(*slope, Fl_sub(x, Qx, p), p), y, p);
     382      503299 :   return mkvecsmall2(Qx, Qy);
     383             : }
     384             : 
     385             : GEN
     386      428142 : Fle_dbl(GEN P, ulong a4, ulong p)
     387             : {
     388             :   ulong slope;
     389      428142 :   return Fle_dbl_slope(P,a4,p,&slope);
     390             : }
     391             : 
     392             : static GEN
     393     1154967 : Fle_add_slope(GEN P, GEN Q, ulong a4, ulong p, ulong *slope)
     394             : {
     395             :   ulong Px, Py, Qx, Qy, Rx, Ry;
     396     1154967 :   if (ell_is_inf(P)) return Q;
     397     1154962 :   if (ell_is_inf(Q)) return P;
     398     1154952 :   Px = P[1]; Py = P[2];
     399     1154952 :   Qx = Q[1]; Qy = Q[2];
     400     1154952 :   if (Px==Qx) return Py==Qy ? Fle_dbl_slope(P, a4, p, slope): ellinf();
     401     1033836 :   *slope = Fl_div(Fl_sub(Py, Qy, p), Fl_sub(Px, Qx, p), p);
     402     1034027 :   Rx = Fl_sub(Fl_sub(Fl_sqr(*slope, p), Px, p), Qx, p);
     403     1033975 :   Ry = Fl_sub(Fl_mul(*slope, Fl_sub(Px, Rx, p), p), Py, p);
     404     1033963 :   return mkvecsmall2(Rx, Ry);
     405             : }
     406             : 
     407             : GEN
     408     1150016 : Fle_add(GEN P, GEN Q, ulong a4, ulong p)
     409             : {
     410             :   ulong slope;
     411     1150016 :   return Fle_add_slope(P,Q,a4,p,&slope);
     412             : }
     413             : 
     414             : static GEN
     415      125846 : Fle_neg(GEN P, ulong p)
     416             : {
     417      125846 :   if (ell_is_inf(P)) return P;
     418      125846 :   return mkvecsmall2(P[1], Fl_neg(P[2], p));
     419             : }
     420             : 
     421             : GEN
     422           0 : Fle_sub(GEN P, GEN Q, ulong a4, ulong p)
     423             : {
     424           0 :   pari_sp av = avma;
     425             :   ulong slope;
     426           0 :   return gerepileupto(av, Fle_add_slope(P, Fle_neg(Q, p), a4, p, &slope));
     427             : }
     428             : 
     429             : struct _Fle { ulong a4, a6, p; };
     430             : 
     431             : static GEN
     432           0 : _Fle_dbl(void *E, GEN P)
     433             : {
     434           0 :   struct _Fle *ell = (struct _Fle *) E;
     435           0 :   return Fle_dbl(P, ell->a4, ell->p);
     436             : }
     437             : 
     438             : static GEN
     439      364490 : _Fle_add(void *E, GEN P, GEN Q)
     440             : {
     441      364490 :   struct _Fle *ell=(struct _Fle *) E;
     442      364490 :   return Fle_add(P, Q, ell->a4, ell->p);
     443             : }
     444             : 
     445             : GEN
     446     1981595 : Fle_mulu(GEN P, ulong n, ulong a4, ulong p)
     447             : {
     448             :   ulong pi;
     449     1981595 :   if (!n || ell_is_inf(P)) return ellinf();
     450     1981518 :   if (n==1) return zv_copy(P);
     451     1969912 :   if (n==2) return Fle_dbl(P, a4, p);
     452     1548878 :   pi = get_Fl_red(p);
     453     1549082 :   return Flj_to_Fle_pre(Flj_mulu_pre(Fle_to_Flj(P), n, a4, p, pi), p, pi);
     454             : }
     455             : 
     456             : static GEN
     457     1454622 : _Fle_mul(void *E, GEN P, GEN n)
     458             : {
     459     1454622 :   pari_sp av = avma;
     460     1454622 :   struct _Fle *e=(struct _Fle *) E;
     461     1454622 :   long s = signe(n);
     462             :   GEN Q;
     463     1454622 :   if (!s || ell_is_inf(P)) return ellinf();
     464     1442854 :   if (s < 0) P = Fle_neg(P, e->p);
     465     1442854 :   if (is_pm1(n)) return s > 0? zv_copy(P): P;
     466     1138573 :   Q = (lgefint(n)==3) ? Fle_mulu(P, uel(n,2), e->a4, e->p):
     467           6 :                         gen_pow(P, n, (void*)e, &_Fle_dbl, &_Fle_add);
     468     1138508 :   return s > 0? Q: gerepileuptoleaf(av, Q);
     469             : }
     470             : 
     471             : GEN
     472         238 : Fle_mul(GEN P, GEN n, ulong a4, ulong p)
     473             : {
     474             :   struct _Fle E;
     475         238 :   E.a4 = a4; E.p = p;
     476         238 :   return _Fle_mul(&E, P, n);
     477             : }
     478             : 
     479             : /* Finds a random nonsingular point on E */
     480             : GEN
     481     2905221 : random_Fle_pre(ulong a4, ulong a6, ulong p, ulong pi)
     482             : {
     483             :   ulong x, y;
     484     2905221 :   random_Fle_pre_indir(a4, a6, p, pi, &x, &y);
     485     2905221 :   return mkvecsmall2(x, y);
     486             : }
     487             : 
     488             : GEN
     489       22456 : random_Fle(ulong a4, ulong a6, ulong p)
     490       22456 : { return random_Fle_pre(a4, a6, p, get_Fl_red(p)); }
     491             : 
     492             : static GEN
     493           0 : _Fle_rand(void *E)
     494             : {
     495           0 :   struct _Fle *e=(struct _Fle *) E;
     496           0 :   return random_Fle(e->a4, e->a6, e->p);
     497             : }
     498             : 
     499             : static const struct bb_group Fle_group={_Fle_add,_Fle_mul,_Fle_rand,hash_GEN,zv_equal,ell_is_inf,NULL};
     500             : 
     501             : GEN
     502      284380 : Fle_order(GEN z, GEN o, ulong a4, ulong p)
     503             : {
     504      284380 :   pari_sp av = avma;
     505             :   struct _Fle e;
     506      284380 :   e.a4=a4;
     507      284380 :   e.p=p;
     508      284380 :   return gerepileuptoint(av, gen_order(z, o, (void*)&e, &Fle_group));
     509             : }
     510             : 
     511             : GEN
     512       50477 : Fle_log(GEN a, GEN b, GEN o, ulong a4, ulong p)
     513             : {
     514       50477 :   pari_sp av = avma;
     515             :   struct _Fle e;
     516       50477 :   e.a4=a4;
     517       50477 :   e.p=p;
     518       50477 :   return gerepileuptoint(av, gen_PH_log(a, b, o, (void*)&e, &Fle_group));
     519             : }
     520             : 
     521             : ulong
     522           0 : Fl_ellj(ulong a4, ulong a6, ulong p)
     523             : {
     524           0 :   if (SMALL_ULONG(p))
     525             :   { /* a43 = 4 a4^3 */
     526           0 :     ulong a43 = Fl_double(Fl_double(Fl_mul(a4, Fl_sqr(a4, p), p), p), p);
     527             :     /* a62 = 27 a6^2 */
     528           0 :     ulong a62 = Fl_mul(Fl_sqr(a6, p), 27 % p, p);
     529           0 :     ulong z1 = Fl_mul(a43, 1728 % p, p);
     530           0 :     ulong z2 = Fl_add(a43, a62, p);
     531           0 :     return Fl_div(z1, z2, p);
     532             :   }
     533           0 :   return Fl_ellj_pre(a4, a6, p, get_Fl_red(p));
     534             : }
     535             : 
     536             : void
     537      132840 : Fl_ellj_to_a4a6(ulong j, ulong p, ulong *pt_a4, ulong *pt_a6)
     538             : {
     539      132840 :   ulong zagier = 1728 % p;
     540      132840 :   if (j == 0)           { *pt_a4 = 0; *pt_a6 =1; }
     541      132840 :   else if (j == zagier) { *pt_a4 = 1; *pt_a6 =0; }
     542             :   else
     543             :   {
     544      132840 :     ulong k = Fl_sub(zagier, j, p);
     545      132840 :     ulong kj = Fl_mul(k, j, p);
     546      132841 :     ulong k2j = Fl_mul(kj, k, p);
     547      132842 :     *pt_a4 = Fl_triple(kj, p);
     548      132840 :     *pt_a6 = Fl_double(k2j, p);
     549             :   }
     550      132841 : }
     551             : 
     552             : ulong
     553     1706957 : Fl_elldisc_pre(ulong a4, ulong a6, ulong p, ulong pi)
     554             : { /* D = -(4A^3 + 27B^2) */
     555             :   ulong t1, t2;
     556     1706957 :   t1 = Fl_mul_pre(a4, Fl_sqr_pre(a4, p, pi), p, pi);
     557     1706957 :   t1 = Fl_double(Fl_double(t1, p), p);
     558     1706957 :   t2 = Fl_mul_pre(27 % p, Fl_sqr_pre(a6, p, pi), p, pi);
     559     1706957 :   return Fl_neg(Fl_add(t1, t2, p), p);
     560             : }
     561             : 
     562             : ulong
     563           0 : Fl_elldisc(ulong a4, ulong a6, ulong p)
     564             : {
     565           0 :   if (SMALL_ULONG(p))
     566             :   { /* D = -(4A^3 + 27B^2) */
     567             :     ulong t1, t2;
     568           0 :     t1 = Fl_mul(a4, Fl_sqr(a4, p), p);
     569           0 :     t1 = Fl_double(Fl_double(t1, p), p);
     570           0 :     t2 = Fl_mul(27 % p, Fl_sqr(a6, p), p);
     571           0 :     return Fl_neg(Fl_add(t1, t2, p), p);
     572             :   }
     573           0 :   return Fl_elldisc_pre(a4, a6, p, get_Fl_red(p));
     574             : }
     575             : 
     576             : void
     577       93547 : Fl_elltwist_disc(ulong a4, ulong a6, ulong D, ulong p, ulong *pa4, ulong *pa6)
     578             : {
     579       93547 :   ulong D2 = Fl_sqr(D, p);
     580       93547 :   *pa4 = Fl_mul(a4, D2, p);
     581       93547 :   *pa6 = Fl_mul(a6, Fl_mul(D, D2, p), p);
     582       93548 : }
     583             : 
     584             : void
     585           0 : Fl_elltwist(ulong a4, ulong a6, ulong p, ulong *pt_a4, ulong *pt_a6)
     586           0 : { Fl_elltwist_disc(a4, a6, nonsquare_Fl(p), p, pt_a4, pt_a6); }
     587             : 
     588             : static void
     589    42450151 : Fle_dbl_sinv_pre_inplace(GEN P, ulong a4, ulong sinv, ulong p, ulong pi)
     590             : {
     591             :   ulong x, y, slope;
     592    42450151 :   if (uel(P,1)==p) return;
     593    42237169 :   if (!P[2]) { P[1] = p; return; }
     594    42108740 :   x = P[1]; y = P[2];
     595    42108740 :   slope = Fl_mul_pre(Fl_add(Fl_triple(Fl_sqr_pre(x, p, pi), p), a4, p),
     596             :                 sinv, p, pi);
     597    42108740 :   P[1] = Fl_sub(Fl_sqr_pre(slope, p, pi), Fl_double(x, p), p);
     598    42108740 :   P[2] = Fl_sub(Fl_mul_pre(slope, Fl_sub(x, P[1], p), p, pi), y, p);
     599             : }
     600             : 
     601             : static void
     602     5623762 : Fle_add_sinv_pre_inplace(GEN P, GEN Q, ulong a4, ulong sinv, ulong p, ulong pi)
     603             : {
     604             :   ulong Px, Py, Qx, Qy, slope;
     605     5623762 :   if (uel(P,1)==p) { P[1] = Q[1]; P[2] = Q[2]; }
     606     5623762 :   if (ell_is_inf(Q)) return;
     607     5623762 :   Px = P[1]; Py = P[2];
     608     5623762 :   Qx = Q[1]; Qy = Q[2];
     609     5623762 :   if (Px==Qx)
     610             :   {
     611       24515 :     if (Py==Qy) Fle_dbl_sinv_pre_inplace(P, a4, sinv, p, pi);
     612       11338 :     else P[1] = p;
     613       24515 :     return;
     614             :   }
     615     5599247 :   slope = Fl_mul_pre(Fl_sub(Py, Qy, p), sinv, p, pi);
     616     5599247 :   P[1] = Fl_sub(Fl_sub(Fl_sqr_pre(slope, p, pi), Px, p), Qx, p);
     617     5599247 :   P[2] = Fl_sub(Fl_mul_pre(slope, Fl_sub(Px, P[1], p), p, pi), Py, p);
     618             : }
     619             : 
     620             : static void
     621     6278391 : Fle_sub_sinv_pre_inplace(GEN P, GEN Q, ulong a4, ulong sinv, ulong p, ulong pi)
     622             : {
     623             :   ulong Px, Py, Qx, Qy, slope;
     624     6278391 :   if (uel(P,1)==p) { P[1] = Q[1]; P[2] = Fl_neg(Q[2], p); }
     625     6278391 :   if (ell_is_inf(Q)) return;
     626     6278391 :   Px = P[1]; Py = P[2];
     627     6278391 :   Qx = Q[1]; Qy = Q[2];
     628     6278391 :   if (Px==Qx)
     629             :   {
     630       28823 :     if (Py==Qy) P[1] = p;
     631             :     else
     632       10991 :       Fle_dbl_sinv_pre_inplace(P, a4, sinv, p, pi);
     633       28823 :     return;
     634             :   }
     635     6249568 :   slope = Fl_mul_pre(Fl_add(Py, Qy, p), sinv, p, pi);
     636     6249568 :   P[1] = Fl_sub(Fl_sub(Fl_sqr_pre(slope, p, pi), Px, p), Qx, p);
     637     6249568 :   P[2] = Fl_sub(Fl_mul_pre(slope, Fl_sub(Px, P[1], p), p, pi), Py, p);
     638             : }
     639             : 
     640             : static long
     641    54091689 : skipzero(long n) { return n ? n:1; }
     642             : 
     643             : void
     644     1244832 : FleV_add_pre_inplace(GEN P, GEN Q, GEN a4, ulong p, ulong pi)
     645             : {
     646     1244832 :   long i, l=lg(a4);
     647     1244832 :   GEN sinv = cgetg(l, t_VECSMALL);
     648     6868594 :   for(i=1; i<l; i++)
     649     5623762 :     uel(sinv,i) = umael(P,i,1)==p? 1: skipzero(Fl_sub(mael(P,i,1), mael(Q,i,1), p));
     650     1244832 :   Flv_inv_pre_inplace(sinv, p, pi);
     651     6868594 :   for (i=1; i<l; i++)
     652     5623762 :     Fle_add_sinv_pre_inplace(gel(P,i), gel(Q,i), uel(a4,i), uel(sinv,i), p, pi);
     653     1244832 : }
     654             : 
     655             : void
     656     1415250 : FleV_sub_pre_inplace(GEN P, GEN Q, GEN a4, ulong p, ulong pi)
     657             : {
     658     1415250 :   long i, l=lg(a4);
     659     1415250 :   GEN sinv = cgetg(l, t_VECSMALL);
     660     7693641 :   for(i=1; i<l; i++)
     661     6278391 :     uel(sinv,i) = umael(P,i,1)==p? 1: skipzero(Fl_sub(mael(P,i,1), mael(Q,i,1), p));
     662     1415250 :   Flv_inv_pre_inplace(sinv, p, pi);
     663     7693641 :   for (i=1; i<l; i++)
     664     6278391 :     Fle_sub_sinv_pre_inplace(gel(P,i), gel(Q,i), uel(a4,i), uel(sinv,i), p, pi);
     665     1415250 : }
     666             : 
     667             : void
     668     9612189 : FleV_dbl_pre_inplace(GEN P, GEN a4, ulong p, ulong pi)
     669             : {
     670     9612189 :   long i, l=lg(a4);
     671     9612189 :   GEN sinv = cgetg(l, t_VECSMALL);
     672    52038172 :   for(i=1; i<l; i++)
     673    42425983 :     uel(sinv,i) = umael(P,i,1)==p? 1: skipzero(Fl_double(umael(P,i,2), p));
     674     9612189 :   Flv_inv_pre_inplace(sinv, p, pi);
     675    52038172 :   for(i=1; i<l; i++)
     676    42425983 :     Fle_dbl_sinv_pre_inplace(gel(P,i), uel(a4,i), uel(sinv,i), p, pi);
     677     9612189 : }
     678             : 
     679             : static void
     680      770561 : FleV_mulu_pre_naf_inplace(GEN P, ulong n, GEN a4, ulong p, ulong pi, const naf_t *x)
     681             : {
     682      770561 :   pari_sp av = avma;
     683             :   ulong pbits, nbits, m;
     684             :   GEN R;
     685      770561 :   if (n == 1) return;
     686             : 
     687      770561 :   R = P; P = gcopy(P);
     688      770561 :   FleV_dbl_pre_inplace(R, a4, p, pi);
     689      770561 :   if (n == 2) return;
     690             : 
     691      770505 :   pbits = x->pbits;
     692      770505 :   nbits = x->nbits;
     693      770505 :   m = (1UL << x->lnzb);
     694     9612133 :   for ( ; m; m >>= 1) {
     695     8841628 :     FleV_dbl_pre_inplace(R, a4, p, pi);
     696     8841628 :     if (m & pbits)
     697     1244832 :       FleV_add_pre_inplace(R, P, a4, p, pi);
     698     7596796 :     else if (m & nbits)
     699     1415250 :       FleV_sub_pre_inplace(R, P, a4, p, pi);
     700             :   }
     701      770505 :   set_avma(av);
     702             : }
     703             : 
     704             : void
     705      770561 : FleV_mulu_pre_inplace(GEN P, ulong n, GEN a4, ulong p, ulong pi)
     706             : {
     707      770561 :   naf_t x; naf_repr(&x, n);
     708      770561 :   FleV_mulu_pre_naf_inplace(P, n, a4, p, pi, &x);
     709      770561 : }
     710             : 
     711             : /***********************************************************************/
     712             : /**                                                                   **/
     713             : /**                            Pairings                               **/
     714             : /**                                                                   **/
     715             : /***********************************************************************/
     716             : 
     717             : /* Derived from APIP from and by Jerome Milan, 2012 */
     718             : 
     719             : static ulong
     720       98099 : Fle_vert(GEN P, GEN Q, ulong a4, ulong p)
     721             : {
     722       98099 :   if (ell_is_inf(P))
     723       33768 :     return 1;
     724       64331 :   if (uel(Q, 1) != uel(P, 1))
     725       60880 :     return Fl_sub(uel(Q, 1), uel(P, 1), p);
     726        3451 :   if (uel(P,2) != 0 ) return 1;
     727        2382 :   return Fl_inv(Fl_add(Fl_triple(Fl_sqr(uel(P,1),p), p), a4, p), p);
     728             : }
     729             : 
     730             : static ulong
     731       34232 : Fle_Miller_line(GEN R, GEN Q, ulong slope, ulong a4, ulong p)
     732             : {
     733       34232 :   ulong x = uel(Q, 1), y = uel(Q, 2);
     734       34232 :   ulong tmp1 = Fl_sub(x, uel(R, 1), p);
     735       34232 :   ulong tmp2 = Fl_add(Fl_mul(tmp1, slope, p), uel(R,2), p);
     736       34232 :   if (y != tmp2)
     737       32672 :     return Fl_sub(y, tmp2, p);
     738        1560 :   if (y == 0)
     739        1009 :     return 1;
     740             :   else
     741             :   {
     742             :     ulong s1, s2;
     743         551 :     ulong y2i = Fl_inv(Fl_double(y, p), p);
     744         551 :     s1 = Fl_mul(Fl_add(Fl_triple(Fl_sqr(x, p), p), a4, p), y2i, p);
     745         551 :     if (s1 != slope)
     746         243 :       return Fl_sub(s1, slope, p);
     747         308 :     s2 = Fl_mul(Fl_sub(Fl_triple(x, p), Fl_sqr(s1, p), p), y2i, p);
     748         308 :     return s2 ? s2: y2i;
     749             :   }
     750             : }
     751             : 
     752             : /* Computes the equation of the line tangent to R and returns its
     753             :    evaluation at the point Q. Also doubles the point R.
     754             :  */
     755             : 
     756             : static ulong
     757       53834 : Fle_tangent_update(GEN R, GEN Q, ulong a4, ulong p, GEN *pt_R)
     758             : {
     759       53834 :   if (ell_is_inf(R))
     760             :   {
     761        4145 :     *pt_R = ellinf();
     762        4145 :     return 1;
     763             :   }
     764       49689 :   else if (uel(R,2) == 0)
     765             :   {
     766       20397 :     *pt_R = ellinf();
     767       20397 :     return Fle_vert(R, Q, a4, p);
     768             :   } else {
     769             :     ulong slope;
     770       29292 :     *pt_R = Fle_dbl_slope(R, a4, p, &slope);
     771       29292 :     return Fle_Miller_line(R, Q, slope, a4, p);
     772             :   }
     773             : }
     774             : 
     775             : /* Computes the equation of the line through R and P, and returns its
     776             :    evaluation at the point Q. Also adds P to the point R.
     777             :  */
     778             : 
     779             : static ulong
     780       14404 : Fle_chord_update(GEN R, GEN P, GEN Q, ulong a4, ulong p, GEN *pt_R)
     781             : {
     782       14404 :   if (ell_is_inf(R))
     783             :   {
     784         238 :     *pt_R = gcopy(P);
     785         238 :     return Fle_vert(P, Q, a4, p);
     786             :   }
     787       14166 :   else if (ell_is_inf(P))
     788             :   {
     789           0 :     *pt_R = gcopy(R);
     790           0 :     return Fle_vert(R, Q, a4, p);
     791             :   }
     792       14166 :   else if (uel(P, 1) == uel(R, 1))
     793             :   {
     794        9226 :     if (uel(P, 2) == uel(R, 2))
     795           0 :       return Fle_tangent_update(R, Q, a4, p, pt_R);
     796             :     else {
     797        9226 :       *pt_R = ellinf();
     798        9226 :       return Fle_vert(R, Q, a4, p);
     799             :     }
     800             :   } else {
     801             :     ulong slope;
     802        4940 :     *pt_R = Fle_add_slope(P, R, a4, p, &slope);
     803        4940 :     return Fle_Miller_line(R, Q, slope, a4, p);
     804             :   }
     805             : }
     806             : 
     807             : struct _Fle_miller { ulong p, a4; GEN P; };
     808             : static GEN
     809       53834 : Fle_Miller_dbl(void* E, GEN d)
     810             : {
     811       53834 :   struct _Fle_miller *m = (struct _Fle_miller *)E;
     812       53834 :   ulong p = m->p, a4 = m->a4;
     813       53834 :   GEN P = m->P;
     814             :   ulong v, line;
     815       53834 :   ulong N = Fl_sqr(umael(d,1,1), p);
     816       53834 :   ulong D = Fl_sqr(umael(d,1,2), p);
     817       53834 :   GEN point = gel(d,2);
     818       53834 :   line = Fle_tangent_update(point, P, a4, p, &point);
     819       53834 :   N  = Fl_mul(N, line, p);
     820       53834 :   v = Fle_vert(point, P, a4, p);
     821       53834 :   D = Fl_mul(D, v, p); return mkvec2(mkvecsmall2(N, D), point);
     822             : }
     823             : static GEN
     824       14404 : Fle_Miller_add(void* E, GEN va, GEN vb)
     825             : {
     826       14404 :   struct _Fle_miller *m = (struct _Fle_miller *)E;
     827       14404 :   ulong p = m->p, a4= m->a4;
     828       14404 :   GEN P = m->P, point;
     829             :   ulong v, line;
     830       14404 :   ulong na = umael(va,1,1), da = umael(va,1,2);
     831       14404 :   ulong nb = umael(vb,1,1), db = umael(vb,1,2);
     832       14404 :   GEN pa = gel(va,2), pb = gel(vb,2);
     833       14404 :   ulong N = Fl_mul(na, nb, p);
     834       14404 :   ulong D = Fl_mul(da, db, p);
     835       14404 :   line = Fle_chord_update(pa, pb, P, a4, p, &point);
     836       14404 :   N = Fl_mul(N, line, p);
     837       14404 :   v = Fle_vert(point, P, a4, p);
     838       14404 :   D = Fl_mul(D, v, p); return mkvec2(mkvecsmall2(N, D), point);
     839             : }
     840             : 
     841             : /* Returns the Miller function f_{m, Q} evaluated at the point P using
     842             :  * the standard Miller algorithm. */
     843             : static ulong
     844       29385 : Fle_Miller(GEN Q, GEN P, ulong m, ulong a4, ulong p)
     845             : {
     846       29385 :   pari_sp av = avma;
     847             :   struct _Fle_miller d;
     848             :   GEN v;
     849             :   ulong N, D;
     850             : 
     851       29385 :   d.a4 = a4; d.p = p; d.P = P;
     852       29385 :   v = gen_powu_i(mkvec2(mkvecsmall2(1,1), Q), m, (void*)&d,
     853             :                 Fle_Miller_dbl, Fle_Miller_add);
     854       29385 :   N = umael(v,1,1); D = umael(v,1,2);
     855       29385 :   return gc_ulong(av, Fl_div(N, D, p));
     856             : }
     857             : 
     858             : ulong
     859        8865 : Fle_weilpairing(GEN P, GEN Q, ulong m, ulong a4, ulong p)
     860             : {
     861        8865 :   pari_sp ltop = avma;
     862             :   ulong N, D, w;
     863        8865 :   if (ell_is_inf(P) || ell_is_inf(Q) || zv_equal(P,Q)) return 1;
     864        8158 :   N = Fle_Miller(P, Q, m, a4, p);
     865        8158 :   D = Fle_Miller(Q, P, m, a4, p);
     866        8158 :   w = Fl_div(N, D, p);
     867        8158 :   if (odd(m)) w  = Fl_neg(w, p);
     868        8158 :   return gc_ulong(ltop, w);
     869             : }
     870             : 
     871             : ulong
     872       13069 : Fle_tatepairing(GEN P, GEN Q, ulong m, ulong a4, ulong p)
     873             : {
     874       13069 :   if (ell_is_inf(P) || ell_is_inf(Q)) return 1;
     875       13069 :   return Fle_Miller(P, Q, m, a4, p);
     876             : }
     877             : 
     878             : GEN
     879       10178 : Fl_ellptors(ulong l, ulong N, ulong a4, ulong a6, ulong p)
     880             : {
     881       10178 :   long v = z_lval(N, l);
     882             :   ulong N0, N1;
     883             :   GEN F;
     884       10178 :   if (v==0) return cgetg(1,t_VEC);
     885       10178 :   N0 = upowuu(l, v); N1 = N/N0;
     886       10178 :   F = mkmat2(mkcols(l), mkcols(v));
     887             :   while(1)
     888        1050 :   {
     889       11228 :     pari_sp av2 = avma;
     890             :     GEN P, Q;
     891             :     ulong d, s, t;
     892             : 
     893       11228 :     P = Fle_mulu(random_Fle(a4, a6, p), N1, a4, p);
     894       11228 :     Q = Fle_mulu(random_Fle(a4, a6, p), N1, a4, p);
     895       11228 :     s = itou(Fle_order(P, F, a4, p));
     896       11228 :     t = itou(Fle_order(Q, F, a4, p));
     897       11228 :     if (s < t) { swap(P,Q); lswap(s,t); }
     898       11228 :     if (s == N0) retmkvec(Fle_mulu(P, s/l, a4, p));
     899        1645 :     d = Fl_order(Fle_weilpairing(P, Q, s, a4, p), s, p);
     900        1645 :     if (s*d == N0)
     901         595 :       retmkvec2(Fle_mulu(P, s/l, a4, p), Fle_mulu(Q, t/l, a4, p));
     902        1050 :     set_avma(av2);
     903             :   }
     904             : }

Generated by: LCOV version 1.13