Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2007 The PARI group.12This file is part of the PARI/GP package.34PARI/GP is free software; you can redistribute it and/or modify it under the5terms of the GNU General Public License as published by the Free Software6Foundation; either version 2 of the License, or (at your option) any later7version. It is distributed in the hope that it will be useful, but WITHOUT8ANY WARRANTY WHATSOEVER.910Check the License for details. You should have received a copy of it, along11with the package; see the file 'COPYING'. If not, write to the Free Software12Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */1314#include "pari.h"15#include "paripriv.h"1617#define DEBUGLEVEL DEBUGLEVEL_fflog1819/* Not so fast arithmetic with polynomials over F_2 */2021/***********************************************************************/22/** **/23/** F2x **/24/** **/25/***********************************************************************/26/* F2x objects are defined as follows:27An F2x is a t_VECSMALL:28x[0] = codeword29x[1] = evalvarn(variable number) (signe is not stored).30x[2] = a_0...a_31 x[3] = a_32..a_63, etc. on 32bit31x[2] = a_0...a_63 x[3] = a_64..a_127, etc. on 64bit3233where the a_i are bits.3435signe(x) is not valid. Use lgpol(x)!=0 instead.36Note: pol0_F2x=pol0_Flx and pol1_F2x=pol1_Flx37*/3839INLINE long40F2x_degreespec(GEN x, long l)41{42return (l==0)?-1:l*BITS_IN_LONG-bfffo(x[l-1])-1;43}4445INLINE long46F2x_degree_lg(GEN x, long l)47{48return (l==2)?-1:bit_accuracy(l)-bfffo(x[l-1])-1;49}5051long52F2x_degree(GEN x)53{54return F2x_degree_lg(x, lg(x));55}5657GEN58monomial_F2x(long d, long vs)59{60long l=nbits2lg(d+1);61GEN z = zero_zv(l-1);62z[1] = vs;63F2x_set(z,d);64return z;65}6667GEN68F2x_to_ZX(GEN x)69{70long l = 3+F2x_degree(x), lx = lg(x);71GEN z = cgetg(l,t_POL);72long i, j ,k;73for (i=2, k=2; i<lx; i++)74for (j=0; j<BITS_IN_LONG && k<l; j++,k++)75gel(z,k) = (x[i]&(1UL<<j))?gen_1:gen_0;76z[1]=evalsigne(l>=3)|x[1];77return z;78}7980GEN81F2x_to_Flx(GEN x)82{83long l = 3+F2x_degree(x), lx = lg(x);84GEN z = cgetg(l,t_VECSMALL);85long i, j, k;86z[1] = x[1];87for (i=2, k=2; i<lx; i++)88for (j=0; j<BITS_IN_LONG && k<l; j++,k++)89z[k] = (x[i]>>j)&1UL;90return z;91}9293GEN94F2x_to_F2xX(GEN z, long sv)95{96long i, d = F2x_degree(z);97GEN x = cgetg(d+3,t_POL);98for (i=0; i<=d; i++)99gel(x,i+2) = F2x_coeff(z,i) ? pol1_F2x(sv): pol0_F2x(sv);100x[1] = evalsigne(d+1!=0)| z[1]; return x;101}102103GEN104Z_to_F2x(GEN x, long sv)105{106return mpodd(x) ? pol1_F2x(sv): pol0_F2x(sv);107}108109GEN110ZX_to_F2x(GEN x)111{112long lx = lg(x), l = nbits2lg(lx-2);113GEN z = cgetg(l,t_VECSMALL);114long i, j, k;115z[1] = ((ulong)x[1])&VARNBITS;116for (i=2, k=1,j=BITS_IN_LONG; i<lx; i++,j++)117{118if (j==BITS_IN_LONG)119{120j=0; z[++k]=0;121}122if (mpodd(gel(x,i)))123z[k] |= 1UL<<j;124}125return F2x_renormalize(z,l);126}127128GEN129Flx_to_F2x(GEN x)130{131long lx = lg(x), l = nbits2lg(lx-2);132GEN z = cgetg(l,t_VECSMALL);133long i, j, k;134z[1] = x[1];135for (i=2, k=1, j=BITS_IN_LONG; i<lx; i++,j++)136{137if (j==BITS_IN_LONG)138{139j=0; z[++k] = 0;140}141if (x[i]&1UL)142z[k] |= 1UL<<j;143}144return F2x_renormalize(z,l);145}146147GEN148F2x_to_F2v(GEN x, long N)149{150long i, l = lg(x);151long n = nbits2lg(N);152GEN z = cgetg(n,t_VECSMALL);153z[1] = N;154for (i=2; i<l ; i++) z[i]=x[i];155for ( ; i<n; i++) z[i]=0;156return z;157}158159GEN160RgX_to_F2x(GEN x)161{162long l=nbits2lg(lgpol(x));163GEN z=cgetg(l,t_VECSMALL);164long i,j,k;165z[1]=((ulong)x[1])&VARNBITS;166for(i=2, k=1,j=BITS_IN_LONG;i<lg(x);i++,j++)167{168if (j==BITS_IN_LONG)169{170j=0; k++; z[k]=0;171}172if (Rg_to_F2(gel(x,i)))173z[k]|=1UL<<j;174}175return F2x_renormalize(z,l);176}177178/* If x is a POLMOD, assume modulus is a multiple of T. */179GEN180Rg_to_F2xq(GEN x, GEN T)181{182long ta, tx = typ(x), v = get_F2x_var(T);183GEN a, b;184if (is_const_t(tx))185{186if (tx == t_FFELT) return FF_to_F2xq(x);187return Rg_to_F2(x)? pol1_F2x(v): pol0_F2x(v);188}189switch(tx)190{191case t_POLMOD:192b = gel(x,1);193a = gel(x,2); ta = typ(a);194if (is_const_t(ta)) return Rg_to_F2(a)? pol1_F2x(v): pol0_F2x(v);195b = RgX_to_F2x(b); if (b[1] != v) break;196a = RgX_to_F2x(a); if (F2x_equal(b,T)) return a;197if (lgpol(F2x_rem(b,T))==0) return F2x_rem(a, T);198break;199case t_POL:200x = RgX_to_F2x(x);201if (x[1] != v) break;202return F2x_rem(x, T);203case t_RFRAC:204a = Rg_to_F2xq(gel(x,1), T);205b = Rg_to_F2xq(gel(x,2), T);206return F2xq_div(a,b, T);207}208pari_err_TYPE("Rg_to_F2xq",x);209return NULL; /* LCOV_EXCL_LINE */210}211212ulong213F2x_eval(GEN P, ulong x)214{215if (odd(x))216{217long i, lP = lg(P);218ulong c = 0;219for (i=2; i<lP; i++)220c ^= P[i];221#ifdef LONG_IS_64BIT222c ^= c >> 32;223#endif224c ^= c >> 16;225c ^= c >> 8;226c ^= c >> 4;227c ^= c >> 2;228c ^= c >> 1;229return c & 1;230}231else return F2x_coeff(P,0);232}233234GEN235F2x_add(GEN x, GEN y)236{237long i,lz;238GEN z;239long lx=lg(x);240long ly=lg(y);241if (ly>lx) swapspec(x,y, lx,ly);242lz = lx; z = cgetg(lz, t_VECSMALL); z[1]=x[1];243for (i=2; i<ly; i++) z[i] = x[i]^y[i];244for ( ; i<lx; i++) z[i] = x[i];245return F2x_renormalize(z, lz);246}247248static GEN249F2x_addspec(GEN x, GEN y, long lx, long ly)250{251long i,lz;252GEN z;253254if (ly>lx) swapspec(x,y, lx,ly);255lz = lx+2; z = cgetg(lz, t_VECSMALL) + 2;256for (i=0; i<ly-3; i+=4)257{258z[i] = x[i]^y[i];259z[i+1] = x[i+1]^y[i+1];260z[i+2] = x[i+2]^y[i+2];261z[i+3] = x[i+3]^y[i+3];262}263for (; i<ly; i++)264z[i] = x[i]^y[i];265for ( ; i<lx; i++) z[i] = x[i];266z -= 2; z[1] = 0; return F2x_renormalize(z, lz);267}268269GEN270F2x_1_add(GEN y)271{272GEN z;273long lz, i;274if (!lgpol(y))275return pol1_F2x(y[1]);276lz=lg(y);277z=cgetg(lz,t_VECSMALL);278z[1] = y[1];279z[2] = y[2]^1UL;280for(i=3;i<lz;i++)281z[i] = y[i];282if (lz==3) z = F2x_renormalize(z,lz);283return z;284}285286INLINE void287F2x_addshiftipspec(GEN x, GEN y, long ny, ulong db)288{289long i;290if (db)291{292ulong dc=BITS_IN_LONG-db;293ulong r=0, yi;294for(i=0; i<ny-3; i+=4)295{296yi = uel(y,i); x[i] ^= (yi<<db)|r; r = yi>>dc;297yi = uel(y,i+1); x[i+1] ^= (yi<<db)|r; r = yi>>dc;298yi = uel(y,i+2); x[i+2] ^= (yi<<db)|r; r = yi>>dc;299yi = uel(y,i+3); x[i+3] ^= (yi<<db)|r; r = yi>>dc;300}301for( ; i<ny; i++)302{303ulong yi = uel(y,i); x[i] ^= (yi<<db)|r; r = yi>>dc;304}305if (r) x[i] ^= r;306}307else308{309for(i=0; i<ny-3; i+=4)310{311x[i] ^= y[i];312x[i+1] ^= y[i+1];313x[i+2] ^= y[i+2];314x[i+3] ^= y[i+3];315}316for( ; i<ny; i++)317x[i] ^= y[i];318}319}320321INLINE void322F2x_addshiftip(GEN x, GEN y, ulong d)323{324ulong db, dl=dvmduBIL(d, &db);325F2x_addshiftipspec(x+2+dl, y+2, lgpol(y), db);326}327328static GEN329F2x_mul1(ulong x, ulong y)330{331ulong x1=(x&HIGHMASK)>>BITS_IN_HALFULONG;332ulong x2=x&LOWMASK;333ulong y1=(y&HIGHMASK)>>BITS_IN_HALFULONG;334ulong y2=y&LOWMASK;335ulong r1,r2,rr;336GEN z;337ulong i;338rr=r1=r2=0UL;339if (x2)340for(i=0;i<BITS_IN_HALFULONG;i++)341if (x2&(1UL<<i))342{343r2^=y2<<i;344rr^=y1<<i;345}346if (x1)347for(i=0;i<BITS_IN_HALFULONG;i++)348if (x1&(1UL<<i))349{350r1^=y1<<i;351rr^=y2<<i;352}353r2^=(rr&LOWMASK)<<BITS_IN_HALFULONG;354r1^=(rr&HIGHMASK)>>BITS_IN_HALFULONG;355z=cgetg((r1?4:3),t_VECSMALL);356z[2]=r2;357if (r1) z[3]=r1;358return z;359}360361static GEN362F2x_mulspec_basecase(GEN x, GEN y, long nx, long ny)363{364long l, i, j;365GEN z;366l = nx + ny;367z = zero_Flv(l+1);368for(i=0; i < ny-1; i++)369{370GEN zi = z+2+i;371ulong yi = uel(y,i);372if (yi)373for(j=0; j < BITS_IN_LONG; j++)374if (yi&(1UL<<j)) F2x_addshiftipspec(zi,x,nx,j);375}376{377GEN zi = z+2+i;378ulong yi = uel(y,i);379long c = BITS_IN_LONG-bfffo(yi);380for(j=0; j < c; j++)381if (yi&(1UL<<j)) F2x_addshiftipspec(zi,x,nx,j);382}383return F2x_renormalize(z, l+2);384}385386static GEN387F2x_addshift(GEN x, GEN y, long d)388{389GEN xd,yd,zd = (GEN)avma;390long a,lz,ny = lgpol(y), nx = lgpol(x);391long vs = x[1];392if (nx == 0) return y;393x += 2; y += 2; a = ny-d;394if (a <= 0)395{396lz = (a>nx)? ny+2: nx+d+2;397(void)new_chunk(lz); xd = x+nx; yd = y+ny;398while (xd > x) *--zd = *--xd;399x = zd + a;400while (zd > x) *--zd = 0;401}402else403{404xd = new_chunk(d); yd = y+d;405x = F2x_addspec(x,yd,nx,a);406lz = (a>nx)? ny+2: lg(x)+d;407x += 2; while (xd > x) *--zd = *--xd;408}409while (yd > y) *--zd = *--yd;410*--zd = vs;411*--zd = evaltyp(t_VECSMALL) | evallg(lz); return zd;412}413414/* shift polynomial + gerepile */415/* Do not set evalvarn. Cf Flx_shiftip */416static GEN417F2x_shiftip(pari_sp av, GEN x, long v)418{419long i, lx = lg(x), ly;420GEN y;421if (!v || lx==2) return gerepileuptoleaf(av, x);422ly = lx + v;423(void)new_chunk(ly); /* check that result fits */424x += lx; y = (GEN)av;425for (i = 2; i<lx; i++) *--y = *--x;426for (i = 0; i< v; i++) *--y = 0;427y -= 2; y[0] = evaltyp(t_VECSMALL) | evallg(ly);428return gc_const((pari_sp)y, y);429}430431static GEN432F2x_to_int(GEN a, long na, long da, long bs)433{434const long BIL = BITS_IN_LONG;435GEN z, zs;436long i,j,k,m;437long lz = nbits2lg(1+da*bs);438z = cgeti(lz); z[1] = evalsigne(1)|evallgefint(lz);439zs = int_LSW(z); *zs = 0;440for (i=0, k=2, m=0; i<na; i++)441for (j=0; j<BIL; j++, m+=bs)442{443if (m >= BIL)444{445k++; if (k>=lz) break;446zs = int_nextW(zs);447*zs = 0;448m -= BIL;449}450*zs |= ((a[i]>>j)&1UL)<<m;451}452return int_normalize(z,0);453}454455static GEN456int_to_F2x(GEN x, long d, long bs)457{458const long BIL = BITS_IN_LONG;459long lx = lgefint(x), lz = nbits2lg(d+1);460long i,j,k,m;461GEN xs = int_LSW(x);462GEN z = cgetg(lz, t_VECSMALL);463z[1] = 0;464for (k=2, i=2, m=0; k < lx; i++)465{466z[i] = 0;467for (j=0; j<BIL; j++, m+=bs)468{469if (m >= BIL)470{471if (++k==lx) break;472xs = int_nextW(xs);473m -= BIL;474}475if ((*xs>>m)&1UL)476z[i]|=1UL<<j;477}478}479return F2x_renormalize(z,lz);480}481482static GEN483F2x_mulspec_mulii(GEN a, GEN b, long na, long nb)484{485long da = F2x_degreespec(a,na), db = F2x_degreespec(b,nb);486long bs = expu(1 + maxss(da, db))+1;487GEN A = F2x_to_int(a,na,da,bs);488GEN B = F2x_to_int(b,nb,db,bs);489GEN z = mulii(A,B);490return int_to_F2x(z,da+db,bs);491}492493/* fast product (Karatsuba) of polynomials a,b. These are not real GENs, a+2,494* b+2 were sent instead. na, nb = number of terms of a, b.495* Only c, c0, c1, c2 are genuine GEN.496*/497static GEN498F2x_mulspec(GEN a, GEN b, long na, long nb)499{500GEN a0,c,c0;501long n0, n0a, i, v = 0;502pari_sp av;503while (na && !a[0]) { a++; na-=1; v++; }504while (nb && !b[0]) { b++; nb-=1; v++; }505if (na < nb) swapspec(a,b, na,nb);506if (!nb) return pol0_F2x(0);507508av = avma;509if (na == 1)510return F2x_shiftip(av, F2x_mul1(*a,*b), v);511if (na < F2x_MUL_KARATSUBA_LIMIT)512return F2x_shiftip(av, F2x_mulspec_basecase(a, b, na, nb), v);513if (nb >= F2x_MUL_MULII_LIMIT)514return F2x_shiftip(av, F2x_mulspec_mulii(a, b, na, nb), v);515i=(na>>1); n0=na-i; na=i;516a0=a+n0; n0a=n0;517while (n0a && !a[n0a-1]) n0a--;518519if (nb > n0)520{521GEN b0,c1,c2;522long n0b;523524nb -= n0; b0 = b+n0; n0b = n0;525while (n0b && !b[n0b-1]) n0b--;526c = F2x_mulspec(a,b,n0a,n0b);527c0 = F2x_mulspec(a0,b0,na,nb);528529c2 = F2x_addspec(a0,a,na,n0a);530c1 = F2x_addspec(b0,b,nb,n0b);531532c1 = F2x_mul(c1,c2);533c2 = F2x_add(c0,c);534535c2 = F2x_add(c1,c2);536c0 = F2x_addshift(c0,c2,n0);537}538else539{540c = F2x_mulspec(a,b,n0a,nb);541c0 = F2x_mulspec(a0,b,na,nb);542}543c0 = F2x_addshift(c0,c,n0);544return F2x_shiftip(av,c0, v);545}546547GEN548F2x_mul(GEN x, GEN y)549{550GEN z = F2x_mulspec(x+2,y+2, lgpol(x),lgpol(y));551z[1] = x[1]; return z;552}553554GEN555F2x_sqr(GEN x)556{557const ulong sq[]={0,1,4,5,16,17,20,21,64,65,68,69,80,81,84,85};558long i,ii,j,jj;559long lx=lg(x), lz=2+((lx-2)<<1);560GEN z;561z = cgetg(lz, t_VECSMALL); z[1]=x[1];562for (j=2,jj=2;j<lx;j++,jj++)563{564ulong x1=((ulong)x[j]&HIGHMASK)>>BITS_IN_HALFULONG;565ulong x2=(ulong)x[j]&LOWMASK;566z[jj]=0;567if (x2)568for(i=0,ii=0;i<BITS_IN_HALFULONG;i+=4,ii+=8)569z[jj]|=sq[(x2>>i)&15UL]<<ii;570z[++jj]=0;571if (x1)572for(i=0,ii=0;i<BITS_IN_HALFULONG;i+=4,ii+=8)573z[jj]|=sq[(x1>>i)&15UL]<<ii;574}575return F2x_renormalize(z, lz);576}577578static GEN579F2x_pow2n(GEN x, long n)580{581long i;582for(i=1;i<=n;i++)583x = F2x_sqr(x);584return x;585}586587int588F2x_issquare(GEN x)589{590const ulong mask = (ULONG_MAX/3UL)*2;591ulong i, lx = lg(x);592for (i=2; i<lx; i++)593if ((x[i]&mask)) return 0;594return 1;595}596597/* Assume x is a perfect square */598GEN599F2x_sqrt(GEN x)600{601const ulong sq[]={0,1,4,5,2,3,6,7,8,9,12,13,10,11,14,15};602long i,ii,j,jj;603long lx=lg(x), lz=2+((lx-1)>>1);604GEN z;605z = cgetg(lz, t_VECSMALL); z[1]=x[1];606for (j=2,jj=2;jj<lz;j++,jj++)607{608ulong x2=x[j++];609z[jj]=0;610if (x2)611for(i=0,ii=0;ii<BITS_IN_HALFULONG;i+=8,ii+=4)612{613ulong rl = (x2>>i)&15UL, rh = (x2>>(i+4))&15UL;614z[jj]|=sq[rl|(rh<<1)]<<ii;615}616if (j<lx)617{618x2 = x[j];619if (x2)620for(i=0,ii=0;ii<BITS_IN_HALFULONG;i+=8,ii+=4)621{622ulong rl = (x2>>i)&15UL, rh = (x2>>(i+4))&15UL;623z[jj]|=(sq[rl|(rh<<1)]<<ii)<<BITS_IN_HALFULONG;624}625}626}627return F2x_renormalize(z, lz);628}629630static GEN631F2x_shiftneg(GEN y, ulong d)632{633long db, dl=dvmdsBIL(d, &db);634long i, ly = lg(y), lx = ly-dl;635GEN x = cgetg(lx, t_VECSMALL);636x[1] = y[1];637if (db)638{639ulong dc=BITS_IN_LONG-db;640ulong r=0;641for(i=lx-1; i>=2; i--)642{643x[i] = (((ulong)y[i+dl])>>db)|r;644r = ((ulong)y[i+dl])<<dc;645}646}647else648for(i=2; i<lx; i++)649x[i] = y[i+dl];650return F2x_renormalize(x,lx);651}652653static GEN654F2x_shiftpos(GEN y, ulong d)655{656long db, dl=dvmdsBIL(d, &db);657long i, ly = lg(y), lx = ly+dl+(!!db);658GEN x = cgetg(lx, t_VECSMALL);659x[1] = y[1]; for(i=0; i<dl; i++) x[i+2] = 0;660if (db)661{662ulong dc=BITS_IN_LONG-db;663ulong r=0;664for(i=2; i<ly; i++)665{666x[i+dl] = (((ulong)y[i])<<db)|r;667r = ((ulong)y[i])>>dc;668}669x[i+dl] = r;670}671else672for(i=2; i<ly; i++)673x[i+dl] = y[i];674return F2x_renormalize(x,lx);675}676677GEN678F2x_shift(GEN y, long d)679{680return d<0 ? F2x_shiftneg(y,-d): F2x_shiftpos(y,d);681}682683#define F2x_recip2(pk,m) u = ((u&m)<<pk)|((u&(~m))>>pk);684#define F2x_recipu(pk) F2x_recip2(pk,((~0UL)/((1UL<<pk)+1)))685686static ulong687F2x_recip1(ulong u)688{689u = (u<<BITS_IN_HALFULONG)|(u>>BITS_IN_HALFULONG);690#ifdef LONG_IS_64BIT691F2x_recipu(16);692#endif693F2x_recipu(8);694F2x_recipu(4);695F2x_recipu(2);696F2x_recipu(1);697return u;698}699700static GEN701F2x_recip_raw(GEN x)702{703long i, l;704GEN y = cgetg_copy(x,&l);705y[1] = x[1];706for (i=0; i<l-2; i++)707uel(y,l-1-i) = F2x_recip1(uel(x,2+i));708return y;709}710711GEN712F2x_recip(GEN x)713{714long lb = remsBIL(F2x_degree(x)+1);715GEN y = F2x_recip_raw(x);716if (lb) y = F2x_shiftneg(y,BITS_IN_LONG-lb);717return y;718}719720GEN721F2xn_red(GEN f, long n)722{723GEN g;724long i, dl, db, l;725if (F2x_degree(f) < n) return zv_copy(f);726dl = dvmdsBIL(n, &db); l = 2 + dl + (db>0);727g = cgetg(l, t_VECSMALL);728g[1] = f[1];729for (i=2; i<l; i++)730uel(g,i) = uel(f,i);731if (db) uel(g,l-1) = uel(f,l-1)&((1UL<<db)-1);732return F2x_renormalize(g, l);733}734735static GEN736F2xn_mul(GEN a, GEN b, long n) { return F2xn_red(F2x_mul(a, b), n); }737738static ulong739F2xn_inv_basecase1(ulong x)740{741ulong u, v, w;742long i;743u = x>>1;744v = (u&1UL)|2UL;745w = u&v; w ^= w >> 1; v = (w&1UL)|(v<<1);746w = u&v; w ^= w >> 2; w ^= w >> 1; v = (w&1UL)|(v<<1);747w = u&v; w ^= w >> 2; w ^= w >> 1; v = (w&1UL)|(v<<1);748for (i=1;i<=4;i++)749{ w = u&v; w ^= w >> 4; w ^= w >> 2; w ^= w >> 1; v = (w&1UL)|(v<<1); }750for (i=1;i<=8;i++)751{ w = u&v; w ^= w >> 8; w ^= w >> 4; w ^= w >> 2; w ^= w >> 1;752v = (w&1UL)|(v<<1); }753for (i=1;i<=16;i++)754{ w = u&v; w ^= w >> 16; w ^= w >> 8; w ^= w >> 4; w ^= w >> 2; w ^= w >> 1;755v = (w&1UL)|(v<<1); }756#ifdef LONG_IS_64BIT757for (i=1; i<=32; i++)758{ w = u&v; w ^= w >> 32; w ^= w >> 16; w ^= w >> 8; w ^= w >> 4; w ^= w >> 2;759w ^= w >> 1; v = (w&1UL)|(v<<1); }760#endif761return (F2x_recip1(v)<<1) | 1UL;762}763764static GEN765F2xn_inv1(GEN v, long e)766{767ulong mask = e==BITS_IN_LONG ? -1UL: ((1UL<<e)-1);768return mkvecsmall2(v[1],F2xn_inv_basecase1(uel(v,2))&mask);769}770771GEN772F2xn_inv(GEN f, long e)773{774pari_sp av = avma, av2;775ulong mask;776GEN W;777long n=1;778if (lg(f)==2) pari_err_INV("Flxn_inv",f);779if (e <= BITS_IN_LONG) return F2xn_inv1(f, e);780W = F2xn_inv1(f, BITS_IN_LONG);781mask = quadratic_prec_mask(divsBIL(e+BITS_IN_LONG-1));782n = BITS_IN_LONG;783av2 = avma;784for (;mask>1;)785{786GEN u, fr;787long n2 = n;788n<<=1; if (mask & 1) n--;789mask >>= 1;790fr = F2xn_red(f, n);791u = F2x_shift(F2xn_mul(W, fr, n), -n2);792W = F2x_add(W, F2x_shift(F2xn_mul(u, W, n-n2), n2));793if (gc_needed(av2,2))794{795if(DEBUGMEM>1) pari_warn(warnmem,"F2xn_inv, e = %ld", n);796W = gerepileupto(av2, W);797}798}799return gerepileupto(av, F2xn_red(W,e));800}801802GEN803F2x_get_red(GEN T)804{805return T;806}807808/* separate from F2x_divrem for maximal speed. */809GEN810F2x_rem(GEN x, GEN y)811{812long dx,dy;813long lx=lg(x);814dy = F2x_degree(y); if (!dy) return pol0_F2x(x[1]);815dx = F2x_degree_lg(x,lx);816x = F2x_copy(x);817while (dx>=dy)818{819F2x_addshiftip(x,y,dx-dy);820while (lx>2 && x[lx-1]==0) lx--;821dx = F2x_degree_lg(x,lx);822}823return F2x_renormalize(x, lx);824}825826GEN827F2x_divrem(GEN x, GEN y, GEN *pr)828{829long dx, dy, dz, lx = lg(x), vs = x[1];830GEN z;831832dy = F2x_degree(y);833if (dy<0) pari_err_INV("F2x_divrem",y);834if (pr == ONLY_REM) return F2x_rem(x, y);835if (!dy)836{837z = F2x_copy(x);838if (pr && pr != ONLY_DIVIDES) *pr = pol0_F2x(vs);839return z;840}841dx = F2x_degree_lg(x,lx);842dz = dx-dy;843if (dz < 0)844{845if (pr == ONLY_DIVIDES) return dx < 0? F2x_copy(x): NULL;846z = pol0_F2x(vs);847if (pr) *pr = F2x_copy(x);848return z;849}850z = zero_zv(lg(x)-lg(y)+2); z[1] = vs;851x = F2x_copy(x);852while (dx>=dy)853{854F2x_set(z,dx-dy);855F2x_addshiftip(x,y,dx-dy);856while (lx>2 && x[lx-1]==0) lx--;857dx = F2x_degree_lg(x,lx);858}859z = F2x_renormalize(z, lg(z));860if (!pr) { cgiv(x); return z; }861x = F2x_renormalize(x, lx);862if (pr == ONLY_DIVIDES) {863if (lg(x) == 2) { cgiv(x); return z; }864return gc_NULL((pari_sp)(z + lg(z)));865}866*pr = x; return z;867}868869long870F2x_valrem(GEN x, GEN *Z)871{872long v, v2, i, l=lg(x);873GEN y;874if (l==2) { *Z = F2x_copy(x); return LONG_MAX; }875for (i=2; i<l && x[i]==0; i++) /*empty*/;876v = i-2;877v2 = (i < l)? vals(x[i]): 0;878if (v+v2 == 0) { *Z = x; return 0; }879l -= i-2;880y = cgetg(l, t_VECSMALL); y[1] = x[1];881if (v2 == 0)882for (i=2; i<l; i++) y[i] = x[i+v];883else if (l == 3)884y[2] = ((ulong)x[2+v]) >> v2;885else886{887const ulong sh = BITS_IN_LONG - v2;888ulong r = x[2+v];889for (i=3; i<l; i++)890{891y[i-1] = (x[i+v] << sh) | (r >> v2);892r = x[i+v];893}894y[l-1] = r >> v2;895(void)F2x_renormalize(y,l);896}897*Z = y; return (v << TWOPOTBITS_IN_LONG) + v2;898}899900GEN901F2x_deflate(GEN x, long d)902{903GEN y;904long i,id, dy, dx = F2x_degree(x);905if (d <= 1) return F2x_copy(x);906if (dx < 0) return F2x_copy(x);907dy = dx/d; /* dy+1 coefficients + 1 extra word for variable */908y = zero_zv(nbits2lg(dy+1)-1); y[1] = x[1];909for (i=id=0; i<=dy; i++,id+=d)910if (F2x_coeff(x,id)) F2x_set(y, i);911return y;912}913914/* write p(X) = e(X^2) + Xo(X^2), shallow function */915void916F2x_even_odd(GEN p, GEN *pe, GEN *po)917{918long n = F2x_degree(p), n0, n1, i;919GEN p0, p1;920921if (n <= 0) { *pe = F2x_copy(p); *po = pol0_F2x(p[1]); return; }922923n0 = (n>>1)+1; n1 = n+1 - n0; /* n1 <= n0 <= n1+1 */924p0 = zero_zv(nbits2lg(n0+1)-1); p0[1] = p[1];925p1 = zero_zv(nbits2lg(n1+1)-1); p1[1] = p[1];926for (i=0; i<n1; i++)927{928if (F2x_coeff(p,i<<1)) F2x_set(p0,i);929if (F2x_coeff(p,1+(i<<1))) F2x_set(p1,i);930}931if (n1 != n0 && F2x_coeff(p,i<<1)) F2x_set(p0,i);932*pe = F2x_renormalize(p0,lg(p0));933*po = F2x_renormalize(p1,lg(p1));934}935936GEN937F2x_deriv(GEN z)938{939const ulong mask = ULONG_MAX/3UL;940long i,l = lg(z);941GEN x = cgetg(l, t_VECSMALL); x[1] = z[1];942for (i=2; i<l; i++) x[i] = (((ulong)z[i])>>1)&mask;943return F2x_renormalize(x,l);944}945946GEN947F2x_gcd(GEN a, GEN b)948{949pari_sp av = avma;950if (lg(b) > lg(a)) swap(a, b);951while (lgpol(b))952{953GEN c = F2x_rem(a,b);954a = b; b = c;955if (gc_needed(av,2))956{957if (DEBUGMEM>1) pari_warn(warnmem,"F2x_gcd (d = %ld)",F2x_degree(c));958gerepileall(av,2, &a,&b);959}960}961if (gc_needed(av,2)) a = gerepileuptoleaf(av, a);962return a;963}964965GEN966F2x_extgcd(GEN a, GEN b, GEN *ptu, GEN *ptv)967{968pari_sp av=avma;969GEN u,v,d,d1,v1;970long vx = a[1];971d = a; d1 = b;972v = pol0_F2x(vx); v1 = pol1_F2x(vx);973while (lgpol(d1))974{975GEN r, q = F2x_divrem(d,d1, &r);976v = F2x_add(v,F2x_mul(q,v1));977u=v; v=v1; v1=u;978u=r; d=d1; d1=u;979if (gc_needed(av,2))980{981if (DEBUGMEM>1) pari_warn(warnmem,"F2x_extgcd (d = %ld)",F2x_degree(d));982gerepileall(av,5, &d,&d1,&u,&v,&v1);983}984}985if (ptu) *ptu = F2x_div(F2x_add(d, F2x_mul(b,v)), a);986*ptv = v;987if (gc_needed(av,2)) gerepileall(av,ptu?3:2,&d,ptv,ptu);988return d;989}990991static GEN992F2x_halfgcd_i(GEN a, GEN b)993{994pari_sp av=avma;995GEN u,u1,v,v1;996long vx = a[1];997long n = (F2x_degree(a)+1)>>1;998u1 = v = pol0_F2x(vx);999u = v1 = pol1_F2x(vx);1000while (F2x_degree(b)>=n)1001{1002GEN r, q = F2x_divrem(a,b, &r);1003a = b; b = r; swap(u,u1); swap(v,v1);1004u1 = F2x_add(u1, F2x_mul(u, q));1005v1 = F2x_add(v1, F2x_mul(v, q));1006if (gc_needed(av,2))1007{1008if (DEBUGMEM>1) pari_warn(warnmem,"F2x_halfgcd (d = %ld)",F2x_degree(b));1009gerepileall(av,6, &a,&b,&u1,&v1,&u,&v);1010}1011}1012return gerepilecopy(av, mkmat2(mkcol2(u,u1), mkcol2(v,v1)));1013}10141015GEN1016F2x_halfgcd(GEN x, GEN y)1017{1018pari_sp av;1019GEN M,q,r;1020if (F2x_degree(y)<F2x_degree(x)) return F2x_halfgcd_i(x,y);1021av = avma;1022q = F2x_divrem(y,x,&r);1023M = F2x_halfgcd_i(x,r);1024gcoeff(M,1,1) = F2x_add(gcoeff(M,1,1), F2x_mul(q, gcoeff(M,1,2)));1025gcoeff(M,2,1) = F2x_add(gcoeff(M,2,1), F2x_mul(q, gcoeff(M,2,2)));1026return gerepilecopy(av, M);1027}10281029GEN1030F2xq_mul(GEN x,GEN y,GEN pol)1031{1032GEN z = F2x_mul(x,y);1033return F2x_rem(z,pol);1034}10351036GEN1037F2xq_sqr(GEN x,GEN pol)1038{1039GEN z = F2x_sqr(x);1040return F2x_rem(z,pol);1041}10421043GEN1044F2xq_invsafe(GEN x, GEN T)1045{1046GEN V, z = F2x_extgcd(get_F2x_mod(T), x, NULL, &V);1047if (F2x_degree(z)) return NULL;1048return V;1049}10501051GEN1052F2xq_inv(GEN x,GEN T)1053{1054pari_sp av=avma;1055GEN U = F2xq_invsafe(x, T);1056if (!U) pari_err_INV("F2xq_inv", F2x_to_ZX(x));1057return gerepileuptoleaf(av, U);1058}10591060GEN1061F2xq_div(GEN x,GEN y,GEN T)1062{1063pari_sp av = avma;1064return gerepileuptoleaf(av, F2xq_mul(x,F2xq_inv(y,T),T));1065}10661067static GEN1068_F2xq_red(void *E, GEN x) { return F2x_rem(x, (GEN)E); }1069static GEN1070_F2xq_add(void *E, GEN x, GEN y) { (void)E; return F2x_add(x,y); }10711072static GEN1073_F2xq_cmul(void *E, GEN P, long a, GEN x)1074{1075GEN pol = (GEN) E;1076return F2x_coeff(P,a) ? x: pol0_F2x(pol[1]);1077}1078static GEN1079_F2xq_sqr(void *E, GEN x) { return F2xq_sqr(x, (GEN) E); }1080static GEN1081_F2xq_mul(void *E, GEN x, GEN y) { return F2xq_mul(x,y, (GEN) E); }10821083static GEN1084_F2xq_one(void *E)1085{1086GEN pol = (GEN) E;1087return pol1_F2x(pol[1]);1088}1089static GEN1090_F2xq_zero(void *E)1091{1092GEN pol = (GEN) E;1093return pol0_F2x(pol[1]);1094}10951096GEN1097F2xq_pow(GEN x, GEN n, GEN pol)1098{1099pari_sp av=avma;1100GEN y;11011102if (!signe(n)) return pol1_F2x(x[1]);1103if (is_pm1(n)) /* +/- 1 */1104return (signe(n) < 0)? F2xq_inv(x,pol): F2x_copy(x);11051106if (signe(n) < 0) x = F2xq_inv(x,pol);1107y = gen_pow_i(x, n, (void*)pol, &_F2xq_sqr, &_F2xq_mul);1108return gerepilecopy(av, y);1109}11101111GEN1112F2xq_powu(GEN x, ulong n, GEN pol)1113{1114pari_sp av=avma;1115GEN y;1116switch(n)1117{1118case 0: return pol1_F2x(x[1]);1119case 1: return F2x_copy(x);1120case 2: return F2xq_sqr(x,pol);1121}1122y = gen_powu_i(x, n, (void*)pol, &_F2xq_sqr, &_F2xq_mul);1123return gerepilecopy(av, y);1124}11251126GEN1127F2xq_pow_init(GEN x, GEN n, long k, GEN T)1128{1129return gen_pow_init(x, n, k, (void*)T, &_F2xq_sqr, &_F2xq_mul);1130}11311132GEN1133F2xq_pow_table(GEN R, GEN n, GEN T)1134{1135return gen_pow_table(R, n, (void*)T, &_F2xq_one, &_F2xq_mul);1136}11371138/* generates the list of powers of x of degree 0,1,2,...,l*/1139GEN1140F2xq_powers(GEN x, long l, GEN T)1141{1142int use_sqr = 2*F2x_degree(x) >= get_F2x_degree(T);1143return gen_powers(x, l, use_sqr, (void*)T, &_F2xq_sqr, &_F2xq_mul, &_F2xq_one);1144}11451146GEN1147F2xq_matrix_pow(GEN y, long n, long m, GEN P)1148{1149return F2xV_to_F2m(F2xq_powers(y,m-1,P),n);1150}11511152GEN1153F2x_Frobenius(GEN T)1154{1155return F2xq_sqr(polx_F2x(get_F2x_var(T)), T);1156}11571158GEN1159F2x_matFrobenius(GEN T)1160{1161long n = get_F2x_degree(T);1162return F2xq_matrix_pow(F2x_Frobenius(T), n, n, T);1163}11641165static struct bb_algebra F2xq_algebra = { _F2xq_red, _F2xq_add, _F2xq_add,1166_F2xq_mul, _F2xq_sqr, _F2xq_one, _F2xq_zero};11671168GEN1169F2x_F2xqV_eval(GEN Q, GEN x, GEN T)1170{1171long d = F2x_degree(Q);1172return gen_bkeval_powers(Q,d,x,(void*)T,&F2xq_algebra,_F2xq_cmul);1173}11741175GEN1176F2x_F2xq_eval(GEN Q, GEN x, GEN T)1177{1178long d = F2x_degree(Q);1179int use_sqr = 2*F2x_degree(x) >= get_F2x_degree(T);1180return gen_bkeval(Q, d, x, use_sqr, (void*)T, &F2xq_algebra, _F2xq_cmul);1181}11821183static GEN1184F2xq_autpow_sqr(void * T, GEN x) { return F2x_F2xq_eval(x, x, (GEN) T); }11851186static GEN1187F2xq_autpow_mul(void * T, GEN x, GEN y) { return F2x_F2xq_eval(x, y, (GEN) T); }11881189GEN1190F2xq_autpow(GEN x, long n, GEN T)1191{1192if (n==0) return F2x_rem(polx_F2x(x[1]), T);1193if (n==1) return F2x_rem(x, T);1194return gen_powu(x,n,(void*)T,F2xq_autpow_sqr,F2xq_autpow_mul);1195}11961197ulong1198F2xq_trace(GEN x, GEN T)1199{1200pari_sp av = avma;1201long n = get_F2x_degree(T)-1;1202GEN z = F2xq_mul(x, F2x_deriv(get_F2x_mod(T)), T);1203return gc_ulong(av, F2x_degree(z) < n ? 0 : 1);1204}12051206GEN1207F2xq_conjvec(GEN x, GEN T)1208{1209long i, l = 1+get_F2x_degree(T);1210GEN z = cgetg(l,t_COL);1211gel(z,1) = F2x_copy(x);1212for (i=2; i<l; i++) gel(z,i) = F2xq_sqr(gel(z,i-1), T);1213return z;1214}12151216static GEN1217_F2xq_pow(void *data, GEN x, GEN n)1218{1219GEN pol = (GEN) data;1220return F2xq_pow(x,n, pol);1221}12221223static GEN1224_F2xq_rand(void *data)1225{1226pari_sp av=avma;1227GEN pol = (GEN) data;1228long d = F2x_degree(pol);1229GEN z;1230do1231{1232set_avma(av);1233z = random_F2x(d,pol[1]);1234} while (lgpol(z)==0);1235return z;1236}12371238static GEN F2xq_easylog(void* E, GEN a, GEN g, GEN ord);12391240static const struct bb_group F2xq_star={_F2xq_mul,_F2xq_pow,_F2xq_rand,hash_GEN,F2x_equal,F2x_equal1,F2xq_easylog};12411242GEN1243F2xq_order(GEN a, GEN ord, GEN T)1244{1245return gen_order(a,ord,(void*)T,&F2xq_star);1246}12471248static long1249F2x_is_smooth_squarefree(GEN f, long r)1250{1251pari_sp av = avma;1252long i, df = F2x_degree(f);1253GEN sx, a;1254if (!df) return 1;1255a = sx = polx_F2x(f[1]);1256for(i = 1;; i++)1257{1258long dg;1259GEN g;1260a = F2xq_sqr(a, f);1261if (F2x_equal(a, sx)) return gc_long(av,1);1262if (i==r) return gc_long(av,0);1263g = F2x_gcd(f, F2x_add(a,sx));1264dg = F2x_degree(g);1265if (dg == df) return gc_long(av,1);1266if (dg) { f = F2x_div(f, g); df -= dg; a = F2x_rem(a, f); }1267}1268}12691270static long1271F2x_is_smooth(GEN g, long r)1272{1273if (lgpol(g)==0) return 0;1274while (1)1275{1276GEN f = F2x_gcd(g, F2x_deriv(g));1277if (!F2x_is_smooth_squarefree(F2x_div(g, f), r)) return 0;1278if (F2x_degree(f)==0) return 1;1279g = F2x_issquare(f) ? F2x_sqrt(f): f;1280}1281}12821283static GEN1284F2x_factorel(GEN h)1285{1286GEN F = F2x_factor(h);1287GEN F1 = gel(F, 1), F2 = gel(F, 2);1288long i, l1 = lg(F1)-1;1289GEN p2 = cgetg(l1+1, t_VECSMALL);1290GEN e2 = cgetg(l1+1, t_VECSMALL);1291for (i = 1; i <= l1; ++i)1292{1293p2[i] = mael(F1, i, 2);1294e2[i] = F2[i];1295}1296return mkmat2(p2, e2);1297}12981299static GEN1300mkF2(ulong x, long v) { return mkvecsmall2(v, x); }13011302static GEN F2xq_log_Coppersmith_d(GEN W, GEN g, long r, long n, GEN T, GEN mo);13031304static GEN1305F2xq_log_from_rel(GEN W, GEN rel, long r, long n, GEN T, GEN m)1306{1307pari_sp av = avma;1308long vT = get_F2x_var(T);1309GEN F = gel(rel,1), E = gel(rel,2), o = gen_0;1310long i, l = lg(F);1311for(i=1; i<l; i++)1312{1313GEN R = gel(W, F[i]);1314if (signe(R)==0) /* Already failed */1315return NULL;1316else if (signe(R)<0) /* Not yet tested */1317{1318setsigne(gel(W,F[i]),0);1319R = F2xq_log_Coppersmith_d(W, mkF2(F[i],vT), r, n, T, m);1320if (!R) return NULL;1321}1322o = Fp_add(o, mulis(R, E[i]), m);1323}1324return gerepileuptoint(av, o);1325}13261327static GEN1328F2xq_log_Coppersmith_d(GEN W, GEN g, long r, long n, GEN T, GEN mo)1329{1330pari_sp av = avma, av2;1331long dT = get_F2x_degree(T), vT = get_F2x_var(T);1332long dg = F2x_degree(g), k = r-1, m = maxss((dg-k)/2,0);1333long i, j, l = dg-m, N;1334GEN v = cgetg(k+m+1,t_MAT);1335long h = dT>>n, d = dT-(h<<n);1336GEN p1 = pol1_F2x(vT);1337GEN R = F2x_add(F2x_shift(p1, dT), T);1338GEN z = F2x_rem(F2x_shift(p1, h), g);1339for(i=1; i<=k+m; i++)1340{1341gel(v,i) = F2x_to_F2v(F2x_shift(z,-l),m);1342z = F2x_rem(F2x_shift(z,1),g);1343}1344v = F2m_ker(v);1345for(i=1; i<=k; i++)1346gel(v,i) = F2v_to_F2x(gel(v,i),vT);1347N = 1<<k;1348av2 = avma;1349for (i=1; i<N; i++)1350{1351GEN p,q,qh,a,b;1352set_avma(av2);1353q = pol0_F2x(vT);1354for(j=0; j<k; j++)1355if (i&(1UL<<j))1356q = F2x_add(q, gel(v,j+1));1357qh= F2x_shift(q,h);1358p = F2x_rem(qh,g);1359b = F2x_add(F2x_mul(R, F2x_pow2n(q, n)), F2x_shift(F2x_pow2n(p, n), d));1360if (lgpol(b)==0 || !F2x_is_smooth(b, r)) continue;1361a = F2x_div(F2x_add(qh,p),g);1362if (F2x_degree(F2x_gcd(a,q)) && F2x_degree(F2x_gcd(a,p))) continue;1363if (!(lgpol(a)==0 || !F2x_is_smooth(a, r)))1364{1365GEN F = F2x_factorel(b);1366GEN G = F2x_factorel(a);1367GEN FG = vecsmall_concat(vecsmall_append(gel(F, 1), 2), gel(G, 1));1368GEN E = vecsmall_concat(vecsmall_append(gel(F, 2), -d),1369zv_z_mul(gel(G, 2),-(1L<<n)));1370GEN R = famatsmall_reduce(mkmat2(FG, E));1371GEN l = F2xq_log_from_rel(W, R, r, n, T, mo);1372if (!l) continue;1373l = Fp_div(l,int2n(n),mo);1374if (dg <= r)1375{1376affii(l,gel(W,g[2]));1377if (DEBUGLEVEL>1) err_printf("Found %lu\n", g[2]);1378}1379return gerepileuptoint(av, l);1380}1381}1382return gc_NULL(av);1383}13841385static GEN1386F2xq_log_find_rel(GEN b, long r, GEN T, GEN *g, ulong *e)1387{1388pari_sp av = avma;1389while (1)1390{1391GEN M;1392*g = F2xq_mul(*g, b, T); (*e)++;1393M = F2x_halfgcd(*g,T);1394if (F2x_is_smooth(gcoeff(M,1,1), r))1395{1396GEN z = F2x_add(F2x_mul(gcoeff(M,1,1),*g), F2x_mul(gcoeff(M,1,2),T));1397if (F2x_is_smooth(z, r))1398{1399GEN F = F2x_factorel(z);1400GEN G = F2x_factorel(gcoeff(M,1,1));1401GEN rel = mkmat2(vecsmall_concat(gel(F, 1),gel(G, 1)),1402vecsmall_concat(gel(F, 2),zv_neg(gel(G, 2))));1403gerepileall(av, 2, g, &rel);1404return rel;1405}1406}1407if (gc_needed(av,2))1408{1409if (DEBUGMEM>1) pari_warn(warnmem,"F2xq_log_find_rel");1410*g = gerepileuptoleaf(av, *g);1411}1412}1413}14141415static GEN1416F2xq_log_Coppersmith_rec(GEN W, long r2, GEN a, long r, long n, GEN T, GEN m)1417{1418long vT = get_F2x_var(T);1419GEN b = polx_F2x(vT);1420ulong AV = 0;1421GEN g = a, bad = pol0_F2x(vT);1422pari_timer ti;1423while(1)1424{1425long i, l;1426GEN V, F, E, Ao;1427timer_start(&ti);1428V = F2xq_log_find_rel(b, r2, T, &g, &AV);1429if (DEBUGLEVEL>1) timer_printf(&ti,"%ld-smooth element",r2);1430F = gel(V,1); E = gel(V,2);1431l = lg(F);1432Ao = gen_0;1433for(i=1; i<l; i++)1434{1435GEN Fi = mkF2(F[i], vT);1436GEN R;1437if (F2x_degree(Fi) <= r)1438{1439if (signe(gel(W,F[i]))==0)1440break;1441else if (signe(gel(W,F[i]))<0)1442{1443setsigne(gel(W,F[i]),0);1444R = F2xq_log_Coppersmith_d(W,Fi,r,n,T,m);1445} else1446R = gel(W,F[i]);1447}1448else1449{1450if (F2x_equal(Fi,bad)) break;1451R = F2xq_log_Coppersmith_d(W,Fi,r,n,T,m);1452if (!R) bad = Fi;1453}1454if (!R) break;1455Ao = Fp_add(Ao, mulis(R, E[i]), m);1456}1457if (i==l) return subiu(Ao,AV);1458}1459}14601461/* Coppersmith:1462T*X^e = X^(h*2^n)-R1463(u*x^h + v)^(2^n) = u^(2^n)*X^(h*2^n)+v^(2^n)1464(u*x^h + v)^(2^n) = u^(2^n)*R+v^(2^n)1465*/14661467static GEN1468rel_Coppersmith(GEN u, GEN v, long h, GEN R, long r, long n, long d)1469{1470GEN b, F, G, M;1471GEN a = F2x_add(F2x_shift(u, h), v);1472if (!F2x_is_smooth(a, r)) return NULL;1473b = F2x_add(F2x_mul(R, F2x_pow2n(u, n)), F2x_shift(F2x_pow2n(v, n),d));1474if (!F2x_is_smooth(b, r)) return NULL;1475F = F2x_factorel(a);1476G = F2x_factorel(b);1477M = mkmat2(vecsmall_concat(gel(F, 1), vecsmall_append(gel(G, 1), 2)),1478vecsmall_concat(zv_z_mul(gel(F, 2),1UL<<n), vecsmall_append(zv_neg(gel(G, 2)),d)));1479return famatsmall_reduce(M);1480}14811482GEN1483F2xq_log_Coppersmith_worker(GEN u, long i, GEN V, GEN R)1484{1485long r = V[1], h = V[2], n = V[3], d = V[4];1486pari_sp ltop = avma;1487GEN v = mkF2(0,u[1]);1488GEN L = cgetg(2*i+1, t_VEC);1489pari_sp av = avma;1490long j;1491long nbtest=0, rel = 1;1492for(j=1; j<=i; j++)1493{1494v[2] = j;1495set_avma(av);1496if (F2x_degree(F2x_gcd(u,v))==0)1497{1498GEN z = rel_Coppersmith(u, v, h, R, r, n, d);1499nbtest++;1500if (z) { gel(L, rel++) = z; av = avma; }1501if (i==j) continue;1502z = rel_Coppersmith(v, u, h, R, r, n, d);1503nbtest++;1504if (z) { gel(L, rel++) = z; av = avma; }1505}1506}1507setlg(L,rel);1508return gerepilecopy(ltop, mkvec2(stoi(nbtest), L));1509}15101511static GEN1512F2xq_log_Coppersmith(long nbrel, long r, long n, GEN T)1513{1514long dT = get_F2x_degree(T), vT = get_F2x_var(T);1515long h = dT>>n, d = dT-(h<<n);1516GEN R = F2x_add(F2x_shift(pol1_F2x(vT), dT), T);1517GEN u = mkF2(0,vT);1518long rel = 1, nbtest = 0;1519GEN M = cgetg(nbrel+1, t_VEC);1520long i = 0;1521GEN worker = snm_closure(is_entry("_F2xq_log_Coppersmith_worker"),1522mkvec2(mkvecsmall4(r, h, n, d), R));1523struct pari_mt pt;1524long running, pending = 0, stop=0;1525mt_queue_start(&pt, worker);1526if (DEBUGLEVEL) err_printf("Coppersmith (R = %ld): ",F2x_degree(R));1527while ((running = !stop) || pending)1528{1529GEN L, done;1530long j, l;1531u[2] = i;1532mt_queue_submit(&pt, 0, running ? mkvec2(u, stoi(i)): NULL);1533done = mt_queue_get(&pt, NULL, &pending);1534if (!done) continue;1535L = gel(done, 2); nbtest += itos(gel(done,1));1536l = lg(L);1537if (l > 1)1538{1539for (j=1; j<l; j++)1540{1541if (rel>nbrel) break;1542gel(M,rel++) = gel(L,j);1543if (DEBUGLEVEL && (rel&511UL)==0)1544err_printf("%ld%%[%ld] ",rel*100/nbrel,i);1545}1546}1547if (rel>nbrel) stop=1;1548i++;1549}1550mt_queue_end(&pt);1551if (DEBUGLEVEL) err_printf(": %ld tests\n", nbtest);1552return M;1553}15541555static GEN1556smallirred_F2x(ulong n, long sv)1557{1558GEN a = zero_zv(nbits2lg(n+1)-1);1559a[1] = sv; F2x_set(a,n); a[2]++;1560while (!F2x_is_irred(a)) a[2]+=2;1561return a;1562}15631564static GEN1565check_kernel(long N, GEN M, long nbi, GEN T, GEN m)1566{1567pari_sp av = avma;1568long dT = get_F2x_degree(T), vT = get_F2x_var(T);1569GEN K = FpMs_leftkernel_elt(M, N, m);1570long i, f=0, tbs;1571long l = lg(K), lm = lgefint(m);1572GEN idx = diviiexact(int2um1(dT), m);1573GEN g = F2xq_pow(polx_F2x(vT), idx, T);1574GEN tab;1575pari_timer ti;1576if (DEBUGLEVEL) timer_start(&ti);1577K = FpC_Fp_mul(K, Fp_inv(gel(K,2), m), m);1578tbs = maxss(1, expu(nbi/expi(m)));1579tab = F2xq_pow_init(g, int2n(dT), tbs, T);1580for(i=1; i<l; i++)1581{1582GEN k = gel(K,i);1583if (signe(k)==0 || !F2x_equal(F2xq_pow_table(tab, k, T),1584F2xq_pow(mkF2(i,vT), idx, T)))1585gel(K,i) = cgetineg(lm);1586else1587f++;1588}1589if (DEBUGLEVEL) timer_printf(&ti,"found %ld/%ld logs", f, nbi);1590return gerepileupto(av, K);1591}15921593static GEN1594F2xq_log_index(GEN a0, GEN b0, GEN m, GEN T0)1595{1596pari_sp av = avma;1597GEN M, S, a, b, Ao=NULL, Bo=NULL, W, e;1598pari_timer ti;1599long n = F2x_degree(T0), r = (long) (sqrt((double) 2*n))-(n>100);1600GEN T = smallirred_F2x(n,T0[1]);1601long d = 2, r2 = 3*r/2, d2 = 2;1602long N = (1UL<<(r+1))-1UL;1603long nbi = itos(ffsumnbirred(gen_2, r)), nbrel=nbi*5/4;1604if (DEBUGLEVEL)1605{1606err_printf("F2xq_log: Parameters r=%ld r2=%ld\n", r,r2);1607err_printf("F2xq_log: Size FB=%ld rel. needed=%ld\n", nbi, nbrel);1608timer_start(&ti);1609}1610S = Flx_to_F2x(Flx_ffisom(F2x_to_Flx(T0),F2x_to_Flx(T),2));1611a = F2x_F2xq_eval(a0, S, T);1612b = F2x_F2xq_eval(b0, S, T);1613if (DEBUGLEVEL) timer_printf(&ti,"model change");1614M = F2xq_log_Coppersmith(nbrel,r,d,T);1615if(DEBUGLEVEL)1616timer_printf(&ti,"relations");1617W = check_kernel(N, M, nbi, T, m);1618timer_start(&ti);1619Ao = F2xq_log_Coppersmith_rec(W, r2, a, r, d2, T, m);1620if (DEBUGLEVEL) timer_printf(&ti,"smooth element");1621Bo = F2xq_log_Coppersmith_rec(W, r2, b, r, d2, T, m);1622if (DEBUGLEVEL) timer_printf(&ti,"smooth generator");1623e = Fp_div(Ao, Bo, m);1624if (!F2x_equal(F2xq_pow(b0,e,T0),a0)) pari_err_BUG("F2xq_log");1625return gerepileupto(av, e);1626}16271628static GEN1629F2xq_easylog(void* E, GEN a, GEN g, GEN ord)1630{1631if (F2x_equal1(a)) return gen_0;1632if (F2x_equal(a,g)) return gen_1;1633if (typ(ord)!=t_INT) return NULL;1634if (expi(ord)<28) return NULL;1635return F2xq_log_index(a,g,ord,(GEN)E);1636}16371638GEN1639F2xq_log(GEN a, GEN g, GEN ord, GEN T)1640{1641GEN z, v = get_arith_ZZM(ord);1642ord = mkvec2(gel(v,1),ZM_famat_limit(gel(v,2),int2n(28)));1643z = gen_PH_log(a,g,ord,(void*)T,&F2xq_star);1644return z? z: cgetg(1,t_VEC);1645}16461647GEN1648F2xq_Artin_Schreier(GEN a, GEN T)1649{1650pari_sp ltop=avma;1651long j,N = get_F2x_degree(T), vT = get_F2x_var(T);1652GEN Q = F2x_matFrobenius(T);1653for (j=1; j<=N; j++)1654F2m_flip(Q,j,j);1655F2v_add_inplace(gel(Q,1),a);1656Q = F2m_ker_sp(Q,0);1657if (lg(Q)!=2) return NULL;1658Q = gel(Q,1);1659Q[1] = vT;1660return gerepileuptoleaf(ltop, F2x_renormalize(Q, lg(Q)));1661}16621663GEN1664F2xq_sqrt_fast(GEN c, GEN sqx, GEN T)1665{1666GEN c0, c1;1667F2x_even_odd(c, &c0, &c1);1668return F2x_add(c0, F2xq_mul(c1, sqx, T));1669}16701671static int1672F2x_is_x(GEN a) { return lg(a)==3 && a[2]==2; }16731674GEN1675F2xq_sqrt(GEN a, GEN T)1676{1677pari_sp av = avma;1678long n = get_F2x_degree(T), vT = get_F2x_var(T);1679GEN sqx;1680if (n==1) return F2x_copy(a);1681if (n==2) return F2xq_sqr(a,T);1682sqx = F2xq_autpow(mkF2(4, vT), n-1, T);1683return gerepileuptoleaf(av, F2x_is_x(a)? sqx: F2xq_sqrt_fast(a,sqx,T));1684}16851686GEN1687F2xq_sqrtn(GEN a, GEN n, GEN T, GEN *zeta)1688{1689long dT = get_F2x_degree(T), vT = get_F2x_var(T);1690if (!lgpol(a))1691{1692if (signe(n) < 0) pari_err_INV("F2xq_sqrtn",a);1693if (zeta)1694*zeta=pol1_F2x(vT);1695return pol0_F2x(vT);1696}1697return gen_Shanks_sqrtn(a, n, int2um1(dT), zeta, (void*)T, &F2xq_star);1698}16991700GEN1701gener_F2xq(GEN T, GEN *po)1702{1703long i, j, vT = get_F2x_var(T), f = get_F2x_degree(T);1704pari_sp av0 = avma, av;1705GEN g, L2, o, q;17061707if (f == 1) {1708if (po) *po = mkvec2(gen_1, trivial_fact());1709return pol1_F2x(vT);1710}1711q = int2um1(f);1712o = factor_pn_1(gen_2,f);1713L2 = leafcopy( gel(o, 1) );1714for (i = j = 1; i < lg(L2); i++)1715{1716if (absequaliu(gel(L2,i),2)) continue;1717gel(L2,j++) = diviiexact(q, gel(L2,i));1718}1719setlg(L2, j);1720for (av = avma;; set_avma(av))1721{1722g = random_F2x(f, vT);1723if (F2x_degree(g) < 1) continue;1724for (i = 1; i < j; i++)1725{1726GEN a = F2xq_pow(g, gel(L2,i), T);1727if (F2x_equal1(a)) break;1728}1729if (i == j) break;1730}1731if (!po) g = gerepilecopy(av0, g);1732else {1733*po = mkvec2(int2um1(f), o);1734gerepileall(av0, 2, &g, po);1735}1736return g;1737}17381739static GEN1740_F2xq_neg(void *E, GEN x) { (void) E; return F2x_copy(x); }1741static GEN1742_F2xq_rmul(void *E, GEN x, GEN y) { (void) E; return F2x_mul(x,y); }1743static GEN1744_F2xq_inv(void *E, GEN x) { return F2xq_inv(x, (GEN) E); }1745static int1746_F2xq_equal0(GEN x) { return lgpol(x)==0; }1747static GEN1748_F2xq_s(void *E, long x)1749{ GEN T = (GEN) E;1750long v = get_F2x_var(T);1751return odd(x)? pol1_F2x(v): pol0_F2x(v);1752}17531754static const struct bb_field F2xq_field={_F2xq_red,_F2xq_add,_F2xq_rmul,_F2xq_neg,1755_F2xq_inv,_F2xq_equal0,_F2xq_s};17561757const struct bb_field *get_F2xq_field(void **E, GEN T)1758{1759*E = (void *) T;1760return &F2xq_field;1761}17621763/***********************************************************************/1764/** **/1765/** F2xV **/1766/** **/1767/***********************************************************************/1768/* F2xV are t_VEC with F2x coefficients. */17691770GEN1771FlxC_to_F2xC(GEN x) { pari_APPLY_type(t_COL, Flx_to_F2x(gel(x,i))) }1772GEN1773F2xC_to_FlxC(GEN x) { pari_APPLY_type(t_COL, F2x_to_Flx(gel(x,i))) }1774GEN1775F2xC_to_ZXC(GEN x) { pari_APPLY_type(t_COL, F2x_to_ZX(gel(x,i))) }1776GEN1777F2xV_to_F2m(GEN x, long n) { pari_APPLY_type(t_MAT, F2x_to_F2v(gel(x,i), n)) }17781779void1780F2xV_to_FlxV_inplace(GEN v)1781{1782long i, l = lg(v);1783for(i = 1; i < l;i++) gel(v,i) = F2x_to_Flx(gel(v,i));1784}1785void1786F2xV_to_ZXV_inplace(GEN v)1787{1788long i, l = lg(v);1789for(i = 1; i < l; i++) gel(v,i)= F2x_to_ZX(gel(v,i));1790}17911792/***********************************************************************/1793/** **/1794/** F2xX **/1795/** **/1796/***********************************************************************/17971798GEN1799F2xX_renormalize(GEN /*in place*/ x, long lx)1800{ return FlxX_renormalize(x, lx); }18011802GEN1803pol1_F2xX(long v, long sv) { return pol1_FlxX(v, sv); }18041805GEN1806polx_F2xX(long v, long sv) { return polx_FlxX(v, sv); }18071808long1809F2xY_degreex(GEN b)1810{1811long deg = 0, i;1812if (!signe(b)) return -1;1813for (i = 2; i < lg(b); ++i)1814deg = maxss(deg, F2x_degree(gel(b, i)));1815return deg;1816}18171818GEN1819FlxX_to_F2xX(GEN B)1820{1821long lb=lg(B);1822long i;1823GEN b=cgetg(lb,t_POL);1824b[1]=evalsigne(1)|(((ulong)B[1])&VARNBITS);1825for (i=2; i<lb; i++)1826gel(b,i) = Flx_to_F2x(gel(B,i));1827return F2xX_renormalize(b, lb);1828}18291830GEN1831ZXX_to_F2xX(GEN B, long v)1832{1833long lb=lg(B);1834long i;1835GEN b=cgetg(lb,t_POL);1836b[1]=evalsigne(1)|(((ulong)B[1])&VARNBITS);1837for (i=2; i<lb; i++)1838switch (typ(gel(B,i)))1839{1840case t_INT:1841gel(b,i) = Z_to_F2x(gel(B,i), evalvarn(v));1842break;1843case t_POL:1844gel(b,i) = ZX_to_F2x(gel(B,i));1845break;1846}1847return F2xX_renormalize(b, lb);1848}18491850GEN1851F2xX_to_FlxX(GEN B)1852{1853long i, lb = lg(B);1854GEN b = cgetg(lb,t_POL);1855for (i=2; i<lb; i++)1856gel(b,i) = F2x_to_Flx(gel(B,i));1857b[1] = B[1]; return b;1858}18591860GEN1861F2xX_to_ZXX(GEN B)1862{1863long i, lb = lg(B);1864GEN b = cgetg(lb,t_POL);1865for (i=2; i<lb; i++)1866{1867GEN c = gel(B,i);1868gel(b,i) = lgpol(c) ? F2x_equal1(c) ? gen_1 : F2x_to_ZX(c) : gen_0;1869}1870b[1] = B[1]; return b;1871}18721873GEN1874F2xX_deriv(GEN z)1875{1876long i,l = lg(z)-1;1877GEN x;1878if (l < 2) l = 2;1879x = cgetg(l, t_POL); x[1] = z[1];1880for (i=2; i<l; i++) gel(x,i) = odd(i) ? pol0_F2x(mael(z,i+1,1)): gel(z,i+1);1881return F2xX_renormalize(x,l);1882}18831884static GEN1885F2xX_addspec(GEN x, GEN y, long lx, long ly)1886{1887long i,lz;1888GEN z;1889if (ly>lx) swapspec(x,y, lx,ly);1890lz = lx+2; z = cgetg(lz, t_POL);1891for (i=0; i<ly; i++) gel(z,i+2) = F2x_add(gel(x,i), gel(y,i));1892for ( ; i<lx; i++) gel(z,i+2) = F2x_copy(gel(x,i));1893z[1] = 0; return F2xX_renormalize(z, lz);1894}18951896GEN1897F2xX_add(GEN x, GEN y)1898{1899long i,lz;1900GEN z;1901long lx=lg(x);1902long ly=lg(y);1903if (ly>lx) swapspec(x,y, lx,ly);1904lz = lx; z = cgetg(lz, t_POL); z[1]=x[1];1905for (i=2; i<ly; i++) gel(z,i) = F2x_add(gel(x,i), gel(y,i));1906for ( ; i<lx; i++) gel(z,i) = F2x_copy(gel(x,i));1907return F2xX_renormalize(z, lz);1908}19091910GEN1911F2xX_F2x_add(GEN x, GEN y)1912{1913long i, lz = lg(y);1914GEN z;1915if (signe(y) == 0) return scalarpol(x, varn(y));1916z = cgetg(lz,t_POL); z[1] = y[1];1917gel(z,2) = F2x_add(gel(y,2), x);1918if (lz == 3) z = F2xX_renormalize(z,lz);1919else1920for(i=3;i<lz;i++) gel(z,i) = F2x_copy(gel(y,i));1921return z;1922}19231924GEN1925F2xX_F2x_mul(GEN P, GEN U)1926{1927long i, lP = lg(P);1928GEN res = cgetg(lP,t_POL);1929res[1] = P[1];1930for(i=2; i<lP; i++)1931gel(res,i) = F2x_mul(U,gel(P,i));1932return F2xX_renormalize(res, lP);1933}19341935GEN1936F2xY_F2xqV_evalx(GEN P, GEN x, GEN T)1937{1938long i, lP = lg(P);1939GEN res = cgetg(lP,t_POL);1940res[1] = P[1];1941for(i=2; i<lP; i++)1942gel(res,i) = F2x_F2xqV_eval(gel(P,i), x, T);1943return F2xX_renormalize(res, lP);1944}19451946GEN1947F2xY_F2xq_evalx(GEN P, GEN x, GEN T)1948{1949pari_sp av = avma;1950long n = brent_kung_optpow(get_F2x_degree(T)-1,lgpol(P),1);1951GEN xp = F2xq_powers(x, n, T);1952return gerepileupto(av, F2xY_F2xqV_evalx(P, xp, T));1953}19541955static GEN1956F2xX_to_Kronecker_spec(GEN P, long n, long d)1957{1958long i, k, l, N = 2*d + 1;1959long dP = n+1;1960GEN x;1961if (n == 0) return pol0_Flx(P[1]&VARNBITS);1962l = nbits2nlong(N*dP+d+1);1963x = zero_zv(l+1);1964for (k=i=0; i<n; i++, k+=N)1965{1966GEN c = gel(P,i);1967F2x_addshiftip(x, c, k);1968}1969x[1] = P[1]&VARNBITS; return F2x_renormalize(x, l+2);1970}19711972GEN1973F2xX_to_Kronecker(GEN P, long d)1974{1975long i, k, l, N = 2*d + 1;1976long dP = degpol(P);1977GEN x;1978if (dP < 0) return pol0_Flx(P[1]&VARNBITS);1979l = nbits2nlong(N*dP+d+1);1980x = zero_zv(l+1);1981for (k=i=0; i<=dP; i++, k+=N)1982{1983GEN c = gel(P,i+2);1984F2x_addshiftip(x, c, k);1985}1986x[1] = P[1]&VARNBITS; return F2x_renormalize(x, l+2);1987}19881989static GEN1990F2x_slice(GEN x, long n, long d)1991{1992ulong ib, il=dvmduBIL(n, &ib);1993ulong db, dl=dvmduBIL(d, &db);1994long lN = dl+2+(db?1:0);1995GEN t = cgetg(lN,t_VECSMALL);1996t[1] = x[1];1997if (ib)1998{1999ulong i, ic = BITS_IN_LONG-ib;2000ulong r = uel(x,2+il)>>ib;2001for(i=0; i<dl; i++)2002{2003uel(t,2+i) = (uel(x,3+il+i)<<ic)|r;2004r = uel(x,3+il+i)>>ib;2005}2006if (db)2007uel(t,2+i) = (uel(x,3+il+i)<<ic)|r;2008}2009else2010{2011long i;2012for(i=2; i<lN; i++)2013uel(t,i) = uel(x,il+i);2014}2015if (db) uel(t,lN-1) &= (1UL<<db)-1;2016return F2x_renormalize(t, lN);2017}20182019GEN2020Kronecker_to_F2xqX(GEN z, GEN T)2021{2022long lz = F2x_degree(z)+1;2023long i, j, N = get_F2x_degree(T)*2 + 1;2024long lx = lz / (N-2);2025GEN x = cgetg(lx+3,t_POL);2026x[1] = z[1];2027for (i=0, j=2; i<lz; i+=N, j++)2028{2029GEN t = F2x_slice(z,i,minss(lz-i,N));2030t[1] = T[1];2031gel(x,j) = F2x_rem(t, T);2032}2033return F2xX_renormalize(x, j);2034}20352036GEN2037F2xX_to_F2xC(GEN x, long N, long sv)2038{2039long i, l;2040GEN z;2041l = lg(x)-1; x++;2042if (l > N+1) l = N+1; /* truncate higher degree terms */2043z = cgetg(N+1,t_COL);2044for (i=1; i<l ; i++) gel(z,i) = gel(x,i);2045for ( ; i<=N; i++) gel(z,i) = pol0_F2x(sv);2046return z;2047}20482049GEN2050F2xXV_to_F2xM(GEN v, long n, long sv)2051{2052long j, N = lg(v);2053GEN y = cgetg(N, t_MAT);2054for (j=1; j<N; j++) gel(y,j) = F2xX_to_F2xC(gel(v,j), n, sv);2055return y;2056}20572058/***********************************************************************/2059/** **/2060/** F2xXV/F2xXC **/2061/** **/2062/***********************************************************************/20632064GEN2065FlxXC_to_F2xXC(GEN x) { pari_APPLY_type(t_COL, FlxX_to_F2xX(gel(x,i))); }2066GEN2067F2xXC_to_ZXXC(GEN x) { pari_APPLY_type(t_COL, F2xX_to_ZXX(gel(x,i))); }20682069/***********************************************************************/2070/** **/2071/** F2xqX **/2072/** **/2073/***********************************************************************/20742075static GEN2076get_F2xqX_red(GEN T, GEN *B)2077{2078if (typ(T)!=t_VEC) { *B=NULL; return T; }2079*B = gel(T,1); return gel(T,2);2080}20812082GEN2083random_F2xqX(long d1, long v, GEN T)2084{2085long dT = get_F2x_degree(T), vT = get_F2x_var(T);2086long i, d = d1+2;2087GEN y = cgetg(d,t_POL); y[1] = evalsigne(1) | evalvarn(v);2088for (i=2; i<d; i++) gel(y,i) = random_F2x(dT, vT);2089return FlxX_renormalize(y,d);2090}20912092GEN2093F2xqX_red(GEN z, GEN T)2094{2095GEN res;2096long i, l = lg(z);2097res = cgetg(l,t_POL); res[1] = z[1];2098for(i=2;i<l;i++) gel(res,i) = F2x_rem(gel(z,i),T);2099return F2xX_renormalize(res,l);2100}21012102GEN2103F2xqX_F2xq_mul(GEN P, GEN U, GEN T)2104{2105long i, lP = lg(P);2106GEN res = cgetg(lP,t_POL);2107res[1] = P[1];2108for(i=2; i<lP; i++)2109gel(res,i) = F2xq_mul(U,gel(P,i), T);2110return F2xX_renormalize(res, lP);2111}21122113GEN2114F2xqX_F2xq_mul_to_monic(GEN P, GEN U, GEN T)2115{2116long i, lP = lg(P);2117GEN res = cgetg(lP,t_POL);2118res[1] = P[1];2119for(i=2; i<lP-1; i++) gel(res,i) = F2xq_mul(U,gel(P,i), T);2120gel(res,lP-1) = pol1_F2x(T[1]);2121return F2xX_renormalize(res, lP);2122}21232124GEN2125F2xqX_normalize(GEN z, GEN T)2126{2127GEN p1 = leading_coeff(z);2128if (!lgpol(z) || (!degpol(p1) && p1[1] == 1)) return z;2129return F2xqX_F2xq_mul_to_monic(z, F2xq_inv(p1,T), T);2130}21312132GEN2133F2xqX_mul(GEN x, GEN y, GEN T)2134{2135pari_sp ltop=avma;2136GEN z, kx, ky;2137long d = get_F2x_degree(T);2138kx= F2xX_to_Kronecker(x, d);2139ky= F2xX_to_Kronecker(y, d);2140z = F2x_mul(ky, kx);2141z = Kronecker_to_F2xqX(z, T);2142return gerepileupto(ltop, z);2143}21442145static GEN2146F2xqX_mulspec(GEN x, GEN y, GEN T, long nx, long ny)2147{2148pari_sp ltop=avma;2149GEN z, kx, ky;2150long dT = get_F2x_degree(T);2151kx= F2xX_to_Kronecker_spec(x, nx, dT);2152ky= F2xX_to_Kronecker_spec(y, ny, dT);2153z = F2x_mul(ky, kx);2154z = Kronecker_to_F2xqX(z,T);2155return gerepileupto(ltop,z);2156}21572158GEN2159F2xqX_sqr(GEN x, GEN T)2160{2161long d = degpol(x), l = 2*d+3;2162GEN z;2163if (!signe(x)) return pol_0(varn(x));2164z = cgetg(l,t_POL);2165z[1] = x[1];2166if (d > 0)2167{2168GEN u = pol0_F2x(T[1]);2169long i,j;2170for (i=2,j=2; i<d+2; i++,j+=2)2171{2172gel(z, j) = F2xq_sqr(gel(x, i), T);2173gel(z, j+1) = u;2174}2175}2176gel(z, 2+2*d) = F2xq_sqr(gel(x, 2+d), T);2177return FlxX_renormalize(z, l);2178}21792180static GEN2181F2xqX_divrem_basecase(GEN x, GEN y, GEN T, GEN *pr)2182{2183long vx, dx, dy, dz, i, j, sx, lr;2184pari_sp av0, av, tetpil;2185GEN z,p1,rem,lead;21862187if (!signe(y)) pari_err_INV("F2xqX_divrem",y);2188vx=varn(x); dy=degpol(y); dx=degpol(x);2189if (dx < dy)2190{2191if (pr)2192{2193av0 = avma; x = F2xqX_red(x, T);2194if (pr == ONLY_DIVIDES) { set_avma(av0); return signe(x)? NULL: pol_0(vx); }2195if (pr == ONLY_REM) return x;2196*pr = x;2197}2198return pol_0(vx);2199}2200lead = leading_coeff(y);2201if (!dy) /* y is constant */2202{2203if (pr && pr != ONLY_DIVIDES)2204{2205if (pr == ONLY_REM) return pol_0(vx);2206*pr = pol_0(vx);2207}2208if (F2x_equal1(lead)) return gcopy(x);2209av0 = avma; x = F2xqX_F2xq_mul(x,F2xq_inv(lead,T),T);2210return gerepileupto(av0,x);2211}2212av0 = avma; dz = dx-dy;2213lead = F2x_equal1(lead)? NULL: gclone(F2xq_inv(lead,T));2214set_avma(av0);2215z = cgetg(dz+3,t_POL); z[1] = x[1];2216x += 2; y += 2; z += 2;22172218p1 = gel(x,dx); av = avma;2219gel(z,dz) = lead? gerepileupto(av, F2xq_mul(p1,lead, T)): leafcopy(p1);2220for (i=dx-1; i>=dy; i--)2221{2222av=avma; p1=gel(x,i);2223for (j=i-dy+1; j<=i && j<=dz; j++)2224p1 = F2x_add(p1, F2x_mul(gel(z,j),gel(y,i-j)));2225if (lead) p1 = F2x_mul(p1, lead);2226tetpil=avma; gel(z,i-dy) = gerepile(av,tetpil,F2x_rem(p1,T));2227}2228if (!pr) { guncloneNULL(lead); return z-2; }22292230rem = (GEN)avma; av = (pari_sp)new_chunk(dx+3);2231for (sx=0; ; i--)2232{2233p1 = gel(x,i);2234for (j=0; j<=i && j<=dz; j++)2235p1 = F2x_add(p1, F2x_mul(gel(z,j),gel(y,i-j)));2236tetpil=avma; p1 = F2x_rem(p1, T); if (lgpol(p1)) { sx = 1; break; }2237if (!i) break;2238set_avma(av);2239}2240if (pr == ONLY_DIVIDES)2241{2242guncloneNULL(lead);2243if (sx) return gc_NULL(av0);2244return gc_const((pari_sp)rem, z-2);2245}2246lr=i+3; rem -= lr;2247rem[0] = evaltyp(t_POL) | evallg(lr);2248rem[1] = z[-1];2249p1 = gerepile((pari_sp)rem,tetpil,p1);2250rem += 2; gel(rem,i) = p1;2251for (i--; i>=0; i--)2252{2253av=avma; p1 = gel(x,i);2254for (j=0; j<=i && j<=dz; j++)2255p1 = F2x_add(p1, F2x_mul(gel(z,j),gel(y,i-j)));2256tetpil=avma; gel(rem,i) = gerepile(av,tetpil, F2x_rem(p1, T));2257}2258rem -= 2;2259guncloneNULL(lead);2260if (!sx) (void)F2xX_renormalize(rem, lr);2261if (pr == ONLY_REM) return gerepileupto(av0,rem);2262*pr = rem; return z-2;2263}22642265static GEN2266F2xX_recipspec(GEN x, long l, long n, long vs)2267{2268long i;2269GEN z = cgetg(n+2,t_POL);2270z[1] = 0; z += 2;2271for(i=0; i<l; i++)2272gel(z,n-i-1) = F2x_copy(gel(x,i));2273for( ; i<n; i++)2274gel(z,n-i-1) = pol0_F2x(vs);2275return F2xX_renormalize(z-2,n+2);2276}22772278static GEN2279F2xqX_invBarrett_basecase(GEN T, GEN Q)2280{2281long i, l=lg(T)-1, lr = l-1, k;2282long sv=Q[1];2283GEN r=cgetg(lr,t_POL); r[1]=T[1];2284gel(r,2) = pol1_F2x(sv);2285for (i=3;i<lr;i++)2286{2287pari_sp ltop=avma;2288GEN u = gel(T,l-i+2);2289for (k=3;k<i;k++)2290u = F2x_add(u, F2xq_mul(gel(T,l-i+k),gel(r,k),Q));2291gel(r,i) = gerepileupto(ltop, u);2292}2293r = F2xX_renormalize(r,lr);2294return r;2295}22962297/* Return new lgpol */2298static long2299F2xX_lgrenormalizespec(GEN x, long lx)2300{2301long i;2302for (i = lx-1; i>=0; i--)2303if (lgpol(gel(x,i))) break;2304return i+1;2305}23062307static GEN2308F2xqX_invBarrett_Newton(GEN S, GEN T)2309{2310pari_sp av = avma;2311long nold, lx, lz, lq, l = degpol(S), i, lQ;2312GEN q, y, z, x = cgetg(l+2, t_POL) + 2;2313long dT = get_F2x_degree(T);2314ulong mask = quadratic_prec_mask(l-2); /* assume l > 2 */2315for (i=0;i<l;i++) gel(x,i) = pol0_F2x(T[1]);2316q = F2xX_recipspec(S+2,l+1,l+1,dT);2317lQ = lgpol(q); q+=2;2318/* We work on _spec_ FlxX's, all the l[xzq] below are lgpol's */23192320/* initialize */2321gel(x,0) = F2xq_inv(gel(q,0),T);2322if (lQ>1 && F2x_degree(gel(q,1)) >= dT)2323gel(q,1) = F2x_rem(gel(q,1), T);2324if (lQ>1 && lgpol(gel(q,1)))2325{2326GEN u = gel(q, 1);2327if (!F2x_equal1(gel(x,0))) u = F2xq_mul(u, F2xq_sqr(gel(x,0), T), T);2328else u = F2x_copy(u);2329gel(x,1) = u; lx = 2;2330}2331else2332lx = 1;2333nold = 1;2334for (; mask > 1; )2335{ /* set x -= x(x*q - 1) + O(t^(nnew + 1)), knowing x*q = 1 + O(t^(nold+1)) */2336long i, lnew, nnew = nold << 1;23372338if (mask & 1) nnew--;2339mask >>= 1;23402341lnew = nnew + 1;2342lq = F2xX_lgrenormalizespec(q, minss(lQ,lnew));2343z = F2xqX_mulspec(x, q, T, lx, lq); /* FIXME: high product */2344lz = lgpol(z); if (lz > lnew) lz = lnew;2345z += 2;2346/* subtract 1 [=>first nold words are 0]: renormalize so that z(0) != 0 */2347for (i = nold; i < lz; i++) if (lgpol(gel(z,i))) break;2348nold = nnew;2349if (i >= lz) continue; /* z-1 = 0(t^(nnew + 1)) */23502351/* z + i represents (x*q - 1) / t^i */2352lz = F2xX_lgrenormalizespec (z+i, lz-i);2353z = F2xqX_mulspec(x, z+i, T, lx, lz); /* FIXME: low product */2354lz = lgpol(z); z += 2;2355if (lz > lnew-i) lz = F2xX_lgrenormalizespec(z, lnew-i);23562357lx = lz+ i;2358y = x + i; /* x -= z * t^i, in place */2359for (i = 0; i < lz; i++) gel(y,i) = gel(z,i);2360}2361x -= 2; setlg(x, lx + 2); x[1] = S[1];2362return gerepilecopy(av, x);2363}23642365GEN2366F2xqX_invBarrett(GEN T, GEN Q)2367{2368pari_sp ltop=avma;2369long l=lg(T), v = varn(T);2370GEN r;2371GEN c = gel(T,l-1);2372if (l<5) return pol_0(v);2373if (l<=F2xqX_INVBARRETT_LIMIT)2374{2375if (!F2x_equal1(c))2376{2377GEN ci = F2xq_inv(c,Q);2378T = F2xqX_F2xq_mul(T, ci, Q);2379r = F2xqX_invBarrett_basecase(T,Q);2380r = F2xqX_F2xq_mul(r,ci,Q);2381} else2382r = F2xqX_invBarrett_basecase(T,Q);2383} else2384r = F2xqX_invBarrett_Newton(T,Q);2385return gerepileupto(ltop, r);2386}23872388GEN2389F2xqX_get_red(GEN S, GEN T)2390{2391if (typ(S)==t_POL && lg(S)>F2xqX_BARRETT_LIMIT)2392retmkvec2(F2xqX_invBarrett(S, T), S);2393return S;2394}23952396/* Compute x mod S where 2 <= degpol(S) <= l+1 <= 2*(degpol(S)-1)2397* * and mg is the Barrett inverse of S. */2398static GEN2399F2xqX_divrem_Barrettspec(GEN x, long l, GEN mg, GEN S, GEN T, GEN *pr)2400{2401GEN q, r;2402long lt = degpol(S); /*We discard the leading term*/2403long ld, lm, lT, lmg;2404ld = l-lt;2405lm = minss(ld, lgpol(mg));2406lT = F2xX_lgrenormalizespec(S+2,lt);2407lmg = F2xX_lgrenormalizespec(mg+2,lm);2408q = F2xX_recipspec(x+lt,ld,ld,0); /* q = rec(x) lq<=ld*/2409q = F2xqX_mulspec(q+2,mg+2,T,lgpol(q),lmg); /* q = rec(x) * mg lq<=ld+lm*/2410q = F2xX_recipspec(q+2,minss(ld,lgpol(q)),ld,0);/* q = rec (rec(x) * mg) lq<=ld*/2411if (!pr) return q;2412r = F2xqX_mulspec(q+2,S+2,T,lgpol(q),lT); /* r = q*pol lr<=ld+lt*/2413r = F2xX_addspec(x,r+2,lt,minss(lt,lgpol(r)));/* r = x - r lr<=lt */2414if (pr == ONLY_REM) return r;2415*pr = r; return q;2416}24172418static GEN2419F2xqX_divrem_Barrett(GEN x, GEN mg, GEN S, GEN T, GEN *pr)2420{2421GEN q = NULL, r = F2xqX_red(x, T);2422long l = lgpol(r), lt = degpol(S), lm = 2*lt-1, v = varn(S);2423long i;2424if (l <= lt)2425{2426if (pr == ONLY_REM) return r;2427if (pr == ONLY_DIVIDES) return signe(r)? NULL: pol_0(v);2428if (pr) *pr = r;2429return pol_0(v);2430}2431if (lt <= 1)2432return F2xqX_divrem_basecase(x,S,T,pr);2433if (pr != ONLY_REM && l>lm)2434{2435long vT = get_F2x_var(T);2436q = cgetg(l-lt+2, t_POL); q[1] = S[1];2437for (i=0;i<l-lt;i++) gel(q+2,i) = pol0_F2x(vT);2438}2439while (l>lm)2440{2441GEN zr, zq = F2xqX_divrem_Barrettspec(r+2+l-lm,lm,mg,S,T,&zr);2442long lz = lgpol(zr);2443if (pr != ONLY_REM)2444{2445long lq = lgpol(zq);2446for(i=0; i<lq; i++) gel(q+2+l-lm,i) = gel(zq,2+i);2447}2448for(i=0; i<lz; i++) gel(r+2+l-lm,i) = gel(zr,2+i);2449l = l-lm+lz;2450}2451if (pr == ONLY_REM)2452{2453if (l > lt)2454r = F2xqX_divrem_Barrettspec(r+2,l,mg,S,T,ONLY_REM);2455else2456r = F2xX_renormalize(r, lg(r));2457setvarn(r, v); return F2xX_renormalize(r, lg(r));2458}2459if (l > lt)2460{2461GEN zq = F2xqX_divrem_Barrettspec(r+2,l,mg,S,T,pr? &r: NULL);2462if (!q) q = zq;2463else2464{2465long lq = lgpol(zq);2466for(i=0; i<lq; i++) gel(q+2,i) = gel(zq,2+i);2467}2468}2469else if (pr)2470r = F2xX_renormalize(r, l+2);2471setvarn(q, v); q = F2xX_renormalize(q, lg(q));2472if (pr == ONLY_DIVIDES) return signe(r)? NULL: q;2473if (pr) { setvarn(r, v); *pr = r; }2474return q;2475}24762477GEN2478F2xqX_divrem(GEN x, GEN S, GEN T, GEN *pr)2479{2480GEN B, y;2481long dy, dx, d;2482if (pr==ONLY_REM) return F2xqX_rem(x, S, T);2483y = get_F2xqX_red(S, &B);2484dy = degpol(y); dx = degpol(x); d = dx-dy;2485if (!B && d+3 < F2xqX_DIVREM_BARRETT_LIMIT)2486return F2xqX_divrem_basecase(x,y,T,pr);2487else2488{2489pari_sp av=avma;2490GEN mg = B? B: F2xqX_invBarrett(y, T);2491GEN q = F2xqX_divrem_Barrett(x,mg,y,T,pr);2492if (!q) return gc_NULL(av);2493if (!pr || pr==ONLY_DIVIDES) return gerepilecopy(av, q);2494gerepileall(av,2,&q,pr);2495return q;2496}2497}24982499GEN2500F2xqX_rem(GEN x, GEN S, GEN T)2501{2502GEN B, y = get_F2xqX_red(S, &B);2503long dy = degpol(y), dx = degpol(x), d = dx-dy;2504if (d < 0) return F2xqX_red(x, T);2505if (!B && d+3 < F2xqX_REM_BARRETT_LIMIT)2506return F2xqX_divrem_basecase(x,y, T, ONLY_REM);2507else2508{2509pari_sp av=avma;2510GEN mg = B? B: F2xqX_invBarrett(y, T);2511GEN r = F2xqX_divrem_Barrett(x, mg, y, T, ONLY_REM);2512return gerepileupto(av, r);2513}2514}25152516static GEN2517F2xqX_halfgcd_basecase(GEN a, GEN b, GEN T)2518{2519pari_sp av=avma;2520GEN u,u1,v,v1;2521long vx = varn(a);2522long n = lgpol(a)>>1;2523u1 = v = pol_0(vx);2524u = v1 = pol1_F2xX(vx, get_F2x_var(T));2525while (lgpol(b)>n)2526{2527GEN r, q = F2xqX_divrem(a,b, T, &r);2528a = b; b = r; swap(u,u1); swap(v,v1);2529u1 = F2xX_add(u1, F2xqX_mul(u, q, T));2530v1 = F2xX_add(v1, F2xqX_mul(v, q ,T));2531if (gc_needed(av,2))2532{2533if (DEBUGMEM>1) pari_warn(warnmem,"F2xqX_halfgcd (d = %ld)",degpol(b));2534gerepileall(av,6, &a,&b,&u1,&v1,&u,&v);2535}2536}2537return gerepilecopy(av, mkmat2(mkcol2(u,u1), mkcol2(v,v1)));2538}2539static GEN2540F2xqX_addmulmul(GEN u, GEN v, GEN x, GEN y, GEN T)2541{2542return F2xX_add(F2xqX_mul(u, x, T),F2xqX_mul(v, y, T));2543}25442545static GEN2546F2xqXM_F2xqX_mul2(GEN M, GEN x, GEN y, GEN T)2547{2548GEN res = cgetg(3, t_COL);2549gel(res, 1) = F2xqX_addmulmul(gcoeff(M,1,1), gcoeff(M,1,2), x, y, T);2550gel(res, 2) = F2xqX_addmulmul(gcoeff(M,2,1), gcoeff(M,2,2), x, y, T);2551return res;2552}25532554static GEN2555F2xqXM_mul2(GEN A, GEN B, GEN T)2556{2557GEN A11=gcoeff(A,1,1),A12=gcoeff(A,1,2), B11=gcoeff(B,1,1),B12=gcoeff(B,1,2);2558GEN A21=gcoeff(A,2,1),A22=gcoeff(A,2,2), B21=gcoeff(B,2,1),B22=gcoeff(B,2,2);2559GEN M1 = F2xqX_mul(F2xX_add(A11,A22), F2xX_add(B11,B22), T);2560GEN M2 = F2xqX_mul(F2xX_add(A21,A22), B11, T);2561GEN M3 = F2xqX_mul(A11, F2xX_add(B12,B22), T);2562GEN M4 = F2xqX_mul(A22, F2xX_add(B21,B11), T);2563GEN M5 = F2xqX_mul(F2xX_add(A11,A12), B22, T);2564GEN M6 = F2xqX_mul(F2xX_add(A21,A11), F2xX_add(B11,B12), T);2565GEN M7 = F2xqX_mul(F2xX_add(A12,A22), F2xX_add(B21,B22), T);2566GEN T1 = F2xX_add(M1,M4), T2 = F2xX_add(M7,M5);2567GEN T3 = F2xX_add(M1,M2), T4 = F2xX_add(M3,M6);2568retmkmat2(mkcol2(F2xX_add(T1,T2), F2xX_add(M2,M4)),2569mkcol2(F2xX_add(M3,M5), F2xX_add(T3,T4)));2570}25712572/* Return [0,1;1,-q]*M */2573static GEN2574F2xqX_F2xqXM_qmul(GEN q, GEN M, GEN T)2575{2576GEN u, v, res = cgetg(3, t_MAT);2577u = F2xX_add(gcoeff(M,1,1), F2xqX_mul(gcoeff(M,2,1), q, T));2578gel(res,1) = mkcol2(gcoeff(M,2,1), u);2579v = F2xX_add(gcoeff(M,1,2), F2xqX_mul(gcoeff(M,2,2), q, T));2580gel(res,2) = mkcol2(gcoeff(M,2,2), v);2581return res;2582}25832584static GEN2585matid2_F2xXM(long v, long sv)2586{2587retmkmat2(mkcol2(pol1_F2xX(v, sv),pol_0(v)),2588mkcol2(pol_0(v),pol1_F2xX(v, sv)));2589}25902591static GEN2592F2xqX_halfgcd_split(GEN x, GEN y, GEN T)2593{2594pari_sp av=avma;2595GEN R, S, V;2596GEN y1, r, q;2597long l = lgpol(x), n = l>>1, k;2598if (lgpol(y)<=n) return matid2_F2xXM(varn(x),get_F2x_var(T));2599R = F2xqX_halfgcd(RgX_shift_shallow(x,-n),RgX_shift_shallow(y,-n), T);2600V = F2xqXM_F2xqX_mul2(R,x,y, T); y1 = gel(V,2);2601if (lgpol(y1)<=n) return gerepilecopy(av, R);2602q = F2xqX_divrem(gel(V,1), y1, T, &r);2603k = 2*n-degpol(y1);2604S = F2xqX_halfgcd(RgX_shift_shallow(y1,-k), RgX_shift_shallow(r,-k), T);2605return gerepileupto(av, F2xqXM_mul2(S,F2xqX_F2xqXM_qmul(q,R, T), T));2606}26072608/* Return M in GL_2(Fp[X]) such that:2609if [a',b']~=M*[a,b]~ then degpol(a')>= (lgpol(a)>>1) >degpol(b')2610*/26112612static GEN2613F2xqX_halfgcd_i(GEN x, GEN y, GEN T)2614{2615if (lg(x)<=F2xqX_HALFGCD_LIMIT) return F2xqX_halfgcd_basecase(x, y, T);2616return F2xqX_halfgcd_split(x, y, T);2617}26182619GEN2620F2xqX_halfgcd(GEN x, GEN y, GEN T)2621{2622pari_sp av = avma;2623GEN M,q,r;2624if (!signe(x))2625{2626long v = varn(x), vT = get_F2x_var(T);2627retmkmat2(mkcol2(pol_0(v),pol1_F2xX(v,vT)),2628mkcol2(pol1_F2xX(v,vT),pol_0(v)));2629}2630if (degpol(y)<degpol(x)) return F2xqX_halfgcd_i(x, y, T);2631q = F2xqX_divrem(y, x, T, &r);2632M = F2xqX_halfgcd_i(x, r, T);2633gcoeff(M,1,1) = F2xX_add(gcoeff(M,1,1), F2xqX_mul(q, gcoeff(M,1,2), T));2634gcoeff(M,2,1) = F2xX_add(gcoeff(M,2,1), F2xqX_mul(q, gcoeff(M,2,2), T));2635return gerepilecopy(av, M);2636}26372638static GEN2639F2xqX_gcd_basecase(GEN a, GEN b, GEN T)2640{2641pari_sp av = avma, av0=avma;2642while (signe(b))2643{2644GEN c;2645if (gc_needed(av0,2))2646{2647if (DEBUGMEM>1) pari_warn(warnmem,"F2xqX_gcd (d = %ld)",degpol(b));2648gerepileall(av0,2, &a,&b);2649}2650av = avma; c = F2xqX_rem(a, b, T); a=b; b=c;2651}2652return gc_const(av, a);2653}26542655GEN2656F2xqX_gcd(GEN x, GEN y, GEN T)2657{2658pari_sp av = avma;2659x = F2xqX_red(x, T);2660y = F2xqX_red(y, T);2661if (!signe(x)) return gerepileupto(av, y);2662while (lg(y)>F2xqX_GCD_LIMIT)2663{2664GEN c;2665if (lgpol(y)<=(lgpol(x)>>1))2666{2667GEN r = F2xqX_rem(x, y, T);2668x = y; y = r;2669}2670c = F2xqXM_F2xqX_mul2(F2xqX_halfgcd(x,y, T), x, y, T);2671x = gel(c,1); y = gel(c,2);2672gerepileall(av,2,&x,&y);2673}2674return gerepileupto(av, F2xqX_gcd_basecase(x, y, T));2675}26762677static GEN2678F2xqX_extgcd_basecase(GEN a, GEN b, GEN T, GEN *ptu, GEN *ptv)2679{2680pari_sp av=avma;2681GEN u,v,d,d1,v1;2682long vx = varn(a);2683d = a; d1 = b;2684v = pol_0(vx); v1 = pol1_F2xX(vx, get_F2x_var(T));2685while (signe(d1))2686{2687GEN r, q = F2xqX_divrem(d, d1, T, &r);2688v = F2xX_add(v,F2xqX_mul(q,v1,T));2689u=v; v=v1; v1=u;2690u=r; d=d1; d1=u;2691if (gc_needed(av,2))2692{2693if (DEBUGMEM>1) pari_warn(warnmem,"F2xqX_extgcd (d = %ld)",degpol(d));2694gerepileall(av,5, &d,&d1,&u,&v,&v1);2695}2696}2697if (ptu) *ptu = F2xqX_div(F2xX_add(d,F2xqX_mul(b,v, T)), a, T);2698*ptv = v; return d;2699}27002701static GEN2702F2xqX_extgcd_halfgcd(GEN x, GEN y, GEN T, GEN *ptu, GEN *ptv)2703{2704pari_sp av=avma;2705GEN u,v,R = matid2_F2xXM(varn(x), get_F2x_var(T));2706while (lg(y)>F2xqX_EXTGCD_LIMIT)2707{2708GEN M, c;2709if (lgpol(y)<=(lgpol(x)>>1))2710{2711GEN r, q = F2xqX_divrem(x, y, T, &r);2712x = y; y = r;2713R = F2xqX_F2xqXM_qmul(q, R, T);2714}2715M = F2xqX_halfgcd(x,y, T);2716c = F2xqXM_F2xqX_mul2(M, x,y, T);2717R = F2xqXM_mul2(M, R, T);2718x = gel(c,1); y = gel(c,2);2719gerepileall(av,3,&x,&y,&R);2720}2721y = F2xqX_extgcd_basecase(x,y, T, &u,&v);2722if (ptu) *ptu = F2xqX_addmulmul(u,v,gcoeff(R,1,1),gcoeff(R,2,1), T);2723*ptv = F2xqX_addmulmul(u,v,gcoeff(R,1,2),gcoeff(R,2,2), T);2724return y;2725}27262727/* x and y in Z[Y][X], return lift(gcd(x mod T,p, y mod T,p)). Set u and v st2728* ux + vy = gcd (mod T,p) */2729GEN2730F2xqX_extgcd(GEN x, GEN y, GEN T, GEN *ptu, GEN *ptv)2731{2732GEN d;2733pari_sp ltop=avma;2734x = F2xqX_red(x, T);2735y = F2xqX_red(y, T);2736if (lg(y)>F2xqX_EXTGCD_LIMIT)2737d = F2xqX_extgcd_halfgcd(x, y, T, ptu, ptv);2738else2739d = F2xqX_extgcd_basecase(x, y, T, ptu, ptv);2740gerepileall(ltop,ptu?3:2,&d,ptv,ptu);2741return d;2742}27432744static GEN2745_F2xqX_mul(void *data,GEN a,GEN b) { return F2xqX_mul(a,b, (GEN) data); }2746static GEN2747_F2xqX_sqr(void *data,GEN a) { return F2xqX_sqr(a, (GEN) data); }2748GEN2749F2xqX_powu(GEN x, ulong n, GEN T)2750{ return gen_powu(x, n, (void*)T, &_F2xqX_sqr, &_F2xqX_mul); }27512752/* Res(A,B) = Res(B,R) * lc(B)^(a-r) * (-1)^(ab), with R=A%B, a=deg(A) ...*/2753GEN2754F2xqX_resultant(GEN a, GEN b, GEN T)2755{2756long vT = get_F2x_var(T);2757long da,db,dc;2758pari_sp av;2759GEN c,lb, res = pol1_F2x(vT);27602761if (!signe(a) || !signe(b)) return pol0_F2x(vT);27622763da = degpol(a);2764db = degpol(b);2765if (db > da)2766swapspec(a,b, da,db);2767if (!da) return pol1_F2x(vT); /* = res * a[2] ^ db, since 0 <= db <= da = 0 */2768av = avma;2769while (db)2770{2771lb = gel(b,db+2);2772c = F2xqX_rem(a,b, T);2773a = b; b = c; dc = degpol(c);2774if (dc < 0) { set_avma(av); return pol0_F2x(vT); }27752776if (!equali1(lb)) res = F2xq_mul(res, F2xq_powu(lb, da - dc, T), T);2777if (gc_needed(av,2))2778{2779if (DEBUGMEM>1) pari_warn(warnmem,"F2xqX_resultant (da = %ld)",da);2780gerepileall(av,3, &a,&b,&res);2781}2782da = db; /* = degpol(a) */2783db = dc; /* = degpol(b) */2784}2785res = F2xq_mul(res, F2xq_powu(gel(b,2), da, T), T);2786return gerepileupto(av, res);2787}27882789/* disc P = (-1)^(n(n-1)/2) lc(P)^(n - deg P' - 2) Res(P,P'), n = deg P */2790GEN2791F2xqX_disc(GEN P, GEN T)2792{2793pari_sp av = avma;2794GEN L, dP = F2xX_deriv(P), D = F2xqX_resultant(P, dP, T);2795long dd;2796if (!lgpol(D)) return pol_0(get_F2x_var(T));2797dd = degpol(P) - 2 - degpol(dP); /* >= -1; > -1 iff p | deg(P) */2798L = leading_coeff(P);2799if (dd && !F2x_equal1(L))2800D = (dd == -1)? F2xq_div(D,L,T): F2xq_mul(D, F2xq_powu(L, dd, T), T);2801return gerepileupto(av, D);2802}28032804/***********************************************************************/2805/** **/2806/** F2xqXQ **/2807/** **/2808/***********************************************************************/28092810GEN2811F2xqXQ_mul(GEN x, GEN y, GEN S, GEN T) {2812return F2xqX_rem(F2xqX_mul(x,y,T),S,T);2813}28142815GEN2816F2xqXQ_sqr(GEN x, GEN S, GEN T) {2817return F2xqX_rem(F2xqX_sqr(x,T),S,T);2818}28192820GEN2821F2xqXQ_invsafe(GEN x, GEN S, GEN T)2822{2823GEN V, z = F2xqX_extgcd(get_F2xqX_mod(S), x, T, NULL, &V);2824if (degpol(z)) return NULL;2825z = F2xq_invsafe(gel(z,2),T);2826if (!z) return NULL;2827return F2xqX_F2xq_mul(V, z, T);2828}28292830GEN2831F2xqXQ_inv(GEN x, GEN S, GEN T)2832{2833pari_sp av = avma;2834GEN U = F2xqXQ_invsafe(x, S, T);2835if (!U) pari_err_INV("F2xqXQ_inv",x);2836return gerepileupto(av, U);2837}28382839struct _F2xqXQ {2840GEN T, S;2841};28422843static GEN2844_F2xqXQ_add(void *data, GEN x, GEN y) {2845(void) data;2846return F2xX_add(x,y);2847}2848static GEN2849_F2xqXQ_cmul(void *data, GEN P, long a, GEN x) {2850(void) data;2851return F2xX_F2x_mul(x,gel(P,a+2));2852}2853static GEN2854_F2xqXQ_red(void *data, GEN x) {2855struct _F2xqXQ *d = (struct _F2xqXQ*) data;2856return F2xqX_red(x, d->T);2857}2858static GEN2859_F2xqXQ_mul(void *data, GEN x, GEN y) {2860struct _F2xqXQ *d = (struct _F2xqXQ*) data;2861return F2xqXQ_mul(x,y, d->S,d->T);2862}2863static GEN2864_F2xqXQ_sqr(void *data, GEN x) {2865struct _F2xqXQ *d = (struct _F2xqXQ*) data;2866return F2xqXQ_sqr(x, d->S,d->T);2867}2868static GEN2869_F2xqXQ_zero(void *data) {2870struct _F2xqXQ *d = (struct _F2xqXQ*) data;2871return pol_0(get_F2xqX_var(d->S));2872}2873static GEN2874_F2xqXQ_one(void *data) {2875struct _F2xqXQ *d = (struct _F2xqXQ*) data;2876return pol1_F2xX(get_F2xqX_var(d->S),get_F2x_var(d->T));2877}28782879static struct bb_algebra F2xqXQ_algebra = { _F2xqXQ_red,2880_F2xqXQ_add, _F2xqXQ_add, _F2xqXQ_mul,_F2xqXQ_sqr,_F2xqXQ_one,_F2xqXQ_zero };28812882GEN2883F2xqXQ_pow(GEN x, GEN n, GEN S, GEN T)2884{2885struct _F2xqXQ D;2886long s = signe(n);2887if (!s) return pol1_F2xX(get_F2xqX_var(S), get_F2x_var(T));2888if (s < 0) x = F2xqXQ_inv(x,S,T);2889if (is_pm1(n)) return s < 0 ? x : gcopy(x);2890if (degpol(x) >= get_F2xqX_degree(S)) x = F2xqX_rem(x,S,T);2891D.T = F2x_get_red(T);2892D.S = F2xqX_get_red(S, T);2893return gen_pow(x, n, (void*)&D, &_F2xqXQ_sqr, &_F2xqXQ_mul);2894}28952896GEN2897F2xqXQ_powers(GEN x, long l, GEN S, GEN T)2898{2899struct _F2xqXQ D;2900int use_sqr = 2*degpol(x) >= get_F2xqX_degree(S);2901D.T = F2x_get_red(T);2902D.S = F2xqX_get_red(S, T);2903return gen_powers(x, l, use_sqr, (void*)&D, &_F2xqXQ_sqr, &_F2xqXQ_mul,&_F2xqXQ_one);2904}29052906GEN2907F2xqX_F2xqXQV_eval(GEN P, GEN V, GEN S, GEN T)2908{2909struct _F2xqXQ D;2910D.T = F2x_get_red(T);2911D.S = F2xqX_get_red(S, T);2912return gen_bkeval_powers(P, degpol(P), V, (void*)&D, &F2xqXQ_algebra,2913_F2xqXQ_cmul);2914}29152916GEN2917F2xqX_F2xqXQ_eval(GEN Q, GEN x, GEN S, GEN T)2918{2919struct _F2xqXQ D;2920int use_sqr = 2*degpol(x) >= get_F2xqX_degree(S);2921D.T = F2x_get_red(T);2922D.S = F2xqX_get_red(S, T);2923return gen_bkeval(Q, degpol(Q), x, use_sqr, (void*)&D, &F2xqXQ_algebra,2924_F2xqXQ_cmul);2925}29262927static GEN2928F2xqXQ_autpow_sqr(void * E, GEN x)2929{2930struct _F2xqXQ *D = (struct _F2xqXQ *)E;2931GEN T = D->T;2932GEN phi = gel(x,1), S = gel(x,2);2933long n = brent_kung_optpow(get_F2x_degree(T)-1,lgpol(S)+1,1);2934GEN V = F2xq_powers(phi, n, T);2935GEN phi2 = F2x_F2xqV_eval(phi, V, T);2936GEN Sphi = F2xY_F2xqV_evalx(S, V, T);2937GEN S2 = F2xqX_F2xqXQ_eval(Sphi, S, D->S, T);2938return mkvec2(phi2, S2);2939}29402941static GEN2942F2xqXQ_autpow_mul(void * E, GEN x, GEN y)2943{2944struct _F2xqXQ *D = (struct _F2xqXQ *)E;2945GEN T = D->T;2946GEN phi1 = gel(x,1), S1 = gel(x,2);2947GEN phi2 = gel(y,1), S2 = gel(y,2);2948long n = brent_kung_optpow(get_F2x_degree(T)-1,lgpol(S1)+1,1);2949GEN V = F2xq_powers(phi2, n, T);2950GEN phi3 = F2x_F2xqV_eval(phi1,V,T);2951GEN Sphi = F2xY_F2xqV_evalx(S1,V,T);2952GEN S3 = F2xqX_F2xqXQ_eval(Sphi, S2, D->S, T);2953return mkvec2(phi3, S3);2954}29552956GEN2957F2xqXQ_autpow(GEN aut, long n, GEN S, GEN T)2958{2959struct _F2xqXQ D;2960D.T = F2x_get_red(T);2961D.S = F2xqX_get_red(S, T);2962return gen_powu(aut,n,&D,F2xqXQ_autpow_sqr,F2xqXQ_autpow_mul);2963}29642965static GEN2966F2xqXQ_auttrace_mul(void *E, GEN x, GEN y)2967{2968struct _F2xqXQ *D = (struct _F2xqXQ *) E;2969GEN T = D->T;2970GEN phi1 = gel(x,1), S1 = gel(x,2), a1 = gel(x,3);2971GEN phi2 = gel(y,1), S2 = gel(y,2), a2 = gel(y,3);2972long n2 = brent_kung_optpow(get_F2x_degree(T)-1, lgpol(S1)+lgpol(a1)+1, 1);2973GEN V2 = F2xq_powers(phi2, n2, T);2974GEN phi3 = F2x_F2xqV_eval(phi1, V2, T);2975GEN Sphi = F2xY_F2xqV_evalx(S1, V2, T);2976GEN aphi = F2xY_F2xqV_evalx(a1, V2, T);2977long n = brent_kung_optpow(maxss(degpol(Sphi),degpol(aphi)),2,1);2978GEN V = F2xqXQ_powers(S2, n, D->S, T);2979GEN S3 = F2xqX_F2xqXQV_eval(Sphi, V, D->S, T);2980GEN aS = F2xqX_F2xqXQV_eval(aphi, V, D->S, T);2981GEN a3 = F2xX_add(aS, a2);2982return mkvec3(phi3, S3, a3);2983}29842985static GEN2986F2xqXQ_auttrace_sqr(void *E, GEN x) { return F2xqXQ_auttrace_mul(E, x, x); }2987GEN2988F2xqXQ_auttrace(GEN aut, long n, GEN S, GEN T)2989{2990struct _F2xqXQ D;2991D.T = F2x_get_red(T);2992D.S = F2xqX_get_red(S, T);2993return gen_powu(aut,n,&D,F2xqXQ_auttrace_sqr,F2xqXQ_auttrace_mul);2994}29952996GEN2997F2xqXQV_red(GEN x, GEN S, GEN T)2998{ pari_APPLY_type(t_VEC, F2xqX_rem(gel(x,i), S, T)) }299930003001