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 Fq,20small characteristic. */2122/***********************************************************************/23/** **/24/** FlxqE **/25/** **/26/***********************************************************************/2728/* Theses functions deal with point over elliptic curves over Fq defined29* by an equation of the form y^2=x^3+a4*x+a6.30* Most of the time a6 is omitted since it can be recovered from any point31* on the curve.32*/3334GEN35RgE_to_FlxqE(GEN x, GEN T, ulong p)36{37if (ell_is_inf(x)) return x;38retmkvec2(Rg_to_Flxq(gel(x,1),T,p),Rg_to_Flxq(gel(x,2),T,p));39}4041GEN42FlxqE_changepoint(GEN x, GEN ch, GEN T, ulong p)43{44pari_sp av = avma;45GEN p1,z,u,r,s,t,v,v2,v3;46if (ell_is_inf(x)) return x;47u = gel(ch,1); r = gel(ch,2);48s = gel(ch,3); t = gel(ch,4);49v = Flxq_inv(u, T, p); v2 = Flxq_sqr(v, T, p); v3 = Flxq_mul(v,v2, T, p);50p1 = Flx_sub(gel(x,1),r, p);51z = cgetg(3,t_VEC);52gel(z,1) = Flxq_mul(v2, p1, T, p);53gel(z,2) = Flxq_mul(v3, Flx_sub(gel(x,2), Flx_add(Flxq_mul(s, p1, T, p),t, p), p), T, p);54return gerepileupto(av, z);55}5657GEN58FlxqE_changepointinv(GEN x, GEN ch, GEN T, ulong p)59{60GEN u, r, s, t, X, Y, u2, u3, u2X, z;61if (ell_is_inf(x)) return x;62X = gel(x,1); Y = gel(x,2);63u = gel(ch,1); r = gel(ch,2);64s = gel(ch,3); t = gel(ch,4);65u2 = Flxq_sqr(u, T, p); u3 = Flxq_mul(u,u2, T, p);66u2X = Flxq_mul(u2,X, T, p);67z = cgetg(3, t_VEC);68gel(z,1) = Flx_add(u2X,r, p);69gel(z,2) = Flx_add(Flxq_mul(u3,Y, T, p), Flx_add(Flxq_mul(s,u2X, T, p), t, p), p);70return z;71}7273static GEN74nonsquare_Flxq(GEN T, ulong p)75{76pari_sp av = avma;77long n = degpol(T), vs = T[1];78GEN a;79if (odd(n))80return mkvecsmall2(vs, nonsquare_Fl(p));81do82{83set_avma(av);84a = random_Flx(n, vs, p);85} while (Flxq_issquare(a, T, p));86return a;87}8889void90Flxq_elltwist(GEN a, GEN a6, GEN T, ulong p, GEN *pt_a, GEN *pt_a6)91{92GEN d = nonsquare_Flxq(T, p);93GEN d2 = Flxq_sqr(d, T, p), d3 = Flxq_mul(d2, d, T, p);94if (typ(a)==t_VECSMALL)95{96*pt_a = Flxq_mul(a, d2, T, p);97*pt_a6 = Flxq_mul(a6, d3, T, p);98} else99{100*pt_a = mkvec(Flxq_mul(gel(a,1), d, T, p));101*pt_a6 = Flxq_mul(a6, d3, T, p);102}103}104105static GEN106FlxqE_dbl_slope(GEN P, GEN a4, GEN T, ulong p, GEN *slope)107{108GEN x, y, Q;109if (ell_is_inf(P) || !lgpol(gel(P,2))) return ellinf();110x = gel(P,1); y = gel(P,2);111if (p==3UL)112*slope = typ(a4)==t_VEC ? Flxq_div(Flxq_mul(x, gel(a4, 1), T, p), y, T, p)113: Flxq_div(a4, Flx_neg(y, p), T, p);114else115{116GEN sx = Flx_add(Flx_triple(Flxq_sqr(x, T, p), p), a4, p);117*slope = Flxq_div(sx, Flx_double(y, p), T, p);118}119Q = cgetg(3,t_VEC);120gel(Q, 1) = Flx_sub(Flxq_sqr(*slope, T, p), Flx_double(x, p), p);121if (typ(a4)==t_VEC) gel(Q, 1) = Flx_sub(gel(Q, 1), gel(a4, 1), p);122gel(Q, 2) = Flx_sub(Flxq_mul(*slope, Flx_sub(x, gel(Q, 1), p), T, p), y, p);123return Q;124}125126GEN127FlxqE_dbl(GEN P, GEN a4, GEN T, ulong p)128{129pari_sp av = avma;130GEN slope;131return gerepileupto(av, FlxqE_dbl_slope(P,a4, T, p,&slope));132}133134static GEN135FlxqE_add_slope(GEN P, GEN Q, GEN a4, GEN T, ulong p, GEN *slope)136{137GEN Px, Py, Qx, Qy, R;138if (ell_is_inf(P)) return Q;139if (ell_is_inf(Q)) return P;140Px = gel(P,1); Py = gel(P,2);141Qx = gel(Q,1); Qy = gel(Q,2);142if (Flx_equal(Px, Qx))143{144if (Flx_equal(Py, Qy))145return FlxqE_dbl_slope(P, a4, T, p, slope);146else147return ellinf();148}149*slope = Flxq_div(Flx_sub(Py, Qy, p), Flx_sub(Px, Qx, p), T, p);150R = cgetg(3,t_VEC);151gel(R, 1) = Flx_sub(Flx_sub(Flxq_sqr(*slope, T, p), Px, p), Qx, p);152if (typ(a4)==t_VEC) gel(R, 1) = Flx_sub(gel(R, 1),gel(a4, 1), p);153gel(R, 2) = Flx_sub(Flxq_mul(*slope, Flx_sub(Px, gel(R, 1), p), T, p), Py, p);154return R;155}156157GEN158FlxqE_add(GEN P, GEN Q, GEN a4, GEN T, ulong p)159{160pari_sp av = avma;161GEN slope;162return gerepileupto(av, FlxqE_add_slope(P,Q,a4, T, p,&slope));163}164165static GEN166FlxqE_neg_i(GEN P, ulong p)167{168if (ell_is_inf(P)) return P;169return mkvec2(gel(P,1), Flx_neg(gel(P,2), p));170}171172GEN173FlxqE_neg(GEN P, GEN T, ulong p)174{175(void) T;176if (ell_is_inf(P)) return ellinf();177return mkvec2(gcopy(gel(P,1)), Flx_neg(gel(P,2), p));178}179180GEN181FlxqE_sub(GEN P, GEN Q, GEN a4, GEN T, ulong p)182{183pari_sp av = avma;184GEN slope;185return gerepileupto(av, FlxqE_add_slope(P, FlxqE_neg_i(Q, p), a4, T, p, &slope));186}187188struct _FlxqE189{190GEN a4, a6;191GEN T;192ulong p;193};194195static GEN196_FlxqE_dbl(void *E, GEN P)197{198struct _FlxqE *ell = (struct _FlxqE *) E;199return FlxqE_dbl(P, ell->a4, ell->T, ell->p);200}201202static GEN203_FlxqE_add(void *E, GEN P, GEN Q)204{205struct _FlxqE *ell=(struct _FlxqE *) E;206return FlxqE_add(P, Q, ell->a4, ell->T, ell->p);207}208209static GEN210_FlxqE_mul(void *E, GEN P, GEN n)211{212pari_sp av = avma;213struct _FlxqE *e=(struct _FlxqE *) E;214long s = signe(n);215if (!s || ell_is_inf(P)) return ellinf();216if (s<0) P = FlxqE_neg(P, e->T, e->p);217if (is_pm1(n)) return s>0? gcopy(P): P;218return gerepilecopy(av, gen_pow_i(P, n, e, &_FlxqE_dbl, &_FlxqE_add));219}220221GEN222FlxqE_mul(GEN P, GEN n, GEN a4, GEN T, ulong p)223{224struct _FlxqE E;225E.a4= a4; E.T = T; E.p = p;226return _FlxqE_mul(&E, P, n);227}228229/* 3*x^2+2*a2*x = -a2*x, and a2!=0 */230231/* Finds a random nonsingular point on E */232static GEN233random_F3xqE(GEN a2, GEN a6, GEN T)234{235pari_sp ltop = avma;236GEN x, y, rhs;237const ulong p = 3;238do239{240set_avma(ltop);241x = random_Flx(get_Flx_degree(T),get_Flx_var(T),p);242rhs = Flx_add(Flxq_mul(Flxq_sqr(x, T, p), Flx_add(x, a2, p), T, p), a6, p);243} while ((!lgpol(rhs) && !lgpol(x)) || !Flxq_issquare(rhs, T, p));244y = Flxq_sqrt(rhs, T, p);245if (!y) pari_err_PRIME("random_F3xqE", T);246return gerepilecopy(ltop, mkvec2(x, y));247}248249/* Finds a random nonsingular point on E */250GEN251random_FlxqE(GEN a4, GEN a6, GEN T, ulong p)252{253pari_sp ltop = avma;254GEN x, x2, y, rhs;255if (typ(a4)==t_VEC)256return random_F3xqE(gel(a4,1), a6, T);257do258{259set_avma(ltop);260x = random_Flx(get_Flx_degree(T),get_Flx_var(T),p);261x2 = Flxq_sqr(x, T, p); /* x^3+a4*x+a6 = x*(x^2+a4)+a6 */262rhs = Flx_add(Flxq_mul(x, Flx_add(x2, a4, p), T, p), a6, p);263} while ((!lgpol(rhs) && !lgpol(Flx_add(Flx_triple(x2, p), a4, p)))264|| !Flxq_issquare(rhs, T, p));265y = Flxq_sqrt(rhs, T, p);266if (!y) pari_err_PRIME("random_FlxqE", T);267return gerepilecopy(ltop, mkvec2(x, y));268}269270static GEN271_FlxqE_rand(void *E)272{273struct _FlxqE *ell=(struct _FlxqE *) E;274return random_FlxqE(ell->a4, ell->a6, ell->T, ell->p);275}276277static const struct bb_group FlxqE_group={_FlxqE_add,_FlxqE_mul,_FlxqE_rand,hash_GEN,zvV_equal,ell_is_inf, NULL};278279const struct bb_group *280get_FlxqE_group(void ** pt_E, GEN a4, GEN a6, GEN T, ulong p)281{282struct _FlxqE *e = (struct _FlxqE *) stack_malloc(sizeof(struct _FlxqE));283e->a4 = a4; e->a6 = a6; e->T = Flx_get_red(T, p); e->p = p;284*pt_E = (void *) e;285return &FlxqE_group;286}287288GEN289FlxqE_order(GEN z, GEN o, GEN a4, GEN T, ulong p)290{291pari_sp av = avma;292struct _FlxqE e;293e.a4=a4; e.T=T; e.p=p;294return gerepileuptoint(av, gen_order(z, o, (void*)&e, &FlxqE_group));295}296297GEN298FlxqE_log(GEN a, GEN b, GEN o, GEN a4, GEN T, ulong p)299{300pari_sp av = avma;301struct _FlxqE e;302e.a4=a4; e.T=T; e.p=p;303return gerepileuptoint(av, gen_PH_log(a, b, o, (void*)&e, &FlxqE_group));304}305306/***********************************************************************/307/** **/308/** Pairings **/309/** **/310/***********************************************************************/311312/* Derived from APIP from and by Jerome Milan, 2012 */313314static GEN315FlxqE_vert(GEN P, GEN Q, GEN a4, GEN T, ulong p)316{317long vT = get_Flx_var(T);318GEN df;319if (ell_is_inf(P))320return pol1_Flx(vT);321if (!Flx_equal(gel(Q, 1), gel(P, 1)))322return Flx_sub(gel(Q, 1), gel(P, 1), p);323if (lgpol(gel(P,2))!=0) return pol1_Flx(vT);324df = typ(a4)==t_VEC ? Flxq_mul(gel(P,1), Flx_mulu(gel(a4, 1), 2, p), T, p)325: a4;326return Flxq_inv(Flx_add(Flx_mulu(Flxq_sqr(gel(P,1), T, p), 3, p),327df, p), T, p);328}329330static GEN331FlxqE_Miller_line(GEN R, GEN Q, GEN slope, GEN a4, GEN T, ulong p)332{333long vT = get_Flx_var(T);334GEN x = gel(Q, 1), y = gel(Q, 2);335GEN tmp1 = Flx_sub(x, gel(R, 1), p);336GEN tmp2 = Flx_add(Flxq_mul(tmp1, slope, T, p), gel(R, 2), p);337if (!Flx_equal(y, tmp2))338return Flx_sub(y, tmp2, p);339if (lgpol(y) == 0)340return pol1_Flx(vT);341else342{343GEN s1, s2, a2 = typ(a4)==t_VEC ? gel(a4,1): NULL;344GEN y2i = Flxq_inv(Flx_mulu(y, 2, p), T, p);345GEN df = a2 ? Flxq_mul(x, Flx_mulu(a2, 2, p), T, p): a4;346GEN x3, ddf;347s1 = Flxq_mul(Flx_add(Flx_mulu(Flxq_sqr(x, T, p), 3, p), df, p), y2i, T, p);348if (!Flx_equal(s1, slope))349return Flx_sub(s1, slope, p);350x3 = Flx_mulu(x, 3, p);351ddf = a2 ? Flx_add(x3, a2, p): x3;352s2 = Flxq_mul(Flx_sub(ddf, Flxq_sqr(s1, T, p), p), y2i, T, p);353return lgpol(s2)!=0 ? s2: y2i;354}355}356357/* Computes the equation of the line tangent to R and returns its358* evaluation at the point Q. Also doubles the point R. */359static GEN360FlxqE_tangent_update(GEN R, GEN Q, GEN a4, GEN T, ulong p, GEN *pt_R)361{362if (ell_is_inf(R))363{364*pt_R = ellinf();365return pol1_Flx(get_Flx_var(T));366}367else if (!lgpol(gel(R,2)))368{369*pt_R = ellinf();370return FlxqE_vert(R, Q, a4, T, p);371} else {372GEN slope;373*pt_R = FlxqE_dbl_slope(R, a4, T, p, &slope);374return FlxqE_Miller_line(R, Q, slope, a4, T, p);375}376}377378/* Computes the equation of the line through R and P, and returns its379* evaluation at the point Q. Also adds P to the point R. */380static GEN381FlxqE_chord_update(GEN R, GEN P, GEN Q, GEN a4, GEN T, ulong p, GEN *pt_R)382{383if (ell_is_inf(R))384{385*pt_R = gcopy(P);386return FlxqE_vert(P, Q, a4, T, p);387}388else if (ell_is_inf(P))389{390*pt_R = gcopy(R);391return FlxqE_vert(R, Q, a4, T, p);392}393else if (Flx_equal(gel(P, 1), gel(R, 1)))394{395if (Flx_equal(gel(P, 2), gel(R, 2)))396return FlxqE_tangent_update(R, Q, a4, T, p, pt_R);397else398{399*pt_R = ellinf();400return FlxqE_vert(R, Q, a4, T, p);401}402} else {403GEN slope;404*pt_R = FlxqE_add_slope(P, R, a4, T, p, &slope);405return FlxqE_Miller_line(R, Q, slope, a4, T, p);406}407}408409struct _FlxqE_miller410{411ulong p;412GEN T, a4, P;413};414415static GEN416FlxqE_Miller_dbl(void* E, GEN d)417{418struct _FlxqE_miller *m = (struct _FlxqE_miller *)E;419ulong p = m->p;420GEN T = m->T, a4 = m->a4, P = m->P;421GEN v, line, point = gel(d,3);422GEN N = Flxq_sqr(gel(d,1), T, p);423GEN D = Flxq_sqr(gel(d,2), T, p);424line = FlxqE_tangent_update(point, P, a4, T, p, &point);425N = Flxq_mul(N, line, T, p);426v = FlxqE_vert(point, P, a4, T, p);427D = Flxq_mul(D, v, T, p); return mkvec3(N, D, point);428}429430static GEN431FlxqE_Miller_add(void* E, GEN va, GEN vb)432{433struct _FlxqE_miller *m = (struct _FlxqE_miller *)E;434ulong p = m->p;435GEN T = m->T, a4 = m->a4, P = m->P;436GEN v, line, point;437GEN na = gel(va,1), da = gel(va,2), pa = gel(va,3);438GEN nb = gel(vb,1), db = gel(vb,2), pb = gel(vb,3);439GEN N = Flxq_mul(na, nb, T, p);440GEN D = Flxq_mul(da, db, T, p);441line = FlxqE_chord_update(pa, pb, P, a4, T, p, &point);442N = Flxq_mul(N, line, T, p);443v = FlxqE_vert(point, P, a4, T, p);444D = Flxq_mul(D, v, T, p); return mkvec3(N, D, point);445}446447/* Returns the Miller function f_{m, Q} evaluated at the point P using448* the standard Miller algorithm. */449static GEN450FlxqE_Miller(GEN Q, GEN P, GEN m, GEN a4, GEN T, ulong p)451{452pari_sp av = avma;453struct _FlxqE_miller d;454GEN v, N, D, g1;455456d.a4 = a4; d.T = T; d.p = p; d.P = P;457g1 = pol1_Flx(get_Flx_var(T));458v = gen_pow_i(mkvec3(g1,g1,Q), m, (void*)&d,459FlxqE_Miller_dbl, FlxqE_Miller_add);460N = gel(v,1); D = gel(v,2);461return gerepileupto(av, Flxq_div(N, D, T, p));462}463464GEN465FlxqE_weilpairing(GEN P, GEN Q, GEN m, GEN a4, GEN T, ulong p)466{467pari_sp av = avma;468GEN N, D, result;469if (ell_is_inf(P) || ell_is_inf(Q)470|| (Flx_equal(gel(P,1),gel(Q,1)) && Flx_equal(gel(P,2),gel(Q,2))))471return pol1_Flx(get_Flx_var(T));472N = FlxqE_Miller(P, Q, m, a4, T, p);473D = FlxqE_Miller(Q, P, m, a4, T, p);474result = Flxq_div(N, D, T, p);475if (mpodd(m)) result = Flx_neg(result, p);476return gerepileupto(av, result);477}478479GEN480FlxqE_tatepairing(GEN P, GEN Q, GEN m, GEN a4, GEN T, ulong p)481{482if (ell_is_inf(P) || ell_is_inf(Q)) return pol1_Flx(get_Flx_var(T));483return FlxqE_Miller(P, Q, m, a4, T, p);484}485486static GEN487_FlxqE_pairorder(void *E, GEN P, GEN Q, GEN m, GEN F)488{489struct _FlxqE *e = (struct _FlxqE *) E;490return Flxq_order(FlxqE_weilpairing(P,Q,m,e->a4,e->T,e->p), F, e->T, e->p);491}492493GEN494Flxq_ellgroup(GEN a4, GEN a6, GEN N, GEN T, ulong p, GEN *pt_m)495{496struct _FlxqE e;497GEN q = powuu(p, get_Flx_degree(T));498e.a4=a4; e.a6=a6; e.T=T; e.p=p;499return gen_ellgroup(N, subiu(q,1), pt_m, (void*)&e, &FlxqE_group, _FlxqE_pairorder);500}501502GEN503Flxq_ellgens(GEN a4, GEN a6, GEN ch, GEN D, GEN m, GEN T, ulong p)504{505GEN P;506pari_sp av = avma;507struct _FlxqE e;508e.a4=a4; e.a6=a6; e.T=T; e.p=p;509switch(lg(D)-1)510{511case 0:512return cgetg(1,t_VEC);513case 1:514P = gen_gener(gel(D,1), (void*)&e, &FlxqE_group);515P = mkvec(FlxqE_changepoint(P, ch, T, p));516break;517default:518P = gen_ellgens(gel(D,1), gel(D,2), m, (void*)&e, &FlxqE_group, _FlxqE_pairorder);519gel(P,1) = FlxqE_changepoint(gel(P,1), ch, T, p);520gel(P,2) = FlxqE_changepoint(gel(P,2), ch, T, p);521break;522}523return gerepilecopy(av, P);524}525/***********************************************************************/526/** **/527/** Point counting **/528/** **/529/***********************************************************************/530531/* assume a and n are coprime */532static GEN533RgX_circular_shallow(GEN P, long a, long n)534{535long i, l = lgpol(P);536GEN Q = cgetg(2+n,t_POL);537Q[1] = P[1];538for(i=0; i<l; i++)539gel(Q,2+(i*a)%n) = gel(P,2+i);540for( ; i<n; i++)541gel(Q,2+(i*a)%n) = gen_0;542return normalizepol_lg(Q,2+n);543}544545static GEN546ZpXQ_frob_cyc(GEN x, GEN T, GEN q, ulong p)547{548long n = get_FpX_degree(T);549return FpX_rem(RgX_circular_shallow(x,p,n+1), T, q);550}551552static GEN553ZpXQ_frob(GEN x, GEN Xm, GEN T, GEN q, ulong p)554{555if (lg(Xm)==1)556return ZpXQ_frob_cyc(x, T, q, p);557else558{559long n = get_FpX_degree(T);560GEN V = RgX_blocks(RgX_inflate(x, p), n, p);561GEN W = ZXV_dotproduct(V, Xm);562return FpX_rem(W, T, q);563}564}565566struct _lift_lin567{568ulong p;569GEN sqx, Tp;570GEN ai, Xm;571};572573static GEN _lift_invl(void *E, GEN x)574{575struct _lift_lin *d = (struct _lift_lin *) E;576GEN T = d->Tp;577ulong p = d->p;578GEN xai = Flxq_mul(ZX_to_Flx(x, p), d->ai, T, p);579return Flx_to_ZX(Flxq_lroot_fast(xai, d->sqx, T, p));580}581582static GEN _lift_lin(void *E, GEN F, GEN x2, GEN q)583{584struct _lift_lin *d = (struct _lift_lin *) E;585pari_sp av = avma;586GEN T = gel(F,3), Xm = gel(F,4);587GEN y2 = ZpXQ_frob(x2, Xm, T, q, d->p);588GEN lin = FpX_add(ZX_mul(gel(F,1), y2), ZX_mul(gel(F,2), x2), q);589return gerepileupto(av, FpX_rem(lin, T, q));590}591592static GEN593FpM_FpXV_bilinear(GEN P, GEN X, GEN Y, GEN p)594{595pari_sp av = avma;596GEN s = ZX_mul(FpXV_FpC_mul(X,gel(P,1),p),gel(Y,1));597long i, l = lg(P);598for(i=2; i<l; i++)599s = ZX_add(s, ZX_mul(FpXV_FpC_mul(X,gel(P,i),p),gel(Y,i)));600return gerepileupto(av, FpX_red(s, p));601}602603static GEN604FpM_FpXQV_bilinear(GEN P, GEN X, GEN Y, GEN T, GEN p)605{606return FpX_rem(FpM_FpXV_bilinear(P,X,Y,p),T,p);607}608609static GEN610FpXC_powderiv(GEN M, GEN p)611{612long i, l;613long v = varn(gel(M,2));614GEN m = cgetg_copy(M, &l);615gel(m,1) = pol_0(v);616gel(m,2) = pol_1(v);617for(i=2; i<l-1; i++)618gel(m,i+1) = FpX_Fp_mul(gel(M,i),utoi(i), p);619return m;620}621622struct _lift_iso623{624GEN phi;625GEN Xm,T;626GEN sqx, Tp;627ulong p;628};629630static GEN631_lift_iter(void *E, GEN x2, GEN q)632{633struct _lift_iso *d = (struct _lift_iso *) E;634ulong p = d->p;635long n = lg(d->phi)-2;636GEN TN = FpXT_red(d->T, q), XN = FpXV_red(d->Xm, q);637GEN y2 = ZpXQ_frob(x2, XN, TN, q, p);638GEN xp = FpXQ_powers(x2, n, TN, q);639GEN yp = FpXQ_powers(y2, n, TN, q);640GEN V = FpM_FpXQV_bilinear(d->phi,xp,yp,TN,q);641return mkvec3(V,xp,yp);642}643644static GEN645_lift_invd(void *E, GEN V, GEN v, GEN qM, long M)646{647struct _lift_iso *d = (struct _lift_iso *) E;648struct _lift_lin e;649ulong p = d->p;650GEN TM = FpXT_red(d->T, qM), XM = FpXV_red(d->Xm, qM);651GEN xp = FpXV_red(gel(v,2), qM);652GEN yp = FpXV_red(gel(v,3), qM);653GEN Dx = FpM_FpXQV_bilinear(d->phi, FpXC_powderiv(xp, qM), yp, TM, qM);654GEN Dy = FpM_FpXQV_bilinear(d->phi, xp, FpXC_powderiv(yp, qM), TM, qM);655GEN F = mkvec4(Dy, Dx, TM, XM);656e.ai = Flxq_inv(ZX_to_Flx(Dy,p),d->Tp,p);657e.sqx = d->sqx; e.Tp = d->Tp; e.p=p; e.Xm = XM;658return gen_ZpX_Dixon(F,V,qM,utoipos(p),M,(void*) &e, _lift_lin, _lift_invl);659}660661static GEN662lift_isogeny(GEN phi, GEN x0, long n, GEN Xm, GEN T, GEN sqx, GEN Tp, ulong p)663{664struct _lift_iso d;665d.phi=phi;666d.Xm=Xm; d.T=T;667d.sqx=sqx; d.Tp=Tp; d.p=p;668return gen_ZpX_Newton(x0, utoipos(p), n,(void*)&d, _lift_iter, _lift_invd);669}670671static GEN672getc2(GEN act, GEN X, GEN T, GEN q, ulong p, long N)673{674GEN A1 = RgV_to_RgX(gel(act,1),0), A2 = RgV_to_RgX(gel(act,2),0);675long n = brent_kung_optpow(maxss(degpol(A1),degpol(A2)),2,1);676GEN xp = FpXQ_powers(X,n,T,q);677GEN P = FpX_FpXQV_eval(A1, xp, T, q);678GEN Q = FpX_FpXQV_eval(A2, xp, T, q);679return ZpXQ_div(P, Q, T, q, utoipos(p), N);680}681682struct _ZpXQ_norm683{684long n;685GEN T, p;686};687688static GEN689ZpXQ_norm_mul(void *E, GEN x, GEN y)690{691struct _ZpXQ_norm *D = (struct _ZpXQ_norm*)E;692GEN P = gel(x,1), Q = gel(y,1);693long a = mael(x,2,1), b = mael(y,2,1);694retmkvec2(FpXQ_mul(P,ZpXQ_frob_cyc(Q, D->T, D->p, a), D->T, D->p),695mkvecsmall((a*b)%D->n));696}697698static GEN699ZpXQ_norm_sqr(void *E, GEN x)700{701return ZpXQ_norm_mul(E, x, x);702}703704/* Assume T = Phi_(n) and n prime */705GEN706ZpXQ_norm_pcyc(GEN x, GEN T, GEN q, GEN p)707{708GEN z;709struct _ZpXQ_norm D;710long d = get_FpX_degree(T);711D.T = T; D.p = q; D.n = d+1;712if (d==1) return ZX_copy(x);713z = mkvec2(x,mkvecsmall(p[2]));714z = gen_powu_i(z,d,(void*)&D,ZpXQ_norm_sqr,ZpXQ_norm_mul);715return gmael(z,1,2);716}717718/* Assume T = Phi_(n) and n prime */719static GEN720ZpXQ_sqrtnorm_pcyc(GEN x, GEN T, GEN q, GEN p, long e)721{722GEN z = ZpXQ_norm_pcyc(x, T, q, p);723return Zp_sqrtlift(z,Fp_sqrt(z,p),p,e);724}725726/* Assume a = 1 [p], return the square root of the norm */727static GEN728ZpXQ_sqrtnorm(GEN a, GEN T, GEN q, GEN p, long e)729{730GEN s = Fp_div(FpXQ_trace(ZpXQ_log(a, T, p, e), T, q), gen_2, q);731return modii(gel(Qp_exp(cvtop(s, p, e-1)),4), q);732}733734struct _teich_lin735{736ulong p;737GEN sqx, Tp;738long m;739};740741static GEN742_teich_invl(void *E, GEN x)743{744struct _teich_lin *d = (struct _teich_lin *) E;745ulong p = d->p;746GEN T = d->Tp;747return Flx_to_ZX(Flxq_lroot_fast(ZX_to_Flx(x, p), d->sqx, T, p));748}749750static GEN751_teich_lin(void *E, GEN F, GEN x2, GEN q)752{753struct _teich_lin *d = (struct _teich_lin *) E;754pari_sp av = avma;755GEN T = gel(F,2), Xm = gel(F,3);756GEN y2 = ZpXQ_frob(x2, Xm, T, q, d->p);757GEN lin = FpX_sub(y2, ZX_mulu(ZX_mul(gel(F,1), x2), d->p), q);758return gerepileupto(av, FpX_rem(lin, T, q));759}760761struct _teich_iso762{763GEN Xm, T;764GEN sqx, Tp;765ulong p;766};767768static GEN769_teich_iter(void *E, GEN x2, GEN q)770{771struct _teich_iso *d = (struct _teich_iso *) E;772ulong p = d->p;773GEN TN = FpXT_red(d->T, q), XN = FpXV_red(d->Xm, q);774GEN y2 = ZpXQ_frob(x2, XN, TN, q, d->p);775GEN x1 = FpXQ_powu(x2, p-1, TN, q);776GEN xp = FpXQ_mul(x2, x1, TN, q);777GEN V = FpX_sub(y2,xp,q);778return mkvec2(V,x1);779}780781static GEN782_teich_invd(void *E, GEN V, GEN v, GEN qM, long M)783{784struct _teich_iso *d = (struct _teich_iso *) E;785struct _teich_lin e;786ulong p = d->p;787GEN TM = FpXT_red(d->T, qM), XM = FpXV_red(d->Xm, qM);788GEN x1 = FpX_red(gel(v,2), qM);789GEN F = mkvec3(x1, TM, XM);790e.sqx = d->sqx; e.Tp = d->Tp; e.p=p;791return gen_ZpX_Dixon(F,V,qM,utoipos(p),M,(void*) &e, _teich_lin, _teich_invl);792}793794static GEN795Teichmuller_lift(GEN x, GEN Xm, GEN T, GEN sqx, GEN Tp, ulong p, long N)796{797struct _teich_iso d;798d.Xm = Xm; d.T = T; d.sqx = sqx; d.Tp = Tp; d.p = p;799return gen_ZpX_Newton(x,utoipos(p), N,(void*)&d, _teich_iter, _teich_invd);800}801802static GEN803get_norm(GEN a4, GEN a6, GEN T, ulong p, long N)804{805long sv=T[1];806GEN a;807if (p==3) a = gel(a4,1);808else809{810GEN P = mkpoln(4, pol1_Flx(sv), pol0_Flx(sv), a4, a6);811a = gel(FlxqX_powu(P,p>>1,T,p),2+p-1);812}813return Zp_sqrtnlift(gen_1,subss(p,1),utoi(Flxq_norm(a,T,p)),utoipos(p), N);814}815816static GEN817fill_pols(long n, const long *v, long m, const long *vn,818const long *vd, GEN *act)819{820long i, j;821long d = upowuu(n,12/(n-1));822GEN N, D, M = zeromatcopy(n+1,n+1);823gmael(M,1,n+1) = gen_1;824for(i=2;i<=n+1;i++)825for(j=i-1;j<=n;j++)826gmael(M,i,j) = mulis(powuu(d,i-2),v[j-i+1]);827N = cgetg(m+1,t_COL);828D = cgetg(m+1,t_COL);829for(i=1;i<=m;i++)830{831gel(N,i) = stoi(*vn++);832gel(D,i) = stoi(*vd++);833}834*act = mkmat2(N,D);835return M;836}837838/*839These polynomials were extracted from the ECHIDNA databases840available at <http://echidna.maths.usyd.edu.au/echidna/>841and computed by David R. Kohel.842Return the matrix of the modular polynomial, set act to the parametrization,843and set dj to the opposite of the supersingular j-invariant.844*/845static GEN846get_Kohel_polynomials(ulong p, GEN *act, long *dj)847{848const long mat3[] = {-1,-36,-270};849const long num3[] = {1,-483,-21141,-59049};850const long den3[] = {1,261, 4347, -6561};851const long mat5[] = {-1,-30,-315,-1300,-1575};852const long num5[] = {-1,490,20620,158750,78125};853const long den5[] = {-1,-254,-4124,-12250,3125};854const long mat7[] = {-1,-28,-322,-1904,-5915,-8624,-4018};855const long num7[] = {1,-485,-24058,-343833,-2021642,-4353013,-823543};856const long den7[] = {1,259,5894,49119,168406,166355,-16807};857const long mat13[]= {-1,-26,-325,-2548,-13832,-54340,-157118,-333580,-509366,858-534820,-354536,-124852,-15145};859const long num13[]= {1,-487,-24056,-391463,-3396483,-18047328,-61622301,860-133245853,-168395656,-95422301,-4826809};861const long den13[]= {1,257,5896,60649,364629,1388256,3396483,5089019,4065464,8621069939,-28561};863switch(p)864{865case 3:866*dj = 0;867return fill_pols(3,mat3,4,num3,den3,act);868case 5:869*dj = 0;870return fill_pols(5,mat5,5,num5,den5,act);871case 7:872*dj = 1;873return fill_pols(7,mat7,7,num7,den7,act);874case 13:875*dj = 8;876return fill_pols(13,mat13,11,num13,den13,act);877}878*dj=0; *act = NULL; return NULL; /* LCOV_EXCL_LINE */879}880881long882zx_is_pcyc(GEN T)883{884long i, n = degpol(T);885if (!uisprime(n+1))886return 0;887for (i=0; i<=n; i++)888if (T[i+2]!=1UL)889return 0;890return 1;891}892893static GEN894Flxq_ellcard_Kohel(GEN a4, GEN a6, GEN T, ulong p)895{896pari_sp av = avma, av2;897pari_timer ti;898long n = get_Flx_degree(T), N = (n+4)/2, dj;899GEN q = powuu(p, N);900GEN T2, Xm, s1, c2, t, lr;901GEN S1, sqx;902GEN Nc2, Np;903GEN act, phi = get_Kohel_polynomials(p, &act, &dj);904long ispcyc = zx_is_pcyc(get_Flx_mod(T));905timer_start(&ti);906if (!ispcyc)907{908T2 = Flx_Teichmuller(get_Flx_mod(T),p,N);909if (DEBUGLEVEL) timer_printf(&ti,"Teich");910} else911T2 = Flx_to_ZX(get_Flx_mod(T));912T2 = FpX_get_red(T2, q); T = ZXT_to_FlxT(T2, p);913av2 = avma;914if (DEBUGLEVEL) timer_printf(&ti,"Barrett");915if (!ispcyc)916{917Xm = FpXQ_powers(pol_xn(n,get_FpX_var(T2)),p-1,T2,q);918if (DEBUGLEVEL) timer_printf(&ti,"Xm");919} else920Xm = cgetg(1,t_VEC);921s1 = Flxq_inv(Flx_Fl_add(Flxq_ellj(a4,a6,T,p),dj, p),T,p);922lr = Flxq_lroot(polx_Flx(get_Flx_var(T)), T, p);923sqx = Flxq_powers(lr, p-1, T, p);924S1 = lift_isogeny(phi, Flx_to_ZX(s1), N, Xm, T2, sqx, T ,p);925if (DEBUGLEVEL) timer_printf(&ti,"Lift isogeny");926c2 = getc2(act, S1, T2, q, p, N);927if (DEBUGLEVEL) timer_printf(&ti,"c^2");928if (p>3 && !ispcyc)929{930GEN c2p = Flx_to_ZX(Flxq_inv(ZX_to_Flx(c2,p),T,p));931GEN tc2 = Teichmuller_lift(c2p,Xm, T2,sqx,T,p,N);932if (DEBUGLEVEL) timer_printf(&ti,"Teichmuller/Fq");933c2 = FpX_rem(FpX_mul(tc2,c2,q),T2,q);934}935c2 = gerepileupto(av2, c2);936if (DEBUGLEVEL) timer_printf(&ti,"tc2");937Nc2 = (ispcyc? ZpXQ_sqrtnorm_pcyc: ZpXQ_sqrtnorm)(c2, T2, q, utoipos(p), N);938if (DEBUGLEVEL) timer_printf(&ti,"Norm");939Np = get_norm(a4,a6,T,p,N);940if (p>3 && ispcyc)941{942GEN Ncpi = utoi(Fl_inv(umodiu(Nc2,p), p));943GEN tNc2 = Zp_sqrtnlift(gen_1, subss(p,1), Ncpi, utoipos(p),N);944if (DEBUGLEVEL) timer_printf(&ti,"Teichmuller/Fp");945Nc2 = Fp_mul(Nc2,tNc2,q);946}947t = Fp_center_i(Fp_mul(Nc2,Np,q),q,shifti(q,-1));948return gerepileupto(av, subii(addiu(powuu(p,n),1),t));949}950951/* Use Damien Robert method */952953static GEN954get_trace_Robert(GEN J, GEN phi, GEN Xm, GEN T, GEN q, ulong p, long e)955{956long n = lg(phi)-2;957GEN K = ZpXQ_frob(J, Xm, T, q, p);958GEN Jp = FpXQ_powers(J, n, T, q);959GEN Kp = FpXQ_powers(K, n, T, q);960GEN Jd = FpXC_powderiv(Jp, q);961GEN Kd = FpXC_powderiv(Kp, q);962GEN Dx = FpM_FpXQV_bilinear(phi, Kd, Jp, T, q);963GEN Dy = FpM_FpXQV_bilinear(phi, Kp, Jd, T, q);964GEN C = ZpXQ_inv(ZX_divuexact(Dy, p), T, utoi(p), e);965return FpX_neg(FpXQ_mul(Dx, C, T, q), q);966}967968static GEN969Flxq_ellcard_Harley(GEN a4, GEN a6, GEN T, ulong p)970{971pari_sp av = avma, av2;972pari_timer ti;973long n = get_Flx_degree(T), N = (n+5)/2;974GEN pp = utoipos(p), q = powuu(p, N);975GEN T2, j, t, phi;976GEN J1,sqx,Xm;977GEN c2, tc2, c2p, Nc2, Np;978long ispcyc = zx_is_pcyc(get_Flx_mod(T));979timer_start(&ti);980if (!ispcyc)981{982T2 = Flx_Teichmuller(get_Flx_mod(T),p,N);983if (DEBUGLEVEL) timer_printf(&ti,"Teich");984} else985T2 = Flx_to_ZX(get_Flx_mod(T));986T2 = FpX_get_red(T2, q); T = ZXT_to_FlxT(T2, p);987av2 = avma;988if (DEBUGLEVEL) timer_printf(&ti,"Barrett");989if (!ispcyc)990{991Xm = FpXQ_powers(pol_xn(n,get_FpX_var(T2)),p-1,T2,q);992if (DEBUGLEVEL) timer_printf(&ti,"Xm");993} else994Xm = cgetg(1,t_VEC);995j = Flxq_ellj(a4,a6,T,p);996sqx = Flxq_powers(Flxq_lroot(polx_Flx(T[1]), T, p), p-1, T, p);997phi = polmodular_ZM(p, 0);998if (DEBUGLEVEL) timer_printf(&ti,"phi");999J1 = lift_isogeny(phi, Flx_to_ZX(j), N, Xm, T2,sqx,T,p);1000if (DEBUGLEVEL) timer_printf(&ti,"Lift isogeny");1001c2 = get_trace_Robert(J1, phi, Xm, T2, q, p, N);1002q = diviuexact(q,p); N--;1003if (DEBUGLEVEL) timer_printf(&ti,"c^2");1004if (!ispcyc)1005{1006c2p = Flx_to_ZX(Flxq_inv(ZX_to_Flx(c2,p),T,p));1007tc2 = Teichmuller_lift(c2p,Xm, T2,sqx,T,p,N);1008if (DEBUGLEVEL) timer_printf(&ti,"teichmuller");1009c2 = FpX_rem(FpX_mul(tc2,c2,q),T2,q);1010}1011c2 = gerepileupto(av2, c2);1012q = powuu(p, N);1013Nc2 = (ispcyc? ZpXQ_sqrtnorm_pcyc: ZpXQ_sqrtnorm)(c2, T2, q, pp, N);1014if (DEBUGLEVEL) timer_printf(&ti,"Norm");1015Np = get_norm(a4,a6,T,p,N);1016if (ispcyc)1017{1018GEN Ncpi = utoi(Fl_inv(umodiu(Nc2,p), p));1019GEN tNc2 = Zp_sqrtnlift(gen_1, subss(p,1), Ncpi, pp, N);1020if (DEBUGLEVEL) timer_printf(&ti,"Teichmuller/Fp");1021Nc2 = Fp_mul(Nc2,tNc2,q);1022}1023t = Fp_center_i(Fp_mul(Nc2,Np,q),q,shifti(q,-1));1024return gerepileupto(av, subii(addiu(powuu(p,n),1),t));1025}10261027/***************************************************************************/1028/* */1029/* Shanks Mestre */1030/* */1031/***************************************************************************/10321033/* Return the lift of a (mod b), which is closest to h */1034static GEN1035closest_lift(GEN a, GEN b, GEN h)1036{1037return addii(a, mulii(b, diviiround(subii(h,a), b)));1038}10391040static GEN1041FlxqE_find_order(GEN f, GEN h, GEN bound, GEN B, GEN a4, GEN T, ulong p)1042{1043pari_sp av = avma, av1;1044pari_timer Ti;1045long s = itos( gceil(gsqrt(gdiv(bound,B),DEFAULTPREC)) ) >> 1;1046GEN tx, ti;1047GEN fh = FlxqE_mul(f, h, a4, T, p);1048GEN F, P = fh, fg;1049long i;1050if (DEBUGLEVEL >= 6) timer_start(&Ti);1051if (ell_is_inf(fh)) return h;1052F = FlxqE_mul(f, B, a4, T, p);1053if (s < 3)1054{ /* we're nearly done: naive search */1055GEN Q = P;1056for (i=1;; i++)1057{1058P = FlxqE_add(P, F, a4, T, p); /* h.f + i.F */1059if (ell_is_inf(P)) return gerepileupto(av, addii(h, mului(i,B)));1060Q = FlxqE_sub(Q, F, a4, T, p); /* h.f - i.F */1061if (ell_is_inf(Q)) return gerepileupto(av, subii(h, mului(i,B)));1062}1063}1064tx = cgetg(s+1,t_VECSMALL);1065/* Baby Step/Giant Step */1066av1 = avma;1067for (i=1; i<=s; i++)1068{ /* baby steps */1069tx[i] = hash_GEN(gel(P, 1));1070P = FlxqE_add(P, F, a4, T, p); /* h.f + i.F */1071if (ell_is_inf(P)) return gerepileupto(av, addii(h, mului(i,B)));1072if (gc_needed(av1,3))1073{1074if(DEBUGMEM>1) pari_warn(warnmem,"[Flxq_ellcard] baby steps, i=%ld",i);1075P = gerepileupto(av1,P);1076}1077}1078if (DEBUGLEVEL >= 6) timer_printf(&Ti, "[Flxq_ellcard] baby steps, s = %ld",s);1079/* giant steps: fg = s.F */1080fg = gerepileupto(av1, FlxqE_sub(P, fh, a4, T, p));1081if (ell_is_inf(fg)) return gerepileupto(av,mului(s,B));1082ti = vecsmall_indexsort(tx); /* = permutation sorting tx */1083tx = perm_mul(tx,ti);1084if (DEBUGLEVEL >= 6) timer_printf(&Ti, "[Flxq_ellcard] sorting");1085av1 = avma;1086for (P=fg, i=1; ; i++)1087{1088long k = hash_GEN(gel(P,1));1089long r = zv_search(tx, k);1090if (r)1091{1092while (r && tx[r] == k) r--;1093for (r++; r <= s && tx[r] == k; r++)1094{1095long j = ti[r]-1;1096GEN Q = FlxqE_add(FlxqE_mul(F, stoi(j), a4, T, p), fh, a4, T, p);1097if (DEBUGLEVEL >= 6)1098timer_printf(&Ti, "[Flxq_ellcard] giant steps, i = %ld",i);1099if (Flx_equal(gel(P,1), gel(Q,1)))1100{1101if (Flx_equal(gel(P,2), gel(Q,2))) i = -i;1102return gerepileupto(av,addii(h, mulii(addis(mulss(s,i), j), B)));1103}1104}1105}1106P = FlxqE_add(P,fg,a4,T,p);1107if (gc_needed(av1,3))1108{1109if(DEBUGMEM>1) pari_warn(warnmem,"[Flxq_ellcard] giants steps, i=%ld",i);1110P = gerepileupto(av1,P);1111}1112}1113}11141115static void1116Flx_next(GEN t, ulong p)1117{1118long i;1119for(i=2;;i++)1120if (uel(t,i)==p-1)1121t[i]=0;1122else1123{1124t[i]++;1125break;1126}1127}11281129static void1130Flx_renormalize_ip(GEN x, long lx)1131{1132long i;1133for (i = lx-1; i>=2; i--)1134if (x[i]) break;1135setlg(x, i+1);1136}11371138static ulong1139F3xq_ellcard_naive(GEN a2, GEN a6, GEN T)1140{1141pari_sp av = avma;1142long i, d = get_Flx_degree(T), lx = d+2;1143long q = upowuu(3, d), a;1144GEN x = zero_zv(lx); x[1] = get_Flx_var(T);1145for(a=1, i=0; i<q; i++)1146{1147GEN rhs;1148Flx_renormalize_ip(x, lx);1149rhs = Flx_add(Flxq_mul(Flxq_sqr(x, T, 3), Flx_add(x, a2, 3), T, 3), a6, 3);1150if (!lgpol(rhs)) a++; else if (Flxq_issquare(rhs, T, 3)) a+=2;1151Flx_next(x, 3);1152}1153set_avma(av);1154return a;1155}11561157static ulong1158Flxq_ellcard_naive(GEN a4, GEN a6, GEN T, ulong p)1159{1160pari_sp av = avma;1161long i, d = get_Flx_degree(T), lx = d+2;1162long q = upowuu(p, d), a;1163GEN x = zero_zv(lx); x[1] = get_Flx_var(T);1164for(a=1, i=0; i<q; i++)1165{1166GEN x2, rhs;1167Flx_renormalize_ip(x, lx);1168x2 = Flxq_sqr(x, T, p);1169rhs = Flx_add(Flxq_mul(x, Flx_add(x2, a4, p), T, p), a6, p);1170if (!lgpol(rhs)) a++; else if (Flxq_issquare(rhs,T,p)) a+=2;1171Flx_next(x,p);1172}1173set_avma(av);1174return a;1175}11761177/* assume T irreducible mod p, m = (q-1)/(p-1) */1178static long1179Flxq_kronecker(GEN x, GEN m, GEN T, ulong p)1180{1181pari_sp av;1182ulong z;1183if (lgpol(x) == 0) return 0;1184av = avma; z = Flxq_pow(x, m, T, p)[2];1185return gc_long(av, krouu(z, p));1186}11871188/* Find x such that kronecker(u = x^3+a4x+a6, p) is KRO.1189* Return point [x*u,u^2] on E (KRO=1) / E^twist (KRO=-1) */1190static GEN1191Flxq_ellpoint(long KRO, GEN a4, GEN a6, GEN m, long n, long vn, GEN T, ulong p)1192{1193for(;;)1194{1195GEN x = random_Flx(n,vn,p);1196GEN u = Flx_add(a6, Flxq_mul(Flx_add(a4, Flxq_sqr(x,T,p), p), x, T,p), p);1197if (Flxq_kronecker(u, m,T,p) == KRO)1198return mkvec2(Flxq_mul(u,x, T,p), Flxq_sqr(u, T,p));1199}1200}12011202static GEN1203Flxq_ellcard_Shanks(GEN a4, GEN a6, GEN q, GEN T, ulong p)1204{1205pari_sp av = avma;1206long vn = get_Flx_var(T), n = get_Flx_degree(T), KRO = -1;1207GEN h,f, ta4, A, B, m;1208GEN q1p = addiu(q,1), q2p = shifti(q1p, 1);1209GEN bound = addiu(sqrti(gmul2n(q,4)), 1); /* ceil( 4sqrt(q) ) */1210/* once #E(Flxq) is know mod B >= bound, it is completely determined */1211/* how many 2-torsion points ? */1212switch(FlxqX_nbroots(mkpoln(4, pol1_Flx(vn), pol0_Flx(vn), a4, a6), T, p))1213{1214case 3: A = gen_0; B = utoipos(4); break;1215case 1: A = gen_0; B = gen_2; break;1216default: A = gen_1; B = gen_2; break; /* 0 */1217}1218m = diviuexact(subiu(powuu(p,n), 1), p-1);1219for(;;)1220{1221h = closest_lift(A, B, q1p);1222/* [ux, u^2] is on E_u: y^2 = x^3 + c4 u^2 x + c6 u^31223* E_u isomorphic to E (resp. E') iff KRO = 1 (resp. -1)1224* #E(F_p) = p+1 - a_p, #E'(F_p) = p+1 + a_p1225*1226* #E_u(Flxq) = A (mod B), h is close to #E_u(Flxq) */1227KRO = -KRO;1228f = Flxq_ellpoint(KRO, a4,a6, m,n,vn, T,p);12291230ta4 = Flxq_mul(a4, gel(f,2), T, p); /* a4 for E_u */1231h = FlxqE_find_order(f, h, bound, B, ta4,T,p);1232h = FlxqE_order(f, h, ta4, T, p);1233/* h | #E_u(Flxq) = A (mod B) */1234A = Z_chinese_all(A, gen_0, B, h, &B);1235if (cmpii(B, bound) >= 0) break;1236/* not done, update A mod B for the _next_ curve, isomorphic to1237* the quadratic twist of this one */1238A = remii(subii(q2p,A), B); /* #E(Fq)+#E'(Fq) = 2q+2 */1239}1240h = closest_lift(A, B, q1p);1241return gerepileuptoint(av, KRO == 1? h: subii(q2p,h));1242}12431244static GEN1245F3xq_ellcard(GEN a2, GEN a6, GEN T)1246{1247long n = get_Flx_degree(T);1248if (n <= 2)1249return utoi(F3xq_ellcard_naive(a2, a6, T));1250else1251{1252GEN q1 = addiu(powuu(3, get_Flx_degree(T)), 1), t;1253GEN a = Flxq_div(a6,Flxq_powu(a2,3,T,3),T,3);1254if (Flx_equal1(Flxq_powu(a, 8, T, 3)))1255{1256GEN P = Flxq_minpoly(a,T,3);1257long dP = degpol(P); /* dP <= 2 */1258ulong q = upowuu(3,dP);1259GEN A2 = pol1_Flx(P[1]), A6 = Flx_rem(polx_Flx(P[1]), P, 3);1260long tP = q + 1 - F3xq_ellcard_naive(A2, A6, P);1261t = elltrace_extension(stoi(tP), n/dP, utoi(q));1262if (umodiu(t, 3)!=1) t = negi(t);1263return Flx_equal1(a2) || Flxq_issquare(a2,T,3) ? subii(q1,t): addii(q1,t);1264}1265else return Flxq_ellcard_Kohel(mkvec(a2), a6, T, 3);1266}1267}12681269static GEN1270Flxq_ellcard_Satoh(GEN a4, GEN a6, GEN j, GEN T, ulong p)1271{1272long n = get_Flx_degree(T);1273if (n <= 2)1274return utoi(Flxq_ellcard_naive(a4, a6, T, p));1275else1276{1277GEN jp = Flxq_powu(j, p, T, p);1278GEN s = Flx_add(j, jp, p);1279if (degpol(s) <= 0)1280{ /* it is assumed j not in F_p */1281GEN m = Flxq_mul(j, jp, T, p);1282if (degpol(m) <= 0)1283{1284GEN q = sqru(p);1285GEN q1 = addiu(powuu(p, get_Flx_degree(T)), 1);1286GEN sk = Flx_Fl_add(Flx_neg(j, p), 1728%p, p);1287GEN sA4 = Flx_triple(Flxq_mul(sk, j, T, p), p);1288GEN u = Flxq_div(a4, sA4, T, p);1289ulong ns = lgpol(s) ? Fl_neg(s[2], p): 0UL;1290GEN P = mkvecsmall4(T[1], m[2], ns, 1L);1291GEN A4, A6, t, tP;1292Flxq_ellj_to_a4a6(polx_Flx(T[1]), P, p, &A4, &A6);1293tP = addis(q, 1 - Flxq_ellcard_naive(A4, A6, P, p));1294t = elltrace_extension(tP, n>>1, q);1295return Flxq_is2npower(u, 2, T, p) ? subii(q1,t): addii(q1,t);1296}1297}1298if (p<=7 || p==13 ) return Flxq_ellcard_Kohel(a4, a6, T, p);1299else return Flxq_ellcard_Harley(a4, a6, T, p);1300}1301}13021303static GEN1304Flxq_ellcard_Kedlaya(GEN a4, GEN a6, GEN T, ulong p)1305{1306pari_sp av = avma;1307GEN H = mkpoln(4, gen_1, gen_0, Flx_to_ZX(a4), Flx_to_ZX(a6));1308GEN Tp = Flx_to_ZX(get_Flx_mod(T));1309long n = degpol(Tp), e = ((p < 16 ? n+1: n)>>1)+1;1310GEN M = ZlXQX_hyperellpadicfrobenius(H, Tp, p, e);1311GEN N = ZpXQM_prodFrobenius(M, Tp, utoipos(p), e);1312GEN q = powuu(p, e);1313GEN tp = Fq_add(gcoeff(N,1,1), gcoeff(N,2,2), Tp, q);1314GEN t = Fp_center_i(typ(tp)==t_INT ? tp: leading_coeff(tp), q, shifti(q,-1));1315return gerepileupto(av, subii(addiu(powuu(p, n), 1), t));1316}13171318GEN1319Flxq_ellj(GEN a4, GEN a6, GEN T, ulong p)1320{1321pari_sp av=avma;1322if (p==3)1323{1324GEN J;1325if (typ(a4)!=t_VEC) return pol0_Flx(get_Flx_var(T));1326J = Flxq_div(Flxq_powu(gel(a4,1),3, T, p),Flx_neg(a6,p), T, p);1327return gerepileuptoleaf(av, J);1328}1329else1330{1331pari_sp av=avma;1332GEN a43 = Flxq_mul(a4,Flxq_sqr(a4,T,p),T,p);1333GEN a62 = Flxq_sqr(a6,T,p);1334GEN num = Flx_mulu(a43,6912,p);1335GEN den = Flx_add(Flx_mulu(a43,4,p),Flx_mulu(a62,27,p),p);1336return gerepileuptoleaf(av, Flxq_div(num, den, T, p));1337}1338}13391340void1341Flxq_ellj_to_a4a6(GEN j, GEN T, ulong p, GEN *pt_a4, GEN *pt_a6)1342{1343ulong zagier = 1728 % p;1344if (lgpol(j)==0)1345{ *pt_a4 = pol0_Flx(T[1]); *pt_a6 =pol1_Flx(T[1]); }1346else if (lgpol(j)==1 && uel(j,2) == zagier)1347{ *pt_a4 = pol1_Flx(T[1]); *pt_a6 =pol0_Flx(T[1]); }1348else1349{1350GEN k = Flx_Fl_add(Flx_neg(j, p), zagier, p);1351GEN kj = Flxq_mul(k, j, T, p);1352GEN k2j = Flxq_mul(kj, k, T, p);1353*pt_a4 = Flx_triple(kj, p);1354*pt_a6 = Flx_double(k2j, p);1355}1356}13571358static GEN1359F3xq_ellcardj(GEN a4, GEN a6, GEN T, GEN q, long n)1360{1361const ulong p = 3;1362ulong t;1363GEN q1 = addiu(q,1);1364GEN na4 = Flx_neg(a4,p), ra4;1365if (!Flxq_issquare(na4,T,p))1366return q1;1367ra4 = Flxq_sqrt(na4,T,p);1368t = Flxq_trace(Flxq_div(a6,Flxq_mul(na4,ra4,T,p),T,p),T,p);1369if (n%2==1)1370{1371GEN q3;1372if (t==0) return q1;1373q3 = powuu(p,(n+1)>>1);1374return (t==1)^(n%4==1) ? subii(q1,q3): addii(q1,q3);1375}1376else1377{1378GEN q22, q2 = powuu(p,n>>1);1379GEN W = Flxq_pow(a4,shifti(q,-2),T,p);1380long s = (W[2]==1)^(n%4==2);1381if (t!=0) return s ? addii(q1,q2): subii(q1, q2);1382q22 = shifti(q2,1);1383return s ? subii(q1,q22): addii(q1, q22);1384}1385}13861387static GEN1388Flxq_ellcardj(GEN a4, GEN a6, ulong j, GEN T, GEN q, ulong p, long n)1389{1390GEN q1 = addiu(q,1);1391if (j==0)1392{1393ulong w;1394GEN W, t, N;1395if (umodiu(q,6)!=1) return q1;1396N = Fp_ffellcard(gen_0,gen_1,q,n,utoipos(p));1397t = subii(q1, N);1398W = Flxq_pow(a6,diviuexact(shifti(q,-1), 3),T,p);1399if (degpol(W)>0) /*p=5 mod 6*/1400return Flx_equal1(Flxq_powu(W,3,T,p)) ? addii(q1,shifti(t,-1)):1401subii(q1,shifti(t,-1));1402w = W[2];1403if (w==1) return N;1404if (w==p-1) return addii(q1,t);1405else /*p=1 mod 6*/1406{1407GEN u = shifti(t,-1), v = sqrtint(diviuexact(subii(q,sqri(u)),3));1408GEN a = addii(u,v), b = shifti(v,1);1409if (Fl_powu(w,3,p)==1)1410{1411if (Fl_add(umodiu(a,p),Fl_mul(w,umodiu(b,p),p),p)==0)1412return subii(q1,subii(shifti(b,1),a));1413else1414return addii(q1,addii(a,b));1415}1416else1417{1418if (Fl_sub(umodiu(a,p),Fl_mul(w,umodiu(b,p),p),p)==0)1419return subii(q1,subii(a,shifti(b,1)));1420else1421return subii(q1,addii(a,b));1422}1423}1424} else if (j==1728%p)1425{1426ulong w;1427GEN W, N, t;1428if (mod4(q)==3) return q1;1429W = Flxq_pow(a4,shifti(q,-2),T,p);1430if (degpol(W)>0) return q1; /*p=3 mod 4*/1431w = W[2];1432N = Fp_ffellcard(gen_1,gen_0,q,n,utoipos(p));1433if(w==1) return N;1434t = subii(q1, N);1435if(w==p-1) return addii(q1, t);1436else /*p=1 mod 4*/1437{1438GEN u = shifti(t,-1), v = sqrtint(subii(q,sqri(u)));1439if (Fl_add(umodiu(u,p),Fl_mul(w,umodiu(v,p),p),p)==0)1440return subii(q1,shifti(v,1));1441else1442return addii(q1,shifti(v,1));1443}1444} else1445{1446ulong g = Fl_div(j, Fl_sub(1728%p, j, p), p);1447GEN l = Flxq_div(Flx_triple(a6,p),Flx_double(a4,p),T,p);1448GEN N = Fp_ffellcard(utoi(Fl_triple(g,p)),utoi(Fl_double(g,p)),q,n,utoipos(p));1449if (Flxq_issquare(l,T,p)) return N;1450return subii(shifti(q1,1),N);1451}1452}14531454GEN1455Flxq_ellcard(GEN a4, GEN a6, GEN T, ulong p)1456{1457pari_sp av = avma;1458long n = get_Flx_degree(T);1459GEN J, r, q = powuu(p, n);1460if (typ(a4)==t_VEC)1461r = F3xq_ellcard(gel(a4,1), a6, T);1462else if (p==3)1463r = F3xq_ellcardj(a4, a6, T, q, n);1464else if (degpol(a4)<=0 && degpol(a6)<=0)1465r = Fp_ffellcard(utoi(Flx_eval(a4,0,p)),utoi(Flx_eval(a6,0,p)),q,n,utoipos(p));1466else if (degpol(J=Flxq_ellj(a4,a6,T,p))<=0)1467r = Flxq_ellcardj(a4,a6,lgpol(J)?J[2]:0,T,q,p,n);1468else if (p <= 7)1469r = Flxq_ellcard_Satoh(a4, a6, J, T, p);1470else if (cmpis(q,100)<0)1471r = utoi(Flxq_ellcard_naive(a4, a6, T, p));1472else if (p == 13 || (7*p <= (ulong)10*n && (BITS_IN_LONG==64 || p <= 103)))1473r = Flxq_ellcard_Satoh(a4, a6, J, T, p);1474else if (p <= (ulong)2*n)1475r = Flxq_ellcard_Kedlaya(a4, a6, T, p);1476else if (expi(q)<=62)1477r = Flxq_ellcard_Shanks(a4, a6, q, T, p);1478else1479r = Fq_ellcard_SEA(Flx_to_ZX(a4),Flx_to_ZX(a6),q,Flx_to_ZX(T),utoipos(p),0);1480return gerepileuptoint(av, r);1481}148214831484