Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2000-2004 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/***********************************************************************/15/** **/16/** GENERIC ALGORITHMS ON BLACKBOX GROUP **/17/** **/18/***********************************************************************/19#include "pari.h"20#include "paripriv.h"21#undef pow /* AIX: pow(a,b) is a macro, wrongly expanded on grp->pow(a,b,c) */2223#define DEBUGLEVEL DEBUGLEVEL_bb_group2425/***********************************************************************/26/** **/27/** POWERING **/28/** **/29/***********************************************************************/3031/* return (n>>(i+1-l)) & ((1<<l)-1) */32static ulong33int_block(GEN n, long i, long l)34{35long q = divsBIL(i), r = remsBIL(i)+1, lr;36GEN nw = int_W(n, q);37ulong w = (ulong) *nw, w2;38if (r>=l) return (w>>(r-l))&((1UL<<l)-1);39w &= (1UL<<r)-1; lr = l-r;40w2 = (ulong) *int_precW(nw); w2 >>= (BITS_IN_LONG-lr);41return (w<<lr)|w2;42}4344/* assume n != 0, t_INT. Compute x^|n| using sliding window powering */45static GEN46sliding_window_powu(GEN x, ulong n, long e, void *E, GEN (*sqr)(void*,GEN),47GEN (*mul)(void*,GEN,GEN))48{49pari_sp av;50long i, l = expu(n), u = (1UL<<(e-1));51long w, v;52GEN tab = cgetg(1+u, t_VEC);53GEN x2 = sqr(E, x), z = NULL, tw;54gel(tab, 1) = x;55for (i=2; i<=u; i++) gel(tab,i) = mul(E, gel(tab,i-1), x2);56av = avma;57while (l>=0)58{59if (e > l+1) e = l+1;60w = (n>>(l+1-e)) & ((1UL<<e)-1); v = vals(w); l-=e;61tw = gel(tab, 1+(w>>(v+1)));62if (z)63{64for (i=1; i<=e-v; i++) z = sqr(E, z);65z = mul(E, z, tw);66} else z = tw;67for (i=1; i<=v; i++) z = sqr(E, z);68while (l>=0)69{70if (gc_needed(av,1))71{72if (DEBUGMEM>1) pari_warn(warnmem,"sliding_window_powu (%ld)", l);73z = gerepilecopy(av, z);74}75if (n&(1UL<<l)) break;76z = sqr(E, z); l--;77}78}79return z;80}8182/* assume n != 0, t_INT. Compute x^|n| using sliding window powering */83static GEN84sliding_window_pow(GEN x, GEN n, long e, void *E, GEN (*sqr)(void*,GEN),85GEN (*mul)(void*,GEN,GEN))86{87pari_sp av;88long i, l = expi(n), u = (1UL<<(e-1));89long w, v;90GEN tab = cgetg(1+u, t_VEC);91GEN x2 = sqr(E, x), z = NULL, tw;92gel(tab, 1) = x;93for (i=2; i<=u; i++) gel(tab,i) = mul(E, gel(tab,i-1), x2);94av = avma;95while (l>=0)96{97if (e > l+1) e = l+1;98w = int_block(n,l,e); v = vals(w); l-=e;99tw = gel(tab, 1+(w>>(v+1)));100if (z)101{102for (i=1; i<=e-v; i++) z = sqr(E, z);103z = mul(E, z, tw);104} else z = tw;105for (i=1; i<=v; i++) z = sqr(E, z);106while (l>=0)107{108if (gc_needed(av,1))109{110if (DEBUGMEM>1) pari_warn(warnmem,"sliding_window_pow (%ld)", l);111z = gerepilecopy(av, z);112}113if (int_bit(n,l)) break;114z = sqr(E, z); l--;115}116}117return z;118}119120/* assume n != 0, t_INT. Compute x^|n| using leftright binary powering */121static GEN122leftright_binary_powu(GEN x, ulong n, void *E, GEN (*sqr)(void*,GEN),123GEN (*mul)(void*,GEN,GEN))124{125pari_sp av = avma;126GEN y;127int j;128129if (n == 1) return x;130y = x; j = 1+bfffo(n);131/* normalize, i.e set highest bit to 1 (we know n != 0) */132n<<=j; j = BITS_IN_LONG-j;133/* first bit is now implicit */134for (; j; n<<=1,j--)135{136y = sqr(E,y);137if (n & HIGHBIT) y = mul(E,y,x); /* first bit set: multiply by base */138if (gc_needed(av,1))139{140if (DEBUGMEM>1) pari_warn(warnmem,"leftright_powu (%d)", j);141y = gerepilecopy(av, y);142}143}144return y;145}146147GEN148gen_powu_i(GEN x, ulong n, void *E, GEN (*sqr)(void*,GEN),149GEN (*mul)(void*,GEN,GEN))150{151long l;152if (n == 1) return x;153l = expu(n);154if (l<=8)155return leftright_binary_powu(x, n, E, sqr, mul);156else157return sliding_window_powu(x, n, l<=24? 2: 3, E, sqr, mul);158}159160GEN161gen_powu(GEN x, ulong n, void *E, GEN (*sqr)(void*,GEN),162GEN (*mul)(void*,GEN,GEN))163{164pari_sp av = avma;165if (n == 1) return gcopy(x);166return gerepilecopy(av, gen_powu_i(x,n,E,sqr,mul));167}168169GEN170gen_pow_i(GEN x, GEN n, void *E, GEN (*sqr)(void*,GEN),171GEN (*mul)(void*,GEN,GEN))172{173long l, e;174if (lgefint(n)==3) return gen_powu_i(x, uel(n,2), E, sqr, mul);175l = expi(n);176if (l<=64) e = 3;177else if (l<=160) e = 4;178else if (l<=384) e = 5;179else if (l<=896) e = 6;180else e = 7;181return sliding_window_pow(x, n, e, E, sqr, mul);182}183184GEN185gen_pow(GEN x, GEN n, void *E, GEN (*sqr)(void*,GEN),186GEN (*mul)(void*,GEN,GEN))187{188pari_sp av = avma;189return gerepilecopy(av, gen_pow_i(x,n,E,sqr,mul));190}191192/* assume n > 0. Compute x^n using left-right binary powering */193GEN194gen_powu_fold_i(GEN x, ulong n, void *E, GEN (*sqr)(void*,GEN),195GEN (*msqr)(void*,GEN))196{197pari_sp av = avma;198GEN y;199int j;200201if (n == 1) return x;202y = x; j = 1+bfffo(n);203/* normalize, i.e set highest bit to 1 (we know n != 0) */204n<<=j; j = BITS_IN_LONG-j;205/* first bit is now implicit */206for (; j; n<<=1,j--)207{208if (n & HIGHBIT) y = msqr(E,y); /* first bit set: multiply by base */209else y = sqr(E,y);210if (gc_needed(av,1))211{212if (DEBUGMEM>1) pari_warn(warnmem,"gen_powu_fold (%d)", j);213y = gerepilecopy(av, y);214}215}216return y;217}218GEN219gen_powu_fold(GEN x, ulong n, void *E, GEN (*sqr)(void*,GEN),220GEN (*msqr)(void*,GEN))221{222pari_sp av = avma;223if (n == 1) return gcopy(x);224return gerepilecopy(av, gen_powu_fold_i(x,n,E,sqr,msqr));225}226227/* assume N != 0, t_INT. Compute x^|N| using left-right binary powering */228GEN229gen_pow_fold_i(GEN x, GEN N, void *E, GEN (*sqr)(void*,GEN),230GEN (*msqr)(void*,GEN))231{232long ln = lgefint(N);233if (ln == 3) return gen_powu_fold_i(x, N[2], E, sqr, msqr);234else235{236GEN nd = int_MSW(N), y = x;237ulong n = *nd;238long i;239int j;240pari_sp av = avma;241242if (n == 1)243j = 0;244else245{246j = 1+bfffo(n); /* < BIL */247/* normalize, i.e set highest bit to 1 (we know n != 0) */248n <<= j; j = BITS_IN_LONG - j;249}250/* first bit is now implicit */251for (i=ln-2;;)252{253for (; j; n<<=1,j--)254{255if (n & HIGHBIT) y = msqr(E,y); /* first bit set: multiply by base */256else y = sqr(E,y);257if (gc_needed(av,1))258{259if (DEBUGMEM>1) pari_warn(warnmem,"gen_pow_fold (%d)", j);260y = gerepilecopy(av, y);261}262}263if (--i == 0) return y;264nd = int_precW(nd);265n = *nd; j = BITS_IN_LONG;266}267}268}269GEN270gen_pow_fold(GEN x, GEN n, void *E, GEN (*sqr)(void*,GEN),271GEN (*msqr)(void*,GEN))272{273pari_sp av = avma;274return gerepilecopy(av, gen_pow_fold_i(x,n,E,sqr,msqr));275}276277GEN278gen_pow_init(GEN x, GEN n, long k, void *E, GEN (*sqr)(void*,GEN), GEN (*mul)(void*,GEN,GEN))279{280long i, j, l = expi(n);281long m = 1UL<<(k-1);282GEN x2 = sqr(E, x), y = gcopy(x);283GEN R = cgetg(m+1, t_VEC);284for(i = 1; i <= m; i++)285{286GEN C = cgetg(l+1, t_VEC);287gel(C,1) = y;288for(j = 2; j <= l; j++)289gel(C,j) = sqr(E, gel(C,j-1));290gel(R,i) = C;291y = mul(E, y, x2);292}293return R;294}295296GEN297gen_pow_table(GEN R, GEN n, void *E, GEN (*one)(void*), GEN (*mul)(void*,GEN,GEN))298{299long e = expu(lg(R)-1) + 1;300long l = expi(n);301long i, w;302GEN z = one(E), tw;303for(i=0; i<=l; )304{305if (int_bit(n, i)==0) { i++; continue; }306if (i+e-1>l) e = l+1-i;307w = int_block(n,i+e-1,e);308tw = gmael(R, 1+(w>>1), i+1);309z = mul(E, z, tw);310i += e;311}312return z;313}314315GEN316gen_powers(GEN x, long l, int use_sqr, void *E, GEN (*sqr)(void*,GEN),317GEN (*mul)(void*,GEN,GEN), GEN (*one)(void*))318{319long i;320GEN V = cgetg(l+2,t_VEC);321gel(V,1) = one(E); if (l==0) return V;322gel(V,2) = gcopy(x); if (l==1) return V;323gel(V,3) = sqr(E,x);324if (use_sqr)325for(i = 4; i < l+2; i++)326gel(V,i) = (i&1)? sqr(E,gel(V, (i+1)>>1))327: mul(E,gel(V, i-1),x);328else329for(i = 4; i < l+2; i++)330gel(V,i) = mul(E,gel(V,i-1),x);331return V;332}333334GEN335producttree_scheme(long n)336{337GEN v, w;338long i, j, k, u, l;339if (n<=2) return mkvecsmall(n);340u = expu(n-1);341v = cgetg(n+1,t_VECSMALL);342w = cgetg(n+1,t_VECSMALL);343v[1] = n; l = 1;344for (i=1; i<=u; i++)345{346for(j=1, k=1; j<=l; j++, k+=2)347{348long vj = v[j], v2 = vj>>1;349w[k] = vj-v2;350w[k+1] = v2;351}352swap(v,w); l<<=1;353}354fixlg(v, l+1); set_avma((pari_sp)v); return v;355}356357GEN358gen_product(GEN x, void *E, GEN (*mul)(void *,GEN,GEN))359{360pari_sp av;361long i, k, l = lg(x);362pari_timer ti;363GEN y, v;364365if (l <= 2) return l == 1? gen_1: gcopy(gel(x,1));366y = cgetg(l, t_VEC); av = avma;367v = producttree_scheme(l-1);368l = lg(v);369if (DEBUGLEVEL>7) timer_start(&ti);370for (k = i = 1; k < l; i += v[k++])371gel(y,k) = v[k]==1? gel(x,i): mul(E, gel(x,i), gel(x,i+1));372while (k > 2)373{374long n = k - 1;375if (DEBUGLEVEL>7) timer_printf(&ti,"gen_product: remaining objects %ld",n);376for (k = i = 1; i < n; i += 2) gel(y,k++) = mul(E, gel(y,i), gel(y,i+1));377if (gc_needed(av,1)) gerepilecoeffs(av, y+1, k-1);378}379return gel(y,1);380}381382/***********************************************************************/383/** **/384/** DISCRETE LOGARITHM **/385/** **/386/***********************************************************************/387static GEN388iter_rho(GEN x, GEN g, GEN q, GEN A, ulong h, void *E, const struct bb_group *grp)389{390GEN a = gel(A,1), b = gel(A,2), c = gel(A,3);391switch((h | grp->hash(a)) % 3UL)392{393case 0: return mkvec3(grp->pow(E,a,gen_2), Fp_mulu(b,2,q), Fp_mulu(c,2,q));394case 1: return mkvec3(grp->mul(E,a,x), addiu(b,1), c);395case 2: return mkvec3(grp->mul(E,a,g), b, addiu(c,1));396}397return NULL; /* LCOV_EXCL_LINE */398}399400/*Generic Pollard rho discrete log algorithm*/401static GEN402gen_Pollard_log(GEN x, GEN g, GEN q, void *E, const struct bb_group *grp)403{404pari_sp av=avma;405GEN A, B, l, sqrt4q = sqrti(shifti(q,4));406ulong i, h = 0, imax = itou_or_0(sqrt4q);407if (!imax) imax = ULONG_MAX;408do {409rho_restart:410A = B = mkvec3(x,gen_1,gen_0);411i=0;412do {413if (i>imax)414{415h++;416if (DEBUGLEVEL)417pari_warn(warner,"changing Pollard rho hash seed to %ld",h);418goto rho_restart;419}420A = iter_rho(x, g, q, A, h, E, grp);421B = iter_rho(x, g, q, B, h, E, grp);422B = iter_rho(x, g, q, B, h, E, grp);423if (gc_needed(av,2))424{425if(DEBUGMEM>1) pari_warn(warnmem,"gen_Pollard_log");426gerepileall(av, 2, &A, &B);427}428i++;429} while (!grp->equal(gel(A,1), gel(B,1)));430gel(A,2) = modii(gel(A,2), q);431gel(B,2) = modii(gel(B,2), q);432h++;433} while (equalii(gel(A,2), gel(B,2)));434l = Fp_div(Fp_sub(gel(B,3), gel(A,3),q),Fp_sub(gel(A,2), gel(B,2), q), q);435return gerepileuptoint(av, l);436}437438/* compute a hash of g^(i-1), 1<=i<=n. Return [sorted hash, perm, g^-n] */439GEN440gen_Shanks_init(GEN g, long n, void *E, const struct bb_group *grp)441{442GEN p1 = g, G, perm, table = cgetg(n+1,t_VECSMALL);443pari_sp av=avma;444long i;445table[1] = grp->hash(grp->pow(E,g,gen_0));446for (i=2; i<=n; i++)447{448table[i] = grp->hash(p1);449p1 = grp->mul(E,p1,g);450if (gc_needed(av,2))451{452if(DEBUGMEM>1) pari_warn(warnmem,"gen_Shanks_log, baby = %ld", i);453p1 = gerepileupto(av, p1);454}455}456G = gerepileupto(av, grp->pow(E,p1,gen_m1)); /* g^-n */457perm = vecsmall_indexsort(table);458table = vecsmallpermute(table,perm);459return mkvec4(table,perm,g,G);460}461/* T from gen_Shanks_init(g,n). Return v < n*N such that x = g^v or NULL */462GEN463gen_Shanks(GEN T, GEN x, ulong N, void *E, const struct bb_group *grp)464{465pari_sp av=avma;466GEN table = gel(T,1), perm = gel(T,2), g = gel(T,3), G = gel(T,4);467GEN p1 = x;468long n = lg(table)-1;469ulong k;470for (k=0; k<N; k++)471{ /* p1 = x G^k, G = g^-n */472long h = grp->hash(p1), i = zv_search(table, h);473if (i)474{475do i--; while (i && table[i] == h);476for (i++; i <= n && table[i] == h; i++)477{478GEN v = addiu(muluu(n,k), perm[i]-1);479if (grp->equal(grp->pow(E,g,v),x)) return gerepileuptoint(av,v);480if (DEBUGLEVEL)481err_printf("gen_Shanks_log: false positive %lu, %lu\n", k,h);482}483}484p1 = grp->mul(E,p1,G);485if (gc_needed(av,2))486{487if(DEBUGMEM>1) pari_warn(warnmem,"gen_Shanks_log, k = %lu", k);488p1 = gerepileupto(av, p1);489}490}491return NULL;492}493/* Generic Shanks baby-step/giant-step algorithm. Return log_g(x), ord g = q.494* One-shot: use gen_Shanks_init/log if many logs are desired; early abort495* if log < sqrt(q) */496static GEN497gen_Shanks_log(GEN x, GEN g, GEN q, void *E, const struct bb_group *grp)498{499pari_sp av=avma, av1;500long lbaby, i, k;501GEN p1, table, giant, perm, ginv;502p1 = sqrti(q);503if (abscmpiu(p1,LGBITS) >= 0)504pari_err_OVERFLOW("gen_Shanks_log [order too large]");505lbaby = itos(p1)+1; table = cgetg(lbaby+1,t_VECSMALL);506ginv = grp->pow(E,g,gen_m1);507av1 = avma;508for (p1=x, i=1;;i++)509{510if (grp->equal1(p1)) { set_avma(av); return stoi(i-1); }511table[i] = grp->hash(p1); if (i==lbaby) break;512p1 = grp->mul(E,p1,ginv);513if (gc_needed(av1,2))514{515if(DEBUGMEM>1) pari_warn(warnmem,"gen_Shanks_log, baby = %ld", i);516p1 = gerepileupto(av1, p1);517}518}519p1 = giant = gerepileupto(av1, grp->mul(E,x,grp->pow(E, p1, gen_m1)));520perm = vecsmall_indexsort(table);521table = vecsmallpermute(table,perm);522av1 = avma;523for (k=1; k<= lbaby; k++)524{525long h = grp->hash(p1), i = zv_search(table, h);526if (i)527{528while (table[i] == h && i) i--;529for (i++; i <= lbaby && table[i] == h; i++)530{531GEN v = addiu(mulss(lbaby-1,k),perm[i]-1);532if (grp->equal(grp->pow(E,g,v),x)) return gerepileuptoint(av,v);533if (DEBUGLEVEL)534err_printf("gen_Shanks_log: false positive %ld, %lu\n", k,h);535}536}537p1 = grp->mul(E,p1,giant);538if (gc_needed(av1,2))539{540if(DEBUGMEM>1) pari_warn(warnmem,"gen_Shanks_log, k = %ld", k);541p1 = gerepileupto(av1, p1);542}543}544set_avma(av); return cgetg(1, t_VEC); /* no solution */545}546547/*Generic discrete logarithme in a group of prime order p*/548GEN549gen_plog(GEN x, GEN g, GEN p, void *E, const struct bb_group *grp)550{551if (grp->easylog)552{553GEN e = grp->easylog(E, x, g, p);554if (e) return e;555}556if (grp->equal1(x)) return gen_0;557if (grp->equal(x,g)) return gen_1;558if (expi(p)<32) return gen_Shanks_log(x,g,p,E,grp);559return gen_Pollard_log(x, g, p, E, grp);560}561562GEN563get_arith_ZZM(GEN o)564{565if (!o) return NULL;566switch(typ(o))567{568case t_INT:569if (signe(o) > 0) return mkvec2(o, Z_factor(o));570break;571case t_MAT:572if (is_Z_factorpos(o)) return mkvec2(factorback(o), o);573break;574case t_VEC:575if (lg(o) == 3 && signe(gel(o,1)) > 0 && is_Z_factorpos(gel(o,2))) return o;576break;577}578pari_err_TYPE("generic discrete logarithm (order factorization)",o);579return NULL; /* LCOV_EXCL_LINE */580}581GEN582get_arith_Z(GEN o)583{584if (!o) return NULL;585switch(typ(o))586{587case t_INT:588if (signe(o) > 0) return o;589break;590case t_MAT:591o = factorback(o);592if (typ(o) == t_INT && signe(o) > 0) return o;593break;594case t_VEC:595if (lg(o) != 3) break;596o = gel(o,1);597if (typ(o) == t_INT && signe(o) > 0) return o;598break;599}600pari_err_TYPE("generic discrete logarithm (order factorization)",o);601return NULL; /* LCOV_EXCL_LINE */602}603604/* Generic Pohlig-Hellman discrete logarithm: smallest integer n >= 0 such that605* g^n=a. Assume ord(g) | ord; grp->easylog() is an optional trapdoor606* function that catches easy logarithms */607GEN608gen_PH_log(GEN a, GEN g, GEN ord, void *E, const struct bb_group *grp)609{610pari_sp av = avma;611GEN v, ginv, fa, ex;612long i, j, l;613614if (grp->equal(g, a)) /* frequent special case */615return grp->equal1(g)? gen_0: gen_1;616if (grp->easylog)617{618GEN e = grp->easylog(E, a, g, ord);619if (e) return e;620}621v = get_arith_ZZM(ord);622ord= gel(v,1);623fa = gel(v,2);624ex = gel(fa,2);625fa = gel(fa,1); l = lg(fa);626ginv = grp->pow(E,g,gen_m1);627v = cgetg(l, t_VEC);628for (i = 1; i < l; i++)629{630GEN q = gel(fa,i), qj, gq, nq, ginv0, a0, t0;631long e = itos(gel(ex,i));632if (DEBUGLEVEL>5)633err_printf("Pohlig-Hellman: DL mod %Ps^%ld\n",q,e);634qj = new_chunk(e+1);635gel(qj,0) = gen_1;636gel(qj,1) = q;637for (j = 2; j <= e; j++) gel(qj,j) = mulii(gel(qj,j-1), q);638t0 = diviiexact(ord, gel(qj,e));639a0 = grp->pow(E, a, t0);640ginv0 = grp->pow(E, ginv, t0); /* ord(ginv0) | q^e */641if (grp->equal1(ginv0)) { gel(v,i) = mkintmod(gen_0, gen_1); continue; }642do gq = grp->pow(E,g, mulii(t0, gel(qj,--e))); while (grp->equal1(gq));643/* ord(gq) = q */644nq = gen_0;645for (j = 0;; j++)646{ /* nq = sum_{i<j} b_i q^i */647GEN b = grp->pow(E,a0, gel(qj,e-j));648/* cheap early abort: wrong local order */649if (j == 0 && !grp->equal1(grp->pow(E,b,q))) {650set_avma(av); return cgetg(1, t_VEC);651}652b = gen_plog(b, gq, q, E, grp);653if (typ(b) != t_INT) { set_avma(av); return cgetg(1, t_VEC); }654nq = addii(nq, mulii(b, gel(qj,j)));655if (j == e) break;656657a0 = grp->mul(E,a0, grp->pow(E,ginv0, b));658ginv0 = grp->pow(E,ginv0, q);659}660gel(v,i) = mkintmod(nq, gel(qj,e+1));661}662return gerepileuptoint(av, lift(chinese1_coprime_Z(v)));663}664665/***********************************************************************/666/** **/667/** ORDER OF AN ELEMENT **/668/** **/669/***********************************************************************/670/*Find the exact order of a assuming a^o==1*/671GEN672gen_order(GEN a, GEN o, void *E, const struct bb_group *grp)673{674pari_sp av = avma;675long i, l;676GEN m;677678m = get_arith_ZZM(o);679if (!m) pari_err_TYPE("gen_order [missing order]",a);680o = gel(m,1);681m = gel(m,2); l = lgcols(m);682for (i = l-1; i; i--)683{684GEN t, y, p = gcoeff(m,i,1);685long j, e = itos(gcoeff(m,i,2));686if (l == 2) {687t = gen_1;688y = a;689} else {690t = diviiexact(o, powiu(p,e));691y = grp->pow(E, a, t);692}693if (grp->equal1(y)) o = t;694else {695for (j = 1; j < e; j++)696{697y = grp->pow(E, y, p);698if (grp->equal1(y)) break;699}700if (j < e) {701if (j > 1) p = powiu(p, j);702o = mulii(t, p);703}704}705}706return gerepilecopy(av, o);707}708709/*Find the exact order of a assuming a^o==1, return [order,factor(order)] */710GEN711gen_factored_order(GEN a, GEN o, void *E, const struct bb_group *grp)712{713pari_sp av = avma;714long i, l, ind;715GEN m, F, P;716717m = get_arith_ZZM(o);718if (!m) pari_err_TYPE("gen_factored_order [missing order]",a);719o = gel(m,1);720m = gel(m,2); l = lgcols(m);721P = cgetg(l, t_COL); ind = 1;722F = cgetg(l, t_COL);723for (i = l-1; i; i--)724{725GEN t, y, p = gcoeff(m,i,1);726long j, e = itos(gcoeff(m,i,2));727if (l == 2) {728t = gen_1;729y = a;730} else {731t = diviiexact(o, powiu(p,e));732y = grp->pow(E, a, t);733}734if (grp->equal1(y)) o = t;735else {736for (j = 1; j < e; j++)737{738y = grp->pow(E, y, p);739if (grp->equal1(y)) break;740}741gel(P,ind) = p;742gel(F,ind) = utoipos(j);743if (j < e) {744if (j > 1) p = powiu(p, j);745o = mulii(t, p);746}747ind++;748}749}750setlg(P, ind); P = vecreverse(P);751setlg(F, ind); F = vecreverse(F);752return gerepilecopy(av, mkvec2(o, mkmat2(P,F)));753}754755/* E has order o[1], ..., or o[#o], draw random points until all solutions756* but one are eliminated */757GEN758gen_select_order(GEN o, void *E, const struct bb_group *grp)759{760pari_sp ltop = avma, btop;761GEN lastgood, so, vo;762long lo = lg(o), nbo=lo-1;763if (nbo == 1) return icopy(gel(o,1));764so = ZV_indexsort(o); /* minimize max( o[i+1] - o[i] ) */765vo = zero_zv(lo);766lastgood = gel(o, so[nbo]);767btop = avma;768for(;;)769{770GEN lasto = gen_0;771GEN P = grp->rand(E), t = mkvec(gen_0);772long i;773for (i = 1; i < lo; i++)774{775GEN newo = gel(o, so[i]);776if (vo[i]) continue;777t = grp->mul(E,t, grp->pow(E, P, subii(newo,lasto)));/*P^o[i]*/778lasto = newo;779if (!grp->equal1(t))780{781if (--nbo == 1) { set_avma(ltop); return icopy(lastgood); }782vo[i] = 1;783}784else785lastgood = lasto;786}787set_avma(btop);788}789}790791/*******************************************************************/792/* */793/* n-th ROOT */794/* */795/*******************************************************************/796/* Assume l is prime. Return a generator of the l-th Sylow and set *zeta to an element797* of order l.798*799* q = l^e*r, e>=1, (r,l)=1800* UNCLEAN */801static GEN802gen_lgener(GEN l, long e, GEN r,GEN *zeta, void *E, const struct bb_group *grp)803{804const pari_sp av1 = avma;805GEN m, m1;806long i;807for (;; set_avma(av1))808{809m1 = m = grp->pow(E, grp->rand(E), r);810if (grp->equal1(m)) continue;811for (i=1; i<e; i++)812{813m = grp->pow(E,m,l);814if (grp->equal1(m)) break;815}816if (i==e) break;817}818*zeta = m; return m1;819}820821/* Let G be a cyclic group of order o>1. Returns a (random) generator */822823GEN824gen_gener(GEN o, void *E, const struct bb_group *grp)825{826pari_sp ltop = avma, av;827long i, lpr;828GEN F, N, pr, z=NULL;829F = get_arith_ZZM(o);830N = gel(F,1); pr = gel(F,2); lpr = lgcols(pr);831av = avma;832833for (i = 1; i < lpr; i++)834{835GEN l = gcoeff(pr,i,1);836long e = itos(gcoeff(pr,i,2));837GEN r = diviiexact(N,powis(l,e));838GEN zetan, zl = gen_lgener(l,e,r,&zetan,E,grp);839z = i==1 ? zl: grp->mul(E,z,zl);840if (gc_needed(av,2))841{ /* n can have lots of prime factors*/842if(DEBUGMEM>1) pari_warn(warnmem,"gen_gener");843z = gerepileupto(av, z);844}845}846return gerepileupto(ltop, z);847}848849/* solve x^l = a , l prime in G of order q.850*851* q = (l^e)*r, e >= 1, (r,l) = 1852* y is not an l-th power, hence generates the l-Sylow of G853* m = y^(q/l) != 1 */854static GEN855gen_Shanks_sqrtl(GEN a, GEN l, long e, GEN r, GEN y, GEN m,void *E,856const struct bb_group *grp)857{858pari_sp av = avma;859long k;860GEN p1, u1, u2, v, w, z, dl;861862(void)bezout(r,l,&u1,&u2);863v = grp->pow(E,a,u2);864w = grp->pow(E,v,l);865w = grp->mul(E,w,grp->pow(E,a,gen_m1));866while (!grp->equal1(w))867{868k = 0;869p1 = w;870do871{872z = p1; p1 = grp->pow(E,p1,l);873k++;874} while(!grp->equal1(p1));875if (k==e) return gc_NULL(av);876dl = gen_plog(z,m,l,E,grp);877if (typ(dl) != t_INT) return gc_NULL(av);878dl = negi(dl);879p1 = grp->pow(E, grp->pow(E,y, dl), powiu(l,e-k-1));880m = grp->pow(E,m,dl);881e = k;882v = grp->mul(E,p1,v);883y = grp->pow(E,p1,l);884w = grp->mul(E,y,w);885if (gc_needed(av,1))886{887if(DEBUGMEM>1) pari_warn(warnmem,"gen_Shanks_sqrtl");888gerepileall(av,4, &y,&v,&w,&m);889}890}891return gerepilecopy(av, v);892}893/* Return one solution of x^n = a in a cyclic group of order q894*895* 1) If there is no solution, return NULL.896*897* 2) If there is a solution, there are exactly m of them [m = gcd(q-1,n)].898* If zetan!=NULL, *zetan is set to a primitive m-th root of unity so that899* the set of solutions is { x*zetan^k; k=0..m-1 }900*/901GEN902gen_Shanks_sqrtn(GEN a, GEN n, GEN q, GEN *zetan, void *E, const struct bb_group *grp)903{904pari_sp ltop = avma;905GEN m, u1, u2, z;906int is_1;907908if (is_pm1(n))909{910if (zetan) *zetan = grp->pow(E,a,gen_0);911return signe(n) < 0? grp->pow(E,a,gen_m1): gcopy(a);912}913is_1 = grp->equal1(a);914if (is_1 && !zetan) return gcopy(a);915916m = bezout(n,q,&u1,&u2);917z = grp->pow(E,a,gen_0);918if (!is_pm1(m))919{920GEN F = Z_factor(m);921long i, j, e;922GEN r, zeta, y, l;923pari_sp av1 = avma;924for (i = nbrows(F); i; i--)925{926l = gcoeff(F,i,1);927j = itos(gcoeff(F,i,2));928e = Z_pvalrem(q,l,&r);929y = gen_lgener(l,e,r,&zeta,E,grp);930if (zetan) z = grp->mul(E,z, grp->pow(E,y,powiu(l,e-j)));931if (!is_1) {932do933{934a = gen_Shanks_sqrtl(a,l,e,r,y,zeta,E,grp);935if (!a) return gc_NULL(ltop);936} while (--j);937}938if (gc_needed(ltop,1))939{ /* n can have lots of prime factors*/940if(DEBUGMEM>1) pari_warn(warnmem,"gen_Shanks_sqrtn");941gerepileall(av1, zetan? 2: 1, &a, &z);942}943}944}945if (!equalii(m, n))946a = grp->pow(E,a,modii(u1,q));947if (zetan)948{949*zetan = z;950gerepileall(ltop,2,&a,zetan);951}952else /* is_1 is 0: a was modified above -> gerepileupto valid */953a = gerepileupto(ltop, a);954return a;955}956957/*******************************************************************/958/* */959/* structure of groups with pairing */960/* */961/*******************************************************************/962963static GEN964ellgroup_d2(GEN N, GEN d)965{966GEN r = gcdii(N, d);967GEN F1 = gel(Z_factor(r), 1);968long i, j, l1 = lg(F1);969GEN F = cgetg(3, t_MAT);970gel(F,1) = cgetg(l1, t_COL);971gel(F,2) = cgetg(l1, t_COL);972for (i = 1, j = 1; i < l1; ++i)973{974long v = Z_pval(N, gel(F1, i));975if (v<=1) continue;976gcoeff(F, j , 1) = gel(F1, i);977gcoeff(F, j++, 2) = stoi(v);978}979setlg(F[1],j); setlg(F[2],j);980return j==1 ? NULL : mkvec2(factorback(F), F);981}982983GEN984gen_ellgroup(GEN N, GEN d, GEN *pt_m, void *E, const struct bb_group *grp,985GEN pairorder(void *E, GEN P, GEN Q, GEN m, GEN F))986{987pari_sp av = avma;988GEN N0, N1, F;989if (pt_m) *pt_m = gen_1;990if (is_pm1(N)) return cgetg(1,t_VEC);991F = ellgroup_d2(N, d);992if (!F) {set_avma(av); return mkveccopy(N);}993N0 = gel(F,1); N1 = diviiexact(N, N0);994while(1)995{996pari_sp av2 = avma;997GEN P, Q, d, s, t, m;998999P = grp->pow(E,grp->rand(E), N1);1000s = gen_order(P, F, E, grp); if (equalii(s, N0)) {set_avma(av); return mkveccopy(N);}10011002Q = grp->pow(E,grp->rand(E), N1);1003t = gen_order(Q, F, E, grp); if (equalii(t, N0)) {set_avma(av); return mkveccopy(N);}10041005m = lcmii(s, t);1006d = pairorder(E, P, Q, m, F);1007/* structure is [N/d, d] iff m d == N0. Note that N/d = N1 m */1008if (is_pm1(d) && equalii(m, N0)) {set_avma(av); return mkveccopy(N);}1009if (equalii(mulii(m, d), N0))1010{1011GEN g = mkvec2(mulii(N1,m), d);1012if (pt_m) *pt_m = m;1013gerepileall(av,pt_m?2:1,&g,pt_m);1014return g;1015}1016set_avma(av2);1017}1018}10191020GEN1021gen_ellgens(GEN D1, GEN d2, GEN m, void *E, const struct bb_group *grp,1022GEN pairorder(void *E, GEN P, GEN Q, GEN m, GEN F))1023{1024pari_sp ltop = avma, av;1025GEN F, d1, dm;1026GEN P, Q, d, s;1027F = get_arith_ZZM(D1);1028d1 = gel(F, 1), dm = diviiexact(d1,m);1029av = avma;1030do1031{1032set_avma(av);1033P = grp->rand(E);1034s = gen_order(P, F, E, grp);1035} while (!equalii(s, d1));1036av = avma;1037do1038{1039set_avma(av);1040Q = grp->rand(E);1041d = pairorder(E, grp->pow(E, P, dm), grp->pow(E, Q, dm), m, F);1042} while (!equalii(d, d2));1043return gerepilecopy(ltop, mkvec2(P,Q));1044}104510461047