Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2014 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/* Not so fast arithmetic with points over elliptic curves over Fl */1819/***********************************************************************/20/** **/21/** Flj **/22/** **/23/***********************************************************************/2425/* Arithmetic is implemented using Jacobian coordinates, representing26* a projective point (x : y : z) on E by [z*x , z^2*y , z]. This is27* probably not the fastest representation available for the given28* problem, but they're easy to implement and up to 60% faster than29* the school-book method. */3031/* Cost: 1M + 8S + 1*a + 10add + 1*8 + 2*2 + 1*3.32* http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl */33INLINE void34Flj_dbl_indir_pre(GEN P, GEN Q, ulong a4, ulong p, ulong pi)35{36ulong X1, Y1, Z1;37ulong XX, YY, YYYY, ZZ, S, M, T;3839X1 = P[1]; Y1 = P[2]; Z1 = P[3];4041if (Z1 == 0) { Q[1] = X1; Q[2] = Y1; Q[3] = Z1; return; }4243XX = Fl_sqr_pre(X1, p, pi);44YY = Fl_sqr_pre(Y1, p, pi);45YYYY = Fl_sqr_pre(YY, p, pi);46ZZ = Fl_sqr_pre(Z1, p, pi);47S = Fl_double(Fl_sub(Fl_sqr_pre(Fl_add(X1, YY, p), p, pi),48Fl_add(XX, YYYY, p), p), p);49M = Fl_addmul_pre(Fl_triple(XX, p), a4, Fl_sqr_pre(ZZ, p, pi), p, pi);50T = Fl_sub(Fl_sqr_pre(M, p, pi), Fl_double(S, p), p);51Q[1] = T;52Q[2] = Fl_sub(Fl_mul_pre(M, Fl_sub(S, T, p), p, pi),53Fl_double(Fl_double(Fl_double(YYYY, p), p), p), p);54Q[3] = Fl_sub(Fl_sqr_pre(Fl_add(Y1, Z1, p), p, pi),55Fl_add(YY, ZZ, p), p);56}5758INLINE void59Flj_dbl_pre_inplace(GEN P, ulong a4, ulong p, ulong pi)60{61Flj_dbl_indir_pre(P, P, a4, p, pi);62}6364GEN65Flj_dbl_pre(GEN P, ulong a4, ulong p, ulong pi)66{67GEN Q = cgetg(4, t_VECSMALL);68Flj_dbl_indir_pre(P, Q, a4, p, pi);69return Q;70}7172/* Cost: 11M + 5S + 9add + 4*2.73* http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-add-2007-bl */74INLINE void75Flj_add_indir_pre(GEN P, GEN Q, GEN R, ulong a4, ulong p, ulong pi)76{77ulong X1, Y1, Z1, X2, Y2, Z2;78ulong Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V, W;79X1 = P[1]; Y1 = P[2]; Z1 = P[3];80X2 = Q[1]; Y2 = Q[2]; Z2 = Q[3];8182if (Z2 == 0) { R[1] = X1; R[2] = Y1; R[3] = Z1; return; }83if (Z1 == 0) { R[1] = X2; R[2] = Y2; R[3] = Z2; return; }8485Z1Z1 = Fl_sqr_pre(Z1, p, pi);86Z2Z2 = Fl_sqr_pre(Z2, p, pi);87U1 = Fl_mul_pre(X1, Z2Z2, p, pi);88U2 = Fl_mul_pre(X2, Z1Z1, p, pi);89S1 = Fl_mul_pre(Y1, Fl_mul_pre(Z2, Z2Z2, p, pi), p, pi);90S2 = Fl_mul_pre(Y2, Fl_mul_pre(Z1, Z1Z1, p, pi), p, pi);91H = Fl_sub(U2, U1, p);92r = Fl_double(Fl_sub(S2, S1, p), p);9394if (H == 0) {95if (r == 0) Flj_dbl_indir_pre(P, R, a4, p, pi); /* P = Q */96else { R[1] = R[2] = 1; R[3] = 0; } /* P = -Q */97return;98}99I = Fl_sqr_pre(Fl_double(H, p), p, pi);100J = Fl_mul_pre(H, I, p, pi);101V = Fl_mul_pre(U1, I, p, pi);102W = Fl_sub(Fl_sqr_pre(r, p, pi), Fl_add(J, Fl_double(V, p), p), p);103R[1] = W;104R[2] = Fl_sub(Fl_mul_pre(r, Fl_sub(V, W, p), p, pi),105Fl_double(Fl_mul_pre(S1, J, p, pi), p), p);106R[3] = Fl_mul_pre(Fl_sub(Fl_sqr_pre(Fl_add(Z1, Z2, p), p, pi),107Fl_add(Z1Z1, Z2Z2, p), p), H, p, pi);108}109110INLINE void111Flj_add_pre_inplace(GEN P, GEN Q, ulong a4, ulong p, ulong pi)112{ Flj_add_indir_pre(P, Q, P, a4, p, pi); }113114GEN115Flj_add_pre(GEN P, GEN Q, ulong a4, ulong p, ulong pi)116{117GEN R = cgetg(4, t_VECSMALL);118Flj_add_indir_pre(P, Q, R, a4, p, pi);119return R;120}121122GEN123Flj_neg(GEN Q, ulong p)124{ return mkvecsmall3(Q[1], Fl_neg(Q[2], p), Q[3]); }125126typedef struct {127ulong pbits, nbits; /* Positive bits and negative bits */128ulong lnzb; /* Leading nonzero bit */129} naf_t;130131/* Return the signed binary representation (i.e. the Non-Adjacent Form132* in base 2) of a; a = x.pbits - x.nbits (+ 2^BILif < 0; this133* exceptional case can happen if a > 2^(BIL-1)) */134static void135naf_repr(naf_t *x, ulong a)136{137ulong pbits = 0, nbits = 0, c0 = 0, c1, a0;138long t, i;139140for (i = 0; a; a >>= 1, ++i) {141a0 = a & 1;142c1 = (c0 + a0 + ((a & 2) >> 1)) >> 1;143t = c0 + a0 - (c1 << 1);144if (t < 0)145nbits |= (1UL << i);146else if (t > 0)147pbits |= (1UL << i);148c0 = c1;149}150c1 = c0 >> 1;151t = c0 - (c1 << 1);152/* since a >= 0, we have t >= 0; if i = BIL, pbits (virtually) overflows;153* that leading overflowed bit is implied and not recorded in pbits */154if (t > 0 && i != BITS_IN_LONG) pbits |= (1UL << i);155x->pbits = pbits;156x->nbits = nbits;157x->lnzb = t? i-2: i-3;158}159160/* Standard left-to-right signed double-and-add to compute [n]P. */161static GEN162Flj_mulu_pre_naf(GEN P, ulong n, ulong a4, ulong p, ulong pi, const naf_t *x)163{164GEN R, Pi;165ulong pbits, nbits;166ulong m;167168if (n == 0) return mkvecsmall3(1, 1, 0);169if (n == 1) return Flv_copy(P);170171R = Flj_dbl_pre(P, a4, p, pi);172if (n == 2) return R;173174pbits = x->pbits;175nbits = x->nbits;176Pi = nbits? Flj_neg(P, p): NULL;177m = (1UL << x->lnzb);178for ( ; m; m >>= 1) {179Flj_dbl_pre_inplace(R, a4, p, pi);180if (m & pbits)181Flj_add_pre_inplace(R, P, a4, p, pi);182else if (m & nbits)183Flj_add_pre_inplace(R, Pi, a4, p, pi);184}185return gc_const((pari_sp)R, R);186}187188GEN189Flj_mulu_pre(GEN P, ulong n, ulong a4, ulong p, ulong pi)190{191naf_t x; naf_repr(&x, n);192return Flj_mulu_pre_naf(P, n, a4, p, pi, &x);193}194195struct _Flj { ulong a4, p, pi; };196197static GEN198_Flj_add(void *E, GEN P, GEN Q)199{200struct _Flj *ell=(struct _Flj *) E;201return Flj_add_pre(P, Q, ell->a4, ell->p, ell->pi);202}203204static GEN205_Flj_mul(void *E, GEN P, GEN n)206{207struct _Flj *ell = (struct _Flj *) E;208long s = signe(n);209GEN Q;210if (s==0) return mkvecsmall3(1, 1, 0);211Q = Flj_mulu_pre(P, itou(n), ell->a4, ell->p, ell->pi);212return s>0 ? Q : Flj_neg(Q, ell->p);213}214static GEN215_Flj_one(void *E)216{ (void) E; return mkvecsmall3(1, 1, 0); }217218GEN219FljV_factorback_pre(GEN P, GEN L, ulong a4, ulong p, ulong pi)220{221struct _Flj E;222E.a4 = a4; E.p = p; E.pi = pi;223return gen_factorback(P, L, (void*)&E, &_Flj_add, &_Flj_mul, &_Flj_one);224}225226ulong227Flj_order_ufact(GEN P, ulong n, GEN F, ulong a4, ulong p, ulong pi)228{229pari_sp av = avma;230ulong res = 1;231long i, nfactors;232GEN primes, exps;233234primes = gel(F, 1);235nfactors = lg(primes);236exps = gel(F, 2);237238for (i = 1; i < nfactors; ++i) {239ulong q, pp = primes[i];240long j, k, ei = exps[i];241naf_t x;242GEN b;243244for (q = pp, j = 1; j < ei; ++j) q *= pp;245b = Flj_mulu_pre(P, n / q, a4, p, pi);246247naf_repr(&x, pp);248for (j = 0; j < ei && b[3]; ++j)249b = Flj_mulu_pre_naf(b, pp, a4, p, pi, &x);250if (b[3]) return 0;251for (k = 0; k < j; ++k) res *= pp;252set_avma(av);253}254return res;255}256257GEN258Fle_to_Flj(GEN P)259{ return ell_is_inf(P) ? mkvecsmall3(1UL, 1UL, 0UL):260mkvecsmall3(P[1], P[2], 1UL);261}262263GEN264Flj_to_Fle(GEN P, ulong p)265{266if (P[3] == 0) return ellinf();267else268{269ulong Z = Fl_inv(P[3], p);270ulong Z2 = Fl_sqr(Z, p);271ulong X3 = Fl_mul(P[1], Z2, p);272ulong Y3 = Fl_mul(P[2], Fl_mul(Z, Z2, p), p);273return mkvecsmall2(X3, Y3);274}275}276277GEN278Flj_to_Fle_pre(GEN P, ulong p, ulong pi)279{280if (P[3] == 0) return ellinf();281else282{283ulong Z = Fl_inv(P[3], p);284ulong Z2 = Fl_sqr_pre(Z, p, pi);285ulong X3 = Fl_mul_pre(P[1], Z2, p, pi);286ulong Y3 = Fl_mul_pre(P[2], Fl_mul_pre(Z, Z2, p, pi), p, pi);287return mkvecsmall2(X3, Y3);288}289}290291INLINE void292random_Fle_pre_indir(ulong a4, ulong a6, ulong p, ulong pi,293ulong *pt_x, ulong *pt_y)294{295ulong x, x2, y, rhs;296do297{298x = random_Fl(p); /* x^3+a4*x+a6 = x*(x^2+a4)+a6 */299x2 = Fl_sqr_pre(x, p, pi);300rhs = Fl_addmul_pre(a6, x, Fl_add(x2, a4, p), p, pi);301} while ((!rhs && !Fl_add(Fl_triple(x2,p),a4,p)) || krouu(rhs, p) < 0);302y = Fl_sqrt_pre(rhs, p, pi);303*pt_x = x; *pt_y = y;304}305306GEN307random_Flj_pre(ulong a4, ulong a6, ulong p, ulong pi)308{309ulong x, y;310random_Fle_pre_indir(a4, a6, p, pi, &x, &y);311return mkvecsmall3(x, y, 1);312}313314GEN315Flj_changepointinv_pre(GEN P, GEN ch, ulong p, ulong pi)316{317ulong c, u, r, s, t, u2, u3, z2;318ulong x = uel(P,1), y = uel(P,2), z = uel(P,3);319GEN w;320if (z == 0) return Flv_copy(P);321u = ch[1]; r = ch[2];322s = ch[3]; t = ch[4];323u2 = Fl_sqr_pre(u, p, pi); u3 = Fl_mul_pre(u, u2, p, pi);324c = Fl_mul_pre(u2, x, p, pi);325z2 = Fl_sqr_pre(z, p, pi);326w = cgetg(4, t_VECSMALL);327uel(w,1) = Fl_add(c, Fl_mul_pre(r, z2, p, pi), p);328uel(w,2) = Fl_add(Fl_mul_pre(u3 ,y, p, pi),329Fl_mul_pre(z, Fl_add(Fl_mul_pre(s,c,p,pi),330Fl_mul_pre(z2,t,p,pi), p), p, pi), p);331uel(w,3) = z;332return w;333}334335/***********************************************************************/336/** **/337/** Fle **/338/** **/339/***********************************************************************/340GEN341Fle_changepoint(GEN P, GEN ch, ulong p)342{343ulong c, u, r, s, t, v, v2, v3;344GEN z;345if (ell_is_inf(P)) return ellinf();346u = ch[1]; r = ch[2];347s = ch[3]; t = ch[4];348v = Fl_inv(u, p); v2 = Fl_sqr(v,p); v3 = Fl_mul(v,v2,p);349c = Fl_sub(uel(P,1),r,p);350z = cgetg(3,t_VECSMALL);351z[1] = Fl_mul(v2, c, p);352z[2] = Fl_mul(v3, Fl_sub(uel(P,2), Fl_add(Fl_mul(s,c, p),t, p),p),p);353return z;354}355356GEN357Fle_changepointinv(GEN P, GEN ch, ulong p)358{359ulong c, u, r, s, t, u2, u3;360GEN z;361if (ell_is_inf(P)) return ellinf();362u = ch[1]; r = ch[2];363s = ch[3]; t = ch[4];364u2 = Fl_sqr(u, p); u3 = Fl_mul(u,u2,p);365c = Fl_mul(u2,uel(P,1), p);366z = cgetg(3, t_VECSMALL);367z[1] = Fl_add(c,r,p);368z[2] = Fl_add(Fl_mul(u3,uel(P,2),p), Fl_add(Fl_mul(s,c,p), t, p), p);369return z;370}371static GEN372Fle_dbl_slope(GEN P, ulong a4, ulong p, ulong *slope)373{374ulong x, y, Qx, Qy;375if (ell_is_inf(P) || !P[2]) return ellinf();376x = P[1]; y = P[2];377*slope = Fl_div(Fl_add(Fl_triple(Fl_sqr(x,p), p), a4, p),378Fl_double(y, p), p);379Qx = Fl_sub(Fl_sqr(*slope, p), Fl_double(x, p), p);380Qy = Fl_sub(Fl_mul(*slope, Fl_sub(x, Qx, p), p), y, p);381return mkvecsmall2(Qx, Qy);382}383384GEN385Fle_dbl(GEN P, ulong a4, ulong p)386{387ulong slope;388return Fle_dbl_slope(P,a4,p,&slope);389}390391static GEN392Fle_add_slope(GEN P, GEN Q, ulong a4, ulong p, ulong *slope)393{394ulong Px, Py, Qx, Qy, Rx, Ry;395if (ell_is_inf(P)) return Q;396if (ell_is_inf(Q)) return P;397Px = P[1]; Py = P[2];398Qx = Q[1]; Qy = Q[2];399if (Px==Qx) return Py==Qy ? Fle_dbl_slope(P, a4, p, slope): ellinf();400*slope = Fl_div(Fl_sub(Py, Qy, p), Fl_sub(Px, Qx, p), p);401Rx = Fl_sub(Fl_sub(Fl_sqr(*slope, p), Px, p), Qx, p);402Ry = Fl_sub(Fl_mul(*slope, Fl_sub(Px, Rx, p), p), Py, p);403return mkvecsmall2(Rx, Ry);404}405406GEN407Fle_add(GEN P, GEN Q, ulong a4, ulong p)408{409ulong slope;410return Fle_add_slope(P,Q,a4,p,&slope);411}412413static GEN414Fle_neg(GEN P, ulong p)415{416if (ell_is_inf(P)) return P;417return mkvecsmall2(P[1], Fl_neg(P[2], p));418}419420GEN421Fle_sub(GEN P, GEN Q, ulong a4, ulong p)422{423pari_sp av = avma;424ulong slope;425return gerepileupto(av, Fle_add_slope(P, Fle_neg(Q, p), a4, p, &slope));426}427428struct _Fle { ulong a4, a6, p; };429430static GEN431_Fle_dbl(void *E, GEN P)432{433struct _Fle *ell = (struct _Fle *) E;434return Fle_dbl(P, ell->a4, ell->p);435}436437static GEN438_Fle_add(void *E, GEN P, GEN Q)439{440struct _Fle *ell=(struct _Fle *) E;441return Fle_add(P, Q, ell->a4, ell->p);442}443444GEN445Fle_mulu(GEN P, ulong n, ulong a4, ulong p)446{447ulong pi;448if (!n || ell_is_inf(P)) return ellinf();449if (n==1) return zv_copy(P);450if (n==2) return Fle_dbl(P, a4, p);451pi = get_Fl_red(p);452return Flj_to_Fle_pre(Flj_mulu_pre(Fle_to_Flj(P), n, a4, p, pi), p, pi);453}454455static GEN456_Fle_mul(void *E, GEN P, GEN n)457{458pari_sp av = avma;459struct _Fle *e=(struct _Fle *) E;460long s = signe(n);461GEN Q;462if (!s || ell_is_inf(P)) return ellinf();463if (s < 0) P = Fle_neg(P, e->p);464if (is_pm1(n)) return s > 0? zv_copy(P): P;465Q = (lgefint(n)==3) ? Fle_mulu(P, uel(n,2), e->a4, e->p):466gen_pow(P, n, (void*)e, &_Fle_dbl, &_Fle_add);467return s > 0? Q: gerepileuptoleaf(av, Q);468}469470GEN471Fle_mul(GEN P, GEN n, ulong a4, ulong p)472{473struct _Fle E;474E.a4 = a4; E.p = p;475return _Fle_mul(&E, P, n);476}477478/* Finds a random nonsingular point on E */479GEN480random_Fle_pre(ulong a4, ulong a6, ulong p, ulong pi)481{482ulong x, y;483random_Fle_pre_indir(a4, a6, p, pi, &x, &y);484return mkvecsmall2(x, y);485}486487GEN488random_Fle(ulong a4, ulong a6, ulong p)489{ return random_Fle_pre(a4, a6, p, get_Fl_red(p)); }490491static GEN492_Fle_rand(void *E)493{494struct _Fle *e=(struct _Fle *) E;495return random_Fle(e->a4, e->a6, e->p);496}497498static const struct bb_group Fle_group={_Fle_add,_Fle_mul,_Fle_rand,hash_GEN,zv_equal,ell_is_inf,NULL};499500GEN501Fle_order(GEN z, GEN o, ulong a4, ulong p)502{503pari_sp av = avma;504struct _Fle e;505e.a4=a4;506e.p=p;507return gerepileuptoint(av, gen_order(z, o, (void*)&e, &Fle_group));508}509510GEN511Fle_log(GEN a, GEN b, GEN o, ulong a4, ulong p)512{513pari_sp av = avma;514struct _Fle e;515e.a4=a4;516e.p=p;517return gerepileuptoint(av, gen_PH_log(a, b, o, (void*)&e, &Fle_group));518}519520ulong521Fl_ellj(ulong a4, ulong a6, ulong p)522{523if (SMALL_ULONG(p))524{ /* a43 = 4 a4^3 */525ulong a43 = Fl_double(Fl_double(Fl_mul(a4, Fl_sqr(a4, p), p), p), p);526/* a62 = 27 a6^2 */527ulong a62 = Fl_mul(Fl_sqr(a6, p), 27 % p, p);528ulong z1 = Fl_mul(a43, 1728 % p, p);529ulong z2 = Fl_add(a43, a62, p);530return Fl_div(z1, z2, p);531}532return Fl_ellj_pre(a4, a6, p, get_Fl_red(p));533}534535void536Fl_ellj_to_a4a6(ulong j, ulong p, ulong *pt_a4, ulong *pt_a6)537{538ulong zagier = 1728 % p;539if (j == 0) { *pt_a4 = 0; *pt_a6 =1; }540else if (j == zagier) { *pt_a4 = 1; *pt_a6 =0; }541else542{543ulong k = Fl_sub(zagier, j, p);544ulong kj = Fl_mul(k, j, p);545ulong k2j = Fl_mul(kj, k, p);546*pt_a4 = Fl_triple(kj, p);547*pt_a6 = Fl_double(k2j, p);548}549}550551ulong552Fl_elldisc_pre(ulong a4, ulong a6, ulong p, ulong pi)553{ /* D = -(4A^3 + 27B^2) */554ulong t1, t2;555t1 = Fl_mul_pre(a4, Fl_sqr_pre(a4, p, pi), p, pi);556t1 = Fl_double(Fl_double(t1, p), p);557t2 = Fl_mul_pre(27 % p, Fl_sqr_pre(a6, p, pi), p, pi);558return Fl_neg(Fl_add(t1, t2, p), p);559}560561ulong562Fl_elldisc(ulong a4, ulong a6, ulong p)563{564if (SMALL_ULONG(p))565{ /* D = -(4A^3 + 27B^2) */566ulong t1, t2;567t1 = Fl_mul(a4, Fl_sqr(a4, p), p);568t1 = Fl_double(Fl_double(t1, p), p);569t2 = Fl_mul(27 % p, Fl_sqr(a6, p), p);570return Fl_neg(Fl_add(t1, t2, p), p);571}572return Fl_elldisc_pre(a4, a6, p, get_Fl_red(p));573}574575void576Fl_elltwist_disc(ulong a4, ulong a6, ulong D, ulong p, ulong *pa4, ulong *pa6)577{578ulong D2 = Fl_sqr(D, p);579*pa4 = Fl_mul(a4, D2, p);580*pa6 = Fl_mul(a6, Fl_mul(D, D2, p), p);581}582583void584Fl_elltwist(ulong a4, ulong a6, ulong p, ulong *pt_a4, ulong *pt_a6)585{ Fl_elltwist_disc(a4, a6, nonsquare_Fl(p), p, pt_a4, pt_a6); }586587static void588Fle_dbl_sinv_pre_inplace(GEN P, ulong a4, ulong sinv, ulong p, ulong pi)589{590ulong x, y, slope;591if (uel(P,1)==p) return;592if (!P[2]) { P[1] = p; return; }593x = P[1]; y = P[2];594slope = Fl_mul_pre(Fl_add(Fl_triple(Fl_sqr_pre(x, p, pi), p), a4, p),595sinv, p, pi);596P[1] = Fl_sub(Fl_sqr_pre(slope, p, pi), Fl_double(x, p), p);597P[2] = Fl_sub(Fl_mul_pre(slope, Fl_sub(x, P[1], p), p, pi), y, p);598}599600static void601Fle_add_sinv_pre_inplace(GEN P, GEN Q, ulong a4, ulong sinv, ulong p, ulong pi)602{603ulong Px, Py, Qx, Qy, slope;604if (uel(P,1)==p) { P[1] = Q[1]; P[2] = Q[2]; }605if (ell_is_inf(Q)) return;606Px = P[1]; Py = P[2];607Qx = Q[1]; Qy = Q[2];608if (Px==Qx)609{610if (Py==Qy) Fle_dbl_sinv_pre_inplace(P, a4, sinv, p, pi);611else P[1] = p;612return;613}614slope = Fl_mul_pre(Fl_sub(Py, Qy, p), sinv, p, pi);615P[1] = Fl_sub(Fl_sub(Fl_sqr_pre(slope, p, pi), Px, p), Qx, p);616P[2] = Fl_sub(Fl_mul_pre(slope, Fl_sub(Px, P[1], p), p, pi), Py, p);617}618619static void620Fle_sub_sinv_pre_inplace(GEN P, GEN Q, ulong a4, ulong sinv, ulong p, ulong pi)621{622ulong Px, Py, Qx, Qy, slope;623if (uel(P,1)==p) { P[1] = Q[1]; P[2] = Fl_neg(Q[2], p); }624if (ell_is_inf(Q)) return;625Px = P[1]; Py = P[2];626Qx = Q[1]; Qy = Q[2];627if (Px==Qx)628{629if (Py==Qy) P[1] = p;630else631Fle_dbl_sinv_pre_inplace(P, a4, sinv, p, pi);632return;633}634slope = Fl_mul_pre(Fl_add(Py, Qy, p), sinv, p, pi);635P[1] = Fl_sub(Fl_sub(Fl_sqr_pre(slope, p, pi), Px, p), Qx, p);636P[2] = Fl_sub(Fl_mul_pre(slope, Fl_sub(Px, P[1], p), p, pi), Py, p);637}638639static long640skipzero(long n) { return n ? n:1; }641642void643FleV_add_pre_inplace(GEN P, GEN Q, GEN a4, ulong p, ulong pi)644{645long i, l=lg(a4);646GEN sinv = cgetg(l, t_VECSMALL);647for(i=1; i<l; i++)648uel(sinv,i) = umael(P,i,1)==p? 1: skipzero(Fl_sub(mael(P,i,1), mael(Q,i,1), p));649Flv_inv_pre_inplace(sinv, p, pi);650for (i=1; i<l; i++)651Fle_add_sinv_pre_inplace(gel(P,i), gel(Q,i), uel(a4,i), uel(sinv,i), p, pi);652}653654void655FleV_sub_pre_inplace(GEN P, GEN Q, GEN a4, ulong p, ulong pi)656{657long i, l=lg(a4);658GEN sinv = cgetg(l, t_VECSMALL);659for(i=1; i<l; i++)660uel(sinv,i) = umael(P,i,1)==p? 1: skipzero(Fl_sub(mael(P,i,1), mael(Q,i,1), p));661Flv_inv_pre_inplace(sinv, p, pi);662for (i=1; i<l; i++)663Fle_sub_sinv_pre_inplace(gel(P,i), gel(Q,i), uel(a4,i), uel(sinv,i), p, pi);664}665666void667FleV_dbl_pre_inplace(GEN P, GEN a4, ulong p, ulong pi)668{669long i, l=lg(a4);670GEN sinv = cgetg(l, t_VECSMALL);671for(i=1; i<l; i++)672uel(sinv,i) = umael(P,i,1)==p? 1: skipzero(Fl_double(umael(P,i,2), p));673Flv_inv_pre_inplace(sinv, p, pi);674for(i=1; i<l; i++)675Fle_dbl_sinv_pre_inplace(gel(P,i), uel(a4,i), uel(sinv,i), p, pi);676}677678static void679FleV_mulu_pre_naf_inplace(GEN P, ulong n, GEN a4, ulong p, ulong pi, const naf_t *x)680{681pari_sp av = avma;682ulong pbits, nbits, m;683GEN R;684if (n == 1) return;685686R = P; P = gcopy(P);687FleV_dbl_pre_inplace(R, a4, p, pi);688if (n == 2) return;689690pbits = x->pbits;691nbits = x->nbits;692m = (1UL << x->lnzb);693for ( ; m; m >>= 1) {694FleV_dbl_pre_inplace(R, a4, p, pi);695if (m & pbits)696FleV_add_pre_inplace(R, P, a4, p, pi);697else if (m & nbits)698FleV_sub_pre_inplace(R, P, a4, p, pi);699}700set_avma(av);701}702703void704FleV_mulu_pre_inplace(GEN P, ulong n, GEN a4, ulong p, ulong pi)705{706naf_t x; naf_repr(&x, n);707FleV_mulu_pre_naf_inplace(P, n, a4, p, pi, &x);708}709710/***********************************************************************/711/** **/712/** Pairings **/713/** **/714/***********************************************************************/715716/* Derived from APIP from and by Jerome Milan, 2012 */717718static ulong719Fle_vert(GEN P, GEN Q, ulong a4, ulong p)720{721if (ell_is_inf(P))722return 1;723if (uel(Q, 1) != uel(P, 1))724return Fl_sub(uel(Q, 1), uel(P, 1), p);725if (uel(P,2) != 0 ) return 1;726return Fl_inv(Fl_add(Fl_triple(Fl_sqr(uel(P,1),p), p), a4, p), p);727}728729static ulong730Fle_Miller_line(GEN R, GEN Q, ulong slope, ulong a4, ulong p)731{732ulong x = uel(Q, 1), y = uel(Q, 2);733ulong tmp1 = Fl_sub(x, uel(R, 1), p);734ulong tmp2 = Fl_add(Fl_mul(tmp1, slope, p), uel(R,2), p);735if (y != tmp2)736return Fl_sub(y, tmp2, p);737if (y == 0)738return 1;739else740{741ulong s1, s2;742ulong y2i = Fl_inv(Fl_double(y, p), p);743s1 = Fl_mul(Fl_add(Fl_triple(Fl_sqr(x, p), p), a4, p), y2i, p);744if (s1 != slope)745return Fl_sub(s1, slope, p);746s2 = Fl_mul(Fl_sub(Fl_triple(x, p), Fl_sqr(s1, p), p), y2i, p);747return s2 ? s2: y2i;748}749}750751/* Computes the equation of the line tangent to R and returns its752evaluation at the point Q. Also doubles the point R.753*/754755static ulong756Fle_tangent_update(GEN R, GEN Q, ulong a4, ulong p, GEN *pt_R)757{758if (ell_is_inf(R))759{760*pt_R = ellinf();761return 1;762}763else if (uel(R,2) == 0)764{765*pt_R = ellinf();766return Fle_vert(R, Q, a4, p);767} else {768ulong slope;769*pt_R = Fle_dbl_slope(R, a4, p, &slope);770return Fle_Miller_line(R, Q, slope, a4, p);771}772}773774/* Computes the equation of the line through R and P, and returns its775evaluation at the point Q. Also adds P to the point R.776*/777778static ulong779Fle_chord_update(GEN R, GEN P, GEN Q, ulong a4, ulong p, GEN *pt_R)780{781if (ell_is_inf(R))782{783*pt_R = gcopy(P);784return Fle_vert(P, Q, a4, p);785}786else if (ell_is_inf(P))787{788*pt_R = gcopy(R);789return Fle_vert(R, Q, a4, p);790}791else if (uel(P, 1) == uel(R, 1))792{793if (uel(P, 2) == uel(R, 2))794return Fle_tangent_update(R, Q, a4, p, pt_R);795else {796*pt_R = ellinf();797return Fle_vert(R, Q, a4, p);798}799} else {800ulong slope;801*pt_R = Fle_add_slope(P, R, a4, p, &slope);802return Fle_Miller_line(R, Q, slope, a4, p);803}804}805806struct _Fle_miller { ulong p, a4; GEN P; };807static GEN808Fle_Miller_dbl(void* E, GEN d)809{810struct _Fle_miller *m = (struct _Fle_miller *)E;811ulong p = m->p, a4 = m->a4;812GEN P = m->P;813ulong v, line;814ulong N = Fl_sqr(umael(d,1,1), p);815ulong D = Fl_sqr(umael(d,1,2), p);816GEN point = gel(d,2);817line = Fle_tangent_update(point, P, a4, p, &point);818N = Fl_mul(N, line, p);819v = Fle_vert(point, P, a4, p);820D = Fl_mul(D, v, p); return mkvec2(mkvecsmall2(N, D), point);821}822static GEN823Fle_Miller_add(void* E, GEN va, GEN vb)824{825struct _Fle_miller *m = (struct _Fle_miller *)E;826ulong p = m->p, a4= m->a4;827GEN P = m->P, point;828ulong v, line;829ulong na = umael(va,1,1), da = umael(va,1,2);830ulong nb = umael(vb,1,1), db = umael(vb,1,2);831GEN pa = gel(va,2), pb = gel(vb,2);832ulong N = Fl_mul(na, nb, p);833ulong D = Fl_mul(da, db, p);834line = Fle_chord_update(pa, pb, P, a4, p, &point);835N = Fl_mul(N, line, p);836v = Fle_vert(point, P, a4, p);837D = Fl_mul(D, v, p); return mkvec2(mkvecsmall2(N, D), point);838}839840/* Returns the Miller function f_{m, Q} evaluated at the point P using841* the standard Miller algorithm. */842static ulong843Fle_Miller(GEN Q, GEN P, ulong m, ulong a4, ulong p)844{845pari_sp av = avma;846struct _Fle_miller d;847GEN v;848ulong N, D;849850d.a4 = a4; d.p = p; d.P = P;851v = gen_powu_i(mkvec2(mkvecsmall2(1,1), Q), m, (void*)&d,852Fle_Miller_dbl, Fle_Miller_add);853N = umael(v,1,1); D = umael(v,1,2);854return gc_ulong(av, Fl_div(N, D, p));855}856857ulong858Fle_weilpairing(GEN P, GEN Q, ulong m, ulong a4, ulong p)859{860pari_sp ltop = avma;861ulong N, D, w;862if (ell_is_inf(P) || ell_is_inf(Q) || zv_equal(P,Q)) return 1;863N = Fle_Miller(P, Q, m, a4, p);864D = Fle_Miller(Q, P, m, a4, p);865w = Fl_div(N, D, p);866if (odd(m)) w = Fl_neg(w, p);867return gc_ulong(ltop, w);868}869870ulong871Fle_tatepairing(GEN P, GEN Q, ulong m, ulong a4, ulong p)872{873if (ell_is_inf(P) || ell_is_inf(Q)) return 1;874return Fle_Miller(P, Q, m, a4, p);875}876877GEN878Fl_ellptors(ulong l, ulong N, ulong a4, ulong a6, ulong p)879{880long v = z_lval(N, l);881ulong N0, N1;882GEN F;883if (v==0) return cgetg(1,t_VEC);884N0 = upowuu(l, v); N1 = N/N0;885F = mkmat2(mkcols(l), mkcols(v));886while(1)887{888pari_sp av2 = avma;889GEN P, Q;890ulong d, s, t;891892P = Fle_mulu(random_Fle(a4, a6, p), N1, a4, p);893Q = Fle_mulu(random_Fle(a4, a6, p), N1, a4, p);894s = itou(Fle_order(P, F, a4, p));895t = itou(Fle_order(Q, F, a4, p));896if (s < t) { swap(P,Q); lswap(s,t); }897if (s == N0) retmkvec(Fle_mulu(P, s/l, a4, p));898d = Fl_order(Fle_weilpairing(P, Q, s, a4, p), s, p);899if (s*d == N0)900retmkvec2(Fle_mulu(P, s/l, a4, p), Fle_mulu(Q, t/l, a4, p));901set_avma(av2);902}903}904905906