1 /* Copyright (C) 2007  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 polynomials over F_2 */
19 
20 /***********************************************************************/
21 /**                                                                   **/
22 /**                             F2x                                   **/
23 /**                                                                   **/
24 /***********************************************************************/
25 /* F2x objects are defined as follows:
26    An F2x is a t_VECSMALL:
27    x[0] = codeword
28    x[1] = evalvarn(variable number)  (signe is not stored).
29    x[2] = a_0...a_31 x[3] = a_32..a_63, etc.  on 32bit
30    x[2] = a_0...a_63 x[3] = a_64..a_127, etc. on 64bit
31 
32    where the a_i are bits.
33 
34    signe(x) is not valid. Use lgpol(x)!=0 instead.
35    Note: pol0_F2x=pol0_Flx and pol1_F2x=pol1_Flx
36 */
37 
38 INLINE long
F2x_degreespec(GEN x,long l)39 F2x_degreespec(GEN x, long l)
40 {
41   return (l==0)?-1:l*BITS_IN_LONG-bfffo(x[l-1])-1;
42 }
43 
44 INLINE long
F2x_degree_lg(GEN x,long l)45 F2x_degree_lg(GEN x, long l)
46 {
47   return (l==2)?-1:bit_accuracy(l)-bfffo(x[l-1])-1;
48 }
49 
50 long
F2x_degree(GEN x)51 F2x_degree(GEN x)
52 {
53   return F2x_degree_lg(x, lg(x));
54 }
55 
56 GEN
monomial_F2x(long d,long vs)57 monomial_F2x(long d, long vs)
58 {
59   long l=nbits2lg(d+1);
60   GEN z = zero_zv(l-1);
61   z[1] = vs;
62   F2x_set(z,d);
63   return z;
64 }
65 
66 GEN
F2x_to_ZX(GEN x)67 F2x_to_ZX(GEN x)
68 {
69   long l = 3+F2x_degree(x), lx = lg(x);
70   GEN z = cgetg(l,t_POL);
71   long i, j ,k;
72   for (i=2, k=2; i<lx; i++)
73     for (j=0; j<BITS_IN_LONG && k<l; j++,k++)
74       gel(z,k) = (x[i]&(1UL<<j))?gen_1:gen_0;
75   z[1]=evalsigne(l>=3)|x[1];
76   return z;
77 }
78 
79 GEN
F2x_to_Flx(GEN x)80 F2x_to_Flx(GEN x)
81 {
82   long l = 3+F2x_degree(x), lx = lg(x);
83   GEN z = cgetg(l,t_VECSMALL);
84   long i, j, k;
85   z[1] = x[1];
86   for (i=2, k=2; i<lx; i++)
87     for (j=0; j<BITS_IN_LONG && k<l; j++,k++)
88       z[k] = (x[i]>>j)&1UL;
89   return z;
90 }
91 
92 GEN
F2x_to_F2xX(GEN z,long sv)93 F2x_to_F2xX(GEN z, long sv)
94 {
95   long i, d = F2x_degree(z);
96   GEN x = cgetg(d+3,t_POL);
97   for (i=0; i<=d; i++)
98     gel(x,i+2) = F2x_coeff(z,i) ? pol1_F2x(sv): pol0_F2x(sv);
99   x[1] = evalsigne(d+1!=0)| z[1]; return x;
100 }
101 
102 GEN
Z_to_F2x(GEN x,long sv)103 Z_to_F2x(GEN x, long sv)
104 {
105   return mpodd(x) ? pol1_F2x(sv): pol0_F2x(sv);
106 }
107 
108 GEN
ZX_to_F2x(GEN x)109 ZX_to_F2x(GEN x)
110 {
111   long lx = lg(x), l = nbits2lg(lx-2);
112   GEN z = cgetg(l,t_VECSMALL);
113   long i, j, k;
114   z[1] = ((ulong)x[1])&VARNBITS;
115   for (i=2, k=1,j=BITS_IN_LONG; i<lx; i++,j++)
116   {
117     if (j==BITS_IN_LONG)
118     {
119       j=0; z[++k]=0;
120     }
121     if (mpodd(gel(x,i)))
122       z[k] |= 1UL<<j;
123   }
124   return F2x_renormalize(z,l);
125 }
126 
127 GEN
Flx_to_F2x(GEN x)128 Flx_to_F2x(GEN x)
129 {
130   long lx = lg(x), l = nbits2lg(lx-2);
131   GEN z = cgetg(l,t_VECSMALL);
132   long i, j, k;
133   z[1] = x[1];
134   for (i=2, k=1, j=BITS_IN_LONG; i<lx; i++,j++)
135   {
136     if (j==BITS_IN_LONG)
137     {
138       j=0; z[++k] = 0;
139     }
140     if (x[i]&1UL)
141       z[k] |= 1UL<<j;
142   }
143   return F2x_renormalize(z,l);
144 }
145 
146 GEN
F2x_to_F2v(GEN x,long N)147 F2x_to_F2v(GEN x, long N)
148 {
149   long i, l = lg(x);
150   long n = nbits2lg(N);
151   GEN z = cgetg(n,t_VECSMALL);
152   z[1] = N;
153   for (i=2; i<l ; i++) z[i]=x[i];
154   for (   ; i<n; i++) z[i]=0;
155   return z;
156 }
157 
158 GEN
RgX_to_F2x(GEN x)159 RgX_to_F2x(GEN x)
160 {
161   long l=nbits2lg(lgpol(x));
162   GEN z=cgetg(l,t_VECSMALL);
163   long i,j,k;
164   z[1]=((ulong)x[1])&VARNBITS;
165   for(i=2, k=1,j=BITS_IN_LONG;i<lg(x);i++,j++)
166   {
167     if (j==BITS_IN_LONG)
168     {
169       j=0; k++; z[k]=0;
170     }
171     if (Rg_to_F2(gel(x,i)))
172       z[k]|=1UL<<j;
173   }
174   return F2x_renormalize(z,l);
175 }
176 
177 /* If x is a POLMOD, assume modulus is a multiple of T. */
178 GEN
Rg_to_F2xq(GEN x,GEN T)179 Rg_to_F2xq(GEN x, GEN T)
180 {
181   long ta, tx = typ(x), v = get_F2x_var(T);
182   GEN a, b;
183   if (is_const_t(tx))
184   {
185     if (tx == t_FFELT) return FF_to_F2xq(x);
186     return Rg_to_F2(x)? pol1_F2x(v): pol0_F2x(v);
187   }
188   switch(tx)
189   {
190     case t_POLMOD:
191       b = gel(x,1);
192       a = gel(x,2); ta = typ(a);
193       if (is_const_t(ta)) return Rg_to_F2(a)? pol1_F2x(v): pol0_F2x(v);
194       b = RgX_to_F2x(b); if (b[1] != v) break;
195       a = RgX_to_F2x(a); if (F2x_equal(b,T)) return a;
196       if (lgpol(F2x_rem(b,T))==0) return F2x_rem(a, T);
197       break;
198     case t_POL:
199       x = RgX_to_F2x(x);
200       if (x[1] != v) break;
201       return F2x_rem(x, T);
202     case t_RFRAC:
203       a = Rg_to_F2xq(gel(x,1), T);
204       b = Rg_to_F2xq(gel(x,2), T);
205       return F2xq_div(a,b, T);
206   }
207   pari_err_TYPE("Rg_to_F2xq",x);
208   return NULL; /* LCOV_EXCL_LINE */
209 }
210 
211 ulong
F2x_eval(GEN P,ulong x)212 F2x_eval(GEN P, ulong x)
213 {
214   if (odd(x))
215   {
216     long i, lP = lg(P);
217     ulong c = 0;
218     for (i=2; i<lP; i++)
219       c ^= P[i];
220 #ifdef LONG_IS_64BIT
221     c ^= c >> 32;
222 #endif
223     c ^= c >> 16;
224     c ^= c >>  8;
225     c ^= c >>  4;
226     c ^= c >>  2;
227     c ^= c >>  1;
228     return c & 1;
229   }
230   else return F2x_coeff(P,0);
231 }
232 
233 GEN
F2x_add(GEN x,GEN y)234 F2x_add(GEN x, GEN y)
235 {
236   long i,lz;
237   GEN z;
238   long lx=lg(x);
239   long ly=lg(y);
240   if (ly>lx) swapspec(x,y, lx,ly);
241   lz = lx; z = cgetg(lz, t_VECSMALL); z[1]=x[1];
242   for (i=2; i<ly; i++) z[i] = x[i]^y[i];
243   for (   ; i<lx; i++) z[i] = x[i];
244   return F2x_renormalize(z, lz);
245 }
246 
247 static GEN
F2x_addspec(GEN x,GEN y,long lx,long ly)248 F2x_addspec(GEN x, GEN y, long lx, long ly)
249 {
250   long i,lz;
251   GEN z;
252 
253   if (ly>lx) swapspec(x,y, lx,ly);
254   lz = lx+2; z = cgetg(lz, t_VECSMALL) + 2;
255   for (i=0; i<ly-3; i+=4)
256   {
257     z[i] = x[i]^y[i];
258     z[i+1] = x[i+1]^y[i+1];
259     z[i+2] = x[i+2]^y[i+2];
260     z[i+3] = x[i+3]^y[i+3];
261   }
262   for (; i<ly; i++)
263     z[i] = x[i]^y[i];
264   for (   ; i<lx; i++) z[i] = x[i];
265   z -= 2; z[1] = 0; return F2x_renormalize(z, lz);
266 }
267 
268 GEN
F2x_1_add(GEN y)269 F2x_1_add(GEN y)
270 {
271   GEN z;
272   long lz, i;
273   if (!lgpol(y))
274     return pol1_F2x(y[1]);
275   lz=lg(y);
276   z=cgetg(lz,t_VECSMALL);
277   z[1] = y[1];
278   z[2] = y[2]^1UL;
279   for(i=3;i<lz;i++)
280     z[i] = y[i];
281   if (lz==3) z = F2x_renormalize(z,lz);
282   return z;
283 }
284 
285 INLINE void
F2x_addshiftipspec(GEN x,GEN y,long ny,ulong db)286 F2x_addshiftipspec(GEN x, GEN y, long ny, ulong db)
287 {
288   long i;
289   if (db)
290   {
291     ulong dc=BITS_IN_LONG-db;
292     ulong r=0, yi;
293     for(i=0; i<ny-3; i+=4)
294     {
295       yi = uel(y,i);   x[i]   ^= (yi<<db)|r; r = yi>>dc;
296       yi = uel(y,i+1); x[i+1] ^= (yi<<db)|r; r = yi>>dc;
297       yi = uel(y,i+2); x[i+2] ^= (yi<<db)|r; r = yi>>dc;
298       yi = uel(y,i+3); x[i+3] ^= (yi<<db)|r; r = yi>>dc;
299     }
300     for(  ; i<ny; i++)
301     {
302       ulong yi = uel(y,i); x[i] ^= (yi<<db)|r; r = yi>>dc;
303     }
304     if (r) x[i] ^= r;
305   }
306   else
307   {
308     for(i=0; i<ny-3; i+=4)
309     {
310       x[i]   ^= y[i];
311       x[i+1] ^= y[i+1];
312       x[i+2] ^= y[i+2];
313       x[i+3] ^= y[i+3];
314     }
315     for(   ; i<ny; i++)
316       x[i] ^= y[i];
317   }
318 }
319 
320 INLINE void
F2x_addshiftip(GEN x,GEN y,ulong d)321 F2x_addshiftip(GEN x, GEN y, ulong d)
322 {
323   ulong db, dl=dvmduBIL(d, &db);
324   F2x_addshiftipspec(x+2+dl, y+2, lgpol(y), db);
325 }
326 
327 static GEN
F2x_mul1(ulong x,ulong y)328 F2x_mul1(ulong x, ulong y)
329 {
330   ulong x1=(x&HIGHMASK)>>BITS_IN_HALFULONG;
331   ulong x2=x&LOWMASK;
332   ulong y1=(y&HIGHMASK)>>BITS_IN_HALFULONG;
333   ulong y2=y&LOWMASK;
334   ulong r1,r2,rr;
335   GEN z;
336   ulong i;
337   rr=r1=r2=0UL;
338   if (x2)
339     for(i=0;i<BITS_IN_HALFULONG;i++)
340       if (x2&(1UL<<i))
341       {
342         r2^=y2<<i;
343         rr^=y1<<i;
344       }
345   if (x1)
346     for(i=0;i<BITS_IN_HALFULONG;i++)
347       if (x1&(1UL<<i))
348       {
349         r1^=y1<<i;
350         rr^=y2<<i;
351       }
352   r2^=(rr&LOWMASK)<<BITS_IN_HALFULONG;
353   r1^=(rr&HIGHMASK)>>BITS_IN_HALFULONG;
354   z=cgetg((r1?4:3),t_VECSMALL);
355   z[2]=r2;
356   if (r1) z[3]=r1;
357   return z;
358 }
359 
360 static GEN
F2x_mulspec_basecase(GEN x,GEN y,long nx,long ny)361 F2x_mulspec_basecase(GEN x, GEN y, long nx, long ny)
362 {
363   long l, i, j;
364   GEN z;
365   l = nx + ny;
366   z = zero_Flv(l+1);
367   for(i=0; i < ny-1; i++)
368   {
369     GEN zi = z+2+i;
370     ulong yi = uel(y,i);
371     if (yi)
372       for(j=0; j < BITS_IN_LONG; j++)
373         if (yi&(1UL<<j)) F2x_addshiftipspec(zi,x,nx,j);
374   }
375   {
376     GEN zi = z+2+i;
377     ulong yi = uel(y,i);
378     long c = BITS_IN_LONG-bfffo(yi);
379     for(j=0; j < c; j++)
380       if (yi&(1UL<<j)) F2x_addshiftipspec(zi,x,nx,j);
381   }
382   return F2x_renormalize(z, l+2);
383 }
384 
385 static GEN
F2x_addshift(GEN x,GEN y,long d)386 F2x_addshift(GEN x, GEN y, long d)
387 {
388   GEN xd,yd,zd = (GEN)avma;
389   long a,lz,ny = lgpol(y), nx = lgpol(x);
390   long vs = x[1];
391   if (nx == 0) return y;
392   x += 2; y += 2; a = ny-d;
393   if (a <= 0)
394   {
395     lz = (a>nx)? ny+2: nx+d+2;
396     (void)new_chunk(lz); xd = x+nx; yd = y+ny;
397     while (xd > x) *--zd = *--xd;
398     x = zd + a;
399     while (zd > x) *--zd = 0;
400   }
401   else
402   {
403     xd = new_chunk(d); yd = y+d;
404     x = F2x_addspec(x,yd,nx,a);
405     lz = (a>nx)? ny+2: lg(x)+d;
406     x += 2; while (xd > x) *--zd = *--xd;
407   }
408   while (yd > y) *--zd = *--yd;
409   *--zd = vs;
410   *--zd = evaltyp(t_VECSMALL) | evallg(lz); return zd;
411 }
412 
413 /* shift polynomial + gerepile */
414 /* Do not set evalvarn. Cf Flx_shiftip */
415 static GEN
F2x_shiftip(pari_sp av,GEN x,long v)416 F2x_shiftip(pari_sp av, GEN x, long v)
417 {
418   long i, lx = lg(x), ly;
419   GEN y;
420   if (!v || lx==2) return gerepileuptoleaf(av, x);
421   ly = lx + v;
422   (void)new_chunk(ly); /* check that result fits */
423   x += lx; y = (GEN)av;
424   for (i = 2; i<lx; i++) *--y = *--x;
425   for (i = 0; i< v; i++) *--y = 0;
426   y -= 2; y[0] = evaltyp(t_VECSMALL) | evallg(ly);
427   return gc_const((pari_sp)y, y);
428 }
429 
430 static GEN
F2x_to_int(GEN a,long na,long da,long bs)431 F2x_to_int(GEN a, long na, long da, long bs)
432 {
433   const long BIL = BITS_IN_LONG;
434   GEN z, zs;
435   long i,j,k,m;
436   long lz = nbits2lg(1+da*bs);
437   z = cgeti(lz); z[1] = evalsigne(1)|evallgefint(lz);
438   zs = int_LSW(z); *zs = 0;
439   for (i=0, k=2, m=0; i<na; i++)
440     for (j=0; j<BIL; j++, m+=bs)
441     {
442       if (m >= BIL)
443       {
444         k++; if (k>=lz) break;
445         zs = int_nextW(zs);
446         *zs = 0;
447         m -= BIL;
448       }
449       *zs |= ((a[i]>>j)&1UL)<<m;
450     }
451   return int_normalize(z,0);
452 }
453 
454 static GEN
int_to_F2x(GEN x,long d,long bs)455 int_to_F2x(GEN x, long d, long bs)
456 {
457   const long BIL = BITS_IN_LONG;
458   long lx = lgefint(x), lz = nbits2lg(d+1);
459   long i,j,k,m;
460   GEN xs = int_LSW(x);
461   GEN z = cgetg(lz, t_VECSMALL);
462   z[1] = 0;
463   for (k=2, i=2, m=0; k < lx; i++)
464   {
465     z[i] = 0;
466     for (j=0; j<BIL; j++, m+=bs)
467     {
468       if (m >= BIL)
469       {
470         if (++k==lx) break;
471         xs = int_nextW(xs);
472         m -= BIL;
473       }
474       if ((*xs>>m)&1UL)
475         z[i]|=1UL<<j;
476     }
477   }
478   return F2x_renormalize(z,lz);
479 }
480 
481 static GEN
F2x_mulspec_mulii(GEN a,GEN b,long na,long nb)482 F2x_mulspec_mulii(GEN a, GEN b, long na, long nb)
483 {
484   long da = F2x_degreespec(a,na), db = F2x_degreespec(b,nb);
485   long bs = expu(1 + maxss(da, db))+1;
486   GEN A = F2x_to_int(a,na,da,bs);
487   GEN B = F2x_to_int(b,nb,db,bs);
488   GEN z = mulii(A,B);
489   return int_to_F2x(z,da+db,bs);
490 }
491 
492 /* fast product (Karatsuba) of polynomials a,b. These are not real GENs, a+2,
493  * b+2 were sent instead. na, nb = number of terms of a, b.
494  * Only c, c0, c1, c2 are genuine GEN.
495  */
496 static GEN
F2x_mulspec(GEN a,GEN b,long na,long nb)497 F2x_mulspec(GEN a, GEN b, long na, long nb)
498 {
499   GEN a0,c,c0;
500   long n0, n0a, i, v = 0;
501   pari_sp av;
502   while (na && !a[0]) { a++; na-=1; v++; }
503   while (nb && !b[0]) { b++; nb-=1; v++; }
504   if (na < nb) swapspec(a,b, na,nb);
505   if (!nb) return pol0_F2x(0);
506 
507   av = avma;
508   if (na == 1)
509     return F2x_shiftip(av, F2x_mul1(*a,*b), v);
510   if (na < F2x_MUL_KARATSUBA_LIMIT)
511     return F2x_shiftip(av, F2x_mulspec_basecase(a, b, na, nb), v);
512   if (nb >= F2x_MUL_MULII_LIMIT)
513     return F2x_shiftip(av, F2x_mulspec_mulii(a, b, na, nb), v);
514   i=(na>>1); n0=na-i; na=i;
515   a0=a+n0; n0a=n0;
516   while (n0a && !a[n0a-1]) n0a--;
517 
518   if (nb > n0)
519   {
520     GEN b0,c1,c2;
521     long n0b;
522 
523     nb -= n0; b0 = b+n0; n0b = n0;
524     while (n0b && !b[n0b-1]) n0b--;
525     c =  F2x_mulspec(a,b,n0a,n0b);
526     c0 = F2x_mulspec(a0,b0,na,nb);
527 
528     c2 = F2x_addspec(a0,a,na,n0a);
529     c1 = F2x_addspec(b0,b,nb,n0b);
530 
531     c1 = F2x_mul(c1,c2);
532     c2 = F2x_add(c0,c);
533 
534     c2 = F2x_add(c1,c2);
535     c0 = F2x_addshift(c0,c2,n0);
536   }
537   else
538   {
539     c  = F2x_mulspec(a,b,n0a,nb);
540     c0 = F2x_mulspec(a0,b,na,nb);
541   }
542   c0 = F2x_addshift(c0,c,n0);
543   return F2x_shiftip(av,c0, v);
544 }
545 
546 GEN
F2x_mul(GEN x,GEN y)547 F2x_mul(GEN x, GEN y)
548 {
549   GEN z = F2x_mulspec(x+2,y+2, lgpol(x),lgpol(y));
550   z[1] = x[1]; return z;
551 }
552 
553 GEN
F2x_sqr(GEN x)554 F2x_sqr(GEN x)
555 {
556   const ulong sq[]={0,1,4,5,16,17,20,21,64,65,68,69,80,81,84,85};
557   long i,ii,j,jj;
558   long lx=lg(x), lz=2+((lx-2)<<1);
559   GEN z;
560   z = cgetg(lz, t_VECSMALL); z[1]=x[1];
561   for (j=2,jj=2;j<lx;j++,jj++)
562   {
563     ulong x1=((ulong)x[j]&HIGHMASK)>>BITS_IN_HALFULONG;
564     ulong x2=(ulong)x[j]&LOWMASK;
565     z[jj]=0;
566     if (x2)
567       for(i=0,ii=0;i<BITS_IN_HALFULONG;i+=4,ii+=8)
568         z[jj]|=sq[(x2>>i)&15UL]<<ii;
569     z[++jj]=0;
570     if (x1)
571       for(i=0,ii=0;i<BITS_IN_HALFULONG;i+=4,ii+=8)
572         z[jj]|=sq[(x1>>i)&15UL]<<ii;
573   }
574   return F2x_renormalize(z, lz);
575 }
576 
577 static GEN
F2x_pow2n(GEN x,long n)578 F2x_pow2n(GEN x, long n)
579 {
580   long i;
581   for(i=1;i<=n;i++)
582     x = F2x_sqr(x);
583   return x;
584 }
585 
586 int
F2x_issquare(GEN x)587 F2x_issquare(GEN x)
588 {
589   const ulong mask = (ULONG_MAX/3UL)*2;
590   ulong i, lx = lg(x);
591   for (i=2; i<lx; i++)
592     if ((x[i]&mask)) return 0;
593   return 1;
594 }
595 
596 /* Assume x is a perfect square */
597 GEN
F2x_sqrt(GEN x)598 F2x_sqrt(GEN x)
599 {
600   const ulong sq[]={0,1,4,5,2,3,6,7,8,9,12,13,10,11,14,15};
601   long i,ii,j,jj;
602   long lx=lg(x), lz=2+((lx-1)>>1);
603   GEN z;
604   z = cgetg(lz, t_VECSMALL); z[1]=x[1];
605   for (j=2,jj=2;jj<lz;j++,jj++)
606   {
607     ulong x2=x[j++];
608     z[jj]=0;
609     if (x2)
610       for(i=0,ii=0;ii<BITS_IN_HALFULONG;i+=8,ii+=4)
611       {
612         ulong rl = (x2>>i)&15UL, rh = (x2>>(i+4))&15UL;
613         z[jj]|=sq[rl|(rh<<1)]<<ii;
614       }
615     if (j<lx)
616     {
617       x2 = x[j];
618       if (x2)
619         for(i=0,ii=0;ii<BITS_IN_HALFULONG;i+=8,ii+=4)
620         {
621           ulong rl = (x2>>i)&15UL, rh = (x2>>(i+4))&15UL;
622           z[jj]|=(sq[rl|(rh<<1)]<<ii)<<BITS_IN_HALFULONG;
623         }
624     }
625   }
626   return F2x_renormalize(z, lz);
627 }
628 
629 static GEN
F2x_shiftneg(GEN y,ulong d)630 F2x_shiftneg(GEN y, ulong d)
631 {
632   long db, dl=dvmdsBIL(d, &db);
633   long i, ly = lg(y), lx = ly-dl;
634   GEN x = cgetg(lx, t_VECSMALL);
635   x[1] = y[1];
636   if (db)
637   {
638     ulong dc=BITS_IN_LONG-db;
639     ulong r=0;
640     for(i=lx-1; i>=2; i--)
641     {
642       x[i] = (((ulong)y[i+dl])>>db)|r;
643       r = ((ulong)y[i+dl])<<dc;
644     }
645   }
646   else
647     for(i=2; i<lx; i++)
648       x[i] = y[i+dl];
649   return F2x_renormalize(x,lx);
650 }
651 
652 static GEN
F2x_shiftpos(GEN y,ulong d)653 F2x_shiftpos(GEN y, ulong d)
654 {
655   long db, dl=dvmdsBIL(d, &db);
656   long i, ly = lg(y), lx = ly+dl+(!!db);
657   GEN x = cgetg(lx, t_VECSMALL);
658   x[1] = y[1]; for(i=0; i<dl; i++) x[i+2] = 0;
659   if (db)
660   {
661     ulong dc=BITS_IN_LONG-db;
662     ulong r=0;
663     for(i=2; i<ly; i++)
664     {
665       x[i+dl] = (((ulong)y[i])<<db)|r;
666       r = ((ulong)y[i])>>dc;
667     }
668     x[i+dl] = r;
669   }
670   else
671     for(i=2; i<ly; i++)
672       x[i+dl] = y[i];
673   return F2x_renormalize(x,lx);
674 }
675 
676 GEN
F2x_shift(GEN y,long d)677 F2x_shift(GEN y, long d)
678 {
679   return d<0 ? F2x_shiftneg(y,-d): F2x_shiftpos(y,d);
680 }
681 
682 #define F2x_recip2(pk,m) u = ((u&m)<<pk)|((u&(~m))>>pk);
683 #define F2x_recipu(pk) F2x_recip2(pk,((~0UL)/((1UL<<pk)+1)))
684 
685 static ulong
F2x_recip1(ulong u)686 F2x_recip1(ulong u)
687 {
688   u = (u<<BITS_IN_HALFULONG)|(u>>BITS_IN_HALFULONG);
689 #ifdef LONG_IS_64BIT
690   F2x_recipu(16);
691 #endif
692   F2x_recipu(8);
693   F2x_recipu(4);
694   F2x_recipu(2);
695   F2x_recipu(1);
696   return u;
697 }
698 
699 static GEN
F2x_recip_raw(GEN x)700 F2x_recip_raw(GEN x)
701 {
702   long i, l;
703   GEN y = cgetg_copy(x,&l);
704   y[1] = x[1];
705   for (i=0; i<l-2; i++)
706     uel(y,l-1-i) = F2x_recip1(uel(x,2+i));
707   return y;
708 }
709 
710 GEN
F2x_recip(GEN x)711 F2x_recip(GEN x)
712 {
713   long lb = remsBIL(F2x_degree(x)+1);
714   GEN y = F2x_recip_raw(x);
715   if (lb) y = F2x_shiftneg(y,BITS_IN_LONG-lb);
716   return y;
717 }
718 
719 GEN
F2xn_red(GEN f,long n)720 F2xn_red(GEN f, long n)
721 {
722   GEN g;
723   long i, dl, db, l;
724   if (F2x_degree(f) < n) return zv_copy(f);
725   dl = dvmdsBIL(n, &db); l = 2 + dl + (db>0);
726   g = cgetg(l, t_VECSMALL);
727   g[1] = f[1];
728   for (i=2; i<l; i++)
729     uel(g,i) = uel(f,i);
730   if (db) uel(g,l-1) = uel(f,l-1)&((1UL<<db)-1);
731   return F2x_renormalize(g, l);
732 }
733 
734 static GEN
F2xn_mul(GEN a,GEN b,long n)735 F2xn_mul(GEN a, GEN b, long n) { return F2xn_red(F2x_mul(a, b), n); }
736 
737 static ulong
F2xn_inv_basecase1(ulong x)738 F2xn_inv_basecase1(ulong x)
739 {
740   ulong u, v, w;
741   long i;
742   u = x>>1;
743   v = (u&1UL)|2UL;
744   w = u&v; w ^= w >> 1; v = (w&1UL)|(v<<1);
745   w = u&v; w ^= w >> 2; w ^= w >> 1; v = (w&1UL)|(v<<1);
746   w = u&v; w ^= w >> 2; w ^= w >> 1; v = (w&1UL)|(v<<1);
747   for (i=1;i<=4;i++)
748    { w = u&v; w ^= w >> 4; w ^= w >> 2; w ^= w >> 1; v = (w&1UL)|(v<<1); }
749   for (i=1;i<=8;i++)
750    { w = u&v; w ^= w >> 8; w ^= w >> 4; w ^= w >> 2; w ^= w >> 1; v = (w&1UL)|(v<<1); }
751   for (i=1;i<=16;i++)
752    { w = u&v; w ^= w >> 16; w ^= w >> 8; w ^= w >> 4; w ^= w >> 2; w ^= w >> 1; v = (w&1UL)|(v<<1); }
753 #ifdef LONG_IS_64BIT
754   for (i=1; i<=32; i++)
755    { w = u&v; w ^= w >> 32; w ^= w >> 16; w ^= w >> 8; w ^= w >> 4; w ^= w >> 2; w ^= w >> 1;
756    v = (w&1UL)|(v<<1); }
757 #endif
758   return (F2x_recip1(v)<<1)|1UL;
759 }
760 
761 static GEN
F2xn_inv1(GEN v,long e)762 F2xn_inv1(GEN v, long e)
763 {
764   ulong mask = e==BITS_IN_LONG ? -1UL: ((1UL<<e)-1);
765   return mkvecsmall2(v[1],F2xn_inv_basecase1(uel(v,2))&mask);
766 }
767 
768 GEN
F2xn_inv(GEN f,long e)769 F2xn_inv(GEN f, long e)
770 {
771   pari_sp av = avma, av2;
772   ulong mask;
773   GEN W;
774   long n=1;
775   if (lg(f)==2) pari_err_INV("Flxn_inv",f);
776   if (e <= BITS_IN_LONG) return F2xn_inv1(f, e);
777   W = F2xn_inv1(f, BITS_IN_LONG);
778   mask = quadratic_prec_mask(divsBIL(e+BITS_IN_LONG-1));
779   n = BITS_IN_LONG;
780   av2 = avma;
781   for (;mask>1;)
782   {
783     GEN u, fr;
784     long n2 = n;
785     n<<=1; if (mask & 1) n--;
786     mask >>= 1;
787     fr = F2xn_red(f, n);
788     u = F2x_shift(F2xn_mul(W, fr, n), -n2);
789     W = F2x_add(W, F2x_shift(F2xn_mul(u, W, n-n2), n2));
790     if (gc_needed(av2,2))
791     {
792       if(DEBUGMEM>1) pari_warn(warnmem,"F2xn_inv, e = %ld", n);
793       W = gerepileupto(av2, W);
794     }
795   }
796   return gerepileupto(av, F2xn_red(W,e));
797 }
798 
799 GEN
F2x_get_red(GEN T)800 F2x_get_red(GEN T)
801 {
802   return T;
803 }
804 
805 /* separate from F2x_divrem for maximal speed. */
806 GEN
F2x_rem(GEN x,GEN y)807 F2x_rem(GEN x, GEN y)
808 {
809   long dx,dy;
810   long lx=lg(x);
811   dy = F2x_degree(y); if (!dy) return pol0_F2x(x[1]);
812   dx = F2x_degree_lg(x,lx);
813   x  = F2x_copy(x);
814   while (dx>=dy)
815   {
816     F2x_addshiftip(x,y,dx-dy);
817     while (lx>2 && x[lx-1]==0) lx--;
818     dx = F2x_degree_lg(x,lx);
819   }
820   return F2x_renormalize(x, lx);
821 }
822 
823 GEN
F2x_divrem(GEN x,GEN y,GEN * pr)824 F2x_divrem(GEN x, GEN y, GEN *pr)
825 {
826   long dx, dy, dz, lx = lg(x), vs = x[1];
827   GEN z;
828 
829   dy = F2x_degree(y);
830   if (dy<0) pari_err_INV("F2x_divrem",y);
831   if (pr == ONLY_REM) return F2x_rem(x, y);
832   if (!dy)
833   {
834     z = F2x_copy(x);
835     if (pr && pr != ONLY_DIVIDES) *pr = pol0_F2x(vs);
836     return z;
837   }
838   dx = F2x_degree_lg(x,lx);
839   dz = dx-dy;
840   if (dz < 0)
841   {
842     if (pr == ONLY_DIVIDES) return dx < 0? F2x_copy(x): NULL;
843     z = pol0_F2x(vs);
844     if (pr) *pr = F2x_copy(x);
845     return z;
846   }
847   z = zero_zv(lg(x)-lg(y)+2); z[1] = vs;
848   x = F2x_copy(x);
849   while (dx>=dy)
850   {
851     F2x_set(z,dx-dy);
852     F2x_addshiftip(x,y,dx-dy);
853     while (lx>2 && x[lx-1]==0) lx--;
854     dx = F2x_degree_lg(x,lx);
855   }
856   z = F2x_renormalize(z, lg(z));
857   if (!pr) { cgiv(x); return z; }
858   x = F2x_renormalize(x, lx);
859   if (pr == ONLY_DIVIDES) {
860     if (lg(x) == 2) { cgiv(x); return z; }
861     return gc_NULL((pari_sp)(z + lg(z)));
862   }
863   *pr = x; return z;
864 }
865 
866 long
F2x_valrem(GEN x,GEN * Z)867 F2x_valrem(GEN x, GEN *Z)
868 {
869   long v, v2, i, l=lg(x);
870   GEN y;
871   if (l==2) { *Z = F2x_copy(x); return LONG_MAX; }
872   for (i=2; i<l && x[i]==0; i++) /*empty*/;
873   v = i-2;
874   v2 = (i < l)? vals(x[i]): 0;
875   if (v+v2 == 0) { *Z = x; return 0; }
876   l -= i-2;
877   y = cgetg(l, t_VECSMALL); y[1] = x[1];
878   if (v2 == 0)
879     for (i=2; i<l; i++) y[i] = x[i+v];
880   else if (l == 3)
881     y[2] = ((ulong)x[2+v]) >> v2;
882   else
883   {
884     const ulong sh = BITS_IN_LONG - v2;
885     ulong r = x[2+v];
886     for (i=3; i<l; i++)
887     {
888       y[i-1] = (x[i+v] << sh) | (r >> v2);
889       r = x[i+v];
890     }
891     y[l-1] = r >> v2;
892     (void)F2x_renormalize(y,l);
893   }
894   *Z = y; return (v << TWOPOTBITS_IN_LONG) + v2;
895 }
896 
897 GEN
F2x_deflate(GEN x,long d)898 F2x_deflate(GEN x, long d)
899 {
900   GEN y;
901   long i,id, dy, dx = F2x_degree(x);
902   if (d <= 1) return F2x_copy(x);
903   if (dx < 0) return F2x_copy(x);
904   dy = dx/d; /* dy+1 coefficients + 1 extra word for variable */
905   y = zero_zv(nbits2lg(dy+1)-1); y[1] = x[1];
906   for (i=id=0; i<=dy; i++,id+=d)
907     if (F2x_coeff(x,id)) F2x_set(y, i);
908   return y;
909 }
910 
911 /* write p(X) = e(X^2) + Xo(X^2), shallow function */
912 void
F2x_even_odd(GEN p,GEN * pe,GEN * po)913 F2x_even_odd(GEN p, GEN *pe, GEN *po)
914 {
915   long n = F2x_degree(p), n0, n1, i;
916   GEN p0, p1;
917 
918   if (n <= 0) { *pe = F2x_copy(p); *po = pol0_F2x(p[1]); return; }
919 
920   n0 = (n>>1)+1; n1 = n+1 - n0; /* n1 <= n0 <= n1+1 */
921   p0 = zero_zv(nbits2lg(n0+1)-1); p0[1] = p[1];
922   p1 = zero_zv(nbits2lg(n1+1)-1); p1[1] = p[1];
923   for (i=0; i<n1; i++)
924   {
925     if (F2x_coeff(p,i<<1)) F2x_set(p0,i);
926     if (F2x_coeff(p,1+(i<<1))) F2x_set(p1,i);
927   }
928   if (n1 != n0 && F2x_coeff(p,i<<1)) F2x_set(p0,i);
929   *pe = F2x_renormalize(p0,lg(p0));
930   *po = F2x_renormalize(p1,lg(p1));
931 }
932 
933 GEN
F2x_deriv(GEN z)934 F2x_deriv(GEN z)
935 {
936   const ulong mask = ULONG_MAX/3UL;
937   long i,l = lg(z);
938   GEN x = cgetg(l, t_VECSMALL); x[1] = z[1];
939   for (i=2; i<l; i++) x[i] = (((ulong)z[i])>>1)&mask;
940   return F2x_renormalize(x,l);
941 }
942 
943 GEN
F2x_gcd(GEN a,GEN b)944 F2x_gcd(GEN a, GEN b)
945 {
946   pari_sp av = avma;
947   if (lg(b) > lg(a)) swap(a, b);
948   while (lgpol(b))
949   {
950     GEN c = F2x_rem(a,b);
951     a = b; b = c;
952     if (gc_needed(av,2))
953     {
954       if (DEBUGMEM>1) pari_warn(warnmem,"F2x_gcd (d = %ld)",F2x_degree(c));
955       gerepileall(av,2, &a,&b);
956     }
957   }
958   if (gc_needed(av,2)) a = gerepileuptoleaf(av, a);
959   return a;
960 }
961 
962 GEN
F2x_extgcd(GEN a,GEN b,GEN * ptu,GEN * ptv)963 F2x_extgcd(GEN a, GEN b, GEN *ptu, GEN *ptv)
964 {
965   pari_sp av=avma;
966   GEN u,v,d,d1,v1;
967   long vx = a[1];
968   d = a; d1 = b;
969   v = pol0_F2x(vx); v1 = pol1_F2x(vx);
970   while (lgpol(d1))
971   {
972     GEN r, q = F2x_divrem(d,d1, &r);
973     v = F2x_add(v,F2x_mul(q,v1));
974     u=v; v=v1; v1=u;
975     u=r; d=d1; d1=u;
976     if (gc_needed(av,2))
977     {
978       if (DEBUGMEM>1) pari_warn(warnmem,"F2x_extgcd (d = %ld)",F2x_degree(d));
979       gerepileall(av,5, &d,&d1,&u,&v,&v1);
980     }
981   }
982   if (ptu) *ptu = F2x_div(F2x_add(d, F2x_mul(b,v)), a);
983   *ptv = v;
984   if (gc_needed(av,2)) gerepileall(av,ptu?3:2,&d,ptv,ptu);
985   return d;
986 }
987 
988 static GEN
F2x_halfgcd_i(GEN a,GEN b)989 F2x_halfgcd_i(GEN a, GEN b)
990 {
991   pari_sp av=avma;
992   GEN u,u1,v,v1;
993   long vx = a[1];
994   long n = (F2x_degree(a)+1)>>1;
995   u1 = v = pol0_F2x(vx);
996   u = v1 = pol1_F2x(vx);
997   while (F2x_degree(b)>=n)
998   {
999     GEN r, q = F2x_divrem(a,b, &r);
1000     a = b; b = r; swap(u,u1); swap(v,v1);
1001     u1 = F2x_add(u1, F2x_mul(u, q));
1002     v1 = F2x_add(v1, F2x_mul(v, q));
1003     if (gc_needed(av,2))
1004     {
1005       if (DEBUGMEM>1) pari_warn(warnmem,"F2x_halfgcd (d = %ld)",F2x_degree(b));
1006       gerepileall(av,6, &a,&b,&u1,&v1,&u,&v);
1007     }
1008   }
1009   return gerepilecopy(av, mkmat2(mkcol2(u,u1), mkcol2(v,v1)));
1010 }
1011 
1012 GEN
F2x_halfgcd(GEN x,GEN y)1013 F2x_halfgcd(GEN x, GEN y)
1014 {
1015   pari_sp av;
1016   GEN M,q,r;
1017   if (F2x_degree(y)<F2x_degree(x)) return F2x_halfgcd_i(x,y);
1018   av = avma;
1019   q = F2x_divrem(y,x,&r);
1020   M = F2x_halfgcd_i(x,r);
1021   gcoeff(M,1,1) = F2x_add(gcoeff(M,1,1), F2x_mul(q, gcoeff(M,1,2)));
1022   gcoeff(M,2,1) = F2x_add(gcoeff(M,2,1), F2x_mul(q, gcoeff(M,2,2)));
1023   return gerepilecopy(av, M);
1024 }
1025 
1026 GEN
F2xq_mul(GEN x,GEN y,GEN pol)1027 F2xq_mul(GEN x,GEN y,GEN pol)
1028 {
1029   GEN z = F2x_mul(x,y);
1030   return F2x_rem(z,pol);
1031 }
1032 
1033 GEN
F2xq_sqr(GEN x,GEN pol)1034 F2xq_sqr(GEN x,GEN pol)
1035 {
1036   GEN z = F2x_sqr(x);
1037   return F2x_rem(z,pol);
1038 }
1039 
1040 GEN
F2xq_invsafe(GEN x,GEN T)1041 F2xq_invsafe(GEN x, GEN T)
1042 {
1043   GEN V, z = F2x_extgcd(get_F2x_mod(T), x, NULL, &V);
1044   if (F2x_degree(z)) return NULL;
1045   return V;
1046 }
1047 
1048 GEN
F2xq_inv(GEN x,GEN T)1049 F2xq_inv(GEN x,GEN T)
1050 {
1051   pari_sp av=avma;
1052   GEN U = F2xq_invsafe(x, T);
1053   if (!U) pari_err_INV("F2xq_inv", F2x_to_ZX(x));
1054   return gerepileuptoleaf(av, U);
1055 }
1056 
1057 GEN
F2xq_div(GEN x,GEN y,GEN T)1058 F2xq_div(GEN x,GEN y,GEN T)
1059 {
1060   pari_sp av = avma;
1061   return gerepileuptoleaf(av, F2xq_mul(x,F2xq_inv(y,T),T));
1062 }
1063 
1064 static GEN
_F2xq_red(void * E,GEN x)1065 _F2xq_red(void *E, GEN x) { return F2x_rem(x, (GEN)E); }
1066 static GEN
_F2xq_add(void * E,GEN x,GEN y)1067 _F2xq_add(void *E, GEN x, GEN y) { (void)E; return F2x_add(x,y); }
1068 
1069 static GEN
_F2xq_cmul(void * E,GEN P,long a,GEN x)1070 _F2xq_cmul(void *E, GEN P, long a, GEN x)
1071 {
1072   GEN pol = (GEN) E;
1073   return F2x_coeff(P,a) ? x: pol0_F2x(pol[1]);
1074 }
1075 static GEN
_F2xq_sqr(void * E,GEN x)1076 _F2xq_sqr(void *E, GEN x) { return F2xq_sqr(x, (GEN) E); }
1077 static GEN
_F2xq_mul(void * E,GEN x,GEN y)1078 _F2xq_mul(void *E, GEN x, GEN y) { return F2xq_mul(x,y, (GEN) E); }
1079 
1080 static GEN
_F2xq_one(void * E)1081 _F2xq_one(void *E)
1082 {
1083   GEN pol = (GEN) E;
1084   return pol1_F2x(pol[1]);
1085 }
1086 static GEN
_F2xq_zero(void * E)1087 _F2xq_zero(void *E)
1088 {
1089   GEN pol = (GEN) E;
1090   return pol0_F2x(pol[1]);
1091 }
1092 
1093 GEN
F2xq_pow(GEN x,GEN n,GEN pol)1094 F2xq_pow(GEN x, GEN n, GEN pol)
1095 {
1096   pari_sp av=avma;
1097   GEN y;
1098 
1099   if (!signe(n)) return pol1_F2x(x[1]);
1100   if (is_pm1(n)) /* +/- 1 */
1101     return (signe(n) < 0)? F2xq_inv(x,pol): F2x_copy(x);
1102 
1103   if (signe(n) < 0) x = F2xq_inv(x,pol);
1104   y = gen_pow_i(x, n, (void*)pol, &_F2xq_sqr, &_F2xq_mul);
1105   return gerepilecopy(av, y);
1106 }
1107 
1108 GEN
F2xq_powu(GEN x,ulong n,GEN pol)1109 F2xq_powu(GEN x, ulong n, GEN pol)
1110 {
1111   pari_sp av=avma;
1112   GEN y;
1113   switch(n)
1114   {
1115     case 0: return pol1_F2x(x[1]);
1116     case 1: return F2x_copy(x);
1117     case 2: return F2xq_sqr(x,pol);
1118   }
1119   y = gen_powu_i(x, n, (void*)pol, &_F2xq_sqr, &_F2xq_mul);
1120   return gerepilecopy(av, y);
1121 }
1122 
1123 GEN
F2xq_pow_init(GEN x,GEN n,long k,GEN T)1124 F2xq_pow_init(GEN x, GEN n, long k,  GEN T)
1125 {
1126   return gen_pow_init(x, n, k, (void*)T, &_F2xq_sqr, &_F2xq_mul);
1127 }
1128 
1129 GEN
F2xq_pow_table(GEN R,GEN n,GEN T)1130 F2xq_pow_table(GEN R, GEN n, GEN T)
1131 {
1132   return gen_pow_table(R, n, (void*)T, &_F2xq_one, &_F2xq_mul);
1133 }
1134 
1135 /* generates the list of powers of x of degree 0,1,2,...,l*/
1136 GEN
F2xq_powers(GEN x,long l,GEN T)1137 F2xq_powers(GEN x, long l, GEN T)
1138 {
1139   int use_sqr = 2*F2x_degree(x) >= get_F2x_degree(T);
1140   return gen_powers(x, l, use_sqr, (void*)T, &_F2xq_sqr, &_F2xq_mul, &_F2xq_one);
1141 }
1142 
1143 GEN
F2xq_matrix_pow(GEN y,long n,long m,GEN P)1144 F2xq_matrix_pow(GEN y, long n, long m, GEN P)
1145 {
1146   return F2xV_to_F2m(F2xq_powers(y,m-1,P),n);
1147 }
1148 
1149 GEN
F2x_Frobenius(GEN T)1150 F2x_Frobenius(GEN T)
1151 {
1152   return F2xq_sqr(polx_F2x(get_F2x_var(T)), T);
1153 }
1154 
1155 GEN
F2x_matFrobenius(GEN T)1156 F2x_matFrobenius(GEN T)
1157 {
1158   long n = get_F2x_degree(T);
1159   return F2xq_matrix_pow(F2x_Frobenius(T), n, n, T);
1160 }
1161 
1162 static struct bb_algebra F2xq_algebra = { _F2xq_red, _F2xq_add, _F2xq_add,
1163               _F2xq_mul, _F2xq_sqr, _F2xq_one, _F2xq_zero};
1164 
1165 GEN
F2x_F2xqV_eval(GEN Q,GEN x,GEN T)1166 F2x_F2xqV_eval(GEN Q, GEN x, GEN T)
1167 {
1168   long d = F2x_degree(Q);
1169   return gen_bkeval_powers(Q,d,x,(void*)T,&F2xq_algebra,_F2xq_cmul);
1170 }
1171 
1172 GEN
F2x_F2xq_eval(GEN Q,GEN x,GEN T)1173 F2x_F2xq_eval(GEN Q, GEN x, GEN T)
1174 {
1175   long d = F2x_degree(Q);
1176   int use_sqr = 2*F2x_degree(x) >= get_F2x_degree(T);
1177   return gen_bkeval(Q, d, x, use_sqr, (void*)T, &F2xq_algebra, _F2xq_cmul);
1178 }
1179 
1180 static GEN
F2xq_autpow_sqr(void * T,GEN x)1181 F2xq_autpow_sqr(void * T, GEN x) { return F2x_F2xq_eval(x, x, (GEN) T); }
1182 
1183 static GEN
F2xq_autpow_mul(void * T,GEN x,GEN y)1184 F2xq_autpow_mul(void * T, GEN x, GEN y) { return F2x_F2xq_eval(x, y, (GEN) T); }
1185 
1186 GEN
F2xq_autpow(GEN x,long n,GEN T)1187 F2xq_autpow(GEN x, long n, GEN T)
1188 {
1189   if (n==0) return F2x_rem(polx_F2x(x[1]), T);
1190   if (n==1) return F2x_rem(x, T);
1191   return gen_powu(x,n,(void*)T,F2xq_autpow_sqr,F2xq_autpow_mul);
1192 }
1193 
1194 ulong
F2xq_trace(GEN x,GEN T)1195 F2xq_trace(GEN x, GEN T)
1196 {
1197   pari_sp av = avma;
1198   long n = get_F2x_degree(T)-1;
1199   GEN z = F2xq_mul(x, F2x_deriv(get_F2x_mod(T)), T);
1200   return gc_ulong(av, F2x_degree(z) < n ? 0 : 1);
1201 }
1202 
1203 GEN
F2xq_conjvec(GEN x,GEN T)1204 F2xq_conjvec(GEN x, GEN T)
1205 {
1206   long i, l = 1+get_F2x_degree(T);
1207   GEN z = cgetg(l,t_COL);
1208   gel(z,1) = F2x_copy(x);
1209   for (i=2; i<l; i++) gel(z,i) = F2xq_sqr(gel(z,i-1), T);
1210   return z;
1211 }
1212 
1213 static GEN
_F2xq_pow(void * data,GEN x,GEN n)1214 _F2xq_pow(void *data, GEN x, GEN n)
1215 {
1216   GEN pol = (GEN) data;
1217   return F2xq_pow(x,n, pol);
1218 }
1219 
1220 static GEN
_F2xq_rand(void * data)1221 _F2xq_rand(void *data)
1222 {
1223   pari_sp av=avma;
1224   GEN pol = (GEN) data;
1225   long d = F2x_degree(pol);
1226   GEN z;
1227   do
1228   {
1229     set_avma(av);
1230     z = random_F2x(d,pol[1]);
1231   } while (lgpol(z)==0);
1232   return z;
1233 }
1234 
1235 static GEN F2xq_easylog(void* E, GEN a, GEN g, GEN ord);
1236 
1237 static const struct bb_group F2xq_star={_F2xq_mul,_F2xq_pow,_F2xq_rand,hash_GEN,F2x_equal,F2x_equal1,F2xq_easylog};
1238 
1239 GEN
F2xq_order(GEN a,GEN ord,GEN T)1240 F2xq_order(GEN a, GEN ord, GEN T)
1241 {
1242   return gen_order(a,ord,(void*)T,&F2xq_star);
1243 }
1244 
1245 static long
F2x_is_smooth_squarefree(GEN f,long r)1246 F2x_is_smooth_squarefree(GEN f, long r)
1247 {
1248   pari_sp av = avma;
1249   long i, df = F2x_degree(f);
1250   GEN sx, a;
1251   if (!df) return 1;
1252   a = sx = polx_F2x(f[1]);
1253   for(i = 1;; i++)
1254   {
1255     long dg;
1256     GEN g;
1257     a = F2xq_sqr(a, f);
1258     if (F2x_equal(a, sx)) return gc_long(av,1);
1259     if (i==r) return gc_long(av,0);
1260     g = F2x_gcd(f, F2x_add(a,sx));
1261     dg = F2x_degree(g);
1262     if (dg == df) return gc_long(av,1);
1263     if (dg) { f = F2x_div(f, g); df -= dg; a = F2x_rem(a, f); }
1264   }
1265 }
1266 
1267 static long
F2x_is_smooth(GEN g,long r)1268 F2x_is_smooth(GEN g, long r)
1269 {
1270   if (lgpol(g)==0) return 0;
1271   while (1)
1272   {
1273     GEN f = F2x_gcd(g, F2x_deriv(g));
1274     if (!F2x_is_smooth_squarefree(F2x_div(g, f), r)) return 0;
1275     if (F2x_degree(f)==0) return 1;
1276     g = F2x_issquare(f) ? F2x_sqrt(f): f;
1277   }
1278 }
1279 
1280 static GEN
F2x_factorel(GEN h)1281 F2x_factorel(GEN h)
1282 {
1283   GEN F = F2x_factor(h);
1284   GEN F1 = gel(F, 1), F2 = gel(F, 2);
1285   long i, l1 = lg(F1)-1;
1286   GEN p2 = cgetg(l1+1, t_VECSMALL);
1287   GEN e2 = cgetg(l1+1, t_VECSMALL);
1288   for (i = 1; i <= l1; ++i)
1289   {
1290     p2[i] = mael(F1, i, 2);
1291     e2[i] = F2[i];
1292   }
1293   return mkmat2(p2, e2);
1294 }
1295 
1296 static GEN
mkF2(ulong x,long v)1297 mkF2(ulong x, long v) { return mkvecsmall2(v, x); }
1298 
1299 static GEN F2xq_log_Coppersmith_d(GEN W, GEN g, long r, long n, GEN T, GEN mo);
1300 
1301 static GEN
F2xq_log_from_rel(GEN W,GEN rel,long r,long n,GEN T,GEN m)1302 F2xq_log_from_rel(GEN W, GEN rel, long r, long n, GEN T, GEN m)
1303 {
1304   pari_sp av = avma;
1305   long vT = get_F2x_var(T);
1306   GEN F = gel(rel,1), E = gel(rel,2), o = gen_0;
1307   long i, l = lg(F);
1308   for(i=1; i<l; i++)
1309   {
1310     GEN R = gel(W, F[i]);
1311     if (signe(R)==0) /* Already failed */
1312       return NULL;
1313     else if (signe(R)<0) /* Not yet tested */
1314     {
1315       setsigne(gel(W,F[i]),0);
1316       R = F2xq_log_Coppersmith_d(W, mkF2(F[i],vT), r, n, T, m);
1317       if (!R) return NULL;
1318     }
1319     o = Fp_add(o, mulis(R, E[i]), m);
1320   }
1321   return gerepileuptoint(av, o);
1322 }
1323 
1324 static GEN
F2xq_log_Coppersmith_d(GEN W,GEN g,long r,long n,GEN T,GEN mo)1325 F2xq_log_Coppersmith_d(GEN W, GEN g, long r, long n, GEN T, GEN mo)
1326 {
1327   pari_sp av = avma, av2;
1328   long dT = get_F2x_degree(T), vT = get_F2x_var(T);
1329   long dg = F2x_degree(g), k = r-1, m = maxss((dg-k)/2,0);
1330   long i, j, l = dg-m, N;
1331   GEN v = cgetg(k+m+1,t_MAT);
1332   long h = dT>>n, d = dT-(h<<n);
1333   GEN p1 = pol1_F2x(vT);
1334   GEN R = F2x_add(F2x_shift(p1, dT), T);
1335   GEN z = F2x_rem(F2x_shift(p1, h), g);
1336   for(i=1; i<=k+m; i++)
1337   {
1338     gel(v,i) = F2x_to_F2v(F2x_shift(z,-l),m);
1339     z = F2x_rem(F2x_shift(z,1),g);
1340   }
1341   v = F2m_ker(v);
1342   for(i=1; i<=k; i++)
1343     gel(v,i) = F2v_to_F2x(gel(v,i),vT);
1344   N = 1<<k;
1345   av2 = avma;
1346   for (i=1; i<N; i++)
1347   {
1348     GEN p,q,qh,a,b;
1349     set_avma(av2);
1350     q = pol0_F2x(vT);
1351     for(j=0; j<k; j++)
1352       if (i&(1UL<<j))
1353         q = F2x_add(q, gel(v,j+1));
1354     qh= F2x_shift(q,h);
1355     p = F2x_rem(qh,g);
1356     b = F2x_add(F2x_mul(R, F2x_pow2n(q, n)), F2x_shift(F2x_pow2n(p, n), d));
1357     if (lgpol(b)==0 || !F2x_is_smooth(b, r)) continue;
1358     a = F2x_div(F2x_add(qh,p),g);
1359     if (F2x_degree(F2x_gcd(a,q)) &&  F2x_degree(F2x_gcd(a,p))) continue;
1360     if (!(lgpol(a)==0 || !F2x_is_smooth(a, r)))
1361     {
1362       GEN F = F2x_factorel(b);
1363       GEN G = F2x_factorel(a);
1364       GEN FG = vecsmall_concat(vecsmall_append(gel(F, 1), 2), gel(G, 1));
1365       GEN E  = vecsmall_concat(vecsmall_append(gel(F, 2), -d),
1366                                zv_z_mul(gel(G, 2),-(1L<<n)));
1367       GEN R  = famatsmall_reduce(mkmat2(FG, E));
1368       GEN l  = F2xq_log_from_rel(W, R, r, n, T, mo);
1369       if (!l) continue;
1370       l = Fp_div(l,int2n(n),mo);
1371       if (dg <= r)
1372       {
1373         affii(l,gel(W,g[2]));
1374         if (DEBUGLEVEL>1) err_printf("Found %lu\n", g[2]);
1375       }
1376       return gerepileuptoint(av, l);
1377     }
1378   }
1379   return gc_NULL(av);
1380 }
1381 
1382 static GEN
F2xq_log_find_rel(GEN b,long r,GEN T,GEN * g,ulong * e)1383 F2xq_log_find_rel(GEN b, long r, GEN T, GEN *g, ulong *e)
1384 {
1385   pari_sp av = avma;
1386   while (1)
1387   {
1388     GEN M;
1389     *g = F2xq_mul(*g, b, T); (*e)++;
1390     M = F2x_halfgcd(*g,T);
1391     if (F2x_is_smooth(gcoeff(M,1,1), r))
1392     {
1393       GEN z = F2x_add(F2x_mul(gcoeff(M,1,1),*g), F2x_mul(gcoeff(M,1,2),T));
1394       if (F2x_is_smooth(z, r))
1395       {
1396         GEN F = F2x_factorel(z);
1397         GEN G = F2x_factorel(gcoeff(M,1,1));
1398         GEN rel = mkmat2(vecsmall_concat(gel(F, 1),gel(G, 1)),
1399                          vecsmall_concat(gel(F, 2),zv_neg(gel(G, 2))));
1400         gerepileall(av, 2, g, &rel);
1401         return rel;
1402       }
1403     }
1404     if (gc_needed(av,2))
1405     {
1406       if (DEBUGMEM>1) pari_warn(warnmem,"F2xq_log_find_rel");
1407       *g = gerepileuptoleaf(av, *g);
1408     }
1409   }
1410 }
1411 
1412 static GEN
F2xq_log_Coppersmith_rec(GEN W,long r2,GEN a,long r,long n,GEN T,GEN m)1413 F2xq_log_Coppersmith_rec(GEN W, long r2, GEN a, long r, long n, GEN T, GEN m)
1414 {
1415   long vT = get_F2x_var(T);
1416   GEN b = polx_F2x(vT);
1417   ulong AV = 0;
1418   GEN g = a, bad = pol0_F2x(vT);
1419   pari_timer ti;
1420   while(1)
1421   {
1422     long i, l;
1423     GEN V, F, E, Ao;
1424     timer_start(&ti);
1425     V = F2xq_log_find_rel(b, r2, T, &g, &AV);
1426     if (DEBUGLEVEL>1) timer_printf(&ti,"%ld-smooth element",r2);
1427     F = gel(V,1); E = gel(V,2);
1428     l = lg(F);
1429     Ao = gen_0;
1430     for(i=1; i<l; i++)
1431     {
1432       GEN Fi = mkF2(F[i], vT);
1433       GEN R;
1434       if (F2x_degree(Fi) <= r)
1435       {
1436         if (signe(gel(W,F[i]))==0)
1437           break;
1438         else if (signe(gel(W,F[i]))<0)
1439         {
1440           setsigne(gel(W,F[i]),0);
1441           R = F2xq_log_Coppersmith_d(W,Fi,r,n,T,m);
1442         } else
1443           R = gel(W,F[i]);
1444       }
1445       else
1446       {
1447         if (F2x_equal(Fi,bad)) break;
1448         R = F2xq_log_Coppersmith_d(W,Fi,r,n,T,m);
1449         if (!R) bad = Fi;
1450       }
1451       if (!R) break;
1452       Ao = Fp_add(Ao, mulis(R, E[i]), m);
1453     }
1454     if (i==l) return subiu(Ao,AV);
1455   }
1456 }
1457 
1458 /* Coppersmith:
1459  T*X^e = X^(h*2^n)-R
1460  (u*x^h + v)^(2^n) = u^(2^n)*X^(h*2^n)+v^(2^n)
1461  (u*x^h + v)^(2^n) = u^(2^n)*R+v^(2^n)
1462 */
1463 
1464 static GEN
rel_Coppersmith(GEN u,GEN v,long h,GEN R,long r,long n,long d)1465 rel_Coppersmith(GEN u, GEN v, long h, GEN R, long r, long n, long d)
1466 {
1467   GEN b, F, G, M;
1468   GEN a = F2x_add(F2x_shift(u, h), v);
1469   if (!F2x_is_smooth(a, r)) return NULL;
1470   b = F2x_add(F2x_mul(R, F2x_pow2n(u, n)), F2x_shift(F2x_pow2n(v, n),d));
1471   if (!F2x_is_smooth(b, r)) return NULL;
1472   F = F2x_factorel(a);
1473   G = F2x_factorel(b);
1474   M = mkmat2(vecsmall_concat(gel(F, 1), vecsmall_append(gel(G, 1), 2)),
1475              vecsmall_concat(zv_z_mul(gel(F, 2),1UL<<n), vecsmall_append(zv_neg(gel(G, 2)),d)));
1476   return famatsmall_reduce(M);
1477 }
1478 
1479 GEN
F2xq_log_Coppersmith_worker(GEN u,long i,GEN V,GEN R)1480 F2xq_log_Coppersmith_worker(GEN u, long i, GEN V, GEN R)
1481 {
1482   long r = V[1], h = V[2], n = V[3], d = V[4];
1483   pari_sp ltop = avma;
1484   GEN v = mkF2(0,u[1]);
1485   GEN L = cgetg(2*i+1, t_VEC);
1486   pari_sp av = avma;
1487   long j;
1488   long nbtest=0, rel = 1;
1489   for(j=1; j<=i; j++)
1490   {
1491     v[2] = j;
1492     set_avma(av);
1493     if (F2x_degree(F2x_gcd(u,v))==0)
1494     {
1495       GEN z = rel_Coppersmith(u, v, h, R, r, n, d);
1496       nbtest++;
1497       if (z) { gel(L, rel++) = z; av = avma; }
1498       if (i==j) continue;
1499       z = rel_Coppersmith(v, u, h, R, r, n, d);
1500       nbtest++;
1501       if (z) { gel(L, rel++) = z; av = avma; }
1502     }
1503   }
1504   setlg(L,rel);
1505   return gerepilecopy(ltop, mkvec2(stoi(nbtest), L));
1506 }
1507 
1508 static GEN
F2xq_log_Coppersmith(long nbrel,long r,long n,GEN T)1509 F2xq_log_Coppersmith(long nbrel, long r, long n, GEN T)
1510 {
1511   long dT = get_F2x_degree(T), vT = get_F2x_var(T);
1512   long h = dT>>n, d = dT-(h<<n);
1513   GEN R = F2x_add(F2x_shift(pol1_F2x(vT), dT), T);
1514   GEN u = mkF2(0,vT);
1515   long rel = 1, nbtest = 0;
1516   GEN M = cgetg(nbrel+1, t_VEC);
1517   long i = 0;
1518   GEN worker = snm_closure(is_entry("_F2xq_log_Coppersmith_worker"),
1519                mkvec2(mkvecsmall4(r, h, n, d), R));
1520   struct pari_mt pt;
1521   long running, pending = 0, stop=0;
1522   mt_queue_start(&pt, worker);
1523   if (DEBUGLEVEL) err_printf("Coppersmith (R = %ld): ",F2x_degree(R));
1524   while ((running = !stop) || pending)
1525   {
1526     GEN L, done;
1527     long j, l;
1528     u[2] = i;
1529     mt_queue_submit(&pt, 0, running ? mkvec2(u, stoi(i)): NULL);
1530     done = mt_queue_get(&pt, NULL, &pending);
1531     if (!done) continue;
1532     L = gel(done, 2); nbtest += itos(gel(done,1));
1533     l = lg(L);
1534     if (l > 1)
1535     {
1536       for (j=1; j<l; j++)
1537       {
1538         if (rel>nbrel) break;
1539         gel(M,rel++) = gel(L,j);
1540         if (DEBUGLEVEL && (rel&511UL)==0)
1541           err_printf("%ld%%[%ld] ",rel*100/nbrel,i);
1542       }
1543     }
1544     if (rel>nbrel) stop=1;
1545     i++;
1546   }
1547   mt_queue_end(&pt);
1548   if (DEBUGLEVEL) err_printf(": %ld tests\n", nbtest);
1549   return M;
1550 }
1551 
1552 static GEN
smallirred_F2x(ulong n,long sv)1553 smallirred_F2x(ulong n, long sv)
1554 {
1555   GEN a = zero_zv(nbits2lg(n+1)-1);
1556   a[1] = sv; F2x_set(a,n); a[2]++;
1557   while (!F2x_is_irred(a)) a[2]+=2;
1558   return a;
1559 }
1560 
1561 static GEN
check_kernel(long N,GEN M,long nbi,GEN T,GEN m)1562 check_kernel(long N, GEN M, long nbi, GEN T, GEN m)
1563 {
1564   pari_sp av = avma;
1565   long dT = get_F2x_degree(T), vT = get_F2x_var(T);
1566   GEN K = FpMs_leftkernel_elt(M, N, m);
1567   long i, f=0, tbs;
1568   long l = lg(K), lm = lgefint(m);
1569   GEN idx = diviiexact(int2um1(dT), m);
1570   GEN g = F2xq_pow(polx_F2x(vT), idx, T);
1571   GEN tab;
1572   pari_timer ti;
1573   if (DEBUGLEVEL) timer_start(&ti);
1574   K = FpC_Fp_mul(K, Fp_inv(gel(K,2), m), m);
1575   tbs = maxss(1, expu(nbi/expi(m)));
1576   tab = F2xq_pow_init(g, int2n(dT), tbs, T);
1577   for(i=1; i<l; i++)
1578   {
1579     GEN k = gel(K,i);
1580     if (signe(k)==0 || !F2x_equal(F2xq_pow_table(tab, k, T),
1581                                   F2xq_pow(mkF2(i,vT), idx, T)))
1582       gel(K,i) = cgetineg(lm);
1583     else
1584       f++;
1585   }
1586   if (DEBUGLEVEL) timer_printf(&ti,"found %ld/%ld logs", f, nbi);
1587   return gerepileupto(av, K);
1588 }
1589 
1590 static GEN
F2xq_log_index(GEN a0,GEN b0,GEN m,GEN T0)1591 F2xq_log_index(GEN a0, GEN b0, GEN m, GEN T0)
1592 {
1593   pari_sp av = avma;
1594   GEN  M, S, a, b, Ao=NULL, Bo=NULL, W, e;
1595   pari_timer ti;
1596   long n = F2x_degree(T0), r = (long) (sqrt((double) 2*n))-(n>100);
1597   GEN T = smallirred_F2x(n,T0[1]);
1598   long d = 2, r2 = 3*r/2, d2 = 2;
1599   long N = (1UL<<(r+1))-1UL;
1600   long nbi = itos(ffsumnbirred(gen_2, r)), nbrel=nbi*5/4;
1601   if (DEBUGLEVEL)
1602   {
1603     err_printf("F2xq_log: Parameters r=%ld r2=%ld\n", r,r2);
1604     err_printf("F2xq_log: Size FB=%ld rel. needed=%ld\n", nbi, nbrel);
1605     timer_start(&ti);
1606   }
1607   S = Flx_to_F2x(Flx_ffisom(F2x_to_Flx(T0),F2x_to_Flx(T),2));
1608   a = F2x_F2xq_eval(a0, S, T);
1609   b = F2x_F2xq_eval(b0, S, T);
1610   if (DEBUGLEVEL) timer_printf(&ti,"model change");
1611   M = F2xq_log_Coppersmith(nbrel,r,d,T);
1612   if(DEBUGLEVEL)
1613     timer_printf(&ti,"relations");
1614   W = check_kernel(N, M, nbi, T, m);
1615   timer_start(&ti);
1616   Ao = F2xq_log_Coppersmith_rec(W, r2, a, r, d2, T, m);
1617   if (DEBUGLEVEL) timer_printf(&ti,"smooth element");
1618   Bo = F2xq_log_Coppersmith_rec(W, r2, b, r, d2, T, m);
1619   if (DEBUGLEVEL) timer_printf(&ti,"smooth generator");
1620   e = Fp_div(Ao, Bo, m);
1621   if (!F2x_equal(F2xq_pow(b0,e,T0),a0)) pari_err_BUG("F2xq_log");
1622   return gerepileupto(av, e);
1623 }
1624 
1625 static GEN
F2xq_easylog(void * E,GEN a,GEN g,GEN ord)1626 F2xq_easylog(void* E, GEN a, GEN g, GEN ord)
1627 {
1628   if (F2x_equal1(a)) return gen_0;
1629   if (F2x_equal(a,g)) return gen_1;
1630   if (typ(ord)!=t_INT) return NULL;
1631   if (expi(ord)<28) return NULL;
1632   return F2xq_log_index(a,g,ord,(GEN)E);
1633 }
1634 
1635 GEN
F2xq_log(GEN a,GEN g,GEN ord,GEN T)1636 F2xq_log(GEN a, GEN g, GEN ord, GEN T)
1637 {
1638   GEN z, v = get_arith_ZZM(ord);
1639   ord = mkvec2(gel(v,1),ZM_famat_limit(gel(v,2),int2n(28)));
1640   z = gen_PH_log(a,g,ord,(void*)T,&F2xq_star);
1641   return z? z: cgetg(1,t_VEC);
1642 }
1643 
1644 GEN
F2xq_Artin_Schreier(GEN a,GEN T)1645 F2xq_Artin_Schreier(GEN a, GEN T)
1646 {
1647   pari_sp ltop=avma;
1648   long j,N = get_F2x_degree(T), vT = get_F2x_var(T);
1649   GEN Q = F2x_matFrobenius(T);
1650   for (j=1; j<=N; j++)
1651     F2m_flip(Q,j,j);
1652   F2v_add_inplace(gel(Q,1),a);
1653   Q = F2m_ker_sp(Q,0);
1654   if (lg(Q)!=2) return NULL;
1655   Q = gel(Q,1);
1656   Q[1] = vT;
1657   return gerepileuptoleaf(ltop, F2x_renormalize(Q, lg(Q)));
1658 }
1659 
1660 GEN
F2xq_sqrt_fast(GEN c,GEN sqx,GEN T)1661 F2xq_sqrt_fast(GEN c, GEN sqx, GEN T)
1662 {
1663   GEN c0, c1;
1664   F2x_even_odd(c, &c0, &c1);
1665   return F2x_add(c0, F2xq_mul(c1, sqx, T));
1666 }
1667 
1668 static int
F2x_is_x(GEN a)1669 F2x_is_x(GEN a) { return lg(a)==3 && a[2]==2; }
1670 
1671 GEN
F2xq_sqrt(GEN a,GEN T)1672 F2xq_sqrt(GEN a, GEN T)
1673 {
1674   pari_sp av = avma;
1675   long n = get_F2x_degree(T), vT = get_F2x_var(T);
1676   GEN sqx;
1677   if (n==1) return F2x_copy(a);
1678   if (n==2) return F2xq_sqr(a,T);
1679   sqx = F2xq_autpow(mkF2(4, vT), n-1, T);
1680   return gerepileuptoleaf(av, F2x_is_x(a)? sqx: F2xq_sqrt_fast(a,sqx,T));
1681 }
1682 
1683 GEN
F2xq_sqrtn(GEN a,GEN n,GEN T,GEN * zeta)1684 F2xq_sqrtn(GEN a, GEN n, GEN T, GEN *zeta)
1685 {
1686   long dT = get_F2x_degree(T), vT = get_F2x_var(T);
1687   if (!lgpol(a))
1688   {
1689     if (signe(n) < 0) pari_err_INV("F2xq_sqrtn",a);
1690     if (zeta)
1691       *zeta=pol1_F2x(vT);
1692     return pol0_F2x(vT);
1693   }
1694   return gen_Shanks_sqrtn(a, n, int2um1(dT), zeta, (void*)T, &F2xq_star);
1695 }
1696 
1697 GEN
gener_F2xq(GEN T,GEN * po)1698 gener_F2xq(GEN T, GEN *po)
1699 {
1700   long i, j, vT = get_F2x_var(T), f = get_F2x_degree(T);
1701   pari_sp av0 = avma, av;
1702   GEN g, L2, o, q;
1703 
1704   if (f == 1) {
1705     if (po) *po = mkvec2(gen_1, trivial_fact());
1706     return pol1_F2x(vT);
1707   }
1708   q = int2um1(f);
1709   o = factor_pn_1(gen_2,f);
1710   L2 = leafcopy( gel(o, 1) );
1711   for (i = j = 1; i < lg(L2); i++)
1712   {
1713     if (absequaliu(gel(L2,i),2)) continue;
1714     gel(L2,j++) = diviiexact(q, gel(L2,i));
1715   }
1716   setlg(L2, j);
1717   for (av = avma;; set_avma(av))
1718   {
1719     g = random_F2x(f, vT);
1720     if (F2x_degree(g) < 1) continue;
1721     for (i = 1; i < j; i++)
1722     {
1723       GEN a = F2xq_pow(g, gel(L2,i), T);
1724       if (F2x_equal1(a)) break;
1725     }
1726     if (i == j) break;
1727   }
1728   if (!po) g = gerepilecopy(av0, g);
1729   else {
1730     *po = mkvec2(int2um1(f), o);
1731     gerepileall(av0, 2, &g, po);
1732   }
1733   return g;
1734 }
1735 
1736 static GEN
_F2xq_neg(void * E,GEN x)1737 _F2xq_neg(void *E, GEN x) { (void) E; return F2x_copy(x); }
1738 static GEN
_F2xq_rmul(void * E,GEN x,GEN y)1739 _F2xq_rmul(void *E, GEN x, GEN y) { (void) E; return F2x_mul(x,y); }
1740 static GEN
_F2xq_inv(void * E,GEN x)1741 _F2xq_inv(void *E, GEN x) { return F2xq_inv(x, (GEN) E); }
1742 static int
_F2xq_equal0(GEN x)1743 _F2xq_equal0(GEN x) { return lgpol(x)==0; }
1744 static GEN
_F2xq_s(void * E,long x)1745 _F2xq_s(void *E, long x)
1746 { GEN T = (GEN) E;
1747   long v = get_F2x_var(T);
1748   return odd(x)? pol1_F2x(v): pol0_F2x(v);
1749 }
1750 
1751 static const struct bb_field F2xq_field={_F2xq_red,_F2xq_add,_F2xq_rmul,_F2xq_neg,
1752                                          _F2xq_inv,_F2xq_equal0,_F2xq_s};
1753 
get_F2xq_field(void ** E,GEN T)1754 const struct bb_field *get_F2xq_field(void **E, GEN T)
1755 {
1756   *E = (void *) T;
1757   return &F2xq_field;
1758 }
1759 
1760 /***********************************************************************/
1761 /**                                                                   **/
1762 /**                               F2xV                                **/
1763 /**                                                                   **/
1764 /***********************************************************************/
1765 /* F2xV are t_VEC with F2x coefficients. */
1766 
1767 GEN
FlxC_to_F2xC(GEN x)1768 FlxC_to_F2xC(GEN x) { pari_APPLY_type(t_COL, Flx_to_F2x(gel(x,i))) }
1769 GEN
F2xC_to_FlxC(GEN x)1770 F2xC_to_FlxC(GEN x) { pari_APPLY_type(t_COL, F2x_to_Flx(gel(x,i))) }
1771 GEN
F2xC_to_ZXC(GEN x)1772 F2xC_to_ZXC(GEN x) { pari_APPLY_type(t_COL, F2x_to_ZX(gel(x,i))) }
1773 GEN
F2xV_to_F2m(GEN x,long n)1774 F2xV_to_F2m(GEN x, long n) { pari_APPLY_type(t_MAT, F2x_to_F2v(gel(x,i), n)) }
1775 
1776 void
F2xV_to_FlxV_inplace(GEN v)1777 F2xV_to_FlxV_inplace(GEN v)
1778 {
1779   long i, l = lg(v);
1780   for(i = 1; i < l;i++) gel(v,i) = F2x_to_Flx(gel(v,i));
1781 }
1782 void
F2xV_to_ZXV_inplace(GEN v)1783 F2xV_to_ZXV_inplace(GEN v)
1784 {
1785   long i, l = lg(v);
1786   for(i = 1; i < l; i++) gel(v,i)= F2x_to_ZX(gel(v,i));
1787 }
1788 
1789 /***********************************************************************/
1790 /**                                                                   **/
1791 /**                             F2xX                                  **/
1792 /**                                                                   **/
1793 /***********************************************************************/
1794 
1795 GEN
F2xX_renormalize(GEN x,long lx)1796 F2xX_renormalize(GEN /*in place*/ x, long lx)
1797 { return FlxX_renormalize(x, lx); }
1798 
1799 GEN
pol1_F2xX(long v,long sv)1800 pol1_F2xX(long v, long sv) { return pol1_FlxX(v, sv); }
1801 
1802 GEN
polx_F2xX(long v,long sv)1803 polx_F2xX(long v, long sv) { return polx_FlxX(v, sv); }
1804 
1805 long
F2xY_degreex(GEN b)1806 F2xY_degreex(GEN b)
1807 {
1808   long deg = 0, i;
1809   if (!signe(b)) return -1;
1810   for (i = 2; i < lg(b); ++i)
1811     deg = maxss(deg, F2x_degree(gel(b, i)));
1812   return deg;
1813 }
1814 
1815 GEN
FlxX_to_F2xX(GEN B)1816 FlxX_to_F2xX(GEN B)
1817 {
1818   long lb=lg(B);
1819   long i;
1820   GEN b=cgetg(lb,t_POL);
1821   b[1]=evalsigne(1)|(((ulong)B[1])&VARNBITS);
1822   for (i=2; i<lb; i++)
1823     gel(b,i) = Flx_to_F2x(gel(B,i));
1824   return F2xX_renormalize(b, lb);
1825 }
1826 
1827 GEN
ZXX_to_F2xX(GEN B,long v)1828 ZXX_to_F2xX(GEN B, long v)
1829 {
1830   long lb=lg(B);
1831   long i;
1832   GEN b=cgetg(lb,t_POL);
1833   b[1]=evalsigne(1)|(((ulong)B[1])&VARNBITS);
1834   for (i=2; i<lb; i++)
1835     switch (typ(gel(B,i)))
1836     {
1837     case t_INT:
1838       gel(b,i) = Z_to_F2x(gel(B,i), evalvarn(v));
1839       break;
1840     case t_POL:
1841       gel(b,i) = ZX_to_F2x(gel(B,i));
1842       break;
1843     }
1844   return F2xX_renormalize(b, lb);
1845 }
1846 
1847 GEN
F2xX_to_FlxX(GEN B)1848 F2xX_to_FlxX(GEN B)
1849 {
1850   long i, lb = lg(B);
1851   GEN b = cgetg(lb,t_POL);
1852   for (i=2; i<lb; i++)
1853     gel(b,i) = F2x_to_Flx(gel(B,i));
1854   b[1] = B[1]; return b;
1855 }
1856 
1857 GEN
F2xX_to_ZXX(GEN B)1858 F2xX_to_ZXX(GEN B)
1859 {
1860   long i, lb = lg(B);
1861   GEN b = cgetg(lb,t_POL);
1862   for (i=2; i<lb; i++)
1863   {
1864     GEN c = gel(B,i);
1865     gel(b,i) = lgpol(c) ?  F2x_equal1(c) ? gen_1 : F2x_to_ZX(c) : gen_0;
1866   }
1867   b[1] = B[1]; return b;
1868 }
1869 
1870 GEN
F2xX_deriv(GEN z)1871 F2xX_deriv(GEN z)
1872 {
1873   long i,l = lg(z)-1;
1874   GEN x;
1875   if (l < 2) l = 2;
1876   x = cgetg(l, t_POL); x[1] = z[1];
1877   for (i=2; i<l; i++) gel(x,i) = odd(i) ? pol0_F2x(mael(z,i+1,1)): gel(z,i+1);
1878   return F2xX_renormalize(x,l);
1879 }
1880 
1881 static GEN
F2xX_addspec(GEN x,GEN y,long lx,long ly)1882 F2xX_addspec(GEN x, GEN y, long lx, long ly)
1883 {
1884   long i,lz;
1885   GEN z;
1886   if (ly>lx) swapspec(x,y, lx,ly);
1887   lz = lx+2; z = cgetg(lz, t_POL);
1888   for (i=0; i<ly; i++) gel(z,i+2) = F2x_add(gel(x,i), gel(y,i));
1889   for (   ; i<lx; i++) gel(z,i+2) = F2x_copy(gel(x,i));
1890   z[1] = 0; return F2xX_renormalize(z, lz);
1891 }
1892 
1893 GEN
F2xX_add(GEN x,GEN y)1894 F2xX_add(GEN x, GEN y)
1895 {
1896   long i,lz;
1897   GEN z;
1898   long lx=lg(x);
1899   long ly=lg(y);
1900   if (ly>lx) swapspec(x,y, lx,ly);
1901   lz = lx; z = cgetg(lz, t_POL); z[1]=x[1];
1902   for (i=2; i<ly; i++) gel(z,i) = F2x_add(gel(x,i), gel(y,i));
1903   for (   ; i<lx; i++) gel(z,i) = F2x_copy(gel(x,i));
1904   return F2xX_renormalize(z, lz);
1905 }
1906 
1907 GEN
F2xX_F2x_add(GEN x,GEN y)1908 F2xX_F2x_add(GEN x, GEN y)
1909 {
1910   long i, lz = lg(y);
1911   GEN z;
1912   if (signe(y) == 0) return scalarpol(x, varn(y));
1913   z = cgetg(lz,t_POL); z[1] = y[1];
1914   gel(z,2) = F2x_add(gel(y,2), x);
1915   if (lz == 3) z = F2xX_renormalize(z,lz);
1916   else
1917     for(i=3;i<lz;i++) gel(z,i) = F2x_copy(gel(y,i));
1918   return z;
1919 }
1920 
1921 GEN
F2xX_F2x_mul(GEN P,GEN U)1922 F2xX_F2x_mul(GEN P, GEN U)
1923 {
1924   long i, lP = lg(P);
1925   GEN res = cgetg(lP,t_POL);
1926   res[1] = P[1];
1927   for(i=2; i<lP; i++)
1928     gel(res,i) = F2x_mul(U,gel(P,i));
1929   return F2xX_renormalize(res, lP);
1930 }
1931 
1932 GEN
F2xY_F2xqV_evalx(GEN P,GEN x,GEN T)1933 F2xY_F2xqV_evalx(GEN P, GEN x, GEN T)
1934 {
1935   long i, lP = lg(P);
1936   GEN res = cgetg(lP,t_POL);
1937   res[1] = P[1];
1938   for(i=2; i<lP; i++)
1939     gel(res,i) = F2x_F2xqV_eval(gel(P,i), x, T);
1940   return F2xX_renormalize(res, lP);
1941 }
1942 
1943 GEN
F2xY_F2xq_evalx(GEN P,GEN x,GEN T)1944 F2xY_F2xq_evalx(GEN P, GEN x, GEN T)
1945 {
1946   pari_sp av = avma;
1947   long n = brent_kung_optpow(get_F2x_degree(T)-1,lgpol(P),1);
1948   GEN xp = F2xq_powers(x, n, T);
1949   return gerepileupto(av, F2xY_F2xqV_evalx(P, xp, T));
1950 }
1951 
1952 static GEN
F2xX_to_Kronecker_spec(GEN P,long n,long d)1953 F2xX_to_Kronecker_spec(GEN P, long n, long d)
1954 {
1955   long i, k, l, N = 2*d + 1;
1956   long dP = n+1;
1957   GEN x;
1958   if (n == 0) return pol0_Flx(P[1]&VARNBITS);
1959   l = nbits2nlong(N*dP+d+1);
1960   x = zero_zv(l+1);
1961   for (k=i=0; i<n; i++, k+=N)
1962   {
1963     GEN c = gel(P,i);
1964     F2x_addshiftip(x, c, k);
1965   }
1966   x[1] = P[1]&VARNBITS; return F2x_renormalize(x, l+2);
1967 }
1968 
1969 GEN
F2xX_to_Kronecker(GEN P,long d)1970 F2xX_to_Kronecker(GEN P, long d)
1971 {
1972   long i, k, l, N = 2*d + 1;
1973   long dP = degpol(P);
1974   GEN x;
1975   if (dP < 0) return pol0_Flx(P[1]&VARNBITS);
1976   l = nbits2nlong(N*dP+d+1);
1977   x = zero_zv(l+1);
1978   for (k=i=0; i<=dP; i++, k+=N)
1979   {
1980     GEN c = gel(P,i+2);
1981     F2x_addshiftip(x, c, k);
1982   }
1983   x[1] = P[1]&VARNBITS; return F2x_renormalize(x, l+2);
1984 }
1985 
1986 static GEN
F2x_slice(GEN x,long n,long d)1987 F2x_slice(GEN x, long n, long d)
1988 {
1989   ulong ib, il=dvmduBIL(n, &ib);
1990   ulong db, dl=dvmduBIL(d, &db);
1991   long lN = dl+2+(db?1:0);
1992   GEN t = cgetg(lN,t_VECSMALL);
1993   t[1] = x[1];
1994   if (ib)
1995   {
1996     ulong i, ic = BITS_IN_LONG-ib;
1997     ulong r = uel(x,2+il)>>ib;
1998     for(i=0; i<dl; i++)
1999     {
2000       uel(t,2+i) = (uel(x,3+il+i)<<ic)|r;
2001       r = uel(x,3+il+i)>>ib;
2002     }
2003     if (db)
2004       uel(t,2+i) = (uel(x,3+il+i)<<ic)|r;
2005   }
2006   else
2007   {
2008     long i;
2009     for(i=2; i<lN; i++)
2010       uel(t,i) = uel(x,il+i);
2011   }
2012   if (db) uel(t,lN-1) &= (1UL<<db)-1;
2013   return F2x_renormalize(t, lN);
2014 }
2015 
2016 GEN
Kronecker_to_F2xqX(GEN z,GEN T)2017 Kronecker_to_F2xqX(GEN z, GEN T)
2018 {
2019   long lz = F2x_degree(z)+1;
2020   long i, j, N = get_F2x_degree(T)*2 + 1;
2021   long lx = lz / (N-2);
2022   GEN x = cgetg(lx+3,t_POL);
2023   x[1] = z[1];
2024   for (i=0, j=2; i<lz; i+=N, j++)
2025   {
2026     GEN t = F2x_slice(z,i,minss(lz-i,N));
2027     t[1] = T[1];
2028     gel(x,j) = F2x_rem(t, T);
2029   }
2030   return F2xX_renormalize(x, j);
2031 }
2032 
2033 GEN
F2xX_to_F2xC(GEN x,long N,long sv)2034 F2xX_to_F2xC(GEN x, long N, long sv)
2035 {
2036   long i, l;
2037   GEN z;
2038   l = lg(x)-1; x++;
2039   if (l > N+1) l = N+1; /* truncate higher degree terms */
2040   z = cgetg(N+1,t_COL);
2041   for (i=1; i<l ; i++) gel(z,i) = gel(x,i);
2042   for (   ; i<=N; i++) gel(z,i) = pol0_F2x(sv);
2043   return z;
2044 }
2045 
2046 GEN
F2xXV_to_F2xM(GEN v,long n,long sv)2047 F2xXV_to_F2xM(GEN v, long n, long sv)
2048 {
2049   long j, N = lg(v);
2050   GEN y = cgetg(N, t_MAT);
2051   for (j=1; j<N; j++) gel(y,j) = F2xX_to_F2xC(gel(v,j), n, sv);
2052   return y;
2053 }
2054 
2055 /***********************************************************************/
2056 /**                                                                   **/
2057 /**                             F2xXV/F2xXC                           **/
2058 /**                                                                   **/
2059 /***********************************************************************/
2060 
2061 GEN
FlxXC_to_F2xXC(GEN x)2062 FlxXC_to_F2xXC(GEN x) { pari_APPLY_type(t_COL, FlxX_to_F2xX(gel(x,i))); }
2063 GEN
F2xXC_to_ZXXC(GEN x)2064 F2xXC_to_ZXXC(GEN x) { pari_APPLY_type(t_COL, F2xX_to_ZXX(gel(x,i))); }
2065 
2066 /***********************************************************************/
2067 /**                                                                   **/
2068 /**                             F2xqX                                 **/
2069 /**                                                                   **/
2070 /***********************************************************************/
2071 
2072 static GEN
get_F2xqX_red(GEN T,GEN * B)2073 get_F2xqX_red(GEN T, GEN *B)
2074 {
2075   if (typ(T)!=t_VEC) { *B=NULL; return T; }
2076   *B = gel(T,1); return gel(T,2);
2077 }
2078 
2079 GEN
random_F2xqX(long d1,long v,GEN T)2080 random_F2xqX(long d1, long v, GEN T)
2081 {
2082   long dT = get_F2x_degree(T), vT = get_F2x_var(T);
2083   long i, d = d1+2;
2084   GEN y = cgetg(d,t_POL); y[1] = evalsigne(1) | evalvarn(v);
2085   for (i=2; i<d; i++) gel(y,i) = random_F2x(dT, vT);
2086   return FlxX_renormalize(y,d);
2087 }
2088 
2089 GEN
F2xqX_red(GEN z,GEN T)2090 F2xqX_red(GEN z, GEN T)
2091 {
2092   GEN res;
2093   long i, l = lg(z);
2094   res = cgetg(l,t_POL); res[1] = z[1];
2095   for(i=2;i<l;i++) gel(res,i) = F2x_rem(gel(z,i),T);
2096   return F2xX_renormalize(res,l);
2097 }
2098 
2099 GEN
F2xqX_F2xq_mul(GEN P,GEN U,GEN T)2100 F2xqX_F2xq_mul(GEN P, GEN U, GEN T)
2101 {
2102   long i, lP = lg(P);
2103   GEN res = cgetg(lP,t_POL);
2104   res[1] = P[1];
2105   for(i=2; i<lP; i++)
2106     gel(res,i) = F2xq_mul(U,gel(P,i), T);
2107   return F2xX_renormalize(res, lP);
2108 }
2109 
2110 GEN
F2xqX_F2xq_mul_to_monic(GEN P,GEN U,GEN T)2111 F2xqX_F2xq_mul_to_monic(GEN P, GEN U, GEN T)
2112 {
2113   long i, lP = lg(P);
2114   GEN res = cgetg(lP,t_POL);
2115   res[1] = P[1];
2116   for(i=2; i<lP-1; i++) gel(res,i) = F2xq_mul(U,gel(P,i), T);
2117   gel(res,lP-1) = pol1_F2x(T[1]);
2118   return F2xX_renormalize(res, lP);
2119 }
2120 
2121 GEN
F2xqX_normalize(GEN z,GEN T)2122 F2xqX_normalize(GEN z, GEN T)
2123 {
2124   GEN p1 = leading_coeff(z);
2125   if (!lgpol(z) || (!degpol(p1) && p1[1] == 1)) return z;
2126   return F2xqX_F2xq_mul_to_monic(z, F2xq_inv(p1,T), T);
2127 }
2128 
2129 GEN
F2xqX_mul(GEN x,GEN y,GEN T)2130 F2xqX_mul(GEN x, GEN y, GEN T)
2131 {
2132   pari_sp ltop=avma;
2133   GEN z, kx, ky;
2134   long d = get_F2x_degree(T);
2135   kx= F2xX_to_Kronecker(x, d);
2136   ky= F2xX_to_Kronecker(y, d);
2137   z = F2x_mul(ky, kx);
2138   z = Kronecker_to_F2xqX(z, T);
2139   return gerepileupto(ltop, z);
2140 }
2141 
2142 static GEN
F2xqX_mulspec(GEN x,GEN y,GEN T,long nx,long ny)2143 F2xqX_mulspec(GEN x, GEN y, GEN T, long nx, long ny)
2144 {
2145   pari_sp ltop=avma;
2146   GEN z, kx, ky;
2147   long dT = get_F2x_degree(T);
2148   kx= F2xX_to_Kronecker_spec(x, nx, dT);
2149   ky= F2xX_to_Kronecker_spec(y, ny, dT);
2150   z = F2x_mul(ky, kx);
2151   z = Kronecker_to_F2xqX(z,T);
2152   return gerepileupto(ltop,z);
2153 }
2154 
2155 GEN
F2xqX_sqr(GEN x,GEN T)2156 F2xqX_sqr(GEN x, GEN T)
2157 {
2158   long d = degpol(x), l = 2*d+3;
2159   GEN z;
2160   if (!signe(x)) return pol_0(varn(x));
2161   z = cgetg(l,t_POL);
2162   z[1] = x[1];
2163   if (d > 0)
2164   {
2165     GEN u = pol0_F2x(T[1]);
2166     long i,j;
2167     for (i=2,j=2; i<d+2; i++,j+=2)
2168     {
2169       gel(z, j) = F2xq_sqr(gel(x, i), T);
2170       gel(z, j+1) = u;
2171     }
2172   }
2173   gel(z, 2+2*d) = F2xq_sqr(gel(x, 2+d), T);
2174   return FlxX_renormalize(z, l);
2175 }
2176 
2177 static GEN
F2xqX_divrem_basecase(GEN x,GEN y,GEN T,GEN * pr)2178 F2xqX_divrem_basecase(GEN x, GEN y, GEN T, GEN *pr)
2179 {
2180   long vx, dx, dy, dz, i, j, sx, lr;
2181   pari_sp av0, av, tetpil;
2182   GEN z,p1,rem,lead;
2183 
2184   if (!signe(y)) pari_err_INV("F2xqX_divrem",y);
2185   vx=varn(x); dy=degpol(y); dx=degpol(x);
2186   if (dx < dy)
2187   {
2188     if (pr)
2189     {
2190       av0 = avma; x = F2xqX_red(x, T);
2191       if (pr == ONLY_DIVIDES) { set_avma(av0); return signe(x)? NULL: pol_0(vx); }
2192       if (pr == ONLY_REM) return x;
2193       *pr = x;
2194     }
2195     return pol_0(vx);
2196   }
2197   lead = leading_coeff(y);
2198   if (!dy) /* y is constant */
2199   {
2200     if (pr && pr != ONLY_DIVIDES)
2201     {
2202       if (pr == ONLY_REM) return pol_0(vx);
2203       *pr = pol_0(vx);
2204     }
2205     if (F2x_equal1(lead)) return gcopy(x);
2206     av0 = avma; x = F2xqX_F2xq_mul(x,F2xq_inv(lead,T),T);
2207     return gerepileupto(av0,x);
2208   }
2209   av0 = avma; dz = dx-dy;
2210   lead = F2x_equal1(lead)? NULL: gclone(F2xq_inv(lead,T));
2211   set_avma(av0);
2212   z = cgetg(dz+3,t_POL); z[1] = x[1];
2213   x += 2; y += 2; z += 2;
2214 
2215   p1 = gel(x,dx); av = avma;
2216   gel(z,dz) = lead? gerepileupto(av, F2xq_mul(p1,lead, T)): leafcopy(p1);
2217   for (i=dx-1; i>=dy; i--)
2218   {
2219     av=avma; p1=gel(x,i);
2220     for (j=i-dy+1; j<=i && j<=dz; j++)
2221       p1 = F2x_add(p1, F2x_mul(gel(z,j),gel(y,i-j)));
2222     if (lead) p1 = F2x_mul(p1, lead);
2223     tetpil=avma; gel(z,i-dy) = gerepile(av,tetpil,F2x_rem(p1,T));
2224   }
2225   if (!pr) { guncloneNULL(lead); return z-2; }
2226 
2227   rem = (GEN)avma; av = (pari_sp)new_chunk(dx+3);
2228   for (sx=0; ; i--)
2229   {
2230     p1 = gel(x,i);
2231     for (j=0; j<=i && j<=dz; j++)
2232       p1 = F2x_add(p1, F2x_mul(gel(z,j),gel(y,i-j)));
2233     tetpil=avma; p1 = F2x_rem(p1, T); if (lgpol(p1)) { sx = 1; break; }
2234     if (!i) break;
2235     set_avma(av);
2236   }
2237   if (pr == ONLY_DIVIDES)
2238   {
2239     guncloneNULL(lead);
2240     if (sx) return gc_NULL(av0);
2241     return gc_const((pari_sp)rem, z-2);
2242   }
2243   lr=i+3; rem -= lr;
2244   rem[0] = evaltyp(t_POL) | evallg(lr);
2245   rem[1] = z[-1];
2246   p1 = gerepile((pari_sp)rem,tetpil,p1);
2247   rem += 2; gel(rem,i) = p1;
2248   for (i--; i>=0; i--)
2249   {
2250     av=avma; p1 = gel(x,i);
2251     for (j=0; j<=i && j<=dz; j++)
2252       p1 = F2x_add(p1, F2x_mul(gel(z,j),gel(y,i-j)));
2253     tetpil=avma; gel(rem,i) = gerepile(av,tetpil, F2x_rem(p1, T));
2254   }
2255   rem -= 2;
2256   guncloneNULL(lead);
2257   if (!sx) (void)F2xX_renormalize(rem, lr);
2258   if (pr == ONLY_REM) return gerepileupto(av0,rem);
2259   *pr = rem; return z-2;
2260 }
2261 
2262 static GEN
F2xX_recipspec(GEN x,long l,long n,long vs)2263 F2xX_recipspec(GEN x, long l, long n, long vs)
2264 {
2265   long i;
2266   GEN z = cgetg(n+2,t_POL);
2267   z[1] = 0; z += 2;
2268   for(i=0; i<l; i++)
2269     gel(z,n-i-1) = F2x_copy(gel(x,i));
2270   for(   ; i<n; i++)
2271     gel(z,n-i-1) = pol0_F2x(vs);
2272   return F2xX_renormalize(z-2,n+2);
2273 }
2274 
2275 static GEN
F2xqX_invBarrett_basecase(GEN T,GEN Q)2276 F2xqX_invBarrett_basecase(GEN T, GEN Q)
2277 {
2278   long i, l=lg(T)-1, lr = l-1, k;
2279   long sv=Q[1];
2280   GEN r=cgetg(lr,t_POL); r[1]=T[1];
2281   gel(r,2) = pol1_F2x(sv);
2282   for (i=3;i<lr;i++)
2283   {
2284     pari_sp ltop=avma;
2285     GEN u = gel(T,l-i+2);
2286     for (k=3;k<i;k++)
2287       u = F2x_add(u, F2xq_mul(gel(T,l-i+k),gel(r,k),Q));
2288     gel(r,i) = gerepileupto(ltop, u);
2289   }
2290   r = F2xX_renormalize(r,lr);
2291   return r;
2292 }
2293 
2294 /* Return new lgpol */
2295 static long
F2xX_lgrenormalizespec(GEN x,long lx)2296 F2xX_lgrenormalizespec(GEN x, long lx)
2297 {
2298   long i;
2299   for (i = lx-1; i>=0; i--)
2300     if (lgpol(gel(x,i))) break;
2301   return i+1;
2302 }
2303 
2304 static GEN
F2xqX_invBarrett_Newton(GEN S,GEN T)2305 F2xqX_invBarrett_Newton(GEN S, GEN T)
2306 {
2307   pari_sp av = avma;
2308   long nold, lx, lz, lq, l = degpol(S), i, lQ;
2309   GEN q, y, z, x = cgetg(l+2, t_POL) + 2;
2310   long dT = get_F2x_degree(T);
2311   ulong mask = quadratic_prec_mask(l-2); /* assume l > 2 */
2312   for (i=0;i<l;i++) gel(x,i) = pol0_F2x(T[1]);
2313   q = F2xX_recipspec(S+2,l+1,l+1,dT);
2314   lQ = lgpol(q); q+=2;
2315   /* We work on _spec_ FlxX's, all the l[xzq] below are lgpol's */
2316 
2317   /* initialize */
2318   gel(x,0) = F2xq_inv(gel(q,0),T);
2319   if (lQ>1 && F2x_degree(gel(q,1)) >= dT)
2320     gel(q,1) = F2x_rem(gel(q,1), T);
2321   if (lQ>1 && lgpol(gel(q,1)))
2322   {
2323     GEN u = gel(q, 1);
2324     if (!F2x_equal1(gel(x,0))) u = F2xq_mul(u, F2xq_sqr(gel(x,0), T), T);
2325     else u = F2x_copy(u);
2326     gel(x,1) = u; lx = 2;
2327   }
2328   else
2329     lx = 1;
2330   nold = 1;
2331   for (; mask > 1; )
2332   { /* set x -= x(x*q - 1) + O(t^(nnew + 1)), knowing x*q = 1 + O(t^(nold+1)) */
2333     long i, lnew, nnew = nold << 1;
2334 
2335     if (mask & 1) nnew--;
2336     mask >>= 1;
2337 
2338     lnew = nnew + 1;
2339     lq = F2xX_lgrenormalizespec(q, minss(lQ,lnew));
2340     z = F2xqX_mulspec(x, q, T, lx, lq); /* FIXME: high product */
2341     lz = lgpol(z); if (lz > lnew) lz = lnew;
2342     z += 2;
2343     /* subtract 1 [=>first nold words are 0]: renormalize so that z(0) != 0 */
2344     for (i = nold; i < lz; i++) if (lgpol(gel(z,i))) break;
2345     nold = nnew;
2346     if (i >= lz) continue; /* z-1 = 0(t^(nnew + 1)) */
2347 
2348     /* z + i represents (x*q - 1) / t^i */
2349     lz = F2xX_lgrenormalizespec (z+i, lz-i);
2350     z = F2xqX_mulspec(x, z+i, T, lx, lz); /* FIXME: low product */
2351     lz = lgpol(z); z += 2;
2352     if (lz > lnew-i) lz = F2xX_lgrenormalizespec(z, lnew-i);
2353 
2354     lx = lz+ i;
2355     y  = x + i; /* x -= z * t^i, in place */
2356     for (i = 0; i < lz; i++) gel(y,i) = gel(z,i);
2357   }
2358   x -= 2; setlg(x, lx + 2); x[1] = S[1];
2359   return gerepilecopy(av, x);
2360 }
2361 
2362 GEN
F2xqX_invBarrett(GEN T,GEN Q)2363 F2xqX_invBarrett(GEN T, GEN Q)
2364 {
2365   pari_sp ltop=avma;
2366   long l=lg(T), v = varn(T);
2367   GEN r;
2368   GEN c = gel(T,l-1);
2369   if (l<5) return pol_0(v);
2370   if (l<=F2xqX_INVBARRETT_LIMIT)
2371   {
2372     if (!F2x_equal1(c))
2373     {
2374       GEN ci = F2xq_inv(c,Q);
2375       T = F2xqX_F2xq_mul(T, ci, Q);
2376       r = F2xqX_invBarrett_basecase(T,Q);
2377       r = F2xqX_F2xq_mul(r,ci,Q);
2378     } else
2379       r = F2xqX_invBarrett_basecase(T,Q);
2380   } else
2381     r = F2xqX_invBarrett_Newton(T,Q);
2382   return gerepileupto(ltop, r);
2383 }
2384 
2385 GEN
F2xqX_get_red(GEN S,GEN T)2386 F2xqX_get_red(GEN S, GEN T)
2387 {
2388   if (typ(S)==t_POL && lg(S)>F2xqX_BARRETT_LIMIT)
2389     retmkvec2(F2xqX_invBarrett(S, T), S);
2390   return S;
2391 }
2392 
2393 /* Compute x mod S where 2 <= degpol(S) <= l+1 <= 2*(degpol(S)-1)
2394  *  * and mg is the Barrett inverse of S. */
2395 static GEN
F2xqX_divrem_Barrettspec(GEN x,long l,GEN mg,GEN S,GEN T,GEN * pr)2396 F2xqX_divrem_Barrettspec(GEN x, long l, GEN mg, GEN S, GEN T, GEN *pr)
2397 {
2398   GEN q, r;
2399   long lt = degpol(S); /*We discard the leading term*/
2400   long ld, lm, lT, lmg;
2401   ld = l-lt;
2402   lm = minss(ld, lgpol(mg));
2403   lT  = F2xX_lgrenormalizespec(S+2,lt);
2404   lmg = F2xX_lgrenormalizespec(mg+2,lm);
2405   q = F2xX_recipspec(x+lt,ld,ld,0);               /* q = rec(x)     lq<=ld*/
2406   q = F2xqX_mulspec(q+2,mg+2,T,lgpol(q),lmg);   /* q = rec(x) * mg lq<=ld+lm*/
2407   q = F2xX_recipspec(q+2,minss(ld,lgpol(q)),ld,0);/* q = rec (rec(x) * mg) lq<=ld*/
2408   if (!pr) return q;
2409   r = F2xqX_mulspec(q+2,S+2,T,lgpol(q),lT);     /* r = q*pol        lr<=ld+lt*/
2410   r = F2xX_addspec(x,r+2,lt,minss(lt,lgpol(r)));/* r = x - r   lr<=lt */
2411   if (pr == ONLY_REM) return r;
2412   *pr = r; return q;
2413 }
2414 
2415 static GEN
F2xqX_divrem_Barrett(GEN x,GEN mg,GEN S,GEN T,GEN * pr)2416 F2xqX_divrem_Barrett(GEN x, GEN mg, GEN S, GEN T, GEN *pr)
2417 {
2418   GEN q = NULL, r = F2xqX_red(x, T);
2419   long l = lgpol(r), lt = degpol(S), lm = 2*lt-1, v = varn(S);
2420   long i;
2421   if (l <= lt)
2422   {
2423     if (pr == ONLY_REM) return r;
2424     if (pr == ONLY_DIVIDES) return signe(r)? NULL: pol_0(v);
2425     if (pr) *pr = r;
2426     return pol_0(v);
2427   }
2428   if (lt <= 1)
2429     return F2xqX_divrem_basecase(x,S,T,pr);
2430   if (pr != ONLY_REM && l>lm)
2431   {
2432     long vT = get_F2x_var(T);
2433     q = cgetg(l-lt+2, t_POL); q[1] = S[1];
2434     for (i=0;i<l-lt;i++) gel(q+2,i) = pol0_F2x(vT);
2435   }
2436   while (l>lm)
2437   {
2438     GEN zr, zq = F2xqX_divrem_Barrettspec(r+2+l-lm,lm,mg,S,T,&zr);
2439     long lz = lgpol(zr);
2440     if (pr != ONLY_REM)
2441     {
2442       long lq = lgpol(zq);
2443       for(i=0; i<lq; i++) gel(q+2+l-lm,i) = gel(zq,2+i);
2444     }
2445     for(i=0; i<lz; i++) gel(r+2+l-lm,i) = gel(zr,2+i);
2446     l = l-lm+lz;
2447   }
2448   if (pr == ONLY_REM)
2449   {
2450     if (l > lt)
2451       r = F2xqX_divrem_Barrettspec(r+2,l,mg,S,T,ONLY_REM);
2452     else
2453       r = F2xX_renormalize(r, lg(r));
2454     setvarn(r, v); return F2xX_renormalize(r, lg(r));
2455   }
2456   if (l > lt)
2457   {
2458     GEN zq = F2xqX_divrem_Barrettspec(r+2,l,mg,S,T,pr? &r: NULL);
2459     if (!q) q = zq;
2460     else
2461     {
2462       long lq = lgpol(zq);
2463       for(i=0; i<lq; i++) gel(q+2,i) = gel(zq,2+i);
2464     }
2465   }
2466   else if (pr)
2467     r = F2xX_renormalize(r, l+2);
2468   setvarn(q, v); q = F2xX_renormalize(q, lg(q));
2469   if (pr == ONLY_DIVIDES) return signe(r)? NULL: q;
2470   if (pr) { setvarn(r, v); *pr = r; }
2471   return q;
2472 }
2473 
2474 GEN
F2xqX_divrem(GEN x,GEN S,GEN T,GEN * pr)2475 F2xqX_divrem(GEN x, GEN S, GEN T, GEN *pr)
2476 {
2477   GEN B, y;
2478   long dy, dx, d;
2479   if (pr==ONLY_REM) return F2xqX_rem(x, S, T);
2480   y = get_F2xqX_red(S, &B);
2481   dy = degpol(y); dx = degpol(x); d = dx-dy;
2482   if (!B && d+3 < F2xqX_DIVREM_BARRETT_LIMIT)
2483     return F2xqX_divrem_basecase(x,y,T,pr);
2484   else
2485   {
2486     pari_sp av=avma;
2487     GEN mg = B? B: F2xqX_invBarrett(y, T);
2488     GEN q = F2xqX_divrem_Barrett(x,mg,y,T,pr);
2489     if (!q) return gc_NULL(av);
2490     if (!pr || pr==ONLY_DIVIDES) return gerepilecopy(av, q);
2491     gerepileall(av,2,&q,pr);
2492     return q;
2493   }
2494 }
2495 
2496 GEN
F2xqX_rem(GEN x,GEN S,GEN T)2497 F2xqX_rem(GEN x, GEN S, GEN T)
2498 {
2499   GEN B, y = get_F2xqX_red(S, &B);
2500   long dy = degpol(y), dx = degpol(x), d = dx-dy;
2501   if (d < 0) return F2xqX_red(x, T);
2502   if (!B && d+3 < F2xqX_REM_BARRETT_LIMIT)
2503     return F2xqX_divrem_basecase(x,y, T, ONLY_REM);
2504   else
2505   {
2506     pari_sp av=avma;
2507     GEN mg = B? B: F2xqX_invBarrett(y, T);
2508     GEN r = F2xqX_divrem_Barrett(x, mg, y, T, ONLY_REM);
2509     return gerepileupto(av, r);
2510   }
2511 }
2512 
2513 static GEN
F2xqX_halfgcd_basecase(GEN a,GEN b,GEN T)2514 F2xqX_halfgcd_basecase(GEN a, GEN b, GEN T)
2515 {
2516   pari_sp av=avma;
2517   GEN u,u1,v,v1;
2518   long vx = varn(a);
2519   long n = lgpol(a)>>1;
2520   u1 = v = pol_0(vx);
2521   u = v1 = pol1_F2xX(vx, get_F2x_var(T));
2522   while (lgpol(b)>n)
2523   {
2524     GEN r, q = F2xqX_divrem(a,b, T, &r);
2525     a = b; b = r; swap(u,u1); swap(v,v1);
2526     u1 = F2xX_add(u1, F2xqX_mul(u, q, T));
2527     v1 = F2xX_add(v1, F2xqX_mul(v, q ,T));
2528     if (gc_needed(av,2))
2529     {
2530       if (DEBUGMEM>1) pari_warn(warnmem,"F2xqX_halfgcd (d = %ld)",degpol(b));
2531       gerepileall(av,6, &a,&b,&u1,&v1,&u,&v);
2532     }
2533   }
2534   return gerepilecopy(av, mkmat2(mkcol2(u,u1), mkcol2(v,v1)));
2535 }
2536 static GEN
F2xqX_addmulmul(GEN u,GEN v,GEN x,GEN y,GEN T)2537 F2xqX_addmulmul(GEN u, GEN v, GEN x, GEN y, GEN T)
2538 {
2539   return F2xX_add(F2xqX_mul(u, x, T),F2xqX_mul(v, y, T));
2540 }
2541 
2542 static GEN
F2xqXM_F2xqX_mul2(GEN M,GEN x,GEN y,GEN T)2543 F2xqXM_F2xqX_mul2(GEN M, GEN x, GEN y, GEN T)
2544 {
2545   GEN res = cgetg(3, t_COL);
2546   gel(res, 1) = F2xqX_addmulmul(gcoeff(M,1,1), gcoeff(M,1,2), x, y, T);
2547   gel(res, 2) = F2xqX_addmulmul(gcoeff(M,2,1), gcoeff(M,2,2), x, y, T);
2548   return res;
2549 }
2550 
2551 static GEN
F2xqXM_mul2(GEN A,GEN B,GEN T)2552 F2xqXM_mul2(GEN A, GEN B, GEN T)
2553 {
2554   GEN A11=gcoeff(A,1,1),A12=gcoeff(A,1,2), B11=gcoeff(B,1,1),B12=gcoeff(B,1,2);
2555   GEN A21=gcoeff(A,2,1),A22=gcoeff(A,2,2), B21=gcoeff(B,2,1),B22=gcoeff(B,2,2);
2556   GEN M1 = F2xqX_mul(F2xX_add(A11,A22), F2xX_add(B11,B22), T);
2557   GEN M2 = F2xqX_mul(F2xX_add(A21,A22), B11, T);
2558   GEN M3 = F2xqX_mul(A11, F2xX_add(B12,B22), T);
2559   GEN M4 = F2xqX_mul(A22, F2xX_add(B21,B11), T);
2560   GEN M5 = F2xqX_mul(F2xX_add(A11,A12), B22, T);
2561   GEN M6 = F2xqX_mul(F2xX_add(A21,A11), F2xX_add(B11,B12), T);
2562   GEN M7 = F2xqX_mul(F2xX_add(A12,A22), F2xX_add(B21,B22), T);
2563   GEN T1 = F2xX_add(M1,M4), T2 = F2xX_add(M7,M5);
2564   GEN T3 = F2xX_add(M1,M2), T4 = F2xX_add(M3,M6);
2565   retmkmat2(mkcol2(F2xX_add(T1,T2), F2xX_add(M2,M4)),
2566             mkcol2(F2xX_add(M3,M5), F2xX_add(T3,T4)));
2567 }
2568 
2569 /* Return [0,1;1,-q]*M */
2570 static GEN
F2xqX_F2xqXM_qmul(GEN q,GEN M,GEN T)2571 F2xqX_F2xqXM_qmul(GEN q, GEN M, GEN T)
2572 {
2573   GEN u, v, res = cgetg(3, t_MAT);
2574   u = F2xX_add(gcoeff(M,1,1), F2xqX_mul(gcoeff(M,2,1), q, T));
2575   gel(res,1) = mkcol2(gcoeff(M,2,1), u);
2576   v = F2xX_add(gcoeff(M,1,2), F2xqX_mul(gcoeff(M,2,2), q, T));
2577   gel(res,2) = mkcol2(gcoeff(M,2,2), v);
2578   return res;
2579 }
2580 
2581 static GEN
matid2_F2xXM(long v,long sv)2582 matid2_F2xXM(long v, long sv)
2583 {
2584   retmkmat2(mkcol2(pol1_F2xX(v, sv),pol_0(v)),
2585             mkcol2(pol_0(v),pol1_F2xX(v, sv)));
2586 }
2587 
2588 static GEN
F2xqX_halfgcd_split(GEN x,GEN y,GEN T)2589 F2xqX_halfgcd_split(GEN x, GEN y, GEN T)
2590 {
2591   pari_sp av=avma;
2592   GEN R, S, V;
2593   GEN y1, r, q;
2594   long l = lgpol(x), n = l>>1, k;
2595   if (lgpol(y)<=n) return matid2_F2xXM(varn(x),get_F2x_var(T));
2596   R = F2xqX_halfgcd(RgX_shift_shallow(x,-n),RgX_shift_shallow(y,-n), T);
2597   V = F2xqXM_F2xqX_mul2(R,x,y, T); y1 = gel(V,2);
2598   if (lgpol(y1)<=n) return gerepilecopy(av, R);
2599   q = F2xqX_divrem(gel(V,1), y1, T, &r);
2600   k = 2*n-degpol(y1);
2601   S = F2xqX_halfgcd(RgX_shift_shallow(y1,-k), RgX_shift_shallow(r,-k), T);
2602   return gerepileupto(av, F2xqXM_mul2(S,F2xqX_F2xqXM_qmul(q,R, T), T));
2603 }
2604 
2605 /* Return M in GL_2(Fp[X]) such that:
2606 if [a',b']~=M*[a,b]~ then degpol(a')>= (lgpol(a)>>1) >degpol(b')
2607 */
2608 
2609 static GEN
F2xqX_halfgcd_i(GEN x,GEN y,GEN T)2610 F2xqX_halfgcd_i(GEN x, GEN y, GEN T)
2611 {
2612   if (lg(x)<=F2xqX_HALFGCD_LIMIT) return F2xqX_halfgcd_basecase(x, y, T);
2613   return F2xqX_halfgcd_split(x, y, T);
2614 }
2615 
2616 GEN
F2xqX_halfgcd(GEN x,GEN y,GEN T)2617 F2xqX_halfgcd(GEN x, GEN y, GEN T)
2618 {
2619   pari_sp av = avma;
2620   GEN M,q,r;
2621   if (!signe(x))
2622   {
2623     long v = varn(x), vT = get_F2x_var(T);
2624     retmkmat2(mkcol2(pol_0(v),pol1_F2xX(v,vT)),
2625         mkcol2(pol1_F2xX(v,vT),pol_0(v)));
2626   }
2627   if (degpol(y)<degpol(x)) return F2xqX_halfgcd_i(x, y, T);
2628   q = F2xqX_divrem(y, x, T, &r);
2629   M = F2xqX_halfgcd_i(x, r, T);
2630   gcoeff(M,1,1) = F2xX_add(gcoeff(M,1,1), F2xqX_mul(q, gcoeff(M,1,2), T));
2631   gcoeff(M,2,1) = F2xX_add(gcoeff(M,2,1), F2xqX_mul(q, gcoeff(M,2,2), T));
2632   return gerepilecopy(av, M);
2633 }
2634 
2635 static GEN
F2xqX_gcd_basecase(GEN a,GEN b,GEN T)2636 F2xqX_gcd_basecase(GEN a, GEN b, GEN T)
2637 {
2638   pari_sp av = avma, av0=avma;
2639   while (signe(b))
2640   {
2641     GEN c;
2642     if (gc_needed(av0,2))
2643     {
2644       if (DEBUGMEM>1) pari_warn(warnmem,"F2xqX_gcd (d = %ld)",degpol(b));
2645       gerepileall(av0,2, &a,&b);
2646     }
2647     av = avma; c = F2xqX_rem(a, b, T); a=b; b=c;
2648   }
2649   return gc_const(av, a);
2650 }
2651 
2652 GEN
F2xqX_gcd(GEN x,GEN y,GEN T)2653 F2xqX_gcd(GEN x, GEN y, GEN T)
2654 {
2655   pari_sp av = avma;
2656   x = F2xqX_red(x, T);
2657   y = F2xqX_red(y, T);
2658   if (!signe(x)) return gerepileupto(av, y);
2659   while (lg(y)>F2xqX_GCD_LIMIT)
2660   {
2661     GEN c;
2662     if (lgpol(y)<=(lgpol(x)>>1))
2663     {
2664       GEN r = F2xqX_rem(x, y, T);
2665       x = y; y = r;
2666     }
2667     c = F2xqXM_F2xqX_mul2(F2xqX_halfgcd(x,y, T), x, y, T);
2668     x = gel(c,1); y = gel(c,2);
2669     gerepileall(av,2,&x,&y);
2670   }
2671   return gerepileupto(av, F2xqX_gcd_basecase(x, y, T));
2672 }
2673 
2674 static GEN
F2xqX_extgcd_basecase(GEN a,GEN b,GEN T,GEN * ptu,GEN * ptv)2675 F2xqX_extgcd_basecase(GEN a, GEN b, GEN T,  GEN *ptu, GEN *ptv)
2676 {
2677   pari_sp av=avma;
2678   GEN u,v,d,d1,v1;
2679   long vx = varn(a);
2680   d = a; d1 = b;
2681   v = pol_0(vx); v1 = pol1_F2xX(vx, get_F2x_var(T));
2682   while (signe(d1))
2683   {
2684     GEN r, q = F2xqX_divrem(d, d1, T, &r);
2685     v = F2xX_add(v,F2xqX_mul(q,v1,T));
2686     u=v; v=v1; v1=u;
2687     u=r; d=d1; d1=u;
2688     if (gc_needed(av,2))
2689     {
2690       if (DEBUGMEM>1) pari_warn(warnmem,"F2xqX_extgcd (d = %ld)",degpol(d));
2691       gerepileall(av,5, &d,&d1,&u,&v,&v1);
2692     }
2693   }
2694   if (ptu) *ptu = F2xqX_div(F2xX_add(d,F2xqX_mul(b,v, T)), a, T);
2695   *ptv = v; return d;
2696 }
2697 
2698 static GEN
F2xqX_extgcd_halfgcd(GEN x,GEN y,GEN T,GEN * ptu,GEN * ptv)2699 F2xqX_extgcd_halfgcd(GEN x, GEN y, GEN T,  GEN *ptu, GEN *ptv)
2700 {
2701   pari_sp av=avma;
2702   GEN u,v,R = matid2_F2xXM(varn(x), get_F2x_var(T));
2703   while (lg(y)>F2xqX_EXTGCD_LIMIT)
2704   {
2705     GEN M, c;
2706     if (lgpol(y)<=(lgpol(x)>>1))
2707     {
2708       GEN r, q = F2xqX_divrem(x, y, T, &r);
2709       x = y; y = r;
2710       R = F2xqX_F2xqXM_qmul(q, R, T);
2711     }
2712     M = F2xqX_halfgcd(x,y, T);
2713     c = F2xqXM_F2xqX_mul2(M, x,y, T);
2714     R = F2xqXM_mul2(M, R, T);
2715     x = gel(c,1); y = gel(c,2);
2716     gerepileall(av,3,&x,&y,&R);
2717   }
2718   y = F2xqX_extgcd_basecase(x,y, T, &u,&v);
2719   if (ptu) *ptu = F2xqX_addmulmul(u,v,gcoeff(R,1,1),gcoeff(R,2,1), T);
2720   *ptv = F2xqX_addmulmul(u,v,gcoeff(R,1,2),gcoeff(R,2,2), T);
2721   return y;
2722 }
2723 
2724 /* x and y in Z[Y][X], return lift(gcd(x mod T,p, y mod T,p)). Set u and v st
2725  * ux + vy = gcd (mod T,p) */
2726 GEN
F2xqX_extgcd(GEN x,GEN y,GEN T,GEN * ptu,GEN * ptv)2727 F2xqX_extgcd(GEN x, GEN y, GEN T,  GEN *ptu, GEN *ptv)
2728 {
2729   GEN d;
2730   pari_sp ltop=avma;
2731   x = F2xqX_red(x, T);
2732   y = F2xqX_red(y, T);
2733   if (lg(y)>F2xqX_EXTGCD_LIMIT)
2734     d = F2xqX_extgcd_halfgcd(x, y, T, ptu, ptv);
2735   else
2736     d = F2xqX_extgcd_basecase(x, y, T, ptu, ptv);
2737   gerepileall(ltop,ptu?3:2,&d,ptv,ptu);
2738   return d;
2739 }
2740 
2741 static GEN
_F2xqX_mul(void * data,GEN a,GEN b)2742 _F2xqX_mul(void *data,GEN a,GEN b) { return F2xqX_mul(a,b, (GEN) data); }
2743 static GEN
_F2xqX_sqr(void * data,GEN a)2744 _F2xqX_sqr(void *data,GEN a) { return F2xqX_sqr(a, (GEN) data); }
2745 GEN
F2xqX_powu(GEN x,ulong n,GEN T)2746 F2xqX_powu(GEN x, ulong n, GEN T)
2747 { return gen_powu(x, n, (void*)T, &_F2xqX_sqr, &_F2xqX_mul); }
2748 
2749 /* Res(A,B) = Res(B,R) * lc(B)^(a-r) * (-1)^(ab), with R=A%B, a=deg(A) ...*/
2750 GEN
F2xqX_resultant(GEN a,GEN b,GEN T)2751 F2xqX_resultant(GEN a, GEN b, GEN T)
2752 {
2753   long vT = get_F2x_var(T);
2754   long da,db,dc;
2755   pari_sp av;
2756   GEN c,lb, res = pol1_F2x(vT);
2757 
2758   if (!signe(a) || !signe(b)) return pol0_F2x(vT);
2759 
2760   da = degpol(a);
2761   db = degpol(b);
2762   if (db > da)
2763     swapspec(a,b, da,db);
2764   if (!da) return pol1_F2x(vT); /* = res * a[2] ^ db, since 0 <= db <= da = 0 */
2765   av = avma;
2766   while (db)
2767   {
2768     lb = gel(b,db+2);
2769     c = F2xqX_rem(a,b, T);
2770     a = b; b = c; dc = degpol(c);
2771     if (dc < 0) { set_avma(av); return pol0_F2x(vT); }
2772 
2773     if (!equali1(lb)) res = F2xq_mul(res, F2xq_powu(lb, da - dc, T), T);
2774     if (gc_needed(av,2))
2775     {
2776       if (DEBUGMEM>1) pari_warn(warnmem,"F2xqX_resultant (da = %ld)",da);
2777       gerepileall(av,3, &a,&b,&res);
2778     }
2779     da = db; /* = degpol(a) */
2780     db = dc; /* = degpol(b) */
2781   }
2782   res = F2xq_mul(res, F2xq_powu(gel(b,2), da, T), T);
2783   return gerepileupto(av, res);
2784 }
2785 
2786 /* disc P = (-1)^(n(n-1)/2) lc(P)^(n - deg P' - 2) Res(P,P'), n = deg P */
2787 GEN
F2xqX_disc(GEN P,GEN T)2788 F2xqX_disc(GEN P, GEN T)
2789 {
2790   pari_sp av = avma;
2791   GEN L, dP = F2xX_deriv(P), D = F2xqX_resultant(P, dP, T);
2792   long dd;
2793   if (!lgpol(D)) return pol_0(get_F2x_var(T));
2794   dd = degpol(P) - 2 - degpol(dP); /* >= -1; > -1 iff p | deg(P) */
2795   L = leading_coeff(P);
2796   if (dd && !F2x_equal1(L))
2797     D = (dd == -1)? F2xq_div(D,L,T): F2xq_mul(D, F2xq_powu(L, dd, T), T);
2798   return gerepileupto(av, D);
2799 }
2800 
2801 /***********************************************************************/
2802 /**                                                                   **/
2803 /**                             F2xqXQ                                **/
2804 /**                                                                   **/
2805 /***********************************************************************/
2806 
2807 GEN
F2xqXQ_mul(GEN x,GEN y,GEN S,GEN T)2808 F2xqXQ_mul(GEN x, GEN y, GEN S, GEN T) {
2809   return F2xqX_rem(F2xqX_mul(x,y,T),S,T);
2810 }
2811 
2812 GEN
F2xqXQ_sqr(GEN x,GEN S,GEN T)2813 F2xqXQ_sqr(GEN x, GEN S, GEN T) {
2814   return F2xqX_rem(F2xqX_sqr(x,T),S,T);
2815 }
2816 
2817 GEN
F2xqXQ_invsafe(GEN x,GEN S,GEN T)2818 F2xqXQ_invsafe(GEN x, GEN S, GEN T)
2819 {
2820   GEN V, z = F2xqX_extgcd(get_F2xqX_mod(S), x, T, NULL, &V);
2821   if (degpol(z)) return NULL;
2822   z = F2xq_invsafe(gel(z,2),T);
2823   if (!z) return NULL;
2824   return F2xqX_F2xq_mul(V, z, T);
2825 }
2826 
2827 GEN
F2xqXQ_inv(GEN x,GEN S,GEN T)2828 F2xqXQ_inv(GEN x, GEN S, GEN T)
2829 {
2830   pari_sp av = avma;
2831   GEN U = F2xqXQ_invsafe(x, S, T);
2832   if (!U) pari_err_INV("F2xqXQ_inv",x);
2833   return gerepileupto(av, U);
2834 }
2835 
2836 struct _F2xqXQ {
2837   GEN T, S;
2838 };
2839 
2840 static GEN
_F2xqXQ_add(void * data,GEN x,GEN y)2841 _F2xqXQ_add(void *data, GEN x, GEN y) {
2842   (void) data;
2843   return F2xX_add(x,y);
2844 }
2845 static GEN
_F2xqXQ_cmul(void * data,GEN P,long a,GEN x)2846 _F2xqXQ_cmul(void *data, GEN P, long a, GEN x) {
2847   (void) data;
2848   return F2xX_F2x_mul(x,gel(P,a+2));
2849 }
2850 static GEN
_F2xqXQ_red(void * data,GEN x)2851 _F2xqXQ_red(void *data, GEN x) {
2852   struct _F2xqXQ *d = (struct _F2xqXQ*) data;
2853   return F2xqX_red(x, d->T);
2854 }
2855 static GEN
_F2xqXQ_mul(void * data,GEN x,GEN y)2856 _F2xqXQ_mul(void *data, GEN x, GEN y) {
2857   struct _F2xqXQ *d = (struct _F2xqXQ*) data;
2858   return F2xqXQ_mul(x,y, d->S,d->T);
2859 }
2860 static GEN
_F2xqXQ_sqr(void * data,GEN x)2861 _F2xqXQ_sqr(void *data, GEN x) {
2862   struct _F2xqXQ *d = (struct _F2xqXQ*) data;
2863   return F2xqXQ_sqr(x, d->S,d->T);
2864 }
2865 static GEN
_F2xqXQ_zero(void * data)2866 _F2xqXQ_zero(void *data) {
2867   struct _F2xqXQ *d = (struct _F2xqXQ*) data;
2868   return pol_0(get_F2xqX_var(d->S));
2869 }
2870 static GEN
_F2xqXQ_one(void * data)2871 _F2xqXQ_one(void *data) {
2872   struct _F2xqXQ *d = (struct _F2xqXQ*) data;
2873   return pol1_F2xX(get_F2xqX_var(d->S),get_F2x_var(d->T));
2874 }
2875 
2876 static struct bb_algebra F2xqXQ_algebra = { _F2xqXQ_red,
2877  _F2xqXQ_add, _F2xqXQ_add, _F2xqXQ_mul,_F2xqXQ_sqr,_F2xqXQ_one,_F2xqXQ_zero };
2878 
2879 GEN
F2xqXQ_pow(GEN x,GEN n,GEN S,GEN T)2880 F2xqXQ_pow(GEN x, GEN n, GEN S, GEN T)
2881 {
2882   struct _F2xqXQ D;
2883   long s = signe(n);
2884   if (!s) return pol1_F2xX(get_F2xqX_var(S), get_F2x_var(T));
2885   if (s < 0) x = F2xqXQ_inv(x,S,T);
2886   if (is_pm1(n)) return s < 0 ? x : gcopy(x);
2887   if (degpol(x) >= get_F2xqX_degree(S)) x = F2xqX_rem(x,S,T);
2888   D.T = F2x_get_red(T);
2889   D.S = F2xqX_get_red(S, T);
2890   return gen_pow(x, n, (void*)&D, &_F2xqXQ_sqr, &_F2xqXQ_mul);
2891 }
2892 
2893 GEN
F2xqXQ_powers(GEN x,long l,GEN S,GEN T)2894 F2xqXQ_powers(GEN x, long l, GEN S, GEN T)
2895 {
2896   struct _F2xqXQ D;
2897   int use_sqr = 2*degpol(x) >= get_F2xqX_degree(S);
2898   D.T = F2x_get_red(T);
2899   D.S = F2xqX_get_red(S, T);
2900   return gen_powers(x, l, use_sqr, (void*)&D, &_F2xqXQ_sqr, &_F2xqXQ_mul,&_F2xqXQ_one);
2901 }
2902 
2903 GEN
F2xqX_F2xqXQV_eval(GEN P,GEN V,GEN S,GEN T)2904 F2xqX_F2xqXQV_eval(GEN P, GEN V, GEN S, GEN T)
2905 {
2906   struct _F2xqXQ D;
2907   D.T = F2x_get_red(T);
2908   D.S = F2xqX_get_red(S, T);
2909   return gen_bkeval_powers(P, degpol(P), V, (void*)&D, &F2xqXQ_algebra,
2910                                                    _F2xqXQ_cmul);
2911 }
2912 
2913 GEN
F2xqX_F2xqXQ_eval(GEN Q,GEN x,GEN S,GEN T)2914 F2xqX_F2xqXQ_eval(GEN Q, GEN x, GEN S, GEN T)
2915 {
2916   struct _F2xqXQ D;
2917   int use_sqr = 2*degpol(x) >= get_F2xqX_degree(S);
2918   D.T = F2x_get_red(T);
2919   D.S = F2xqX_get_red(S, T);
2920   return gen_bkeval(Q, degpol(Q), x, use_sqr, (void*)&D, &F2xqXQ_algebra,
2921                                                     _F2xqXQ_cmul);
2922 }
2923 
2924 static GEN
F2xqXQ_autpow_sqr(void * E,GEN x)2925 F2xqXQ_autpow_sqr(void * E, GEN x)
2926 {
2927   struct _F2xqXQ *D = (struct _F2xqXQ *)E;
2928   GEN T = D->T;
2929   GEN phi = gel(x,1), S = gel(x,2);
2930   long n = brent_kung_optpow(get_F2x_degree(T)-1,lgpol(S)+1,1);
2931   GEN V = F2xq_powers(phi, n, T);
2932   GEN phi2 = F2x_F2xqV_eval(phi, V, T);
2933   GEN Sphi = F2xY_F2xqV_evalx(S, V, T);
2934   GEN S2 = F2xqX_F2xqXQ_eval(Sphi, S, D->S, T);
2935   return mkvec2(phi2, S2);
2936 }
2937 
2938 static GEN
F2xqXQ_autpow_mul(void * E,GEN x,GEN y)2939 F2xqXQ_autpow_mul(void * E, GEN x, GEN y)
2940 {
2941   struct _F2xqXQ *D = (struct _F2xqXQ *)E;
2942   GEN T = D->T;
2943   GEN phi1 = gel(x,1), S1 = gel(x,2);
2944   GEN phi2 = gel(y,1), S2 = gel(y,2);
2945   long n = brent_kung_optpow(get_F2x_degree(T)-1,lgpol(S1)+1,1);
2946   GEN V = F2xq_powers(phi2, n, T);
2947   GEN phi3 = F2x_F2xqV_eval(phi1,V,T);
2948   GEN Sphi = F2xY_F2xqV_evalx(S1,V,T);
2949   GEN S3 = F2xqX_F2xqXQ_eval(Sphi, S2, D->S, T);
2950   return mkvec2(phi3, S3);
2951 }
2952 
2953 GEN
F2xqXQ_autpow(GEN aut,long n,GEN S,GEN T)2954 F2xqXQ_autpow(GEN aut, long n, GEN S, GEN T)
2955 {
2956   struct _F2xqXQ D;
2957   D.T = F2x_get_red(T);
2958   D.S = F2xqX_get_red(S, T);
2959   return gen_powu(aut,n,&D,F2xqXQ_autpow_sqr,F2xqXQ_autpow_mul);
2960 }
2961 
2962 static GEN
F2xqXQ_auttrace_mul(void * E,GEN x,GEN y)2963 F2xqXQ_auttrace_mul(void *E, GEN x, GEN y)
2964 {
2965   struct _F2xqXQ *D = (struct _F2xqXQ *) E;
2966   GEN T = D->T;
2967   GEN phi1 = gel(x,1), S1 = gel(x,2), a1 = gel(x,3);
2968   GEN phi2 = gel(y,1), S2 = gel(y,2), a2 = gel(y,3);
2969   long n2 = brent_kung_optpow(get_F2x_degree(T)-1, lgpol(S1)+lgpol(a1)+1, 1);
2970   GEN V2 = F2xq_powers(phi2, n2, T);
2971   GEN phi3 = F2x_F2xqV_eval(phi1, V2, T);
2972   GEN Sphi = F2xY_F2xqV_evalx(S1, V2, T);
2973   GEN aphi = F2xY_F2xqV_evalx(a1, V2, T);
2974   long n = brent_kung_optpow(maxss(degpol(Sphi),degpol(aphi)),2,1);
2975   GEN V = F2xqXQ_powers(S2, n, D->S, T);
2976   GEN S3 = F2xqX_F2xqXQV_eval(Sphi, V, D->S, T);
2977   GEN aS = F2xqX_F2xqXQV_eval(aphi, V, D->S, T);
2978   GEN a3 = F2xX_add(aS, a2);
2979   return mkvec3(phi3, S3, a3);
2980 }
2981 
2982 static GEN
F2xqXQ_auttrace_sqr(void * E,GEN x)2983 F2xqXQ_auttrace_sqr(void *E, GEN x) { return F2xqXQ_auttrace_mul(E, x, x); }
2984 GEN
F2xqXQ_auttrace(GEN aut,long n,GEN S,GEN T)2985 F2xqXQ_auttrace(GEN aut, long n, GEN S, GEN T)
2986 {
2987   struct _F2xqXQ D;
2988   D.T = F2x_get_red(T);
2989   D.S = F2xqX_get_red(S, T);
2990   return gen_powu(aut,n,&D,F2xqXQ_auttrace_sqr,F2xqXQ_auttrace_mul);
2991 }
2992 
2993 GEN
F2xqXQV_red(GEN x,GEN S,GEN T)2994 F2xqXQV_red(GEN x, GEN S, GEN T)
2995 { pari_APPLY_type(t_VEC, F2xqX_rem(gel(x,i), S, T)) }
2996