Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2009 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 Fp */2021/***********************************************************************/22/** **/23/** FpJ **/24/** **/25/***********************************************************************/2627/* Arithmetic is implemented using Jacobian coordinates, representing28* a projective point (x : y : z) on E by [z*x , z^2*y , z]. This is29* probably not the fastest representation available for the given30* problem, but they're easy to implement and up to 60% faster than31* the school-book method used in FpE_mulu().32*/3334/*35* Cost: 1M + 8S + 1*a + 10add + 1*8 + 2*2 + 1*3.36* Source: http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl37*/3839GEN40FpJ_dbl(GEN P, GEN a4, GEN p)41{42GEN X1, Y1, Z1;43GEN XX, YY, YYYY, ZZ, S, M, T, Q;4445if (signe(gel(P,3)) == 0)46return gcopy(P);4748X1 = gel(P,1); Y1 = gel(P,2); Z1 = gel(P,3);4950XX = Fp_sqr(X1, p);51YY = Fp_sqr(Y1, p);52YYYY = Fp_sqr(YY, p);53ZZ = Fp_sqr(Z1, p);54S = Fp_mulu(Fp_sub(Fp_sqr(Fp_add(X1, YY, p), p),55Fp_add(XX, YYYY, p), p), 2, p);56M = Fp_addmul(Fp_mulu(XX, 3, p), a4, Fp_sqr(ZZ, p), p);57T = Fp_sub(Fp_sqr(M, p), Fp_mulu(S, 2, p), p);58Q = cgetg(4, t_VEC);59gel(Q,1) = T;60gel(Q,2) = Fp_sub(Fp_mul(M, Fp_sub(S, T, p), p),61Fp_mulu(YYYY, 8, p), p);62gel(Q,3) = Fp_sub(Fp_sqr(Fp_add(Y1, Z1, p), p),63Fp_add(YY, ZZ, p), p);64return Q;65}6667/*68* Cost: 11M + 5S + 9add + 4*2.69* Source: http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-add-2007-bl70*/7172GEN73FpJ_add(GEN P, GEN Q, GEN a4, GEN p)74{75GEN X1, Y1, Z1, X2, Y2, Z2;76GEN Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V, W, R;7778if (signe(gel(Q,3)) == 0) return gcopy(P);79if (signe(gel(P,3)) == 0) return gcopy(Q);8081X1 = gel(P,1); Y1 = gel(P,2); Z1 = gel(P,3);82X2 = gel(Q,1); Y2 = gel(Q,2); Z2 = gel(Q,3);8384Z1Z1 = Fp_sqr(Z1, p);85Z2Z2 = Fp_sqr(Z2, p);86U1 = Fp_mul(X1, Z2Z2, p);87U2 = Fp_mul(X2, Z1Z1, p);88S1 = mulii(Y1, Fp_mul(Z2, Z2Z2, p));89S2 = mulii(Y2, Fp_mul(Z1, Z1Z1, p));90H = Fp_sub(U2, U1, p);91r = Fp_mulu(Fp_sub(S2, S1, p), 2, p);9293/* If points are equal we must double. */94if (signe(H)== 0) {95if (signe(r) == 0)96/* Points are equal so double. */97return FpJ_dbl(P, a4, p);98else99return mkvec3(gen_1, gen_1, gen_0);100}101I = Fp_sqr(Fp_mulu(H, 2, p), p);102J = Fp_mul(H, I, p);103V = Fp_mul(U1, I, p);104W = Fp_sub(Fp_sqr(r, p), Fp_add(J, Fp_mulu(V, 2, p), p), p);105R = cgetg(4, t_VEC);106gel(R,1) = W;107gel(R,2) = Fp_sub(mulii(r, subii(V, W)),108shifti(mulii(S1, J), 1), p);109gel(R,3) = Fp_mul(Fp_sub(Fp_sqr(Fp_add(Z1, Z2, p), p),110Fp_add(Z1Z1, Z2Z2, p), p), H, p);111return R;112}113114GEN115FpJ_neg(GEN Q, GEN p)116{117return mkvec3(icopy(gel(Q,1)), Fp_neg(gel(Q,2), p), icopy(gel(Q,3)));118}119120GEN121FpE_to_FpJ(GEN P)122{ return ell_is_inf(P) ? mkvec3(gen_1, gen_1, gen_0):123mkvec3(icopy(gel(P,1)),icopy(gel(P,2)), gen_1);124}125126GEN127FpJ_to_FpE(GEN P, GEN p)128{129if (signe(gel(P,3)) == 0) return ellinf();130else131{132GEN Z = Fp_inv(gel(P,3), p);133GEN Z2 = Fp_sqr(Z, p), Z3 = Fp_mul(Z, Z2, p);134retmkvec2(Fp_mul(gel(P,1), Z2, p), Fp_mul(gel(P,2), Z3, p));135}136}137138struct _FpE { GEN p,a4,a6; };139static GEN140_FpJ_dbl(void *E, GEN P)141{142struct _FpE *ell = (struct _FpE *) E;143return FpJ_dbl(P, ell->a4, ell->p);144}145static GEN146_FpJ_add(void *E, GEN P, GEN Q)147{148struct _FpE *ell=(struct _FpE *) E;149return FpJ_add(P, Q, ell->a4, ell->p);150}151static GEN152_FpJ_mul(void *E, GEN P, GEN n)153{154pari_sp av = avma;155struct _FpE *e=(struct _FpE *) E;156long s = signe(n);157if (!s || ell_is_inf(P)) return ellinf();158if (s<0) P = FpJ_neg(P, e->p);159if (is_pm1(n)) return s>0? gcopy(P): P;160return gerepilecopy(av, gen_pow_i(P, n, e, &_FpJ_dbl, &_FpJ_add));161}162163GEN164FpJ_mul(GEN P, GEN n, GEN a4, GEN p)165{166struct _FpE E;167E.a4= a4; E.p = p;168return _FpJ_mul(&E, P, n);169}170171/***********************************************************************/172/** **/173/** FpE **/174/** **/175/***********************************************************************/176177/* These functions deal with point over elliptic curves over Fp defined178* by an equation of the form y^2=x^3+a4*x+a6.179* Most of the time a6 is omitted since it can be recovered from any point180* on the curve.181*/182183GEN184RgE_to_FpE(GEN x, GEN p)185{186if (ell_is_inf(x)) return x;187retmkvec2(Rg_to_Fp(gel(x,1),p),Rg_to_Fp(gel(x,2),p));188}189190GEN191FpE_to_mod(GEN x, GEN p)192{193if (ell_is_inf(x)) return x;194retmkvec2(Fp_to_mod(gel(x,1),p),Fp_to_mod(gel(x,2),p));195}196197GEN198FpE_changepoint(GEN P, GEN ch, GEN p)199{200pari_sp av = avma;201GEN c, z, u, r, s, t, v, v2, v3;202if (ell_is_inf(P)) return P;203if (lgefint(p) == 3)204{205ulong pp = p[2];206z = Fle_changepoint(ZV_to_Flv(P, pp), ZV_to_Flv(ch, pp), pp);207return gerepileupto(av, Flv_to_ZV(z));208}209u = gel(ch,1); r = gel(ch,2); s = gel(ch,3); t = gel(ch,4);210v = Fp_inv(u, p); v2 = Fp_sqr(v,p); v3 = Fp_mul(v,v2,p);211c = Fp_sub(gel(P,1),r,p);212z = cgetg(3,t_VEC);213gel(z,1) = Fp_mul(v2, c, p);214gel(z,2) = Fp_mul(v3, Fp_sub(gel(P,2), Fp_add(Fp_mul(s,c, p),t, p),p),p);215return gerepileupto(av, z);216}217218GEN219FpE_changepointinv(GEN P, GEN ch, GEN p)220{221GEN u, r, s, t, u2, u3, c, z;222if (ell_is_inf(P)) return P;223if (lgefint(p) == 3)224{225ulong pp = p[2];226z = Fle_changepointinv(ZV_to_Flv(P, pp), ZV_to_Flv(ch, pp), pp);227return Flv_to_ZV(z);228}229u = gel(ch,1); r = gel(ch,2); s = gel(ch,3); t = gel(ch,4);230u2 = Fp_sqr(u, p); u3 = Fp_mul(u,u2,p);231c = Fp_mul(u2, gel(P,1), p);232z = cgetg(3, t_VEC);233gel(z,1) = Fp_add(c,r,p);234gel(z,2) = Fp_add(Fp_mul(u3,gel(P,2),p), Fp_add(Fp_mul(s,c,p), t, p), p);235return z;236}237238static GEN239nonsquare_Fp(GEN p)240{241pari_sp av = avma;242GEN a;243do244{245set_avma(av);246a = randomi(p);247} while (kronecker(a, p) >= 0);248return a;249}250251void252Fp_elltwist(GEN a4, GEN a6, GEN p, GEN *pt_a4, GEN *pt_a6)253{254GEN d = nonsquare_Fp(p), d2 = Fp_sqr(d, p), d3 = Fp_mul(d2, d, p);255*pt_a4 = Fp_mul(a4, d2, p);256*pt_a6 = Fp_mul(a6, d3, p);257}258259static GEN260FpE_dbl_slope(GEN P, GEN a4, GEN p, GEN *slope)261{262GEN x, y, Q;263if (ell_is_inf(P) || !signe(gel(P,2))) return ellinf();264x = gel(P,1); y = gel(P,2);265*slope = Fp_div(Fp_add(Fp_mulu(Fp_sqr(x,p), 3, p), a4, p),266Fp_mulu(y, 2, p), p);267Q = cgetg(3,t_VEC);268gel(Q, 1) = Fp_sub(Fp_sqr(*slope, p), Fp_mulu(x, 2, p), p);269gel(Q, 2) = Fp_sub(Fp_mul(*slope, Fp_sub(x, gel(Q, 1), p), p), y, p);270return Q;271}272273GEN274FpE_dbl(GEN P, GEN a4, GEN p)275{276pari_sp av = avma;277GEN slope;278return gerepileupto(av, FpE_dbl_slope(P,a4,p,&slope));279}280281static GEN282FpE_add_slope(GEN P, GEN Q, GEN a4, GEN p, GEN *slope)283{284GEN Px, Py, Qx, Qy, R;285if (ell_is_inf(P)) return Q;286if (ell_is_inf(Q)) return P;287Px = gel(P,1); Py = gel(P,2);288Qx = gel(Q,1); Qy = gel(Q,2);289if (equalii(Px, Qx))290{291if (equalii(Py, Qy))292return FpE_dbl_slope(P, a4, p, slope);293else294return ellinf();295}296*slope = Fp_div(Fp_sub(Py, Qy, p), Fp_sub(Px, Qx, p), p);297R = cgetg(3,t_VEC);298gel(R, 1) = Fp_sub(Fp_sub(Fp_sqr(*slope, p), Px, p), Qx, p);299gel(R, 2) = Fp_sub(Fp_mul(*slope, Fp_sub(Px, gel(R, 1), p), p), Py, p);300return R;301}302303GEN304FpE_add(GEN P, GEN Q, GEN a4, GEN p)305{306pari_sp av = avma;307GEN slope;308return gerepileupto(av, FpE_add_slope(P,Q,a4,p,&slope));309}310311static GEN312FpE_neg_i(GEN P, GEN p)313{314if (ell_is_inf(P)) return P;315return mkvec2(gel(P,1), Fp_neg(gel(P,2), p));316}317318GEN319FpE_neg(GEN P, GEN p)320{321if (ell_is_inf(P)) return ellinf();322return mkvec2(gcopy(gel(P,1)), Fp_neg(gel(P,2), p));323}324325GEN326FpE_sub(GEN P, GEN Q, GEN a4, GEN p)327{328pari_sp av = avma;329GEN slope;330return gerepileupto(av, FpE_add_slope(P, FpE_neg_i(Q, p), a4, p, &slope));331}332333static GEN334_FpE_dbl(void *E, GEN P)335{336struct _FpE *ell = (struct _FpE *) E;337return FpE_dbl(P, ell->a4, ell->p);338}339340static GEN341_FpE_add(void *E, GEN P, GEN Q)342{343struct _FpE *ell=(struct _FpE *) E;344return FpE_add(P, Q, ell->a4, ell->p);345}346347static GEN348_FpE_mul(void *E, GEN P, GEN n)349{350pari_sp av = avma;351struct _FpE *e=(struct _FpE *) E;352long s = signe(n);353GEN Q;354if (!s || ell_is_inf(P)) return ellinf();355if (s<0) P = FpE_neg(P, e->p);356if (is_pm1(n)) return s>0? gcopy(P): P;357if (equalis(n,2)) return _FpE_dbl(E, P);358Q = gen_pow_i(FpE_to_FpJ(P), n, e, &_FpJ_dbl, &_FpJ_add);359return gerepileupto(av, FpJ_to_FpE(Q, e->p));360}361362GEN363FpE_mul(GEN P, GEN n, GEN a4, GEN p)364{365struct _FpE E;366E.a4 = a4; E.p = p;367return _FpE_mul(&E, P, n);368}369370/* Finds a random nonsingular point on E */371372GEN373random_FpE(GEN a4, GEN a6, GEN p)374{375pari_sp ltop = avma;376GEN x, x2, y, rhs;377do378{379set_avma(ltop);380x = randomi(p); /* x^3+a4*x+a6 = x*(x^2+a4)+a6 */381x2 = Fp_sqr(x, p);382rhs = Fp_add(Fp_mul(x, Fp_add(x2, a4, p), p), a6, p);383} while ((!signe(rhs) && !signe(Fp_add(Fp_mulu(x2,3,p),a4,p)))384|| kronecker(rhs, p) < 0);385y = Fp_sqrt(rhs, p);386if (!y) pari_err_PRIME("random_FpE", p);387return gerepilecopy(ltop, mkvec2(x, y));388}389390static GEN391_FpE_rand(void *E)392{393struct _FpE *e=(struct _FpE *) E;394return random_FpE(e->a4, e->a6, e->p);395}396397static const struct bb_group FpE_group={_FpE_add,_FpE_mul,_FpE_rand,hash_GEN,ZV_equal,ell_is_inf,NULL};398399const struct bb_group *400get_FpE_group(void ** pt_E, GEN a4, GEN a6, GEN p)401{402struct _FpE *e = (struct _FpE *) stack_malloc(sizeof(struct _FpE));403e->a4 = a4; e->a6 = a6; e->p = p;404*pt_E = (void *) e;405return &FpE_group;406}407408GEN409FpE_order(GEN z, GEN o, GEN a4, GEN p)410{411pari_sp av = avma;412struct _FpE e;413GEN r;414if (lgefint(p) == 3)415{416ulong pp = p[2];417r = Fle_order(ZV_to_Flv(z, pp), o, umodiu(a4,pp), pp);418}419else420{421e.a4 = a4;422e.p = p;423r = gen_order(z, o, (void*)&e, &FpE_group);424}425return gerepileuptoint(av, r);426}427428GEN429FpE_log(GEN a, GEN b, GEN o, GEN a4, GEN p)430{431pari_sp av = avma;432struct _FpE e;433GEN r;434if (lgefint(p) == 3)435{436ulong pp = p[2];437r = Fle_log(ZV_to_Flv(a,pp), ZV_to_Flv(b,pp), o, umodiu(a4,pp), pp);438}439else440{441e.a4 = a4;442e.p = p;443r = gen_PH_log(a, b, o, (void*)&e, &FpE_group);444}445return gerepileuptoint(av, r);446}447448/***********************************************************************/449/** **/450/** Pairings **/451/** **/452/***********************************************************************/453454/* Derived from APIP from and by Jerome Milan, 2012 */455456static GEN457FpE_vert(GEN P, GEN Q, GEN a4, GEN p)458{459if (ell_is_inf(P))460return gen_1;461if (!equalii(gel(Q, 1), gel(P, 1)))462return Fp_sub(gel(Q, 1), gel(P, 1), p);463if (signe(gel(P,2))!=0) return gen_1;464return Fp_inv(Fp_add(Fp_mulu(Fp_sqr(gel(P,1),p), 3, p), a4, p), p);465}466467static GEN468FpE_Miller_line(GEN R, GEN Q, GEN slope, GEN a4, GEN p)469{470GEN x = gel(Q, 1), y = gel(Q, 2);471GEN tmp1 = Fp_sub(x, gel(R, 1), p);472GEN tmp2 = Fp_add(Fp_mul(tmp1, slope, p), gel(R,2), p);473if (!equalii(y, tmp2))474return Fp_sub(y, tmp2, p);475if (signe(y) == 0)476return gen_1;477else478{479GEN s1, s2;480GEN y2i = Fp_inv(Fp_mulu(y, 2, p), p);481s1 = Fp_mul(Fp_add(Fp_mulu(Fp_sqr(x, p), 3, p), a4, p), y2i, p);482if (!equalii(s1, slope))483return Fp_sub(s1, slope, p);484s2 = Fp_mul(Fp_sub(Fp_mulu(x, 3, p), Fp_sqr(s1, p), p), y2i, p);485return signe(s2)!=0 ? s2: y2i;486}487}488489/* Computes the equation of the line tangent to R and returns its490evaluation at the point Q. Also doubles the point R.491*/492493static GEN494FpE_tangent_update(GEN R, GEN Q, GEN a4, GEN p, GEN *pt_R)495{496if (ell_is_inf(R))497{498*pt_R = ellinf();499return gen_1;500}501else if (signe(gel(R,2)) == 0)502{503*pt_R = ellinf();504return FpE_vert(R, Q, a4, p);505} else {506GEN slope;507*pt_R = FpE_dbl_slope(R, a4, p, &slope);508return FpE_Miller_line(R, Q, slope, a4, p);509}510}511512/* Computes the equation of the line through R and P, and returns its513evaluation at the point Q. Also adds P to the point R.514*/515516static GEN517FpE_chord_update(GEN R, GEN P, GEN Q, GEN a4, GEN p, GEN *pt_R)518{519if (ell_is_inf(R))520{521*pt_R = gcopy(P);522return FpE_vert(P, Q, a4, p);523}524else if (ell_is_inf(P))525{526*pt_R = gcopy(R);527return FpE_vert(R, Q, a4, p);528}529else if (equalii(gel(P, 1), gel(R, 1)))530{531if (equalii(gel(P, 2), gel(R, 2)))532return FpE_tangent_update(R, Q, a4, p, pt_R);533else {534*pt_R = ellinf();535return FpE_vert(R, Q, a4, p);536}537} else {538GEN slope;539*pt_R = FpE_add_slope(P, R, a4, p, &slope);540return FpE_Miller_line(R, Q, slope, a4, p);541}542}543544struct _FpE_miller { GEN p, a4, P; };545static GEN546FpE_Miller_dbl(void* E, GEN d)547{548struct _FpE_miller *m = (struct _FpE_miller *)E;549GEN p = m->p, a4 = m->a4, P = m->P;550GEN v, line;551GEN N = Fp_sqr(gel(d,1), p);552GEN D = Fp_sqr(gel(d,2), p);553GEN point = gel(d,3);554line = FpE_tangent_update(point, P, a4, p, &point);555N = Fp_mul(N, line, p);556v = FpE_vert(point, P, a4, p);557D = Fp_mul(D, v, p); return mkvec3(N, D, point);558}559static GEN560FpE_Miller_add(void* E, GEN va, GEN vb)561{562struct _FpE_miller *m = (struct _FpE_miller *)E;563GEN p = m->p, a4= m->a4, P = m->P;564GEN v, line, point;565GEN na = gel(va,1), da = gel(va,2), pa = gel(va,3);566GEN nb = gel(vb,1), db = gel(vb,2), pb = gel(vb,3);567GEN N = Fp_mul(na, nb, p);568GEN D = Fp_mul(da, db, p);569line = FpE_chord_update(pa, pb, P, a4, p, &point);570N = Fp_mul(N, line, p);571v = FpE_vert(point, P, a4, p);572D = Fp_mul(D, v, p); return mkvec3(N, D, point);573}574575/* Returns the Miller function f_{m, Q} evaluated at the point P using576* the standard Miller algorithm. */577static GEN578FpE_Miller(GEN Q, GEN P, GEN m, GEN a4, GEN p)579{580pari_sp av = avma;581struct _FpE_miller d;582GEN v, N, D;583584d.a4 = a4; d.p = p; d.P = P;585v = gen_pow_i(mkvec3(gen_1,gen_1,Q), m, (void*)&d,586FpE_Miller_dbl, FpE_Miller_add);587N = gel(v,1); D = gel(v,2);588return gerepileuptoint(av, Fp_div(N, D, p));589}590591GEN592FpE_weilpairing(GEN P, GEN Q, GEN m, GEN a4, GEN p)593{594pari_sp av = avma;595GEN N, D, w;596if (ell_is_inf(P) || ell_is_inf(Q) || ZV_equal(P,Q)) return gen_1;597if (lgefint(p)==3 && lgefint(m)==3)598{599ulong pp = p[2];600GEN Pp = ZV_to_Flv(P, pp), Qp = ZV_to_Flv(Q, pp);601ulong w = Fle_weilpairing(Pp, Qp, itou(m), umodiu(a4, pp), pp);602set_avma(av); return utoi(w);603}604N = FpE_Miller(P, Q, m, a4, p);605D = FpE_Miller(Q, P, m, a4, p);606w = Fp_div(N, D, p);607if (mpodd(m)) w = Fp_neg(w, p);608return gerepileuptoint(av, w);609}610611GEN612FpE_tatepairing(GEN P, GEN Q, GEN m, GEN a4, GEN p)613{614if (ell_is_inf(P) || ell_is_inf(Q)) return gen_1;615if (lgefint(p)==3 && lgefint(m)==3)616{617pari_sp av = avma;618ulong pp = p[2];619GEN Pp = ZV_to_Flv(P, pp), Qp = ZV_to_Flv(Q, pp);620ulong w = Fle_tatepairing(Pp, Qp, itou(m), umodiu(a4, pp), pp);621set_avma(av); return utoi(w);622}623return FpE_Miller(P, Q, m, a4, p);624}625626/***********************************************************************/627/** **/628/** CM by principal order **/629/** **/630/***********************************************************************/631632/* is jn/jd = J (mod p) */633static int634is_CMj(long J, GEN jn, GEN jd, GEN p)635{ return dvdii(subii(mulis(jd,J), jn), p); }636#ifndef LONG_IS_64BIT637/* is jn/jd = -(2^32 a + b) (mod p) */638static int639u2_is_CMj(ulong a, ulong b, GEN jn, GEN jd, GEN p)640{641GEN mJ = uu32toi(a,b);642return dvdii(addii(mulii(jd,mJ), jn), p);643}644#endif645646static long647Fp_ellj_get_CM(GEN jn, GEN jd, GEN p)648{649#define CHECK(CM,J) if (is_CMj(J,jn,jd,p)) return CM;650CHECK(-3, 0);651CHECK(-4, 1728);652CHECK(-7, -3375);653CHECK(-8, 8000);654CHECK(-11, -32768);655CHECK(-12, 54000);656CHECK(-16, 287496);657CHECK(-19, -884736);658CHECK(-27, -12288000);659CHECK(-28, 16581375);660CHECK(-43, -884736000);661#ifdef LONG_IS_64BIT662CHECK(-67, -147197952000L);663CHECK(-163, -262537412640768000L);664#else665if (u2_is_CMj(0x00000022UL,0x45ae8000UL,jn,jd,p)) return -67;666if (u2_is_CMj(0x03a4b862UL,0xc4b40000UL,jn,jd,p)) return -163;667#endif668#undef CHECK669return 0;670}671672/***********************************************************************/673/** **/674/** issupersingular **/675/** **/676/***********************************************************************/677678/* assume x reduced mod p, monic. Return one root, or NULL if irreducible */679static GEN680FqX_quad_root(GEN x, GEN T, GEN p)681{682GEN b = gel(x,3), c = gel(x,2);683GEN D = Fq_sub(Fq_sqr(b, T, p), Fq_mulu(c,4, T, p), T, p);684GEN s = Fq_sqrt(D,T, p);685if (!s) return NULL;686return Fq_Fp_mul(Fq_sub(s, b, T, p), shifti(addiu(p, 1),-1),T, p);687}688689/*690* pol is the modular polynomial of level 2 modulo p.691*692* (T, p) defines the field FF_{p^2} in which j_prev and j live.693*/694static long695path_extends_to_floor(GEN j_prev, GEN j, GEN T, GEN p, GEN Phi2, ulong max_len)696{697pari_sp ltop = avma;698GEN Phi2_j;699ulong mult, d;700701/* A path made its way to the floor if (i) its length was cut off702* before reaching max_path_len, or (ii) it reached max_path_len but703* only has one neighbour. */704for (d = 1; d < max_len; ++d) {705GEN j_next;706707Phi2_j = FqX_div_by_X_x(FqXY_evalx(Phi2, j, T, p), j_prev, T, p, NULL);708j_next = FqX_quad_root(Phi2_j, T, p);709if (!j_next)710{ /* j is on the floor */711set_avma(ltop);712return 1;713}714715j_prev = j; j = j_next;716if (gc_needed(ltop, 2))717gerepileall(ltop, 2, &j, &j_prev);718}719720/* Check that we didn't end up at the floor on the last step (j will721* point to the last element in the path. */722Phi2_j = FqX_div_by_X_x(FqXY_evalx(Phi2, j, T, p), j_prev, T, p, NULL);723mult = FqX_nbroots(Phi2_j, T, p);724set_avma(ltop);725return mult == 0;726}727728static int729jissupersingular(GEN j, GEN S, GEN p)730{731long max_path_len = expi(p)+1;732GEN Phi2 = FpXX_red(polmodular_ZXX(2,0,0,1), p);733GEN Phi2_j = FqXY_evalx(Phi2, j, S, p);734GEN roots = FpXQX_roots(Phi2_j, S, p);735long nbroots = lg(roots)-1;736int res = 1;737738/* Every node in a supersingular L-volcano has L + 1 neighbours. */739/* Note: a multiple root only occur when j has CM by sqrt(-15). */740if (nbroots==0 || (nbroots==1 && FqX_is_squarefree(Phi2_j, S, p)))741res = 0;742else {743long i, l = lg(roots);744for (i = 1; i < l; ++i) {745if (path_extends_to_floor(j, gel(roots, i), S, p, Phi2, max_path_len)) {746res = 0;747break;748}749}750}751/* If none of the paths reached the floor, then the j-invariant is752* supersingular. */753return res;754}755756int757Fp_elljissupersingular(GEN j, GEN p)758{759pari_sp ltop = avma;760long CM;761if (abscmpiu(p, 5) <= 0) return signe(j) == 0; /* valid if p <= 5 */762CM = Fp_ellj_get_CM(j, gen_1, p);763if (CM < 0) return krosi(CM, p) < 0; /* valid if p > 3 */764else765{766GEN S = init_Fq(p, 2, fetch_var());767int res = jissupersingular(j, S, p);768(void)delete_var(); return gc_bool(ltop, res);769}770}771772/***********************************************************************/773/** **/774/** Cardinal **/775/** **/776/***********************************************************************/777778/*assume a4,a6 reduced mod p odd */779static ulong780Fl_elltrace_naive(ulong a4, ulong a6, ulong p)781{782ulong i, j;783long a = 0;784long d0, d1, d2, d3;785GEN k = const_vecsmall(p, -1);786k[1] = 0;787for (i=1, j=1; i < p; i += 2, j = Fl_add(j, i, p))788k[j+1] = 1;789d0 = 6%p; d1 = d0; d2 = Fl_add(a4, 1, p); d3 = a6;790for(i=0;; i++)791{792a -= k[1+d3];793if (i==p-1) break;794d3 = Fl_add(d3, d2, p);795d2 = Fl_add(d2, d1, p);796d1 = Fl_add(d1, d0, p);797}798return a;799}800801/* z1 <-- z1 + z2, with precomputed inverse */802static void803FpE_add_ip(GEN z1, GEN z2, GEN a4, GEN p, GEN p2inv)804{805GEN p1,x,x1,x2,y,y1,y2;806807x1 = gel(z1,1); y1 = gel(z1,2);808x2 = gel(z2,1); y2 = gel(z2,2);809if (x1 == x2)810p1 = Fp_add(a4, mulii(x1,mului(3,x1)), p);811else812p1 = Fp_sub(y2,y1, p);813814p1 = Fp_mul(p1, p2inv, p);815x = Fp_sub(sqri(p1), addii(x1,x2), p);816y = Fp_sub(mulii(p1,subii(x1,x)), y1, p);817affii(x, x1);818affii(y, y1);819}820821/* make sure *x has lgefint >= k */822static void823_fix(GEN x, long k)824{825GEN y = (GEN)*x;826if (lgefint(y) < k) { GEN p1 = cgeti(k); affii(y,p1); *x = (long)p1; }827}828829/* Return the lift of a (mod b), which is closest to c */830static GEN831closest_lift(GEN a, GEN b, GEN c)832{833return addii(a, mulii(b, diviiround(subii(c,a), b)));834}835836static long837get_table_size(GEN pordmin, GEN B)838{839pari_sp av = avma;840GEN t = ceilr( sqrtr( divri(itor(pordmin, DEFAULTPREC), B) ) );841if (is_bigint(t))842pari_err_OVERFLOW("ellap [large prime: install the 'seadata' package]");843set_avma(av);844return itos(t) >> 1;845}846847/* Find x such that kronecker(u = x^3+c4x+c6, p) is KRO.848* Return point [x*u,u^2] on E (KRO=1) / E^twist (KRO=-1) */849static GEN850Fp_ellpoint(long KRO, ulong *px, GEN c4, GEN c6, GEN p)851{852ulong x = *px;853GEN u;854for(;;)855{856x++; /* u = x^3 + c4 x + c6 */857u = modii(addii(c6, mului(x, addii(c4, sqru(x)))), p);858if (kronecker(u,p) == KRO) break;859}860*px = x;861return mkvec2(modii(mului(x,u),p), Fp_sqr(u,p));862}863static GEN864Fl_ellpoint(long KRO, ulong *px, ulong c4, ulong c6, ulong p)865{866ulong t, u, x = *px;867for(;;)868{869if (++x >= p) pari_err_PRIME("ellap",utoi(p));870t = Fl_add(c4, Fl_sqr(x,p), p);871u = Fl_add(c6, Fl_mul(x, t, p), p);872if (krouu(u,p) == KRO) break;873}874*px = x;875return mkvecsmall2(Fl_mul(x,u,p), Fl_sqr(u,p));876}877878static GEN ap_j1728(GEN a4,GEN p);879/* compute a_p using Shanks/Mestre + Montgomery's trick. Assume p > 457 */880static GEN881Fp_ellcard_Shanks(GEN c4, GEN c6, GEN p)882{883pari_timer T;884long *tx, *ty, *ti, pfinal, i, j, s, KRO, nb;885ulong x;886pari_sp av = avma, av2;887GEN p1, P, mfh, h, F,f, fh,fg, pordmin, u, v, p1p, p2p, A, B, a4, pts;888tx = NULL;889ty = ti = NULL; /* gcc -Wall */890891if (!signe(c6)) {892GEN ap = ap_j1728(c4, p);893return gerepileuptoint(av, subii(addiu(p,1), ap));894}895896if (DEBUGLEVEL >= 6) timer_start(&T);897/* once #E(Fp) is know mod B >= pordmin, it is completely determined */898pordmin = addiu(sqrti(gmul2n(p,4)), 1); /* ceil( 4sqrt(p) ) */899p1p = addiu(p, 1);900p2p = shifti(p1p, 1);901x = 0; KRO = 0;902/* how many 2-torsion points ? */903switch(FpX_nbroots(mkpoln(4, gen_1, gen_0, c4, c6), p))904{905case 3: A = gen_0; B = utoipos(4); break;906case 1: A = gen_0; B = gen_2; break;907default: A = gen_1; B = gen_2; break; /* 0 */908}909for(;;)910{911h = closest_lift(A, B, p1p);912if (!KRO) /* first time, initialize */913{914KRO = kronecker(c6,p);915f = mkvec2(gen_0, Fp_sqr(c6,p));916}917else918{919KRO = -KRO;920f = Fp_ellpoint(KRO, &x, c4,c6,p);921}922/* [ux, u^2] is on E_u: y^2 = x^3 + c4 u^2 x + c6 u^3923* E_u isomorphic to E (resp. E') iff KRO = 1 (resp. -1)924* #E(F_p) = p+1 - a_p, #E'(F_p) = p+1 + a_p925*926* #E_u(Fp) = A (mod B), h is close to #E_u(Fp) */927a4 = modii(mulii(c4, gel(f,2)), p); /* c4 for E_u */928fh = FpE_mul(f, h, a4, p);929if (ell_is_inf(fh)) goto FOUND;930931s = get_table_size(pordmin, B);932/* look for h s.t f^h = 0 */933if (!tx)934{ /* first time: initialize */935tx = newblock(3*(s+1));936ty = tx + (s+1);937ti = ty + (s+1);938}939F = FpE_mul(f,B,a4,p);940*tx = evaltyp(t_VECSMALL) | evallg(s+1);941942/* F = B.f */943P = gcopy(fh);944if (s < 3)945{ /* we're nearly done: naive search */946GEN q1 = P, mF = FpE_neg(F, p); /* -F */947for (i=1;; i++)948{949P = FpE_add(P,F,a4,p); /* h.f + i.F */950if (ell_is_inf(P)) { h = addii(h, mului(i,B)); goto FOUND; }951q1 = FpE_add(q1,mF,a4,p); /* h.f - i.F */952if (ell_is_inf(q1)) { h = subii(h, mului(i,B)); goto FOUND; }953}954}955/* Baby Step/Giant Step */956nb = minss(128, s >> 1); /* > 0. Will do nb pts at a time: faster inverse */957pts = cgetg(nb+1, t_VEC);958j = lgefint(p);959for (i=1; i<=nb; i++)960{ /* baby steps */961gel(pts,i) = P; /* h.f + (i-1).F */962_fix(P+1, j); tx[i] = mod2BIL(gel(P,1));963_fix(P+2, j); ty[i] = mod2BIL(gel(P,2));964P = FpE_add(P,F,a4,p); /* h.f + i.F */965if (ell_is_inf(P)) { h = addii(h, mului(i,B)); goto FOUND; }966}967mfh = FpE_neg(fh, p);968fg = FpE_add(P,mfh,a4,p); /* h.f + nb.F - h.f = nb.F */969if (ell_is_inf(fg)) { h = mului(nb,B); goto FOUND; }970u = cgetg(nb+1, t_VEC);971av2 = avma; /* more baby steps, nb points at a time */972while (i <= s)973{974long maxj;975for (j=1; j<=nb; j++) /* adding nb.F (part 1) */976{977P = gel(pts,j); /* h.f + (i-nb-1+j-1).F */978gel(u,j) = subii(gel(fg,1), gel(P,1));979if (!signe(gel(u,j))) /* sum = 0 or doubling */980{981long k = i+j-2;982if (equalii(gel(P,2),gel(fg,2))) k -= 2*nb; /* fg == P */983h = addii(h, mulsi(k,B)); goto FOUND;984}985}986v = FpV_inv(u, p);987maxj = (i-1 + nb <= s)? nb: s % nb;988for (j=1; j<=maxj; j++,i++) /* adding nb.F (part 2) */989{990P = gel(pts,j);991FpE_add_ip(P,fg, a4,p, gel(v,j));992tx[i] = mod2BIL(gel(P,1));993ty[i] = mod2BIL(gel(P,2));994}995set_avma(av2);996}997P = FpE_add(gel(pts,j-1),mfh,a4,p); /* = (s-1).F */998if (ell_is_inf(P)) { h = mului(s-1,B); goto FOUND; }999if (DEBUGLEVEL >= 6)1000timer_printf(&T, "[Fp_ellcard_Shanks] baby steps, s = %ld",s);10011002/* giant steps: fg = s.F */1003fg = FpE_add(P,F,a4,p);1004if (ell_is_inf(fg)) { h = mului(s,B); goto FOUND; }1005pfinal = mod2BIL(p); av2 = avma;1006/* Goal of the following: sort points by increasing x-coordinate hash.1007* Done in a complicated way to avoid allocating a large temp vector */1008p1 = vecsmall_indexsort(tx); /* = permutation sorting tx */1009for (i=1; i<=s; i++) ti[i] = tx[p1[i]];1010/* ti = tx sorted */1011for (i=1; i<=s; i++) { tx[i] = ti[i]; ti[i] = ty[p1[i]]; }1012/* tx is sorted. ti = ty sorted */1013for (i=1; i<=s; i++) { ty[i] = ti[i]; ti[i] = p1[i]; }1014/* ty is sorted. ti = permutation sorting tx */1015if (DEBUGLEVEL >= 6) timer_printf(&T, "[Fp_ellcard_Shanks] sorting");1016set_avma(av2);10171018gaffect(fg, gel(pts,1));1019for (j=2; j<=nb; j++) /* pts[j] = j.fg = (s*j).F */1020{1021P = FpE_add(gel(pts,j-1),fg,a4,p);1022if (ell_is_inf(P)) { h = mulii(mulss(s,j), B); goto FOUND; }1023gaffect(P, gel(pts,j));1024}1025/* replace fg by nb.fg since we do nb points at a time */1026set_avma(av2);1027fg = gcopy(gel(pts,nb)); /* copy: we modify (temporarily) pts[nb] below */1028av2 = avma;10291030for (i=1,j=1; ; i++)1031{1032GEN ftest = gel(pts,j);1033long m, l = 1, r = s+1;1034long k, k2, j2;10351036set_avma(av2);1037k = mod2BIL(gel(ftest,1));1038while (l < r)1039{1040m = (l+r) >> 1;1041if (tx[m] < k) l = m+1; else r = m;1042}1043if (r <= s && tx[r] == k)1044{1045while (r && tx[r] == k) r--;1046k2 = mod2BIL(gel(ftest,2));1047for (r++; r <= s && tx[r] == k; r++)1048if (ty[r] == k2 || ty[r] == pfinal - k2)1049{ /* [h+j2] f == +/- ftest (= [i.s] f)? */1050j2 = ti[r] - 1;1051if (DEBUGLEVEL >=6)1052timer_printf(&T, "[Fp_ellcard_Shanks] giant steps, i = %ld",i);1053P = FpE_add(FpE_mul(F,stoi(j2),a4,p),fh,a4,p);1054if (equalii(gel(P,1), gel(ftest,1)))1055{1056if (equalii(gel(P,2), gel(ftest,2))) i = -i;1057h = addii(h, mulii(addis(mulss(s,i), j2), B));1058goto FOUND;1059}1060}1061}1062if (++j > nb)1063{ /* compute next nb points */1064long save = 0; /* gcc -Wall */;1065for (j=1; j<=nb; j++)1066{1067P = gel(pts,j);1068gel(u,j) = subii(gel(fg,1), gel(P,1));1069if (gel(u,j) == gen_0) /* occurs once: i = j = nb, P == fg */1070{1071gel(u,j) = shifti(gel(P,2),1);1072save = fg[1]; fg[1] = P[1];1073}1074}1075v = FpV_inv(u, p);1076for (j=1; j<=nb; j++)1077FpE_add_ip(gel(pts,j),fg,a4,p, gel(v,j));1078if (i == nb) { fg[1] = save; }1079j = 1;1080}1081}1082FOUND: /* found a point of exponent h on E_u */1083h = FpE_order(f, h, a4, p);1084/* h | #E_u(Fp) = A (mod B) */1085A = Z_chinese_all(A, gen_0, B, h, &B);1086if (cmpii(B, pordmin) >= 0) break;1087/* not done: update A mod B for the _next_ curve, isomorphic to1088* the quadratic twist of this one */1089A = remii(subii(p2p,A), B); /* #E(Fp)+#E'(Fp) = 2p+2 */1090}1091if (tx) killblock(tx);1092h = closest_lift(A, B, p1p);1093return gerepileuptoint(av, KRO==1? h: subii(p2p,h));1094}10951096typedef struct1097{1098ulong x,y,i;1099} multiple;11001101static int1102compare_multiples(multiple *a, multiple *b) { return a->x > b->x? 1:a->x<b->x?-1:0; }11031104/* find x such that h := a + b x is closest to c and return h:1105* x = round((c-a) / b) = floor( (2(c-a) + b) / 2b )1106* Assume 0 <= a < b < c and b + 2c < 2^BIL */1107static ulong1108uclosest_lift(ulong a, ulong b, ulong c)1109{1110ulong x = (b + ((c-a) << 1)) / (b << 1);1111return a + b * x;1112}11131114static long1115Fle_dbl_inplace(GEN P, ulong a4, ulong p)1116{1117ulong x, y, slope;1118if (!P[2]) return 1;1119x = P[1]; y = P[2];1120slope = Fl_div(Fl_add(Fl_triple(Fl_sqr(x,p), p), a4, p),1121Fl_double(y, p), p);1122P[1] = Fl_sub(Fl_sqr(slope, p), Fl_double(x, p), p);1123P[2] = Fl_sub(Fl_mul(slope, Fl_sub(x, P[1], p), p), y, p);1124return 0;1125}11261127static long1128Fle_add_inplace(GEN P, GEN Q, ulong a4, ulong p)1129{1130ulong Px, Py, Qx, Qy, slope;1131if (ell_is_inf(Q)) return 0;1132Px = P[1]; Py = P[2];1133Qx = Q[1]; Qy = Q[2];1134if (Px==Qx)1135return Py==Qy ? Fle_dbl_inplace(P, a4, p): 1;1136slope = Fl_div(Fl_sub(Py, Qy, p), Fl_sub(Px, Qx, p), p);1137P[1] = Fl_sub(Fl_sub(Fl_sqr(slope, p), Px, p), Qx, p);1138P[2] = Fl_sub(Fl_mul(slope, Fl_sub(Px, P[1], p), p), Py, p);1139return 0;1140}11411142/* assume 99 < p < 2^(BIL-1) - 2^((BIL+1)/2) and e has good reduction at p.1143* Should use Barett reduction + multi-inverse. See Fp_ellcard_Shanks() */1144static long1145Fl_ellcard_Shanks(ulong c4, ulong c6, ulong p)1146{1147GEN f, fh, fg, ftest, F;1148ulong i, l, r, s, h, x, cp4, p1p, p2p, pordmin,A,B;1149long KRO;1150pari_sp av = avma;1151multiple *table;11521153if (!c6) {1154GEN ap = ap_j1728(utoi(c4), utoipos(p));1155return gc_long(av, p+1 - itos(ap));1156}11571158pordmin = (ulong)(1 + 4*sqrt((double)p));1159p1p = p+1;1160p2p = p1p << 1;1161x = 0; KRO = 0;1162switch(Flx_nbroots(mkvecsmall5(0L, c6,c4,0L,1L), p))1163{1164case 3: A = 0; B = 4; break;1165case 1: A = 0; B = 2; break;1166default: A = 1; B = 2; break; /* 0 */1167}1168for(;;)1169{ /* see comments in Fp_ellcard_Shanks */1170h = uclosest_lift(A, B, p1p);1171if (!KRO) /* first time, initialize */1172{1173KRO = krouu(c6,p); /* != 0 */1174f = mkvecsmall2(0, Fl_sqr(c6,p));1175}1176else1177{1178KRO = -KRO;1179f = Fl_ellpoint(KRO, &x, c4,c6,p);1180}1181cp4 = Fl_mul(c4, f[2], p);1182fh = Fle_mulu(f, h, cp4, p);1183if (ell_is_inf(fh)) goto FOUND;11841185s = (ulong) (sqrt(((double)pordmin)/B) / 2);1186if (!s) s = 1;1187table = (multiple *) stack_malloc((s+1) * sizeof(multiple));1188F = Fle_mulu(f, B, cp4, p);1189for (i=0; i < s; i++)1190{1191table[i].x = fh[1];1192table[i].y = fh[2];1193table[i].i = i;1194if (Fle_add_inplace(fh, F, cp4, p)) { h += B*(i+1); goto FOUND; }1195}1196qsort(table,s,sizeof(multiple),(QSCOMP)compare_multiples);1197fg = Fle_mulu(F, s, cp4, p); ftest = zv_copy(fg);1198if (ell_is_inf(ftest)) {1199if (!uisprime(p)) pari_err_PRIME("ellap",utoi(p));1200pari_err_BUG("ellap (f^(i*s) = 1)");1201}1202for (i=1; ; i++)1203{1204l=0; r=s;1205while (l<r)1206{1207ulong m = (l+r) >> 1;1208if (table[m].x < uel(ftest,1)) l=m+1; else r=m;1209}1210if (r < s && table[r].x == uel(ftest,1)) break;1211if (Fle_add_inplace(ftest, fg, cp4, p)) pari_err_PRIME("ellap",utoi(p));1212}1213h += table[r].i * B;1214if (table[r].y == uel(ftest,2))1215h -= s * i * B;1216else1217h += s * i * B;1218FOUND:1219h = itou(Fle_order(f, utoipos(h), cp4, p));1220/* h | #E_u(Fp) = A (mod B) */1221{1222GEN C;1223A = itou( Z_chinese_all(gen_0, utoi(A), utoipos(h), utoipos(B), &C) );1224if (abscmpiu(C, pordmin) >= 0) { /* uclosest_lift could overflow */1225h = itou( closest_lift(utoi(A), C, utoipos(p1p)) );1226break;1227}1228B = itou(C);1229}1230A = (p2p - A) % B; set_avma(av);1231}1232return gc_long(av, KRO==1? h: p2p-h);1233}12341235/** ellap from CM (original code contributed by Mark Watkins) **/12361237static GEN1238ap_j0(GEN a6,GEN p)1239{1240GEN a, b, e, d;1241if (umodiu(p,3) != 1) return gen_0;1242(void)cornacchia2(utoipos(27),p, &a,&b);1243if (umodiu(a, 3) == 1) a = negi(a);1244d = mulis(a6,-108);1245e = diviuexact(shifti(p,-1), 3); /* (p-1) / 6 */1246return centermod(mulii(a, Fp_pow(d, e, p)), p);1247}1248static GEN1249ap_j1728(GEN a4,GEN p)1250{1251GEN a, b, e;1252if (mod4(p) != 1) return gen_0;1253(void)cornacchia2(utoipos(4),p, &a,&b);1254if (Mod4(a)==0) a = b;1255if (Mod2(a)==1) a = shifti(a,1);1256if (Mod8(a)==6) a = negi(a);1257e = shifti(p,-2); /* (p-1) / 4 */1258return centermod(mulii(a, Fp_pow(a4, e, p)), p);1259}1260static GEN1261ap_j8000(GEN a6, GEN p)1262{1263GEN a, b;1264long r = mod8(p), s = 1;1265if (r != 1 && r != 3) return gen_0;1266(void)cornacchia2(utoipos(8),p, &a,&b);1267switch(Mod16(a)) {1268case 2: case 6: if (Mod4(b)) s = -s;1269break;1270case 10: case 14: if (!Mod4(b)) s = -s;1271break;1272}1273if (kronecker(mulis(a6, 42), p) < 0) s = -s;1274return s > 0? a: negi(a);1275}1276static GEN1277ap_j287496(GEN a6, GEN p)1278{1279GEN a, b;1280long s = 1;1281if (mod4(p) != 1) return gen_0;1282(void)cornacchia2(utoipos(4),p, &a,&b);1283if (Mod4(a)==0) a = b;1284if (Mod2(a)==1) a = shifti(a,1);1285if (Mod8(a)==6) s = -s;1286if (krosi(2,p) < 0) s = -s;1287if (kronecker(mulis(a6, -14), p) < 0) s = -s;1288return s > 0? a: negi(a);1289}1290static GEN1291ap_cm(int CM, long A6B, GEN a6, GEN p)1292{1293GEN a, b;1294long s = 1;1295if (krosi(CM,p) < 0) return gen_0;1296(void)cornacchia2(utoipos(-CM),p, &a, &b);1297if ((CM&3) == 0) CM >>= 2;1298if ((krois(a, -CM) > 0) ^ (CM == -7)) s = -s;1299if (kronecker(mulis(a6,A6B), p) < 0) s = -s;1300return s > 0? a: negi(a);1301}1302static GEN1303ec_ap_cm(int CM, GEN a4, GEN a6, GEN p)1304{1305switch(CM)1306{1307case -3: return ap_j0(a6, p);1308case -4: return ap_j1728(a4, p);1309case -8: return ap_j8000(a6, p);1310case -16: return ap_j287496(a6, p);1311case -7: return ap_cm(CM, -2, a6, p);1312case -11: return ap_cm(CM, 21, a6, p);1313case -12: return ap_cm(CM, 22, a6, p);1314case -19: return ap_cm(CM, 1, a6, p);1315case -27: return ap_cm(CM, 253, a6, p);1316case -28: return ap_cm(-7, -114, a6, p); /* yes, -7 ! */1317case -43: return ap_cm(CM, 21, a6, p);1318case -67: return ap_cm(CM, 217, a6, p);1319case -163:return ap_cm(CM, 185801, a6, p);1320default: return NULL;1321}1322}13231324static GEN1325Fp_ellj_nodiv(GEN a4, GEN a6, GEN p)1326{1327GEN a43 = Fp_mulu(Fp_powu(a4, 3, p), 4, p);1328GEN a62 = Fp_mulu(Fp_sqr(a6, p), 27, p);1329return mkvec2(Fp_mulu(a43, 1728, p), Fp_add(a43, a62, p));1330}13311332GEN1333Fp_ellj(GEN a4, GEN a6, GEN p)1334{1335pari_sp av = avma;1336GEN z;1337if (lgefint(p) == 3)1338{1339ulong pp = p[2];1340return utoi(Fl_ellj(umodiu(a4,pp), umodiu(a6,pp), pp));1341}1342z = Fp_ellj_nodiv(a4, a6, p);1343return gerepileuptoint(av,Fp_div(gel(z,1),gel(z,2),p));1344}13451346static GEN /* Only compute a mod p, so assume p>=17 */1347Fp_ellcard_CM(GEN a4, GEN a6, GEN p)1348{1349pari_sp av = avma;1350GEN a;1351if (!signe(a4)) a = ap_j0(a6,p);1352else if (!signe(a6)) a = ap_j1728(a4,p);1353else1354{1355GEN j = Fp_ellj_nodiv(a4, a6, p);1356long CM = Fp_ellj_get_CM(gel(j,1), gel(j,2), p);1357if (!CM) return gc_NULL(av);1358a = ec_ap_cm(CM,a4,a6,p);1359}1360return gerepileuptoint(av, subii(addiu(p,1),a));1361}13621363GEN1364Fp_ellcard(GEN a4, GEN a6, GEN p)1365{1366long lp = expi(p);1367ulong pp = p[2];1368if (lp < 11)1369return utoi(pp+1 - Fl_elltrace_naive(umodiu(a4,pp), umodiu(a6,pp), pp));1370{ GEN a = Fp_ellcard_CM(a4,a6,p); if (a) return a; }1371if (lp >= 56)1372return Fp_ellcard_SEA(a4, a6, p, 0);1373if (lp <= BITS_IN_LONG-2)1374return utoi(Fl_ellcard_Shanks(umodiu(a4,pp), umodiu(a6,pp), pp));1375return Fp_ellcard_Shanks(a4, a6, p);1376}13771378long1379Fl_elltrace(ulong a4, ulong a6, ulong p)1380{1381pari_sp av;1382long lp;1383GEN a;1384if (p < (1<<11)) return Fl_elltrace_naive(a4, a6, p);1385lp = expu(p);1386if (lp <= minss(56, BITS_IN_LONG-2)) return p+1-Fl_ellcard_Shanks(a4, a6, p);1387av = avma; a = subui(p+1, Fp_ellcard(utoi(a4), utoi(a6), utoipos(p)));1388return gc_long(av, itos(a));1389}1390long1391Fl_elltrace_CM(long CM, ulong a4, ulong a6, ulong p)1392{1393pari_sp av;1394GEN a;1395if (!CM) return Fl_elltrace(a4,a6,p);1396if (p < (1<<11)) return Fl_elltrace_naive(a4, a6, p);1397av = avma; a = ec_ap_cm(CM, utoi(a4), utoi(a6), utoipos(p));1398return gc_long(av, itos(a));1399}14001401static GEN1402_FpE_pairorder(void *E, GEN P, GEN Q, GEN m, GEN F)1403{1404struct _FpE *e = (struct _FpE *) E;1405return Fp_order(FpE_weilpairing(P,Q,m,e->a4,e->p), F, e->p);1406}14071408GEN1409Fp_ellgroup(GEN a4, GEN a6, GEN N, GEN p, GEN *pt_m)1410{1411struct _FpE e;1412e.a4=a4; e.a6=a6; e.p=p;1413return gen_ellgroup(N, subiu(p,1), pt_m, (void*)&e, &FpE_group, _FpE_pairorder);1414}14151416GEN1417Fp_ellgens(GEN a4, GEN a6, GEN ch, GEN D, GEN m, GEN p)1418{1419GEN P;1420pari_sp av = avma;1421struct _FpE e;1422e.a4=a4; e.a6=a6; e.p=p;1423switch(lg(D)-1)1424{1425case 1:1426P = gen_gener(gel(D,1), (void*)&e, &FpE_group);1427P = mkvec(FpE_changepoint(P, ch, p));1428break;1429default:1430P = gen_ellgens(gel(D,1), gel(D,2), m, (void*)&e, &FpE_group, _FpE_pairorder);1431gel(P,1) = FpE_changepoint(gel(P,1), ch, p);1432gel(P,2) = FpE_changepoint(gel(P,2), ch, p);1433break;1434}1435return gerepilecopy(av, P);1436}14371438/* Not so fast arithmetic with points over elliptic curves over FpXQ */14391440/***********************************************************************/1441/** **/1442/** FpXQE **/1443/** **/1444/***********************************************************************/14451446/* Theses functions deal with point over elliptic curves over FpXQ defined1447* by an equation of the form y^2=x^3+a4*x+a6.1448* Most of the time a6 is omitted since it can be recovered from any point1449* on the curve.1450*/14511452GEN1453RgE_to_FpXQE(GEN x, GEN T, GEN p)1454{1455if (ell_is_inf(x)) return x;1456retmkvec2(Rg_to_FpXQ(gel(x,1),T,p),Rg_to_FpXQ(gel(x,2),T,p));1457}14581459GEN1460FpXQE_changepoint(GEN x, GEN ch, GEN T, GEN p)1461{1462pari_sp av = avma;1463GEN p1,z,u,r,s,t,v,v2,v3;1464if (ell_is_inf(x)) return x;1465u = gel(ch,1); r = gel(ch,2);1466s = gel(ch,3); t = gel(ch,4);1467v = FpXQ_inv(u, T, p); v2 = FpXQ_sqr(v, T, p); v3 = FpXQ_mul(v,v2, T, p);1468p1 = FpX_sub(gel(x,1),r, p);1469z = cgetg(3,t_VEC);1470gel(z,1) = FpXQ_mul(v2, p1, T, p);1471gel(z,2) = FpXQ_mul(v3, FpX_sub(gel(x,2), FpX_add(FpXQ_mul(s,p1, T, p),t, p), p), T, p);1472return gerepileupto(av, z);1473}14741475GEN1476FpXQE_changepointinv(GEN x, GEN ch, GEN T, GEN p)1477{1478GEN u, r, s, t, X, Y, u2, u3, u2X, z;1479if (ell_is_inf(x)) return x;1480X = gel(x,1); Y = gel(x,2);1481u = gel(ch,1); r = gel(ch,2);1482s = gel(ch,3); t = gel(ch,4);1483u2 = FpXQ_sqr(u, T, p); u3 = FpXQ_mul(u,u2, T, p);1484u2X = FpXQ_mul(u2,X, T, p);1485z = cgetg(3, t_VEC);1486gel(z,1) = FpX_add(u2X,r, p);1487gel(z,2) = FpX_add(FpXQ_mul(u3,Y, T, p), FpX_add(FpXQ_mul(s,u2X, T, p), t, p), p);1488return z;1489}14901491static GEN1492nonsquare_FpXQ(GEN T, GEN p)1493{1494pari_sp av = avma;1495long n = degpol(T), v = varn(T);1496GEN a;1497if (odd(n))1498{1499GEN z = cgetg(3, t_POL);1500z[1] = evalsigne(1) | evalvarn(v);1501gel(z,2) = nonsquare_Fp(p); return z;1502}1503do1504{1505set_avma(av);1506a = random_FpX(n, v, p);1507} while (FpXQ_issquare(a, T, p));1508return a;1509}15101511void1512FpXQ_elltwist(GEN a4, GEN a6, GEN T, GEN p, GEN *pt_a4, GEN *pt_a6)1513{1514GEN d = nonsquare_FpXQ(T, p);1515GEN d2 = FpXQ_sqr(d, T, p), d3 = FpXQ_mul(d2, d, T, p);1516*pt_a4 = FpXQ_mul(a4, d2, T, p);1517*pt_a6 = FpXQ_mul(a6, d3, T, p);1518}15191520static GEN1521FpXQE_dbl_slope(GEN P, GEN a4, GEN T, GEN p, GEN *slope)1522{1523GEN x, y, Q;1524if (ell_is_inf(P) || !signe(gel(P,2))) return ellinf();1525x = gel(P,1); y = gel(P,2);1526*slope = FpXQ_div(FpX_add(FpX_mulu(FpXQ_sqr(x, T, p), 3, p), a4, p),1527FpX_mulu(y, 2, p), T, p);1528Q = cgetg(3,t_VEC);1529gel(Q, 1) = FpX_sub(FpXQ_sqr(*slope, T, p), FpX_mulu(x, 2, p), p);1530gel(Q, 2) = FpX_sub(FpXQ_mul(*slope, FpX_sub(x, gel(Q, 1), p), T, p), y, p);1531return Q;1532}15331534GEN1535FpXQE_dbl(GEN P, GEN a4, GEN T, GEN p)1536{1537pari_sp av = avma;1538GEN slope;1539return gerepileupto(av, FpXQE_dbl_slope(P,a4,T,p,&slope));1540}15411542static GEN1543FpXQE_add_slope(GEN P, GEN Q, GEN a4, GEN T, GEN p, GEN *slope)1544{1545GEN Px, Py, Qx, Qy, R;1546if (ell_is_inf(P)) return Q;1547if (ell_is_inf(Q)) return P;1548Px = gel(P,1); Py = gel(P,2);1549Qx = gel(Q,1); Qy = gel(Q,2);1550if (ZX_equal(Px, Qx))1551{1552if (ZX_equal(Py, Qy))1553return FpXQE_dbl_slope(P, a4, T, p, slope);1554else1555return ellinf();1556}1557*slope = FpXQ_div(FpX_sub(Py, Qy, p), FpX_sub(Px, Qx, p), T, p);1558R = cgetg(3,t_VEC);1559gel(R, 1) = FpX_sub(FpX_sub(FpXQ_sqr(*slope, T, p), Px, p), Qx, p);1560gel(R, 2) = FpX_sub(FpXQ_mul(*slope, FpX_sub(Px, gel(R, 1), p), T, p), Py, p);1561return R;1562}15631564GEN1565FpXQE_add(GEN P, GEN Q, GEN a4, GEN T, GEN p)1566{1567pari_sp av = avma;1568GEN slope;1569return gerepileupto(av, FpXQE_add_slope(P,Q,a4,T,p,&slope));1570}15711572static GEN1573FpXQE_neg_i(GEN P, GEN p)1574{1575if (ell_is_inf(P)) return P;1576return mkvec2(gel(P,1), FpX_neg(gel(P,2), p));1577}15781579GEN1580FpXQE_neg(GEN P, GEN T, GEN p)1581{1582(void) T;1583if (ell_is_inf(P)) return ellinf();1584return mkvec2(gcopy(gel(P,1)), FpX_neg(gel(P,2), p));1585}15861587GEN1588FpXQE_sub(GEN P, GEN Q, GEN a4, GEN T, GEN p)1589{1590pari_sp av = avma;1591GEN slope;1592return gerepileupto(av, FpXQE_add_slope(P, FpXQE_neg_i(Q, p), a4, T, p, &slope));1593}15941595struct _FpXQE { GEN a4,a6,T,p; };1596static GEN1597_FpXQE_dbl(void *E, GEN P)1598{1599struct _FpXQE *ell = (struct _FpXQE *) E;1600return FpXQE_dbl(P, ell->a4, ell->T, ell->p);1601}1602static GEN1603_FpXQE_add(void *E, GEN P, GEN Q)1604{1605struct _FpXQE *ell=(struct _FpXQE *) E;1606return FpXQE_add(P, Q, ell->a4, ell->T, ell->p);1607}1608static GEN1609_FpXQE_mul(void *E, GEN P, GEN n)1610{1611pari_sp av = avma;1612struct _FpXQE *e=(struct _FpXQE *) E;1613long s = signe(n);1614if (!s || ell_is_inf(P)) return ellinf();1615if (s<0) P = FpXQE_neg(P, e->T, e->p);1616if (is_pm1(n)) return s>0? gcopy(P): P;1617return gerepilecopy(av, gen_pow_i(P, n, e, &_FpXQE_dbl, &_FpXQE_add));1618}16191620GEN1621FpXQE_mul(GEN P, GEN n, GEN a4, GEN T, GEN p)1622{1623struct _FpXQE E;1624E.a4= a4; E.T = T; E.p = p;1625return _FpXQE_mul(&E, P, n);1626}16271628/* Finds a random nonsingular point on E */16291630GEN1631random_FpXQE(GEN a4, GEN a6, GEN T, GEN p)1632{1633pari_sp ltop = avma;1634GEN x, x2, y, rhs;1635long v = get_FpX_var(T), d = get_FpX_degree(T);1636do1637{1638set_avma(ltop);1639x = random_FpX(d,v,p); /* x^3+a4*x+a6 = x*(x^2+a4)+a6 */1640x2 = FpXQ_sqr(x, T, p);1641rhs = FpX_add(FpXQ_mul(x, FpX_add(x2, a4, p), T, p), a6, p);1642} while ((!signe(rhs) && !signe(FpX_add(FpX_mulu(x2,3,p), a4, p)))1643|| !FpXQ_issquare(rhs, T, p));1644y = FpXQ_sqrt(rhs, T, p);1645if (!y) pari_err_PRIME("random_FpE", p);1646return gerepilecopy(ltop, mkvec2(x, y));1647}16481649static GEN1650_FpXQE_rand(void *E)1651{1652struct _FpXQE *e=(struct _FpXQE *) E;1653return random_FpXQE(e->a4, e->a6, e->T, e->p);1654}16551656static const struct bb_group FpXQE_group={_FpXQE_add,_FpXQE_mul,_FpXQE_rand,hash_GEN,ZXV_equal,ell_is_inf};16571658const struct bb_group *1659get_FpXQE_group(void ** pt_E, GEN a4, GEN a6, GEN T, GEN p)1660{1661struct _FpXQE *e = (struct _FpXQE *) stack_malloc(sizeof(struct _FpXQE));1662e->a4 = a4; e->a6 = a6; e->T = T; e->p = p;1663*pt_E = (void *) e;1664return &FpXQE_group;1665}16661667GEN1668FpXQE_order(GEN z, GEN o, GEN a4, GEN T, GEN p)1669{1670pari_sp av = avma;1671struct _FpXQE e;1672e.a4=a4; e.T=T; e.p=p;1673return gerepileuptoint(av, gen_order(z, o, (void*)&e, &FpXQE_group));1674}16751676GEN1677FpXQE_log(GEN a, GEN b, GEN o, GEN a4, GEN T, GEN p)1678{1679pari_sp av = avma;1680struct _FpXQE e;1681e.a4=a4; e.T=T; e.p=p;1682return gerepileuptoint(av, gen_PH_log(a, b, o, (void*)&e, &FpXQE_group));1683}16841685/***********************************************************************/1686/** **/1687/** Pairings **/1688/** **/1689/***********************************************************************/16901691/* Derived from APIP from and by Jerome Milan, 2012 */16921693static GEN1694FpXQE_vert(GEN P, GEN Q, GEN a4, GEN T, GEN p)1695{1696long vT = get_FpX_var(T);1697if (ell_is_inf(P))1698return pol_1(get_FpX_var(T));1699if (!ZX_equal(gel(Q, 1), gel(P, 1)))1700return FpX_sub(gel(Q, 1), gel(P, 1), p);1701if (signe(gel(P,2))!=0) return pol_1(vT);1702return FpXQ_inv(FpX_add(FpX_mulu(FpXQ_sqr(gel(P,1), T, p), 3, p),1703a4, p), T, p);1704}17051706static GEN1707FpXQE_Miller_line(GEN R, GEN Q, GEN slope, GEN a4, GEN T, GEN p)1708{1709long vT = get_FpX_var(T);1710GEN x = gel(Q, 1), y = gel(Q, 2);1711GEN tmp1 = FpX_sub(x, gel(R, 1), p);1712GEN tmp2 = FpX_add(FpXQ_mul(tmp1, slope, T, p), gel(R, 2), p);1713if (!ZX_equal(y, tmp2))1714return FpX_sub(y, tmp2, p);1715if (signe(y) == 0)1716return pol_1(vT);1717else1718{1719GEN s1, s2;1720GEN y2i = FpXQ_inv(FpX_mulu(y, 2, p), T, p);1721s1 = FpXQ_mul(FpX_add(FpX_mulu(FpXQ_sqr(x, T, p), 3, p), a4, p), y2i, T, p);1722if (!ZX_equal(s1, slope))1723return FpX_sub(s1, slope, p);1724s2 = FpXQ_mul(FpX_sub(FpX_mulu(x, 3, p), FpXQ_sqr(s1, T, p), p), y2i, T, p);1725return signe(s2)!=0 ? s2: y2i;1726}1727}17281729/* Computes the equation of the line tangent to R and returns its1730evaluation at the point Q. Also doubles the point R.1731*/17321733static GEN1734FpXQE_tangent_update(GEN R, GEN Q, GEN a4, GEN T, GEN p, GEN *pt_R)1735{1736if (ell_is_inf(R))1737{1738*pt_R = ellinf();1739return pol_1(get_FpX_var(T));1740}1741else if (!signe(gel(R,2)))1742{1743*pt_R = ellinf();1744return FpXQE_vert(R, Q, a4, T, p);1745} else {1746GEN slope;1747*pt_R = FpXQE_dbl_slope(R, a4, T, p, &slope);1748return FpXQE_Miller_line(R, Q, slope, a4, T, p);1749}1750}17511752/* Computes the equation of the line through R and P, and returns its1753evaluation at the point Q. Also adds P to the point R.1754*/17551756static GEN1757FpXQE_chord_update(GEN R, GEN P, GEN Q, GEN a4, GEN T, GEN p, GEN *pt_R)1758{1759if (ell_is_inf(R))1760{1761*pt_R = gcopy(P);1762return FpXQE_vert(P, Q, a4, T, p);1763}1764else if (ell_is_inf(P))1765{1766*pt_R = gcopy(R);1767return FpXQE_vert(R, Q, a4, T, p);1768}1769else if (ZX_equal(gel(P, 1), gel(R, 1)))1770{1771if (ZX_equal(gel(P, 2), gel(R, 2)))1772return FpXQE_tangent_update(R, Q, a4, T, p, pt_R);1773else1774{1775*pt_R = ellinf();1776return FpXQE_vert(R, Q, a4, T, p);1777}1778} else {1779GEN slope;1780*pt_R = FpXQE_add_slope(P, R, a4, T, p, &slope);1781return FpXQE_Miller_line(R, Q, slope, a4, T, p);1782}1783}17841785struct _FpXQE_miller { GEN p, T, a4, P; };1786static GEN1787FpXQE_Miller_dbl(void* E, GEN d)1788{1789struct _FpXQE_miller *m = (struct _FpXQE_miller *)E;1790GEN p = m->p;1791GEN T = m->T, a4 = m->a4, P = m->P;1792GEN v, line;1793GEN N = FpXQ_sqr(gel(d,1), T, p);1794GEN D = FpXQ_sqr(gel(d,2), T, p);1795GEN point = gel(d,3);1796line = FpXQE_tangent_update(point, P, a4, T, p, &point);1797N = FpXQ_mul(N, line, T, p);1798v = FpXQE_vert(point, P, a4, T, p);1799D = FpXQ_mul(D, v, T, p); return mkvec3(N, D, point);1800}18011802static GEN1803FpXQE_Miller_add(void* E, GEN va, GEN vb)1804{1805struct _FpXQE_miller *m = (struct _FpXQE_miller *)E;1806GEN p = m->p;1807GEN T = m->T, a4 = m->a4, P = m->P;1808GEN v, line, point;1809GEN na = gel(va,1), da = gel(va,2), pa = gel(va,3);1810GEN nb = gel(vb,1), db = gel(vb,2), pb = gel(vb,3);1811GEN N = FpXQ_mul(na, nb, T, p);1812GEN D = FpXQ_mul(da, db, T, p);1813line = FpXQE_chord_update(pa, pb, P, a4, T, p, &point);1814N = FpXQ_mul(N, line, T, p);1815v = FpXQE_vert(point, P, a4, T, p);1816D = FpXQ_mul(D, v, T, p); return mkvec3(N, D, point);1817}18181819/* Returns the Miller function f_{m, Q} evaluated at the point P using1820* the standard Miller algorithm. */1821static GEN1822FpXQE_Miller(GEN Q, GEN P, GEN m, GEN a4, GEN T, GEN p)1823{1824pari_sp av = avma;1825struct _FpXQE_miller d;1826GEN v, N, D, g1;18271828d.a4 = a4; d.T = T; d.p = p; d.P = P;1829g1 = pol_1(get_FpX_var(T));1830v = gen_pow_i(mkvec3(g1,g1,Q), m, (void*)&d,1831FpXQE_Miller_dbl, FpXQE_Miller_add);1832N = gel(v,1); D = gel(v,2);1833return gerepileupto(av, FpXQ_div(N, D, T, p));1834}18351836GEN1837FpXQE_weilpairing(GEN P, GEN Q, GEN m, GEN a4, GEN T, GEN p)1838{1839pari_sp av = avma;1840GEN N, D, w;1841if (ell_is_inf(P) || ell_is_inf(Q) || ZXV_equal(P,Q))1842return pol_1(get_FpX_var(T));1843N = FpXQE_Miller(P, Q, m, a4, T, p);1844D = FpXQE_Miller(Q, P, m, a4, T, p);1845w = FpXQ_div(N, D, T, p);1846if (mpodd(m)) w = FpX_neg(w, p);1847return gerepileupto(av, w);1848}18491850GEN1851FpXQE_tatepairing(GEN P, GEN Q, GEN m, GEN a4, GEN T, GEN p)1852{1853if (ell_is_inf(P) || ell_is_inf(Q)) return pol_1(get_FpX_var(T));1854return FpXQE_Miller(P, Q, m, a4, T, p);1855}18561857/***********************************************************************/1858/** **/1859/** issupersingular **/1860/** **/1861/***********************************************************************/18621863GEN1864FpXQ_ellj(GEN a4, GEN a6, GEN T, GEN p)1865{1866if (absequaliu(p,3)) return pol_0(get_FpX_var(T));1867else1868{1869pari_sp av=avma;1870GEN a43 = FpXQ_mul(a4,FpXQ_sqr(a4,T,p),T,p);1871GEN a62 = FpXQ_sqr(a6,T,p);1872GEN num = FpX_mulu(a43,6912,p);1873GEN den = FpX_add(FpX_mulu(a43,4,p),FpX_mulu(a62,27,p),p);1874return gerepileuptoleaf(av, FpXQ_div(num, den, T, p));1875}1876}18771878int1879FpXQ_elljissupersingular(GEN j, GEN T, GEN p)1880{1881pari_sp ltop = avma;18821883/* All supersingular j-invariants are in FF_{p^2}, so we first check1884* whether j is in FF_{p^2}. If d is odd, then FF_{p^2} is not a1885* subfield of FF_{p^d} so the j-invariants are all in FF_p. Hence1886* the j-invariants are in FF_{p^{2 - e}}. */1887ulong d = get_FpX_degree(T);1888GEN S;18891890if (degpol(j) <= 0) return Fp_elljissupersingular(constant_coeff(j), p);1891if (abscmpiu(p, 5) <= 0) return 0; /* j != 0*/18921893/* Set S so that FF_p[T]/(S) is isomorphic to FF_{p^2}: */1894if (d == 2)1895S = T;1896else { /* d > 2 */1897/* We construct FF_{p^2} = FF_p[t]/((T - j)(T - j^p)) which1898* injects into FF_{p^d} via the map T |--> j. */1899GEN j_pow_p = FpXQ_pow(j, p, T, p);1900GEN j_sum = FpX_add(j, j_pow_p, p), j_prod;1901long var = varn(T);1902if (degpol(j_sum) > 0) return gc_bool(ltop,0); /* j not in Fp^2 */1903j_prod = FpXQ_mul(j, j_pow_p, T, p);1904if (degpol(j_prod) > 0 ) return gc_bool(ltop,0); /* j not in Fp^2 */1905j_sum = constant_coeff(j_sum); j_prod = constant_coeff(j_prod);1906S = mkpoln(3, gen_1, Fp_neg(j_sum, p), j_prod);1907setvarn(S, var);1908j = pol_x(var);1909}1910return gc_bool(ltop, jissupersingular(j,S,p));1911}19121913/***********************************************************************/1914/** **/1915/** Point counting **/1916/** **/1917/***********************************************************************/19181919GEN1920elltrace_extension(GEN t, long n, GEN q)1921{1922pari_sp av = avma;1923GEN v = RgX_to_RgC(RgXQ_powu(pol_x(0), n, mkpoln(3,gen_1,negi(t),q)),2);1924GEN te = addii(shifti(gel(v,1),1), mulii(t,gel(v,2)));1925return gerepileuptoint(av, te);1926}19271928GEN1929Fp_ffellcard(GEN a4, GEN a6, GEN q, long n, GEN p)1930{1931pari_sp av = avma;1932GEN ap = subii(addiu(p, 1), Fp_ellcard(a4, a6, p));1933GEN te = elltrace_extension(ap, n, p);1934return gerepileuptoint(av, subii(addiu(q, 1), te));1935}19361937static GEN1938FpXQ_ellcardj(GEN a4, GEN a6, GEN j, GEN T, GEN q, GEN p, long n)1939{1940GEN q1 = addiu(q,1);1941if (signe(j)==0)1942{1943GEN W, w, t, N;1944if (umodiu(q,6)!=1) return q1;1945N = Fp_ffellcard(gen_0,gen_1,q,n,p);1946t = subii(q1, N);1947W = FpXQ_pow(a6,diviuexact(shifti(q,-1), 3),T,p);1948if (degpol(W)>0) /*p=5 mod 6*/1949return ZX_equal1(FpXQ_powu(W,3,T,p)) ? addii(q1,shifti(t,-1)):1950subii(q1,shifti(t,-1));1951w = modii(gel(W,2),p);1952if (equali1(w)) return N;1953if (equalii(w,subiu(p,1))) return addii(q1,t);1954else /*p=1 mod 6*/1955{1956GEN u = shifti(t,-1), v = sqrtint(diviuexact(subii(q,sqri(u)),3));1957GEN a = addii(u,v), b = shifti(v,1);1958if (equali1(Fp_powu(w,3,p)))1959{1960if (dvdii(addmulii(a, w, b), p))1961return subii(q1,subii(shifti(b,1),a));1962else1963return addii(q1,addii(a,b));1964}1965else1966{1967if (dvdii(submulii(a, w, b), p))1968return subii(q1,subii(a,shifti(b,1)));1969else1970return subii(q1,addii(a,b));1971}1972}1973} else if (equalii(j,modsi(1728,p)))1974{1975GEN w, W, N, t;1976if (mod4(q)==3) return q1;1977W = FpXQ_pow(a4,shifti(q,-2),T,p);1978if (degpol(W)>0) return q1; /*p=3 mod 4*/1979w = modii(gel(W,2),p);1980N = Fp_ffellcard(gen_1,gen_0,q,n,p);1981if (equali1(w)) return N;1982t = subii(q1, N);1983if (equalii(w,subiu(p,1))) return addii(q1,t);1984else /*p=1 mod 4*/1985{1986GEN u = shifti(t,-1), v = sqrtint(subii(q,sqri(u)));1987if (dvdii(addmulii(u, w, v), p))1988return subii(q1,shifti(v,1));1989else1990return addii(q1,shifti(v,1));1991}1992} else1993{1994GEN g = Fp_div(j, Fp_sub(utoi(1728), j, p), p);1995GEN l = FpXQ_div(FpX_mulu(a6,3,p),FpX_mulu(a4,2,p),T,p);1996GEN N = Fp_ffellcard(Fp_mulu(g,3,p),Fp_mulu(g,2,p),q,n,p);1997if (FpXQ_issquare(l,T,p)) return N;1998return subii(shifti(q1,1),N);1999}2000}20012002GEN2003FpXQ_ellcard(GEN a4, GEN a6, GEN T, GEN p)2004{2005pari_sp av = avma;2006long n = get_FpX_degree(T);2007GEN q = powiu(p, n), r, J;2008if (degpol(a4)<=0 && degpol(a6)<=0)2009r = Fp_ffellcard(constant_coeff(a4),constant_coeff(a6),q,n,p);2010else if (lgefint(p)==3)2011{2012ulong pp = p[2];2013r = Flxq_ellcard(ZX_to_Flx(a4,pp),ZX_to_Flx(a6,pp),ZX_to_Flx(T,pp),pp);2014}2015else if (degpol(J=FpXQ_ellj(a4,a6,T,p))<=0)2016r = FpXQ_ellcardj(a4,a6,constant_coeff(J),T,q,p,n);2017else2018r = Fq_ellcard_SEA(a4, a6, q, T, p, 0);2019return gerepileuptoint(av, r);2020}20212022static GEN2023_FpXQE_pairorder(void *E, GEN P, GEN Q, GEN m, GEN F)2024{2025struct _FpXQE *e = (struct _FpXQE *) E;2026return FpXQ_order(FpXQE_weilpairing(P,Q,m,e->a4,e->T,e->p), F, e->T, e->p);2027}20282029GEN2030FpXQ_ellgroup(GEN a4, GEN a6, GEN N, GEN T, GEN p, GEN *pt_m)2031{2032struct _FpXQE e;2033GEN q = powiu(p, get_FpX_degree(T));2034e.a4=a4; e.a6=a6; e.T=T; e.p=p;2035return gen_ellgroup(N, subiu(q,1), pt_m, (void*)&e, &FpXQE_group, _FpXQE_pairorder);2036}20372038GEN2039FpXQ_ellgens(GEN a4, GEN a6, GEN ch, GEN D, GEN m, GEN T, GEN p)2040{2041GEN P;2042pari_sp av = avma;2043struct _FpXQE e;2044e.a4=a4; e.a6=a6; e.T=T; e.p=p;2045switch(lg(D)-1)2046{2047case 1:2048P = gen_gener(gel(D,1), (void*)&e, &FpXQE_group);2049P = mkvec(FpXQE_changepoint(P, ch, T, p));2050break;2051default:2052P = gen_ellgens(gel(D,1), gel(D,2), m, (void*)&e, &FpXQE_group, _FpXQE_pairorder);2053gel(P,1) = FpXQE_changepoint(gel(P,1), ch, T, p);2054gel(P,2) = FpXQE_changepoint(gel(P,2), ch, T, p);2055break;2056}2057return gerepilecopy(av, P);2058}205920602061