Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2012 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_ellcard1819/* Not so fast arithmetic with points over elliptic curves over F_2^n */2021/***********************************************************************/22/** **/23/** F2xqE **/24/** **/25/***********************************************************************/2627/* Theses functions deal with point over elliptic curves over F_2^n defined28* by an equation of the form:29** y^2+x*y=x^3+a_2*x^2+a_6 if the curve is ordinary.30** y^2+a_3*y=x^3+a_4*x+a_6 if the curve is supersingular.31* Most of the time a6 is omitted since it can be recovered from any point32* on the curve.33* For supersingular curves, the parameter a2 is replaced by [a3,a4,a3^-1].34*/3536GEN37RgE_to_F2xqE(GEN x, GEN T)38{39if (ell_is_inf(x)) return x;40retmkvec2(Rg_to_F2xq(gel(x,1),T),Rg_to_F2xq(gel(x,2),T));41}4243GEN44F2xqE_changepoint(GEN x, GEN ch, GEN T)45{46pari_sp av = avma;47GEN p1,z,u,r,s,t,v,v2,v3;48if (ell_is_inf(x)) return x;49u = gel(ch,1); r = gel(ch,2);50s = gel(ch,3); t = gel(ch,4);51v = F2xq_inv(u, T); v2 = F2xq_sqr(v, T); v3 = F2xq_mul(v,v2, T);52p1 = F2x_add(gel(x,1),r);53z = cgetg(3,t_VEC);54gel(z,1) = F2xq_mul(v2, p1, T);55gel(z,2) = F2xq_mul(v3, F2x_add(gel(x,2), F2x_add(F2xq_mul(s, p1, T),t)), T);56return gerepileupto(av, z);57}5859GEN60F2xqE_changepointinv(GEN x, GEN ch, GEN T)61{62GEN u, r, s, t, X, Y, u2, u3, u2X, z;63if (ell_is_inf(x)) return x;64X = gel(x,1); Y = gel(x,2);65u = gel(ch,1); r = gel(ch,2);66s = gel(ch,3); t = gel(ch,4);67u2 = F2xq_sqr(u, T); u3 = F2xq_mul(u,u2, T);68u2X = F2xq_mul(u2,X, T);69z = cgetg(3, t_VEC);70gel(z,1) = F2x_add(u2X,r);71gel(z,2) = F2x_add(F2xq_mul(u3,Y, T), F2x_add(F2xq_mul(s,u2X, T), t));72return z;73}7475static GEN76nonzerotrace_F2xq(GEN T)77{78pari_sp av = avma;79long n = F2x_degree(T), vs = T[1];80GEN a;81if (odd(n))82return pol1_F2x(vs);83do84{85set_avma(av);86a = random_F2x(n, vs);87} while (F2xq_trace(a, T)==0);88return a;89}9091void92F2xq_elltwist(GEN a, GEN a6, GEN T, GEN *pt_a, GEN *pt_a6)93{94pari_sp av = avma;95GEN n = nonzerotrace_F2xq(T);96if (typ(a)==t_VECSMALL)97{98*pt_a = gerepileuptoleaf(av, F2x_add(n, a));99*pt_a6 = vecsmall_copy(a6);100} else101{102GEN a6t = F2x_add(a6, F2xq_mul(n, F2xq_sqr(gel(a,1), T), T));103*pt_a6 = gerepileuptoleaf(av, a6t);104*pt_a = vecsmall_copy(a);105}106}107108static GEN109F2xqE_dbl_slope(GEN P, GEN a, GEN T, GEN *slope)110{111GEN x, y, Q;112if (ell_is_inf(P)) return ellinf();113x = gel(P,1); y = gel(P,2);114if (typ(a)==t_VECSMALL)115{116GEN a2 = a;117if (!lgpol(gel(P,1))) return ellinf();118*slope = F2x_add(x, F2xq_div(y, x, T));119Q = cgetg(3,t_VEC);120gel(Q, 1) = F2x_add(F2xq_sqr(*slope, T), F2x_add(*slope, a2));121gel(Q, 2) = F2x_add(F2xq_mul(*slope, F2x_add(x, gel(Q, 1)), T), F2x_add(y, gel(Q, 1)));122}123else124{125GEN a3 = gel(a,1), a4 = gel(a,2), a3i = gel(a,3);126*slope = F2xq_mul(F2x_add(a4, F2xq_sqr(x, T)), a3i, T);127Q = cgetg(3,t_VEC);128gel(Q, 1) = F2xq_sqr(*slope, T);129gel(Q, 2) = F2x_add(F2xq_mul(*slope, F2x_add(x, gel(Q, 1)), T), F2x_add(y, a3));130}131return Q;132}133134GEN135F2xqE_dbl(GEN P, GEN a, GEN T)136{137pari_sp av = avma;138GEN slope;139return gerepileupto(av, F2xqE_dbl_slope(P, a, T,&slope));140}141142static GEN143F2xqE_add_slope(GEN P, GEN Q, GEN a, GEN T, GEN *slope)144{145GEN Px, Py, Qx, Qy, R;146if (ell_is_inf(P)) return Q;147if (ell_is_inf(Q)) return P;148Px = gel(P,1); Py = gel(P,2);149Qx = gel(Q,1); Qy = gel(Q,2);150if (F2x_equal(Px, Qx))151{152if (F2x_equal(Py, Qy))153return F2xqE_dbl_slope(P, a, T, slope);154else155return ellinf();156}157*slope = F2xq_div(F2x_add(Py, Qy), F2x_add(Px, Qx), T);158R = cgetg(3,t_VEC);159if (typ(a)==t_VECSMALL)160{161GEN a2 = a;162gel(R, 1) = F2x_add(F2x_add(F2x_add(F2x_add(F2xq_sqr(*slope, T), *slope), Px), Qx), a2);163gel(R, 2) = F2x_add(F2xq_mul(*slope, F2x_add(Px, gel(R, 1)), T), F2x_add(Py, gel(R, 1)));164}165else166{167GEN a3 = gel(a,1);168gel(R, 1) = F2x_add(F2x_add(F2xq_sqr(*slope, T), Px), Qx);169gel(R, 2) = F2x_add(F2xq_mul(*slope, F2x_add(Px, gel(R, 1)), T), F2x_add(Py, a3));170}171return R;172}173174GEN175F2xqE_add(GEN P, GEN Q, GEN a, GEN T)176{177pari_sp av = avma;178GEN slope;179return gerepileupto(av, F2xqE_add_slope(P, Q, a, T, &slope));180}181182static GEN183F2xqE_neg_i(GEN P, GEN a)184{185GEN LHS;186if (ell_is_inf(P)) return P;187LHS = typ(a)==t_VECSMALL ? gel(P,1): gel(a,1);188return mkvec2(gel(P,1), F2x_add(LHS, gel(P,2)));189}190191GEN192F2xqE_neg(GEN P, GEN a, GEN T)193{194GEN LHS;195(void) T;196if (ell_is_inf(P)) return ellinf();197LHS = typ(a)==t_VECSMALL ? gel(P,1): gel(a,1);198return mkvec2(gcopy(gel(P,1)), F2x_add(LHS, gel(P,2)));199}200201GEN202F2xqE_sub(GEN P, GEN Q, GEN a2, GEN T)203{204pari_sp av = avma;205GEN slope;206return gerepileupto(av, F2xqE_add_slope(P, F2xqE_neg_i(Q, a2), a2, T, &slope));207}208209struct _F2xqE210{211GEN a2, a6;212GEN T;213};214215static GEN216_F2xqE_dbl(void *E, GEN P)217{218struct _F2xqE *ell = (struct _F2xqE *) E;219return F2xqE_dbl(P, ell->a2, ell->T);220}221222static GEN223_F2xqE_add(void *E, GEN P, GEN Q)224{225struct _F2xqE *ell=(struct _F2xqE *) E;226return F2xqE_add(P, Q, ell->a2, ell->T);227}228229static GEN230_F2xqE_mul(void *E, GEN P, GEN n)231{232pari_sp av = avma;233struct _F2xqE *e=(struct _F2xqE *) E;234long s = signe(n);235if (!s || ell_is_inf(P)) return ellinf();236if (s<0) P = F2xqE_neg(P, e->a2, e->T);237if (is_pm1(n)) return s>0? gcopy(P): P;238return gerepilecopy(av, gen_pow_i(P, n, e, &_F2xqE_dbl, &_F2xqE_add));239}240241GEN242F2xqE_mul(GEN P, GEN n, GEN a2, GEN T)243{244struct _F2xqE E;245E.a2 = a2; E.T = T;246return _F2xqE_mul(&E, P, n);247}248249/* Finds a random nonsingular point on E */250GEN251random_F2xqE(GEN a, GEN a6, GEN T)252{253pari_sp ltop = avma;254GEN x, y, rhs, u;255do256{257set_avma(ltop);258x = random_F2x(F2x_degree(T),T[1]);259if (typ(a) == t_VECSMALL)260{261GEN a2 = a, x2;262if (!lgpol(x))263{ set_avma(ltop); retmkvec2(pol0_Flx(T[1]), F2xq_sqrt(a6,T)); }264u = x; x2 = F2xq_sqr(x, T);265rhs = F2x_add(F2xq_mul(x2,F2x_add(x,a2),T),a6);266rhs = F2xq_div(rhs,x2,T);267}268else269{270GEN a3 = gel(a,1), a4 = gel(a,2), a3i = gel(a,3), u2i;271u = a3; u2i = F2xq_sqr(a3i,T);272rhs = F2x_add(F2xq_mul(x,F2x_add(F2xq_sqr(x,T),a4),T),a6);273rhs = F2xq_mul(rhs,u2i,T);274}275} while (F2xq_trace(rhs,T));276y = F2xq_mul(F2xq_Artin_Schreier(rhs, T), u, T);277return gerepilecopy(ltop, mkvec2(x, y));278}279280static GEN281_F2xqE_rand(void *E)282{283struct _F2xqE *ell=(struct _F2xqE *) E;284return random_F2xqE(ell->a2, ell->a6, ell->T);285}286287static const struct bb_group F2xqE_group={_F2xqE_add,_F2xqE_mul,_F2xqE_rand,hash_GEN,zvV_equal,ell_is_inf, NULL};288289const struct bb_group *290get_F2xqE_group(void ** pt_E, GEN a2, GEN a6, GEN T)291{292struct _F2xqE *e = (struct _F2xqE *) stack_malloc(sizeof(struct _F2xqE));293e->a2 = a2; e->a6 = a6; e->T = T;294*pt_E = (void *) e;295return &F2xqE_group;296}297298GEN299F2xqE_order(GEN z, GEN o, GEN a2, GEN T)300{301pari_sp av = avma;302struct _F2xqE e;303e.a2=a2; e.T=T;304return gerepileuptoint(av, gen_order(z, o, (void*)&e, &F2xqE_group));305}306307GEN308F2xqE_log(GEN a, GEN b, GEN o, GEN a2, GEN T)309{310pari_sp av = avma;311struct _F2xqE e;312e.a2=a2; e.T=T;313return gerepileuptoint(av, gen_PH_log(a, b, o, (void*)&e, &F2xqE_group));314}315316/***********************************************************************/317/** **/318/** Pairings **/319/** **/320/***********************************************************************/321322/* Derived from APIP from and by Jerome Milan, 2012 */323324static long325is_2_torsion(GEN Q, GEN a)326{327return (typ(a)==t_VEC || lgpol(gel(Q, 1))) ? 0: 1;328}329330static GEN331F2xqE_vert(GEN P, GEN Q, GEN a, GEN T)332{333long vT = T[1];334if (ell_is_inf(P))335return pol1_F2x(T[1]);336if (!F2x_equal(gel(Q, 1), gel(P, 1)))337return F2x_add(gel(Q, 1), gel(P, 1));338if (is_2_torsion(Q, a))339return F2xq_inv(gel(Q,2), T);340return pol1_F2x(vT);341}342343static GEN344F2xqE_Miller_line(GEN R, GEN Q, GEN slope, GEN a, GEN T)345{346long vT = T[1];347GEN x = gel(Q, 1), y = gel(Q, 2);348GEN tmp1 = F2x_add(x, gel(R, 1));349GEN tmp2 = F2x_add(F2xq_mul(tmp1, slope, T), gel(R, 2));350GEN s1, s2, ix;351if (!F2x_equal(y, tmp2))352return F2x_add(y, tmp2);353if (is_2_torsion(Q, a)) return pol1_F2x(vT);354if (typ(a)==t_VEC)355{356GEN a4 = gel(a,2), a3i = gel(a,3);357s1 = F2xq_mul(F2x_add(a4, F2xq_sqr(x, T)), a3i, T);358if (!F2x_equal(s1, slope))359return F2x_add(s1, slope);360s2 = F2xq_mul(F2x_add(x, F2xq_sqr(s1, T)), a3i, T);361if (lgpol(s2)) return s2;362return zv_copy(a3i);363} else364{365GEN a2 = a ;366ix = F2xq_inv(x, T);367s1 = F2x_add(x, F2xq_mul(y, ix, T));368if (!F2x_equal(s1, slope))369return F2x_add(s1, slope);370s2 =F2x_add(a2, F2x_add(F2xq_sqr(s1,T), s1));371if (!F2x_equal(s2, x))372return F2x_add(pol1_F2x(vT), F2xq_mul(s2, ix, T));373return ix;374}375}376377/* Computes the equation of the line tangent to R and returns its378evaluation at the point Q. Also doubles the point R.379*/380381static GEN382F2xqE_tangent_update(GEN R, GEN Q, GEN a2, GEN T, GEN *pt_R)383{384if (ell_is_inf(R))385{386*pt_R = ellinf();387return pol1_F2x(T[1]);388}389else if (is_2_torsion(R, a2))390{391*pt_R = ellinf();392return F2xqE_vert(R, Q, a2, T);393} else {394GEN slope;395*pt_R = F2xqE_dbl_slope(R, a2, T, &slope);396return F2xqE_Miller_line(R, Q, slope, a2, T);397}398}399400/* Computes the equation of the line through R and P, and returns its401evaluation at the point Q. Also adds P to the point R.402*/403404static GEN405F2xqE_chord_update(GEN R, GEN P, GEN Q, GEN a2, GEN T, GEN *pt_R)406{407if (ell_is_inf(R))408{409*pt_R = gcopy(P);410return F2xqE_vert(P, Q, a2, T);411}412else if (ell_is_inf(P))413{414*pt_R = gcopy(R);415return F2xqE_vert(R, Q, a2, T);416}417else if (F2x_equal(gel(P, 1), gel(R, 1)))418{419if (F2x_equal(gel(P, 2), gel(R, 2)))420return F2xqE_tangent_update(R, Q, a2, T, pt_R);421else422{423*pt_R = ellinf();424return F2xqE_vert(R, Q, a2, T);425}426} else {427GEN slope;428*pt_R = F2xqE_add_slope(P, R, a2, T, &slope);429return F2xqE_Miller_line(R, Q, slope, a2, T);430}431}432433struct _F2xqE_miller { GEN T, a2, P; };434435static GEN436F2xqE_Miller_dbl(void* E, GEN d)437{438struct _F2xqE_miller *m = (struct _F2xqE_miller *)E;439GEN T = m->T, a2 = m->a2, P = m->P;440GEN v, line, point = gel(d,3);441GEN N = F2xq_sqr(gel(d,1), T);442GEN D = F2xq_sqr(gel(d,2), T);443line = F2xqE_tangent_update(point, P, a2, T, &point);444N = F2xq_mul(N, line, T);445v = F2xqE_vert(point, P, a2, T);446D = F2xq_mul(D, v, T); return mkvec3(N, D, point);447}448static GEN449F2xqE_Miller_add(void* E, GEN va, GEN vb)450{451struct _F2xqE_miller *m = (struct _F2xqE_miller *)E;452GEN T = m->T, a2 = m->a2, P = m->P;453GEN v, line, point;454GEN na = gel(va,1), da = gel(va,2), pa = gel(va,3);455GEN nb = gel(vb,1), db = gel(vb,2), pb = gel(vb,3);456GEN N = F2xq_mul(na, nb, T);457GEN D = F2xq_mul(da, db, T);458line = F2xqE_chord_update(pa, pb, P, a2, T, &point);459N = F2xq_mul(N, line, T);460v = F2xqE_vert(point, P, a2, T);461D = F2xq_mul(D, v, T); return mkvec3(N, D, point);462}463/* Returns the Miller function f_{m, Q} evaluated at the point P using464* the standard Miller algorithm. */465static GEN466F2xqE_Miller(GEN Q, GEN P, GEN m, GEN a2, GEN T)467{468pari_sp av = avma;469struct _F2xqE_miller d;470GEN v, N, D, g1;471472d.a2 = a2; d.T = T; d.P = P;473g1 = pol1_F2x(T[1]);474v = gen_pow_i(mkvec3(g1,g1,Q), m, (void*)&d, F2xqE_Miller_dbl, F2xqE_Miller_add);475N = gel(v,1); D = gel(v,2);476return gerepileupto(av, F2xq_div(N, D, T));477}478479GEN480F2xqE_weilpairing(GEN P, GEN Q, GEN m, GEN a2, GEN T)481{482pari_sp av = avma;483GEN N, D;484if (ell_is_inf(P) || ell_is_inf(Q)485|| (F2x_equal(gel(P,1),gel(Q,1)) && F2x_equal(gel(P,2),gel(Q,2))))486return pol1_F2x(T[1]);487N = F2xqE_Miller(P, Q, m, a2, T);488D = F2xqE_Miller(Q, P, m, a2, T);489return gerepileupto(av, F2xq_div(N, D, T));490}491492GEN493F2xqE_tatepairing(GEN P, GEN Q, GEN m, GEN a2, GEN T)494{495if (ell_is_inf(P) || ell_is_inf(Q))496return pol1_F2x(T[1]);497return F2xqE_Miller(P, Q, m, a2, T);498}499500/***********************************************************************/501/** **/502/** Point counting **/503/** **/504/***********************************************************************/505506static GEN507Z2x_rshift(GEN y, long x)508{509GEN z;510long i, l;511if (!x) return pol0_Flx(y[1]);512z = cgetg_copy(y, &l); z[1] = y[1];513for(i=2; i<l; i++) z[i] = y[i]>>x;514return Flx_renormalize(z, l);515}516517/* Solve the linear equation approximation in the Newton algorithm */518519static GEN520gen_Z2x_Dixon(GEN F, GEN V, long N, void *E, GEN lin(void *E, GEN F, GEN d, long N), GEN invl(void *E, GEN d))521{522pari_sp av = avma;523long N2, M;524GEN VN2, V2, VM, bil;525ulong q = 1UL<<N;526if (N == 1) return invl(E, V);527V = Flx_red(V, q);528N2 = (N + 1)>>1; M = N - N2;529F = FlxT_red(F, q);530VN2 = gen_Z2x_Dixon(F, V, N2, E, lin, invl);531bil = lin(E, F, VN2, N);532V2 = Z2x_rshift(Flx_sub(V, bil, q), N2);533VM = gen_Z2x_Dixon(F, V2, M, E, lin, invl);534return gerepileupto(av, Flx_add(VN2, Flx_Fl_mul(VM, 1UL<<N2, q), q));535}536537/* Solve F(X) = V mod 2^N538F(Xn) = V [mod 2^n]539Vm = (V-F(Xn))/(2^n)540F(Xm) = Vm541X = Xn + 2^n*Xm542*/543544static GEN545gen_Z2X_Dixon(GEN F, GEN V, long N, void *E,546GEN lin(void *E, GEN F, GEN d, long N),547GEN lins(void *E, GEN F, GEN d, long N),548GEN invls(void *E, GEN d))549{550pari_sp av = avma;551long n, m;552GEN Xn, Xm, FXn, Vm;553if (N<BITS_IN_LONG)554{555ulong q = 1UL<<N;556return Flx_to_ZX(gen_Z2x_Dixon(ZXT_to_FlxT(F,q), ZX_to_Flx(V,q),N,E,lins,invls));557}558V = ZX_remi2n(V, N);559n = (N + 1)>>1; m = N - n;560F = ZXT_remi2n(F, N);561Xn = gen_Z2X_Dixon(F, V, n, E, lin, lins, invls);562FXn = lin(E, F, Xn, N);563Vm = ZX_shifti(ZX_sub(V, FXn), -n);564Xm = gen_Z2X_Dixon(F, Vm, m, E, lin, lins, invls);565return gerepileupto(av, ZX_remi2n(ZX_add(Xn, ZX_shifti(Xm, n)), N));566}567568/* H -> H mod 2*/569570static GEN _can_invls(void *E, GEN V) {(void) E; return V; }571572/* H -> H-(f0*H0-f1*H1) */573574static GEN _can_lin(void *E, GEN F, GEN V, long N)575{576pari_sp av=avma;577GEN d0, d1, z;578(void) E;579RgX_even_odd(V, &d0, &d1);580z = ZX_sub(V, ZX_sub(ZX_mul(gel(F,1), d0), ZX_mul(gel(F,2), d1)));581return gerepileupto(av, ZX_remi2n(z, N));582}583584static GEN _can_lins(void *E, GEN F, GEN V, long N)585{586GEN D=Flx_splitting(V, 2), z;587ulong q = 1UL<<N;588(void) E;589z = Flx_sub(Flx_mul(gel(F,1), gel(D,1), q), Flx_mul(gel(F,2), gel(D,2), q), q);590return Flx_sub(V, z, q);591}592593/* P -> P-(P0^2-X*P1^2) */594595static GEN596_can_iter(void *E, GEN f2, GEN q)597{598GEN f0, f1, z;599(void) E;600RgX_even_odd(f2, &f0, &f1);601z = ZX_add(ZX_sub(f2, FpX_sqr(f0, q)), RgX_shift_shallow(FpX_sqr(f1, q), 1));602return mkvec3(z,f0,f1);603}604605/* H -> H-(2*P0*H0-2*X*P1*H1) */606607static GEN608_can_invd(void *E, GEN V, GEN v, GEN q, long M)609{610GEN F;611(void)E; (void)q;612F = mkvec2(ZX_shifti(gel(v,2),1), ZX_shifti(RgX_shift_shallow(gel(v,3),1),1));613return gen_Z2X_Dixon(F, V, M, NULL, _can_lin, _can_lins, _can_invls);614}615616/* Lift P to Q such that Q(x^2)=Q(x)*Q(-x) mod 2^n617if Q = Q0(X^2)+X*Q1(X^2), solve Q(X^2) = Q0^2-X*Q1^2618*/619GEN620F2x_Teichmuller(GEN P, long n)621{ return gen_ZpX_Newton(F2x_to_ZX(P),gen_2, n, NULL, _can_iter, _can_invd); }622623static GEN624Z2XQ_frob(GEN x, GEN T, GEN q)625{626return FpX_rem(RgX_inflate(x, 2), T, q);627}628629static GEN630Z2xq_frob(GEN x, GEN T, ulong q)631{632return Flx_rem(Flx_inflate(x, 2), T, q);633}634635struct _frob_lift636{637GEN T, sqx;638};639640/* H -> S^-1(H) mod 2 */641642static GEN _frob_invls(void *E, GEN V)643{644struct _frob_lift *F = (struct _frob_lift*) E;645GEN sqx = F->sqx;646return F2x_to_Flx(F2xq_sqrt_fast(Flx_to_F2x(V), gel(sqx,1), gel(sqx,2)));647}648649/* H -> f1*S(H) + f2*H */650651static GEN _frob_lin(void *E, GEN F, GEN x2, long N)652{653GEN T = gel(F,3);654GEN q = int2n(N);655GEN y2 = Z2XQ_frob(x2, T, q);656GEN lin = ZX_add(ZX_mul(gel(F,1), y2), ZX_mul(gel(F,2), x2));657(void) E;658return FpX_rem(ZX_remi2n(lin, N), T, q);659}660661static GEN _frob_lins(void *E, GEN F, GEN x2, long N)662{663GEN T = gel(F,3);664ulong q = 1UL<<N;665GEN y2 = Z2xq_frob(x2, T, q);666GEN lin = Flx_add(Flx_mul(gel(F,1), y2,q), Flx_mul(gel(F,2), x2,q),q);667(void) E;668return Flx_rem(lin, T, q);669}670671/* X -> P(X,S(X)) */672673static GEN674_lift_iter(void *E, GEN x2, GEN q)675{676struct _frob_lift *F = (struct _frob_lift*) E;677long N = expi(q);678GEN TN = ZXT_remi2n(F->T, N);679GEN y2 = Z2XQ_frob(x2, TN, q);680GEN x2y2 = FpX_rem(ZX_remi2n(ZX_mul(x2, y2), N), TN, q);681GEN s = ZX_add(ZX_add(x2, ZX_shifti(y2, 1)), ZX_shifti(x2y2, 3));682GEN V = ZX_add(ZX_add(ZX_sqr(s), y2), ZX_shifti(x2y2, 2));683return mkvec4(FpX_rem(ZX_remi2n(V, N), TN, q),x2,y2,s);684}685686/* H -> Dx*H+Dy*S(H) */687688static GEN689_lift_invd(void *E, GEN V, GEN v, GEN qM, long M)690{691struct _frob_lift *F = (struct _frob_lift*) E;692GEN TM = ZXT_remi2n(F->T, M);693GEN x2 = gel(v,2), y2 = gel(v,3), s = gel(v,4), r;694GEN Dx = ZX_add(ZX_mul(ZX_Z_add(ZX_shifti(y2, 4), gen_2), s),695ZX_shifti(y2, 2));696GEN Dy = ZX_add(ZX_Z_add(ZX_mul(ZX_Z_add(ZX_shifti(x2, 4), utoi(4)), s),697gen_1), ZX_shifti(x2, 2));698Dx = FpX_rem(ZX_remi2n(Dx, M), TM, qM);699Dy = FpX_rem(ZX_remi2n(Dy, M), TM, qM);700r = mkvec3(Dy, Dx, TM);701return gen_Z2X_Dixon(r, V, M, E, _frob_lin, _frob_lins, _frob_invls);702}703704/*705Let P(X,Y)=(X+2*Y+8*X*Y)^2+Y+4*X*Y706Solve P(x,S(x))=0 [mod 2^n,T]707assuming x = x0 [mod 2,T]708709we set s = X+2*Y+8*X*Y, P = s^2+Y+4*X*Y710Dx = dP/dx = (16*s+4)*x+(4*s+1)711Dy = dP/dy = (16*y+2)*s+4*y712*/713714static GEN715solve_AGM_eqn(GEN x0, long n, GEN T, GEN sqx)716{717struct _frob_lift F;718F.T=T; F.sqx=sqx;719return gen_ZpX_Newton(x0, gen_2, n, &F, _lift_iter, _lift_invd);720}721722static GEN723Z2XQ_invnorm_pcyc(GEN a, GEN T, long e)724{725GEN q = int2n(e);726GEN z = ZpXQ_norm_pcyc(a, T, q, gen_2);727return Fp_inv(z, q);728}729730/* Assume a = 1 [4] */731static GEN732Z2XQ_invnorm(GEN a, GEN T, long e)733{734pari_timer ti;735GEN pe = int2n(e), s;736if (degpol(a)==0)737return Fp_inv(Fp_powu(gel(a,2), get_FpX_degree(T), pe), pe);738if (DEBUGLEVEL>=3) timer_start(&ti);739s = ZpXQ_log(a, T, gen_2, e);740if (DEBUGLEVEL>=3) timer_printf(&ti,"Z2XQ_log");741s = Fp_neg(FpXQ_trace(s, T, pe), pe);742if (DEBUGLEVEL>=3) timer_printf(&ti,"FpXQ_trace");743s = modii(gel(Qp_exp(cvtop(s, gen_2, e-2)),4),pe);744if (DEBUGLEVEL>=3) timer_printf(&ti,"Qp_exp");745return s;746}747748/* Assume a2==0, so 4|E(F_p): if t^4 = a6 then (t,t^2) is of order 47498|E(F_p) <=> trace(a6)==0750*/751752static GEN753F2xq_elltrace_Harley(GEN a6, GEN T2)754{755pari_sp ltop = avma;756pari_timer ti;757GEN T, sqx;758GEN x, x2, t;759long n = F2x_degree(T2), N = ((n + 1)>>1) + 2;760long ispcyc;761if (n==1) return gen_m1;762if (n==2) return F2x_degree(a6) ? gen_1 : stoi(-3);763if (n==3) return F2x_degree(a6) ? (F2xq_trace(a6,T2) ? stoi(-3): gen_1)764: stoi(5);765timer_start(&ti);766sqx = mkvec2(F2xq_sqrt(polx_F2x(T2[1]),T2), T2);767if (DEBUGLEVEL>1) timer_printf(&ti,"Sqrtx");768ispcyc = zx_is_pcyc(F2x_to_Flx(T2));769T = ispcyc? F2x_to_ZX(T2): F2x_Teichmuller(T2, N-2);770if (DEBUGLEVEL>1) timer_printf(&ti,"Teich");771T = FpX_get_red(T, int2n(N));772if (DEBUGLEVEL>1) timer_printf(&ti,"Barrett");773x = solve_AGM_eqn(F2x_to_ZX(a6), N-2, T, sqx);774if (DEBUGLEVEL>1) timer_printf(&ti,"Lift");775x2 = ZX_Z_add_shallow(ZX_shifti(x,2), gen_1);776t = (ispcyc? Z2XQ_invnorm_pcyc: Z2XQ_invnorm)(x2, T, N);777if (DEBUGLEVEL>1) timer_printf(&ti,"Norm");778if (cmpii(sqri(t), int2n(n + 2)) > 0)779t = subii(t, int2n(N));780return gerepileuptoint(ltop, t);781}782783static GEN784get_v(GEN u, GEN a, GEN T)785{786GEN a4 = gel(a,2), a3i = gel(a,3);787GEN ui2 = F2xq_mul(u, a3i, T), ui4 = F2xq_sqr(ui2, T);788return F2xq_mul(a4, ui4, T);789}790791static GEN792get_r(GEN w, GEN u, GEN T)793{794return F2xq_sqr(F2xq_mul(F2xq_Artin_Schreier(w, T), u, T), T);795}796797static GEN798F2xq_elltracej(GEN a, GEN a6, GEN T, GEN q, long n)799{800GEN a3 = gel(a,1), a4 = gel(a,2), a3i = gel(a,3);801GEN r, pi, rhs;802long t, s, m = n >> 1;803if (odd(n))804{805GEN u, v, w;806u = F2xq_pow(a3,diviuexact(subiu(shifti(q,1), 1), 3),T);807v = get_v(u, a, T);808if (F2xq_trace(v, T)==0) return gen_0;809w = F2xq_Artin_Schreier(F2x_1_add(v), T);810if (F2xq_trace(w, T)) w = F2x_1_add(w);811r = get_r(w, u, T);812pi = int2n(m+1);813s = (((m+3)&3L) <= 1) ? -1: 1;814}815else816{817if (F2x_degree(F2xq_pow(a3,diviuexact(subiu(q, 1), 3),T))==0)818{819GEN u, v, w;820u = F2xq_sqrtn(a3, utoi(3), T, NULL);821v = get_v(u, a, T);822if (F2xq_trace(v, T)==1) return gen_0;823w = F2xq_Artin_Schreier(v, T);824if (F2xq_trace(w, T)==1) return gen_0;825r = get_r(w, u, T);826pi = int2n(m+1);827s = odd(m+1) ? -1: 1;828}829else830{831long sv = T[1];832GEN P = mkpoln(5, pol1_F2x(sv), pol0_F2x(sv), pol0_F2x(sv), a3, a4);833r = F2xq_sqr(gel(F2xqX_roots(P,T), 1), T);834pi = int2n(m);835s = odd(m) ? -1: 1;836}837}838rhs = F2x_add(F2xq_mul(F2x_add(F2xq_sqr(r, T), a4), r, T), a6);839t = F2xq_trace(F2xq_mul(rhs, F2xq_sqr(a3i, T), T), T);840return (t==0)^(s==1)? pi: negi(pi);841}842843GEN844F2xq_ellcard(GEN a, GEN a6, GEN T)845{846pari_sp av = avma;847long n = F2x_degree(T);848GEN c;849if (typ(a)==t_VECSMALL)850{851GEN t = F2xq_elltrace_Harley(a6, T);852c = addii(int2u(n), F2xq_trace(a,T) ? addui(1,t): subui(1,t));853} else if (n==1)854{855long a4i = lgpol(gel(a,2)), a6i = lgpol(a6);856return utoi(a4i? (a6i? 1: 5): 3);857}858else859{860GEN q = int2u(n);861c = subii(addiu(q,1), F2xq_elltracej(a, a6, T, q, n));862}863return gerepileuptoint(av, c);864}865866/***********************************************************************/867/** **/868/** Group structure **/869/** **/870/***********************************************************************/871872static GEN873_F2xqE_pairorder(void *E, GEN P, GEN Q, GEN m, GEN F)874{875struct _F2xqE *e = (struct _F2xqE *) E;876return F2xq_order(F2xqE_weilpairing(P,Q,m,e->a2,e->T), F, e->T);877}878879GEN880F2xq_ellgroup(GEN a2, GEN a6, GEN N, GEN T, GEN *pt_m)881{882struct _F2xqE e;883GEN q = int2u(F2x_degree(T));884e.a2=a2; e.a6=a6; e.T=T;885return gen_ellgroup(N, subiu(q,1), pt_m, (void*)&e, &F2xqE_group,886_F2xqE_pairorder);887}888889GEN890F2xq_ellgens(GEN a2, GEN a6, GEN ch, GEN D, GEN m, GEN T)891{892GEN P;893pari_sp av = avma;894struct _F2xqE e;895e.a2=a2; e.a6=a6; e.T=T;896switch(lg(D)-1)897{898case 0:899return cgetg(1,t_VEC);900case 1:901P = gen_gener(gel(D,1), (void*)&e, &F2xqE_group);902P = mkvec(F2xqE_changepoint(P, ch, T));903break;904default:905P = gen_ellgens(gel(D,1), gel(D,2), m, (void*)&e, &F2xqE_group,906_F2xqE_pairorder);907gel(P,1) = F2xqE_changepoint(gel(P,1), ch, T);908gel(P,2) = F2xqE_changepoint(gel(P,2), ch, T);909break;910}911return gerepilecopy(av, P);912}913914915