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 - bb_group.c (source / functions) Coverage Total Hit
Test: PARI/GP v2.18.1 lcov report (development 31041-bd73e9fcdd) Lines: 94.4 % 586 553
Test Date: 2026-07-22 22:45:42 Functions: 100.0 % 37 37
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Copyright (C) 2000-2004  The PARI group.
       2              : 
       3              : This file is part of the PARI/GP package.
       4              : 
       5              : PARI/GP is free software; you can redistribute it and/or modify it under the
       6              : terms of the GNU General Public License as published by the Free Software
       7              : Foundation; either version 2 of the License, or (at your option) any later
       8              : version. It is distributed in the hope that it will be useful, but WITHOUT
       9              : ANY WARRANTY WHATSOEVER.
      10              : 
      11              : Check the License for details. You should have received a copy of it, along
      12              : with the package; see the file 'COPYING'. If not, write to the Free Software
      13              : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
      14              : 
      15              : /***********************************************************************/
      16              : /**                                                                   **/
      17              : /**             GENERIC ALGORITHMS ON BLACKBOX GROUP                  **/
      18              : /**                                                                   **/
      19              : /***********************************************************************/
      20              : #include "pari.h"
      21              : #include "paripriv.h"
      22              : #undef pow /* AIX: pow(a,b) is a macro, wrongly expanded on grp->pow(a,b,c) */
      23              : 
      24              : #define DEBUGLEVEL DEBUGLEVEL_bb_group
      25              : 
      26              : /***********************************************************************/
      27              : /**                                                                   **/
      28              : /**                    POWERING                                       **/
      29              : /**                                                                   **/
      30              : /***********************************************************************/
      31              : 
      32              : /* return (n>>(i+1-l)) & ((1<<l)-1) */
      33              : static ulong
      34      8031441 : int_block(GEN n, long i, long l)
      35              : {
      36      8031441 :   long q = divsBIL(i), r = remsBIL(i)+1, lr;
      37      8032255 :   GEN nw = int_W(n, q);
      38      8032255 :   ulong w = (ulong) *nw, w2;
      39      8032255 :   if (r>=l) return (w>>(r-l))&((1UL<<l)-1);
      40       541446 :   w &= (1UL<<r)-1; lr = l-r;
      41       541446 :   w2 = (ulong) *int_precW(nw); w2 >>= (BITS_IN_LONG-lr);
      42       541446 :   return (w<<lr)|w2;
      43              : }
      44              : 
      45              : /* assume n != 0, t_INT. Compute x^|n| using sliding window powering */
      46              : static GEN
      47      9344424 : sliding_window_powu(GEN x, ulong n, long e, void *E, GEN (*sqr)(void*,GEN),
      48              :                                                      GEN (*mul)(void*,GEN,GEN))
      49              : {
      50      9344424 :   long i, l = expu(n), u = (1UL<<(e-1));
      51      9343951 :   GEN tab = cgetg(1+u, t_VEC), x2 = sqr(E, x), z = NULL;
      52              : 
      53      9346375 :   gel(tab, 1) = x;
      54     24768248 :   for (i = 2; i <= u; i++) gel(tab,i) = mul(E, gel(tab,i-1), x2);
      55     69070553 :   while (l >= 0)
      56              :   {
      57              :     long w, v;
      58              :     GEN tw;
      59     59820153 :     if (e > l+1) e = l+1;
      60     59820153 :     w = (n>>(l+1-e)) & ((1UL<<e)-1); v = vals(w); l-=e;
      61     59835999 :     tw = gel(tab, 1 + (w>>(v+1)));
      62     59835999 :     if (!z) z = tw;
      63              :     else
      64              :     {
      65    137575253 :       for (i = 1; i <= e-v; i++) z = sqr(E, z);
      66     50358653 :       z = mul(E, z, tw);
      67              :     }
      68     97477245 :     for (i = 1; i <= v; i++) z = sqr(E, z);
      69    109761696 :     while (l >= 0)
      70              :     {
      71    100611294 :       if (n&(1UL<<l)) break;
      72     50027094 :       z = sqr(E, z); l--;
      73              :     }
      74              :   }
      75      9250400 :   return z;
      76              : }
      77              : 
      78              : /* assume n != 0, t_INT. Compute x^|n| using sliding window powering */
      79              : static GEN
      80       221070 : sliding_window_pow(GEN x, GEN n, long e, void *E, GEN (*sqr)(void*,GEN),
      81              :                                                   GEN (*mul)(void*,GEN,GEN))
      82              : {
      83              :   pari_sp av;
      84       221070 :   long i, l = expi(n), u = (1UL<<(e-1));
      85       221064 :   GEN tab = cgetg(1+u, t_VEC);
      86       221064 :   GEN x2 = sqr(E, x), z = NULL;
      87              : 
      88       221062 :   gel(tab, 1) = x;
      89      2859828 :   for (i=2; i<=u; i++) gel(tab,i) = mul(E, gel(tab,i-1), x2);
      90       221090 :   av = avma;
      91      7670620 :   while (l >= 0)
      92              :   {
      93              :     long w, v;
      94              :     GEN tw;
      95      7426037 :     if (e > l+1) e = l+1;
      96      7426037 :     w = int_block(n,l,e); v = vals(w); l-=e;
      97      7426771 :     tw = gel(tab, 1+(w>>(v+1)));
      98      7426771 :     if (!z) z = tw;
      99              :     else
     100              :     {
     101     39040253 :       for (i = 1; i <= e-v; i++) z = sqr(E, z);
     102      7197332 :       z = mul(E, z, tw);
     103              :     }
     104     14142922 :     for (i = 1; i <= v; i++) z = sqr(E, z);
     105     20022958 :     while (l >= 0)
     106              :     {
     107     19778517 :       if (gc_needed(av,1))
     108              :       {
     109         3054 :         if (DEBUGMEM>1) pari_warn(warnmem,"sliding_window_pow (%ld)", l);
     110         3054 :         z = gc_GEN(av, z);
     111              :       }
     112     19778517 :       if (int_bit(n,l)) break;
     113     12559451 :       z = sqr(E, z); l--;
     114              :     }
     115              :   }
     116       244583 :   return z;
     117              : }
     118              : 
     119              : /* assume n != 0, t_INT. Compute x^|n| using leftright binary powering */
     120              : static GEN
     121     97549305 : leftright_binary_powu(GEN x, ulong n, void *E, GEN (*sqr)(void*,GEN),
     122              :                                                GEN (*mul)(void*,GEN,GEN))
     123              : {
     124     97549305 :   pari_sp av = avma;
     125              :   GEN  y;
     126              :   int j;
     127              : 
     128     97549305 :   if (n == 1) return x;
     129     97549305 :   y = x; j = 1+bfffo(n);
     130              :   /* normalize, i.e set highest bit to 1 (we know n != 0) */
     131     97549305 :   n<<=j; j = BITS_IN_LONG-j;
     132              :   /* first bit is now implicit */
     133    320843336 :   for (; j; n<<=1,j--)
     134              :   {
     135    223332262 :     y = sqr(E,y);
     136    223293535 :     if (n & HIGHBIT) y = mul(E,y,x); /* first bit set: multiply by base */
     137    223285382 :     if (gc_needed(av,1))
     138              :     {
     139            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"leftright_powu (%d)", j);
     140            0 :       y = gc_GEN(av, y);
     141              :     }
     142              :   }
     143     97511074 :   return y;
     144              : }
     145              : 
     146              : GEN
     147    110027920 : gen_powu_i(GEN x, ulong n, void *E, GEN (*sqr)(void*,GEN),
     148              :                                     GEN (*mul)(void*,GEN,GEN))
     149              : {
     150    110027920 :   if (n == 1) return x;
     151    106890220 :   if (n < 512)
     152     97548580 :     return leftright_binary_powu(x, n, E, sqr, mul);
     153              :   else
     154      9341640 :     return sliding_window_powu(x, n, n < (1UL<<25)? 2: 3, E, sqr, mul);
     155              : }
     156              : 
     157              : GEN
     158       215991 : gen_powu(GEN x, ulong n, void *E, GEN (*sqr)(void*,GEN),
     159              :                                   GEN (*mul)(void*,GEN,GEN))
     160              : {
     161       215991 :   pari_sp av = avma;
     162       215991 :   if (n == 1) return gcopy(x);
     163       181620 :   return gc_GEN(av, gen_powu_i(x,n,E,sqr,mul));
     164              : }
     165              : 
     166              : GEN
     167     38209847 : gen_pow_i(GEN x, GEN n, void *E, GEN (*sqr)(void*,GEN),
     168              :                                  GEN (*mul)(void*,GEN,GEN))
     169              : {
     170              :   long l, e;
     171     38209847 :   if (lgefint(n)==3) return gen_powu_i(x, uel(n,2), E, sqr, mul);
     172       221072 :   l = expi(n);
     173       221072 :   if      (l<=64)  e = 3;
     174       161905 :   else if (l<=160) e = 4;
     175        81936 :   else if (l<=384) e = 5;
     176        20583 :   else if (l<=896) e = 6;
     177        10808 :   else             e = 7;
     178       221072 :   return sliding_window_pow(x, n, e, E, sqr, mul);
     179              : }
     180              : 
     181              : GEN
     182     12042859 : gen_pow(GEN x, GEN n, void *E, GEN (*sqr)(void*,GEN),
     183              :                                GEN (*mul)(void*,GEN,GEN))
     184              : {
     185     12042859 :   pari_sp av = avma;
     186     12042859 :   return gc_GEN(av, gen_pow_i(x,n,E,sqr,mul));
     187              : }
     188              : 
     189              : /* assume n > 0. Compute x^n using left-right binary powering */
     190              : GEN
     191      1273486 : gen_powu_fold_i(GEN x, ulong n, void *E, GEN  (*sqr)(void*,GEN),
     192              :                                          GEN (*msqr)(void*,GEN))
     193              : {
     194      1273486 :   pari_sp av = avma;
     195              :   GEN y;
     196              :   int j;
     197              : 
     198      1273486 :   if (n == 1) return x;
     199      1273486 :   y = x; j = 1+bfffo(n);
     200              :   /* normalize, i.e set highest bit to 1 (we know n != 0) */
     201      1273486 :   n<<=j; j = BITS_IN_LONG-j;
     202              :   /* first bit is now implicit */
     203      5796297 :   for (; j; n<<=1,j--)
     204              :   {
     205      4522880 :     if (n & HIGHBIT) y = msqr(E,y); /* first bit set: multiply by base */
     206      3232249 :     else y = sqr(E,y);
     207      4522826 :     if (gc_needed(av,1))
     208              :     {
     209            0 :       if (DEBUGMEM>1) pari_warn(warnmem,"gen_powu_fold (%d)", j);
     210            0 :       y = gc_GEN(av, y);
     211              :     }
     212              :   }
     213      1273417 :   return y;
     214              : }
     215              : GEN
     216       215447 : gen_powu_fold(GEN x, ulong n, void *E, GEN (*sqr)(void*,GEN),
     217              :                                        GEN (*msqr)(void*,GEN))
     218              : {
     219       215447 :   pari_sp av = avma;
     220       215447 :   if (n == 1) return gcopy(x);
     221       201527 :   return gc_GEN(av, gen_powu_fold_i(x,n,E,sqr,msqr));
     222              : }
     223              : 
     224              : /* assume N != 0, t_INT. Compute x^|N| using left-right binary powering */
     225              : GEN
     226       687545 : gen_pow_fold_i(GEN x, GEN N, void *E, GEN (*sqr)(void*,GEN),
     227              :                                       GEN (*msqr)(void*,GEN))
     228              : {
     229       687545 :   long ln = lgefint(N);
     230       687545 :   if (ln == 3) return gen_powu_fold_i(x, N[2], E, sqr, msqr);
     231              :   else
     232              :   {
     233       152647 :     GEN nd = int_MSW(N), y = x;
     234       152647 :     ulong n = *nd;
     235              :     long i;
     236              :     int j;
     237       152647 :     pari_sp av = avma;
     238              : 
     239       152647 :     if (n == 1)
     240         7176 :       j = 0;
     241              :     else
     242              :     {
     243       145471 :       j = 1+bfffo(n); /* < BIL */
     244              :       /* normalize, i.e set highest bit to 1 (we know n != 0) */
     245       145471 :       n <<= j; j = BITS_IN_LONG - j;
     246              :     }
     247              :     /* first bit is now implicit */
     248       152647 :     for (i=ln-2;;)
     249              :     {
     250     50831203 :       for (; j; n<<=1,j--)
     251              :       {
     252     50069241 :         if (n & HIGHBIT) y = msqr(E,y); /* first bit set: multiply by base */
     253     35597683 :         else y = sqr(E,y);
     254     50102813 :         if (gc_needed(av,1))
     255              :         {
     256            0 :           if (DEBUGMEM>1) pari_warn(warnmem,"gen_pow_fold (%ld,%d)", i,j);
     257            0 :           y = gc_GEN(av, y);
     258              :         }
     259              :       }
     260       803625 :       if (--i == 0) return y;
     261       827067 :       nd = int_precW(nd);
     262       827067 :       n = *nd; j = BITS_IN_LONG;
     263              :     }
     264              :   }
     265              : }
     266              : GEN
     267       534898 : gen_pow_fold(GEN x, GEN n, void *E, GEN (*sqr)(void*,GEN),
     268              :                                     GEN (*msqr)(void*,GEN))
     269              : {
     270       534898 :   pari_sp av = avma;
     271       534898 :   return gc_GEN(av, gen_pow_fold_i(x,n,E,sqr,msqr));
     272              : }
     273              : 
     274              : GEN
     275          147 : gen_pow_init(GEN x, GEN n, long k, void *E, GEN (*sqr)(void*,GEN), GEN (*mul)(void*,GEN,GEN))
     276              : {
     277          147 :   long i, j, l = expi(n);
     278          147 :   long m = 1UL<<(k-1);
     279          147 :   GEN R = cgetg(m+1, t_VEC);
     280          147 :   GEN x2 = sqr(E, x), y = gcopy(x);
     281          644 :   for(i = 1; i <= m; i++)
     282              :   {
     283          497 :     GEN C = cgetg(l+1, t_VEC);
     284          497 :     gel(C,1) = y;
     285        27118 :     for(j = 2; j <= l; j++)
     286        26621 :       gel(C,j) = sqr(E, gel(C,j-1));
     287          497 :     gel(R,i) = C;
     288          497 :     y = mul(E, y, x2);
     289              :   }
     290          147 :   return R;
     291              : }
     292              : 
     293              : GEN
     294        53332 : gen_pow_table(GEN R, GEN n, void *E, GEN (*one)(void*), GEN (*mul)(void*,GEN,GEN))
     295              : {
     296        53332 :   long e = expu(lg(R)-1) + 1;
     297        53332 :   long l = expi(n);
     298              :   long i, w;
     299        53332 :   GEN z = one(E), tw;
     300      1241339 :   for(i=0; i<=l; )
     301              :   {
     302      1188007 :     if (int_bit(n, i)==0) { i++; continue; }
     303       605979 :     if (i+e-1>l) e = l+1-i;
     304       605979 :     w = int_block(n,i+e-1,e);
     305       605979 :     tw = gmael(R, 1+(w>>1), i+1);
     306       605979 :     z = mul(E, z, tw);
     307       605979 :     i += e;
     308              :   }
     309        53332 :   return z;
     310              : }
     311              : 
     312              : GEN
     313     28545512 : gen_powers(GEN x, long l, int use_sqr, void *E, GEN (*sqr)(void*,GEN),
     314              :                                       GEN (*mul)(void*,GEN,GEN), GEN (*one)(void*))
     315              : {
     316              :   long i;
     317     28545512 :   GEN V = cgetg(l+2,t_VEC);
     318     28545064 :   gel(V,1) = one(E); if (l==0) return V;
     319     28516256 :   gel(V,2) = gcopy(x); if (l==1) return V;
     320     12515592 :   gel(V,3) = sqr(E,x);
     321     12518650 :   if (use_sqr)
     322     41531885 :     for(i = 4; i < l+2; i++)
     323     31619684 :       gel(V,i) = (i&1)? sqr(E,gel(V, (i+1)>>1))
     324     31620419 :                       : mul(E,gel(V, i-1),x);
     325              :   else
     326      7320019 :     for(i = 4; i < l+2; i++)
     327      4713583 :       gel(V,i) = mul(E,gel(V,i-1),x);
     328     12517902 :   return V;
     329              : }
     330              : 
     331              : GEN
     332     59884800 : producttree_scheme(long n)
     333              : {
     334              :   GEN v, w;
     335              :   long i, j, k, u, l;
     336     59884800 :   if (n<=2) return mkvecsmall(n);
     337     49835236 :   u = expu(n-1);
     338     49835230 :   v = cgetg(n+1,t_VECSMALL);
     339     49835314 :   w = cgetg(n+1,t_VECSMALL);
     340     49835771 :   v[1] = n; l = 1;
     341    161022407 :   for (i=1; i<=u; i++)
     342              :   {
     343    424570494 :     for(j=1, k=1; j<=l; j++, k+=2)
     344              :     {
     345    313383858 :       long vj = v[j], v2 = vj>>1;
     346    313383858 :       w[k]    = vj-v2;
     347    313383858 :       w[k+1]  = v2;
     348              :     }
     349    111186636 :     swap(v,w); l<<=1;
     350              :   }
     351     49835771 :   fixlg(v, l+1); set_avma((pari_sp)v); return v;
     352              : }
     353              : 
     354              : GEN
     355     62394662 : gen_product(GEN x, void *E, GEN (*mul)(void *,GEN,GEN))
     356              : {
     357              :   pari_sp av;
     358     62394662 :   long i, k, l = lg(x);
     359              :   pari_timer ti;
     360              :   GEN y, v;
     361              : 
     362     62394662 :   if (l <= 2) return l == 1? gen_1: gcopy(gel(x,1));
     363     58104183 :   y = cgetg(l, t_VEC); av = avma;
     364     58104516 :   v = producttree_scheme(l-1);
     365     58105089 :   l = lg(v);
     366     58105089 :   if (DEBUGLEVEL>7) timer_start(&ti);
     367    421328290 :   for (k = i = 1; k < l; i += v[k++])
     368    363227863 :     gel(y,k) = v[k]==1? gel(x,i): mul(E, gel(x,i), gel(x,i+1));
     369    166223334 :   while (k > 2)
     370              :   {
     371    108118487 :     long n = k - 1;
     372    108118487 :     if (DEBUGLEVEL>7) timer_printf(&ti,"gen_product: remaining objects %ld",n);
     373    413225465 :     for (k = i = 1; i < n; i += 2) gel(y,k++) = mul(E, gel(y,i), gel(y,i+1));
     374    108120588 :     if (gc_needed(av,1)) gc_slice(av, y+1, k-1);
     375              :   }
     376     58104847 :   return gel(y,1);
     377              : }
     378              : 
     379              : /***********************************************************************/
     380              : /**                                                                   **/
     381              : /**                    DISCRETE LOGARITHM                             **/
     382              : /**                                                                   **/
     383              : /***********************************************************************/
     384              : static GEN
     385     63149955 : iter_rho(GEN x, GEN g, GEN q, GEN A, ulong h, void *E, const struct bb_group *grp)
     386              : {
     387     63149955 :   GEN a = gel(A,1), b = gel(A,2), c = gel(A,3);
     388     63149955 :   switch((h | grp->hash(a)) % 3UL)
     389              :   {
     390     21071935 :     case 0: return mkvec3(grp->pow(E,a,gen_2), Fp_mulu(b,2,q), Fp_mulu(c,2,q));
     391     21044759 :     case 1: return mkvec3(grp->mul(E,a,x), addiu(b,1), c);
     392     21033261 :     case 2: return mkvec3(grp->mul(E,a,g), b, addiu(c,1));
     393              :   }
     394              :   return NULL; /* LCOV_EXCL_LINE */
     395              : }
     396              : 
     397              : /*Generic Pollard rho discrete log algorithm*/
     398              : static GEN
     399           49 : gen_Pollard_log(GEN x, GEN g, GEN q, void *E, const struct bb_group *grp)
     400              : {
     401           49 :   pari_sp av=avma;
     402           49 :   GEN A, B, l, sqrt4q = sqrti(shifti(q,4));
     403           49 :   ulong i, h = 0, imax = itou_or_0(sqrt4q);
     404           49 :   if (!imax) imax = ULONG_MAX;
     405              :   do {
     406           49 :  rho_restart:
     407           49 :     A = B = mkvec3(x,gen_1,gen_0);
     408           49 :     i=0;
     409              :     do {
     410     21049985 :       if (i>imax)
     411              :       {
     412            0 :         h++;
     413            0 :         if (DEBUGLEVEL)
     414            0 :           pari_warn(warner,"changing Pollard rho hash seed to %ld",h);
     415            0 :         goto rho_restart;
     416              :       }
     417     21049985 :       A = iter_rho(x, g, q, A, h, E, grp);
     418     21049985 :       B = iter_rho(x, g, q, B, h, E, grp);
     419     21049985 :       B = iter_rho(x, g, q, B, h, E, grp);
     420     21049985 :       if (gc_needed(av,2))
     421              :       {
     422         1477 :         if(DEBUGMEM>1) pari_warn(warnmem,"gen_Pollard_log");
     423         1477 :         (void)gc_all(av, 2, &A, &B);
     424              :       }
     425     21049985 :       i++;
     426     21049985 :     } while (!grp->equal(gel(A,1), gel(B,1)));
     427           49 :     gel(A,2) = modii(gel(A,2), q);
     428           49 :     gel(B,2) = modii(gel(B,2), q);
     429           49 :     h++;
     430           49 :   } while (equalii(gel(A,2), gel(B,2)));
     431           49 :   l = Fp_div(Fp_sub(gel(B,3), gel(A,3),q),Fp_sub(gel(A,2), gel(B,2), q), q);
     432           49 :   return gc_INT(av, l);
     433              : }
     434              : 
     435              : /* compute a hash of g^(i-1), 1<=i<=n. Return [sorted hash, perm, g^-n] */
     436              : GEN
     437       763031 : gen_Shanks_init(GEN g, long n, void *E, const struct bb_group *grp)
     438              : {
     439       763031 :   GEN p1 = g, G, perm, table = cgetg(n+1,t_VECSMALL);
     440       763031 :   pari_sp av=avma;
     441              :   long i;
     442       763031 :   table[1] = grp->hash(grp->pow(E,g,gen_0));
     443      4422247 :   for (i=2; i<=n; i++)
     444              :   {
     445      3659216 :     table[i] = grp->hash(p1);
     446      3659216 :     p1 = grp->mul(E,p1,g);
     447      3659216 :     if (gc_needed(av,2))
     448              :     {
     449            0 :       if(DEBUGMEM>1) pari_warn(warnmem,"gen_Shanks_log, baby = %ld", i);
     450            0 :       p1 = gc_upto(av, p1);
     451              :     }
     452              :   }
     453       763031 :   G = gc_upto(av, grp->pow(E,p1,gen_m1)); /* g^-n */
     454       763031 :   perm = vecsmall_indexsort(table);
     455       763031 :   table = vecsmallpermute(table,perm);
     456       763031 :   return mkvec4(table,perm,g,G);
     457              : }
     458              : /* T from gen_Shanks_init(g,n). Return v < n*N such that x = g^v or NULL */
     459              : GEN
     460       768407 : gen_Shanks(GEN T, GEN x, ulong N, void *E, const struct bb_group *grp)
     461              : {
     462       768407 :   pari_sp av=avma;
     463       768407 :   GEN table = gel(T,1), perm = gel(T,2), g = gel(T,3), G = gel(T,4);
     464       768407 :   GEN p1 = x;
     465       768407 :   long n = lg(table)-1;
     466              :   ulong k;
     467      4660452 :   for (k=0; k<N; k++)
     468              :   { /* p1 = x G^k, G = g^-n */
     469      4308544 :     long h = grp->hash(p1), i = zv_search(table, h);
     470      4308544 :     if (i)
     471              :     {
     472       417407 :       do i--; while (i && table[i] == h);
     473       416499 :       for (i++; i <= n && table[i] == h; i++)
     474              :       {
     475       416499 :         GEN v = addiu(muluu(n,k), perm[i]-1);
     476       416499 :         if (grp->equal(grp->pow(E,g,v),x)) return gc_INT(av,v);
     477            0 :         if (DEBUGLEVEL)
     478            0 :           err_printf("gen_Shanks_log: false positive %lu, %lu\n", k,h);
     479              :       }
     480              :     }
     481      3892045 :     p1 = grp->mul(E,p1,G);
     482      3892045 :     if (gc_needed(av,2))
     483              :     {
     484            0 :       if(DEBUGMEM>1) pari_warn(warnmem,"gen_Shanks_log, k = %lu", k);
     485            0 :       p1 = gc_upto(av, p1);
     486              :     }
     487              :   }
     488       351908 :   return NULL;
     489              : }
     490              : /* Generic Shanks baby-step/giant-step algorithm. Return log_g(x), ord g = q.
     491              :  * One-shot: use gen_Shanks_init/log if many logs are desired; early abort
     492              :  * if log < sqrt(q) */
     493              : static GEN
     494      1548779 : gen_Shanks_log(GEN x, GEN g, GEN q, void *E, const struct bb_group *grp)
     495              : {
     496      1548779 :   pari_sp av=avma, av1;
     497              :   long lbaby, i, k;
     498              :   GEN p1, table, giant, perm, ginv;
     499      1548779 :   p1 = sqrti(q);
     500      1548780 :   if (abscmpiu(p1,LGBITS) >= 0)
     501            0 :     pari_err_OVERFLOW("gen_Shanks_log [order too large]");
     502      1548780 :   lbaby = itos(p1)+1; table = cgetg(lbaby+1,t_VECSMALL);
     503      1548780 :   ginv = grp->pow(E,g,gen_m1);
     504      1548780 :   av1 = avma;
     505      1548780 :   for (p1=x, i=1;;i++)
     506              :   {
     507      5115553 :     if (grp->equal1(p1)) return gc_stoi(av, i-1);
     508      4959737 :     table[i] = grp->hash(p1); if (i==lbaby) break;
     509      3566773 :     p1 = grp->mul(E,p1,ginv);
     510      3566773 :     if (gc_needed(av1,2))
     511              :     {
     512            6 :       if(DEBUGMEM>1) pari_warn(warnmem,"gen_Shanks_log, baby = %ld", i);
     513            6 :       p1 = gc_upto(av1, p1);
     514              :     }
     515              :   }
     516      1392964 :   p1 = giant = gc_upto(av1, grp->mul(E,x,grp->pow(E, p1, gen_m1)));
     517      1392964 :   perm = vecsmall_indexsort(table);
     518      1392964 :   table = vecsmallpermute(table,perm);
     519      1392964 :   av1 = avma;
     520      2202325 :   for (k=1; k<= lbaby; k++)
     521              :   {
     522      2202325 :     long h = grp->hash(p1), i = zv_search(table, h);
     523      2202325 :     if (i)
     524              :     {
     525      2785928 :       while (table[i] == h && i) i--;
     526      1392964 :       for (i++; i <= lbaby && table[i] == h; i++)
     527              :       {
     528      1392964 :         GEN v = addiu(mulss(lbaby-1,k),perm[i]-1);
     529      1392964 :         if (grp->equal(grp->pow(E,g,v),x)) return gc_INT(av,v);
     530            0 :         if (DEBUGLEVEL)
     531            0 :           err_printf("gen_Shanks_log: false positive %ld, %lu\n", k,h);
     532              :       }
     533              :     }
     534       809361 :     p1 = grp->mul(E,p1,giant);
     535       809361 :     if (gc_needed(av1,2))
     536              :     {
     537            1 :       if(DEBUGMEM>1) pari_warn(warnmem,"gen_Shanks_log, k = %ld", k);
     538            1 :       p1 = gc_upto(av1, p1);
     539              :     }
     540              :   }
     541            0 :   retgc_const(av, cgetg(1, t_VEC)); /* no solution */
     542              : }
     543              : 
     544              : /*Generic discrete logarithme in a group of prime order p*/
     545              : GEN
     546      6088242 : gen_plog(GEN x, GEN g, GEN p, void *E, const struct bb_group *grp)
     547              : {
     548      6088242 :   if (grp->easylog)
     549              :   {
     550      6009914 :     GEN e = grp->easylog(E, x, g, p);
     551      6009915 :     if (e) return e;
     552              :   }
     553      2798963 :   if (grp->equal1(x)) return gen_0;
     554      2792649 :   if (grp->equal(x,g)) return gen_1;
     555      1548829 :   if (expi(p)<32) return gen_Shanks_log(x,g,p,E,grp);
     556           49 :   return gen_Pollard_log(x, g, p, E, grp);
     557              : }
     558              : 
     559              : GEN
     560     11845175 : get_arith_ZZM(GEN o)
     561              : {
     562     11845175 :   if (!o) return NULL;
     563     11845175 :   switch(typ(o))
     564              :   {
     565      4028033 :     case t_INT:
     566      4028033 :       if (signe(o) > 0) return mkvec2(o, Z_factor(o));
     567            7 :       break;
     568      1454651 :     case t_MAT:
     569      1454651 :       if (is_Z_factorpos(o)) return mkvec2(factorback(o), o);
     570           14 :       break;
     571      6362498 :     case t_VEC:
     572      6362498 :       if (lg(o) == 3 && signe(gel(o,1)) > 0 && is_Z_factorpos(gel(o,2))) return o;
     573            0 :       break;
     574              :   }
     575           24 :   pari_err_TYPE("generic discrete logarithm (order factorization)",o);
     576              :   return NULL; /* LCOV_EXCL_LINE */
     577              : }
     578              : GEN
     579      1425271 : get_arith_Z(GEN o)
     580              : {
     581      1425271 :   if (!o) return NULL;
     582      1425271 :   switch(typ(o))
     583              :   {
     584      1159883 :     case t_INT:
     585      1159883 :       if (signe(o) > 0) return o;
     586            7 :       break;
     587           14 :     case t_MAT:
     588           14 :       o = factorback(o);
     589            0 :       if (typ(o) == t_INT && signe(o) > 0) return o;
     590            0 :       break;
     591       265367 :     case t_VEC:
     592       265367 :       if (lg(o) != 3) break;
     593       265367 :       o = gel(o,1);
     594       265367 :       if (typ(o) == t_INT && signe(o) > 0) return o;
     595            0 :       break;
     596              :   }
     597           14 :   pari_err_TYPE("generic discrete logarithm (order factorization)",o);
     598              :   return NULL; /* LCOV_EXCL_LINE */
     599              : }
     600              : 
     601              : /* Generic Pohlig-Hellman discrete logarithm: smallest integer n >= 0 such that
     602              :  * g^n=a. Assume ord(g) | ord; grp->easylog() is an optional trapdoor
     603              :  * function that catches easy logarithms */
     604              : GEN
     605      5021931 : gen_PH_log(GEN a, GEN g, GEN ord, void *E, const struct bb_group *grp)
     606              : {
     607      5021931 :   pari_sp av = avma;
     608              :   GEN v, ginv, fa, ex;
     609              :   long i, j, l;
     610              : 
     611      5021931 :   if (grp->equal(g, a)) /* frequent special case */
     612      1083921 :     return grp->equal1(g)? gen_0: gen_1;
     613      3938004 :   if (grp->easylog)
     614              :   {
     615      3888179 :     GEN e = grp->easylog(E, a, g, ord);
     616      3888150 :     if (e) return e;
     617              :   }
     618      2199029 :   v = get_arith_ZZM(ord);
     619      2199058 :   ord= gel(v,1);
     620      2199058 :   fa = gel(v,2);
     621      2199058 :   ex = gel(fa,2);
     622      2199058 :   fa = gel(fa,1); l = lg(fa);
     623      2199058 :   ginv = grp->pow(E,g,gen_m1);
     624      2199058 :   v = cgetg(l, t_VEC);
     625      6399661 :   for (i = 1; i < l; i++)
     626              :   {
     627      4200610 :     GEN q = gel(fa,i), qj, gq, nq, ginv0, a0, t0;
     628      4200610 :     long e = itos(gel(ex,i));
     629      4200610 :     if (DEBUGLEVEL>5)
     630            0 :       err_printf("Pohlig-Hellman: DL mod %Ps^%ld\n",q,e);
     631      4200610 :     qj = new_chunk(e+1);
     632      4200610 :     gel(qj,0) = gen_1;
     633      4200610 :     gel(qj,1) = q;
     634      6057266 :     for (j = 2; j <= e; j++) gel(qj,j) = mulii(gel(qj,j-1), q);
     635      4200610 :     t0 = diviiexact(ord, gel(qj,e));
     636      4200610 :     a0 = grp->pow(E, a, t0);
     637      4200610 :     ginv0 = grp->pow(E, ginv, t0); /* ord(ginv0) | q^e */
     638      4200610 :     if (grp->equal1(ginv0)) { gel(v,i) = mkintmod(gen_0, gen_1); continue; }
     639      4200603 :     do gq = grp->pow(E,g, mulii(t0, gel(qj,--e))); while (grp->equal1(gq));
     640              :     /* ord(gq) = q */
     641      4200596 :     nq = gen_0;
     642      4200596 :     for (j = 0;; j++)
     643      1856621 :     { /* nq = sum_{i<j} b_i q^i */
     644      6057217 :       GEN b = grp->pow(E,a0, gel(qj,e-j));
     645              :       /* cheap early abort: wrong local order */
     646      6057216 :       if (j == 0 && !grp->equal1(grp->pow(E,b,q))) {
     647            7 :         retgc_const(av, cgetg(1, t_VEC));
     648              :       }
     649      6057209 :       b = gen_plog(b, gq, q, E, grp);
     650      6057210 :       if (typ(b) != t_INT) retgc_const(av, cgetg(1, t_VEC));
     651      6057210 :       nq = addii(nq, mulii(b, gel(qj,j)));
     652      6057210 :       if (j == e) break;
     653              : 
     654      1856621 :       a0 = grp->mul(E,a0, grp->pow(E,ginv0, b));
     655      1856620 :       ginv0 = grp->pow(E,ginv0, q);
     656              :     }
     657      4200589 :     gel(v,i) = mkintmod(nq, gel(qj,e+1));
     658              :   }
     659      2199051 :   return gc_INT(av, lift(chinese1_coprime_Z(v)));
     660              : }
     661              : 
     662              : /***********************************************************************/
     663              : /**                                                                   **/
     664              : /**                    ORDER OF AN ELEMENT                            **/
     665              : /**                                                                   **/
     666              : /***********************************************************************/
     667              : 
     668              : static GEN
     669     13148794 : rec_order(GEN a, GEN o, GEN m,
     670              :           void *E, const struct bb_group *grp, long x, long y)
     671              : {
     672     13148794 :   pari_sp av = avma;
     673     13148794 :   if (grp->equal1(a)) return gen_1;
     674     10857074 :   if (x == y)
     675              :   {
     676      6488714 :     GEN p = gcoeff(m, x, 1);
     677      6488714 :     long i, e = itos(gcoeff(m, x, 2));
     678      6488697 :     if (e == 1) return icopy(p); /* a != 1 */
     679      4443486 :     for (i = 1; i < e; i++)
     680              :     {
     681      3263998 :       a = grp->pow(E, a, p);
     682      3263930 :       if (grp->equal1(a)) break;
     683              :     }
     684      2104963 :     return gc_INT(av, powiu(p, i));
     685              :   }
     686              :   else
     687              :   {
     688      4368360 :     GEN b, o1, o2, cof = gen_1;
     689      4368360 :     long i, z = (x+y)/2;
     690      9978640 :     for (i = x; i <= z; i++)
     691      5608010 :       cof = mulii(cof, powii(gcoeff(m, i, 1), gcoeff(m, i, 2)));
     692      4370630 :     b = grp->pow(E, a, cof);
     693      4369376 :     o1 = rec_order(b, diviiexact(o, cof), m, E, grp, z+1, y);
     694      4370396 :     b = grp->pow(E, a, o1);
     695      4369301 :     o2 = rec_order(b, diviiexact(o, o1), m, E, grp, x, z);
     696      4370703 :     return gc_INT(av, mulii(o1, o2));
     697              :   }
     698              : }
     699              : 
     700              : /*Find the exact order of a assuming a^o==1*/
     701              : GEN
     702      4418588 : gen_order(GEN a, GEN o, void *E, const struct bb_group *grp)
     703              : {
     704      4418588 :   pari_sp av = avma;
     705              :   long l;
     706              :   GEN m;
     707              : 
     708      4418588 :   m = get_arith_ZZM(o);
     709      4418605 :   if (!m) pari_err_TYPE("gen_order [missing order]",a);
     710      4418605 :   o = gel(m,1);
     711      4418605 :   if (is_pm1(o)) return gc_const(av, gen_1);
     712      4411052 :   m = gel(m,2); l = lgcols(m);
     713      4411050 :   return gc_INT(av, rec_order(a, o, m, E, grp, 1, l-1));
     714              : }
     715              : 
     716              : /*Find the exact order of a assuming a^o==1, return [order,factor(order)] */
     717              : GEN
     718         5488 : gen_factored_order(GEN a, GEN o, void *E, const struct bb_group *grp)
     719              : {
     720         5488 :   pari_sp av = avma;
     721              :   long i, l, ind;
     722              :   GEN m, F, P;
     723              : 
     724         5488 :   m = get_arith_ZZM(o);
     725         5488 :   if (!m) pari_err_TYPE("gen_factored_order [missing order]",a);
     726         5488 :   o = gel(m,1);
     727         5488 :   m = gel(m,2); l = lgcols(m);
     728         5488 :   P = cgetg(l, t_COL); ind = 1;
     729         5488 :   F = cgetg(l, t_COL);
     730        18935 :   for (i = l-1; i; i--)
     731              :   {
     732        13447 :     GEN t, y, p = gcoeff(m,i,1);
     733        13447 :     long j, e = itos(gcoeff(m,i,2));
     734        13447 :     if (l == 2) {
     735          679 :       t = gen_1;
     736          679 :       y = a;
     737              :     } else {
     738        12768 :       t = diviiexact(o, powiu(p,e));
     739        12768 :       y = grp->pow(E, a, t);
     740              :     }
     741        13447 :     if (grp->equal1(y)) o = t;
     742              :     else {
     743        16233 :       for (j = 1; j < e; j++)
     744              :       {
     745         4655 :         y = grp->pow(E, y, p);
     746         4655 :         if (grp->equal1(y)) break;
     747              :       }
     748        12285 :       gel(P,ind) = p;
     749        12285 :       gel(F,ind) = utoipos(j);
     750        12285 :       if (j < e) {
     751          707 :         if (j > 1) p = powiu(p, j);
     752          707 :         o = mulii(t, p);
     753              :       }
     754        12285 :       ind++;
     755              :     }
     756              :   }
     757         5488 :   setlg(P, ind); P = vecreverse(P);
     758         5488 :   setlg(F, ind); F = vecreverse(F);
     759         5488 :   return gc_GEN(av, mkvec2(o, mkmat2(P,F)));
     760              : }
     761              : 
     762              : /* E has order o[1], ..., or o[#o], draw random points until all solutions
     763              :  * but one are eliminated */
     764              : GEN
     765          973 : gen_select_order(GEN o, void *E, const struct bb_group *grp)
     766              : {
     767          973 :   pari_sp ltop = avma, btop;
     768              :   GEN lastgood, so, vo;
     769          973 :   long lo = lg(o), nbo=lo-1;
     770          973 :   if (nbo == 1) return icopy(gel(o,1));
     771          441 :   so = ZV_indexsort(o); /* minimize max( o[i+1] - o[i] ) */
     772          441 :   vo = zero_zv(lo);
     773          441 :   lastgood = gel(o, so[nbo]);
     774          441 :   btop = avma;
     775              :   for(;;)
     776            0 :   {
     777          441 :     GEN lasto = gen_0;
     778          441 :     GEN P = grp->rand(E), t = mkvec(gen_0);
     779              :     long i;
     780          567 :     for (i = 1; i < lo; i++)
     781              :     {
     782          567 :       GEN newo = gel(o, so[i]);
     783          567 :       if (vo[i]) continue;
     784          567 :       t = grp->mul(E,t, grp->pow(E, P, subii(newo,lasto)));/*P^o[i]*/
     785          567 :       lasto = newo;
     786          567 :       if (!grp->equal1(t))
     787              :       {
     788          483 :         if (--nbo == 1) { set_avma(ltop); return icopy(lastgood); }
     789           42 :         vo[i] = 1;
     790              :       }
     791              :       else
     792           84 :         lastgood = lasto;
     793              :     }
     794            0 :     set_avma(btop);
     795              :   }
     796              : }
     797              : 
     798              : /*******************************************************************/
     799              : /*                                                                 */
     800              : /*                          n-th ROOT                              */
     801              : /*                                                                 */
     802              : /*******************************************************************/
     803              : /* Assume l is prime. Return a generator of the l-th Sylow and set *zeta to an element
     804              :  * of order l.
     805              :  *
     806              :  * q = l^e*r, e>=1, (r,l)=1
     807              :  * UNCLEAN */
     808              : static GEN
     809       124147 : gen_lgener(GEN l, long e, GEN r,GEN *zeta, void *E, const struct bb_group *grp)
     810              : {
     811       124147 :   const pari_sp av1 = avma;
     812              :   GEN m, m1;
     813              :   long i;
     814        58614 :   for (;; set_avma(av1))
     815              :   {
     816       182761 :     m1 = m = grp->pow(E, grp->rand(E), r);
     817       182765 :     if (grp->equal1(m)) continue;
     818       218801 :     for (i=1; i<e; i++)
     819              :     {
     820        94650 :       m = grp->pow(E,m,l);
     821        94650 :       if (grp->equal1(m)) break;
     822              :     }
     823       141853 :     if (i==e) break;
     824              :   }
     825       124151 :   *zeta = m; return m1;
     826              : }
     827              : 
     828              : /* Let G be a cyclic group of order o>1. Returns a (random) generator */
     829              : 
     830              : GEN
     831        15883 : gen_gener(GEN o, void *E, const struct bb_group *grp)
     832              : {
     833        15883 :   pari_sp ltop = avma, av;
     834              :   long i, lpr;
     835        15883 :   GEN F, N, pr, z=NULL;
     836        15883 :   F = get_arith_ZZM(o);
     837        15883 :   N = gel(F,1); pr = gel(F,2); lpr = lgcols(pr);
     838        15883 :   av = avma;
     839              : 
     840        51562 :   for (i = 1; i < lpr; i++)
     841              :   {
     842        35679 :     GEN l = gcoeff(pr,i,1);
     843        35679 :     long e = itos(gcoeff(pr,i,2));
     844        35679 :     GEN r = diviiexact(N,powis(l,e));
     845        35679 :     GEN zetan, zl = gen_lgener(l,e,r,&zetan,E,grp);
     846        35679 :     z = i==1 ? zl: grp->mul(E,z,zl);
     847        35679 :     if (gc_needed(av,2))
     848              :     { /* n can have lots of prime factors*/
     849            0 :       if(DEBUGMEM>1) pari_warn(warnmem,"gen_gener");
     850            0 :       z = gc_upto(av, z);
     851              :     }
     852              :   }
     853        15883 :   return gc_upto(ltop, z);
     854              : }
     855              : 
     856              : /* solve x^l = a, l prime in G of order q.
     857              :  *
     858              :  * q =  (l^e)*r, e >= 1, (r,l) = 1
     859              :  * y is not an l-th power, hence generates the l-Sylow of G
     860              :  * m = y^(q/l) != 1 */
     861              : static GEN
     862        88528 : gen_Shanks_sqrtl(GEN a, GEN l, long e, GEN r, GEN y, GEN m,void *E,
     863              :                  const struct bb_group *grp)
     864              : {
     865        88528 :   pari_sp av = avma;
     866              :   long k;
     867              :   GEN p1, u1, u2, v, w, z, dl;
     868              : 
     869        88528 :   (void)bezout(r,l,&u1,&u2);
     870        88529 :   v = grp->pow(E,a,u2);
     871        88529 :   w = grp->pow(E,v,l);
     872        88529 :   w = grp->mul(E,w,grp->pow(E,a,gen_m1));
     873       119562 :   while (!grp->equal1(w))
     874              :   {
     875        31039 :     k = 0;
     876        31039 :     p1 = w;
     877              :     do
     878              :     {
     879        46088 :       z = p1; p1 = grp->pow(E,p1,l);
     880        46089 :       k++;
     881        46089 :     } while(!grp->equal1(p1));
     882        31040 :     if (k==e) return gc_NULL(av);
     883        31033 :     dl = gen_plog(z,m,l,E,grp);
     884        31033 :     if (typ(dl) != t_INT) return gc_NULL(av);
     885        31033 :     dl = negi(dl);
     886        31033 :     p1 = grp->pow(E, grp->pow(E,y, dl), powiu(l,e-k-1));
     887        31033 :     m = grp->pow(E,m,dl);
     888        31033 :     e = k;
     889        31033 :     v = grp->mul(E,p1,v);
     890        31033 :     y = grp->pow(E,p1,l);
     891        31033 :     w = grp->mul(E,y,w);
     892        31033 :     if (gc_needed(av,1))
     893              :     {
     894            0 :       if(DEBUGMEM>1) pari_warn(warnmem,"gen_Shanks_sqrtl");
     895            0 :       (void)gc_all(av,4, &y,&v,&w,&m);
     896              :     }
     897              :   }
     898        88521 :   return gc_GEN(av, v);
     899              : }
     900              : /* Return one solution of x^n = a in a cyclic group of order q
     901              :  *
     902              :  * 1) If there is no solution, return NULL.
     903              :  *
     904              :  * 2) If there is a solution, there are exactly m of them [m = gcd(q-1,n)].
     905              :  * If zetan!=NULL, *zetan is set to a primitive m-th root of unity so that
     906              :  * the set of solutions is { x*zetan^k; k=0..m-1 }
     907              :  */
     908              : GEN
     909        91239 : gen_Shanks_sqrtn(GEN a, GEN n, GEN q, GEN *zetan, void *E, const struct bb_group *grp)
     910              : {
     911        91239 :   pari_sp ltop = avma;
     912              :   GEN m, u1, u2, z;
     913              :   int is_1;
     914              : 
     915        91239 :   if (is_pm1(n))
     916              :   {
     917           28 :     if (zetan) *zetan = grp->pow(E,a,gen_0);
     918           28 :     return signe(n) < 0? grp->pow(E,a,gen_m1): gcopy(a);
     919              :   }
     920        91211 :   is_1 = grp->equal1(a);
     921        91210 :   if (is_1 && !zetan) return gcopy(a);
     922              : 
     923        89231 :   m = bezout(n,q,&u1,&u2);
     924        89235 :   z = grp->pow(E,a,gen_0);
     925        89232 :   if (!is_pm1(m))
     926              :   {
     927        88462 :     GEN F = Z_factor(m);
     928              :     long i, j, e;
     929              :     GEN r, zeta, y, l;
     930        88461 :     pari_sp av1 = avma;
     931       176925 :     for (i = nbrows(F); i; i--)
     932              :     {
     933        88468 :       l = gcoeff(F,i,1);
     934        88468 :       j = itos(gcoeff(F,i,2));
     935        88468 :       e = Z_pvalrem(q,l,&r);
     936        88468 :       y = gen_lgener(l,e,r,&zeta,E,grp);
     937        88472 :       if (zetan) z = grp->mul(E,z, grp->pow(E,y,powiu(l,e-j)));
     938        88472 :       if (!is_1) {
     939              :         do
     940              :         {
     941        88528 :           a = gen_Shanks_sqrtl(a,l,e,r,y,zeta,E,grp);
     942        88527 :           if (!a) return gc_NULL(ltop);
     943        88520 :         } while (--j);
     944              :       }
     945        88464 :       if (gc_needed(ltop,1))
     946              :       { /* n can have lots of prime factors*/
     947            0 :         if(DEBUGMEM>1) pari_warn(warnmem,"gen_Shanks_sqrtn");
     948            0 :         (void)gc_all(av1, zetan? 2: 1, &a, &z);
     949              :       }
     950              :     }
     951              :   }
     952        89227 :   if (!equalii(m, n))
     953          784 :     a = grp->pow(E,a,modii(u1,q));
     954        89227 :   if (zetan)
     955              :   {
     956         1607 :     *zetan = z;
     957         1607 :     (void)gc_all(ltop,2,&a,zetan);
     958              :   }
     959              :   else /* is_1 is 0: a was modified above -> gc_upto valid */
     960        87620 :     a = gc_upto(ltop, a);
     961        89227 :   return a;
     962              : }
     963              : 
     964              : /*******************************************************************/
     965              : /*                                                                 */
     966              : /*               Structure of groups with pairing                  */
     967              : /*                                                                 */
     968              : /*******************************************************************/
     969              : /* Return \prod_{p^2 | (N,d^2)} p^{v_p(N)} as a factorization; multiple of d2 */
     970              : static GEN
     971       146671 : d2_multiple(GEN N, GEN d)
     972              : {
     973       146671 :   GEN P = gel(Z_factor(gcdii(N,d)), 1);
     974       146671 :   long i, j, l = lg(P);
     975       146671 :   GEN E = cgetg(l, t_VECSMALL);
     976       271747 :   for (i = 1, j = 1; i < l; i++)
     977              :   {
     978       125076 :     GEN p = gel(P, i);
     979       125076 :     long v = Z_pval(N, p);
     980       125076 :     if (v > 1) { gel(P, j) = p; E[j] = v; j++; }
     981              :   }
     982       146671 :   if (j == 1) return NULL;
     983        65100 :   setlg(P,j); setlg(E,j); return mkvec2(P, E);
     984              : }
     985              : 
     986              : /* Return elementary divisors [d1, d2], d2 | d1, for group of order N.
     987              :  * We have d2 | D */
     988              : GEN
     989       146832 : gen_ellgroup(GEN N, GEN D, GEN *pm, void *E, const struct bb_group *grp,
     990              :              GEN pairorder(void *E, GEN P, GEN Q, GEN m, GEN F))
     991              : {
     992       146832 :   pari_sp av = avma;
     993       146832 :   GEN N0, N1, F, fa0, L0, E0, m = gen_1, d = gen_1;
     994       146832 :   long n = 0, n0, j;
     995              : 
     996       146832 :   if (pm) *pm = gen_1;
     997       146832 :   if (is_pm1(N)) return cgetg(1,t_VEC);
     998       146671 :   fa0 = d2_multiple(N, D); if (!fa0) { set_avma(av); return mkveccopy(N); }
     999        65100 :   L0 = gel(fa0, 1); n0 = lg(L0)-1;
    1000        65100 :   E0 = gel(fa0, 2);
    1001        65100 :   N0 = factorback2(L0, E0); /* d2 | N0 */
    1002        65100 :   N1 = diviiexact(N, N0); /* N1 | d1 */
    1003        65100 :   F = mkvec2(N0, mkmat2(L0, zc_to_ZC(E0)));
    1004              :   while (1)
    1005        51775 :   { /* g1 | (d1/N1), g2 | d2 */
    1006       116875 :     pari_sp av2 = avma;
    1007              :     GEN P, Q, s, t, mi, o;
    1008              : 
    1009       116875 :     P = grp->pow(E,grp->rand(E), N1);
    1010       116875 :     s = gen_order(P, F, E, grp); /* s | N0 */
    1011       116875 :     if (equalii(s, N0)) { set_avma(av); return mkveccopy(N); }
    1012              : 
    1013        93495 :     Q = grp->pow(E,grp->rand(E), N1);
    1014        93495 :     t = gen_order(Q, F, E, grp); /* t | N0 */
    1015        93495 :     if (equalii(t, N0)) { set_avma(av); return mkveccopy(N); }
    1016              : 
    1017        82230 :     mi = lcmii(s, t); /* mi | N0 */
    1018        82230 :     o = pairorder(E, P, Q, mi, F);
    1019              : 
    1020              :     /* For each prime p | N0, check whether P and Q generate the p-Sylow */
    1021       139206 :     for (j = 1; j <= n0; j++)
    1022              :     {
    1023        87431 :       long vm, vo, e = uel(E0, j);
    1024        87431 :       GEN p = gel(L0, j);
    1025        87431 :       if (e == 0) continue;
    1026        85447 :       vm = Z_pval(mi, p); vo = e - vm;
    1027        85447 :       if (Z_pval(o, p) != vo) continue;
    1028        33289 :       m = mulii(m, powiu(p, vm));
    1029        33289 :       d = mulii(d, powiu(p, vo));
    1030        33289 :       if (++n == n0)
    1031              :       { /* done with all primes p */
    1032              :         GEN g;
    1033        30455 :         if (equali1(d)) { set_avma(av); return mkveccopy(N); }
    1034        30296 :         g = mkvec2(mulii(m, N1), d);
    1035        30296 :         if (!pm) return gc_GEN(av, g);
    1036        30296 :         *pm = m; return gc_all(av, 2, &g, pm);
    1037              :       }
    1038         2834 :       uel(E0, j) = 0; /* done with this prime p */
    1039              :     }
    1040        51775 :     (void)gc_all(av2, 2, &m, &d);
    1041              :   }
    1042              : }
    1043              : 
    1044              : GEN
    1045         2716 : gen_ellgens(GEN D1, GEN d2, GEN m, void *E, const struct bb_group *grp,
    1046              :              GEN pairorder(void *E, GEN P, GEN Q, GEN m, GEN F))
    1047              : {
    1048         2716 :   pari_sp ltop = avma, av;
    1049              :   GEN F, d1, dm;
    1050              :   GEN P, Q, d, s;
    1051         2716 :   F = get_arith_ZZM(D1);
    1052         2716 :   d1 = gel(F, 1), dm =  diviiexact(d1,m);
    1053         2716 :   av = avma;
    1054              :   do
    1055              :   {
    1056         7102 :     set_avma(av);
    1057         7102 :     P = grp->rand(E);
    1058         7102 :     s = gen_order(P, F, E, grp);
    1059         7102 :   } while (!equalii(s, d1));
    1060         2716 :   av = avma;
    1061              :   do
    1062              :   {
    1063         5186 :     set_avma(av);
    1064         5186 :     Q = grp->rand(E);
    1065         5186 :     d = pairorder(E, grp->pow(E, P, dm), grp->pow(E, Q, dm), m, F);
    1066         5186 :   } while (!equalii(d, d2));
    1067         2716 :   return gc_GEN(ltop, mkvec2(P,Q));
    1068              : }
        

Generated by: LCOV version 2.0-1