Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2000 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/* THE APRCL PRIMALITY TEST */16/*******************************************************************/17#include "pari.h"18#include "paripriv.h"1920#define DEBUGLEVEL DEBUGLEVEL_isprime2122typedef struct Red {23/* global data */24GEN N; /* prime we are certifying */25GEN N2; /* floor(N/2) */26/* global data for flexible window */27long k, lv;28ulong mask;29/* reduction data */30long n;31GEN C; /* polcyclo(n) */32GEN (*red)(GEN x, struct Red*);33} Red;3435#define cache_aall(C) (gel((C),1))36#define cache_tall(C) (gel((C),2))37#define cache_cyc(C) (gel((C),3))38#define cache_E(C) (gel((C),4))39#define cache_eta(C) (gel((C),5))40/* the last 4 only when N = 1 mod p^k */41#define cache_mat(C) (gel((C),6))42#define cache_matinv(C) (gel((C),7))43#define cache_a(C) (gel((C),8)) /* a has order p^k in (Z/NZ)^* */44#define cache_pk(C) (gel((C),9)) /* p^k */4546static GEN47makepoldeg1(GEN c, GEN d)48{49GEN z;50if (signe(c)) {51z = cgetg(4,t_POL); z[1] = evalsigne(1);52gel(z,2) = d; gel(z,3) = c;53} else if (signe(d)) {54z = cgetg(3,t_POL); z[1] = evalsigne(1);55gel(z,2) = d;56} else {57z = cgetg(2,t_POL); z[1] = evalsigne(0);58}59return z;60}6162/* T mod polcyclo(p), assume deg(T) < 2p */63static GEN64red_cyclop(GEN T, long p)65{66long i, d;67GEN y, z;6869d = degpol(T) - p; /* < p */70if (d <= -2) return T;7172/* reduce mod (x^p - 1) */73y = ZX_mod_Xnm1(T, p);74z = y+2;7576/* reduce mod x^(p-1) + ... + 1 */77d = p-1;78if (degpol(y) == d)79for (i=0; i<d; i++) gel(z,i) = subii(gel(z,i), gel(z,d));80return normalizepol_lg(y, d+2);81}8283/* x t_VECSMALL, as red_cyclo2n_ip */84static GEN85u_red_cyclo2n_ip(GEN x, long n)86{87long i, pow2 = 1L<<(n-1);88GEN z;8990for (i = lg(x)-1; i>pow2; i--) x[i-pow2] -= x[i];91for (; i>0; i--)92if (x[i]) break;93i += 2;94z = cgetg(i, t_POL); z[1] = evalsigne(1);95for (i--; i>=2; i--) gel(z,i) = stoi(x[i-1]);96return z;97}98/* x t_POL, n > 0. Return x mod polcyclo(2^n) = (x^(2^(n-1)) + 1). IN PLACE */99static GEN100red_cyclo2n_ip(GEN x, long n)101{102long i, pow2 = 1L<<(n-1);103for (i = lg(x)-1; i>pow2+1; i--)104if (signe(gel(x,i))) gel(x,i-pow2) = subii(gel(x,i-pow2), gel(x,i));105return normalizepol_lg(x, i+1);106}107static GEN108red_cyclo2n(GEN x, long n) { return red_cyclo2n_ip(leafcopy(x), n); }109110/* special case R->C = polcyclo(2^n) */111static GEN112_red_cyclo2n(GEN x, Red *R)113{ return centermod_i(red_cyclo2n(x, R->n), R->N, R->N2); }114/* special case R->C = polcyclo(p) */115static GEN116_red_cyclop(GEN x, Red *R)117{ return centermod_i(red_cyclop(x, R->n), R->N, R->N2); }118static GEN119_red(GEN x, Red *R)120{ return centermod_i(ZX_rem(x, R->C), R->N, R->N2); }121static GEN122modZ(GEN x, Red *R) { return centermodii(x, R->N, R->N2); }123static GEN124sqrmodZ(GEN x, Red *R) { return modZ(sqri(x), R); }125static GEN126sqrmod(GEN x, Red *R) { return R->red(ZX_sqr(x), R); }127static GEN128_mul(GEN x, GEN y, Red *R)129{ return typ(x) == t_INT? modZ(mulii(x,y), R)130: R->red(ZX_mul(x,y), R); }131132static GEN133sqrconst(GEN pol, Red *R)134{135GEN z = cgetg(3,t_POL);136gel(z,2) = modZ(sqri(gel(pol,2)), R);137z[1] = pol[1]; return z;138}139140/* pol^2 mod (x^2+x+1, N) */141static GEN142sqrmod3(GEN pol, Red *R)143{144GEN a,b,bma,A,B;145long lv = lg(pol);146147if (lv==2) return pol;148if (lv==3) return sqrconst(pol, R);149a = gel(pol,3);150b = gel(pol,2); bma = subii(b,a);151A = modZ(mulii(a,addii(b,bma)), R);152B = modZ(mulii(bma,addii(a,b)), R); return makepoldeg1(A,B);153}154155/* pol^2 mod (x^2+1,N) */156static GEN157sqrmod4(GEN pol, Red *R)158{159GEN a,b,A,B;160long lv = lg(pol);161162if (lv==2) return pol;163if (lv==3) return sqrconst(pol, R);164a = gel(pol,3);165b = gel(pol,2);166A = modZ(mulii(a, shifti(b,1)), R);167B = modZ(mulii(subii(b,a),addii(b,a)), R); return makepoldeg1(A,B);168}169170/* pol^2 mod (polcyclo(5),N) */171static GEN172sqrmod5(GEN pol, Red *R)173{174GEN c2,b,c,d,A,B,C,D;175long lv = lg(pol);176177if (lv==2) return pol;178if (lv==3) return sqrconst(pol, R);179c = gel(pol,3); c2 = shifti(c,1);180d = gel(pol,2);181if (lv==4)182{183A = modZ(sqri(d), R);184B = modZ(mulii(c2, d), R);185C = modZ(sqri(c), R); return mkpoln(3,A,B,C);186}187b = gel(pol,4);188if (lv==5)189{190A = mulii(b, subii(c2,b));191B = addii(sqri(c), mulii(b, subii(shifti(d,1),b)));192C = subii(mulii(c2,d), sqri(b));193D = mulii(subii(d,b), addii(d,b));194}195else196{ /* lv == 6 */197GEN a = gel(pol,5), a2 = shifti(a,1);198/* 2a(d - c) + b(2c - b) */199A = addii(mulii(a2, subii(d,c)), mulii(b, subii(c2,b)));200/* c(c - 2a) + b(2d - b) */201B = addii(mulii(c, subii(c,a2)), mulii(b, subii(shifti(d,1),b)));202/* (a-b)(a+b) + 2c(d - a) */203C = addii(mulii(subii(a,b),addii(a,b)), mulii(c2,subii(d,a)));204/* 2a(b - c) + (d-b)(d+b) */205D = addii(mulii(a2, subii(b,c)), mulii(subii(d,b), addii(d,b)));206}207A = modZ(A, R);208B = modZ(B, R);209C = modZ(C, R);210D = modZ(D, R); return mkpoln(4,A,B,C,D);211}212213/* jac^floor(N/pk) mod (N, polcyclo(pk)), flexible window */214static GEN215_powpolmod(GEN C, GEN jac, Red *R, GEN (*_sqr)(GEN, Red *))216{217const GEN taba = cache_aall(C);218const GEN tabt = cache_tall(C);219const long efin = lg(taba)-1, lv = R->lv;220GEN L, res = jac, pol2 = _sqr(res, R);221long f;222pari_sp av0 = avma, av;223224L = cgetg(lv+1, t_VEC); gel(L,1) = res;225for (f=2; f<=lv; f++) gel(L,f) = _mul(gel(L,f-1), pol2, R);226av = avma;227for (f = efin; f >= 1; f--)228{229GEN t = gel(L, taba[f]);230long tf = tabt[f];231res = (f==efin)? t: _mul(t, res, R);232while (tf--) {233res = _sqr(res, R);234if (gc_needed(av,1)) {235res = gerepilecopy(av, res);236if(DEBUGMEM>1) pari_warn(warnmem,"powpolmod: f = %ld",f);237}238}239}240return gerepilecopy(av0, res);241}242243static GEN244_powpolmodsimple(GEN C, Red *R, GEN jac)245{246pari_sp av = avma;247GEN w = ZM_ZX_mul(cache_mat(C), jac);248long j, ph = lg(w);249250R->red = &modZ;251for (j=1; j<ph; j++) gel(w,j) = _powpolmod(C, modZ(gel(w,j), R), R, &sqrmodZ);252w = centermod_i( ZM_ZC_mul(cache_matinv(C), w), R->N, R->N2);253w = gerepileupto(av, w);254return RgV_to_RgX(w, 0);255}256257static GEN258powpolmod(GEN C, Red *R, long p, long k, GEN jac)259{260GEN (*_sqr)(GEN, Red *);261262if (!isintzero(cache_mat(C))) return _powpolmodsimple(C, R, jac);263if (p == 2) /* p = 2 */264{265if (k == 2) _sqr = &sqrmod4;266else _sqr = &sqrmod;267R->n = k;268R->red = &_red_cyclo2n;269} else if (k == 1)270{271if (p == 3) _sqr = &sqrmod3;272else if (p == 5) _sqr = &sqrmod5;273else _sqr = &sqrmod;274R->n = p;275R->red = &_red_cyclop;276} else {277R->red = &_red; _sqr = &sqrmod;278}279return _powpolmod(C, jac, R, _sqr);280}281282/* Return e(t) = \prod_{p-1 | t} p^{1+v_p(t)}}283* faet contains the odd prime divisors of e(t) */284static GEN285compute_e(ulong t, GEN *faet)286{287GEN L, P, D = divisorsu(t);288long l = lg(D);289ulong k;290291P = vecsmalltrunc_init(l);292L = vecsmalltrunc_init(l);293for (k=l-1; k>1; k--) /* k != 1: avoid d = 1 */294{295ulong d = D[k];296if (uisprime(++d))297{ /* we want q = 1 (mod p) prime, not too large */298#ifdef LONG_IS_64BIT299if (d > 5000000000UL) return gen_0;300#endif301vecsmalltrunc_append(P, d);302vecsmalltrunc_append(L, upowuu(d, 1 + u_lval(t,d)));303}304}305if (faet) *faet = P;306return shifti(zv_prod_Z(L), 2 + u_lval(t,2));307}308309/* Table obtained by the following script:310311install(compute_e, "LD&"); \\ remove 'static' first312table(first = 6, step = 6, MAXT = 6983776800)=313{314emax = 0;315forstep(t = first, MAXT, step,316e = compute_e(t);317if (e > 1.9*emax, emax = e;318printf(" if (C < %7.2f) return %8d;\n", 2*log(e)/log(2) - 1e-2, t)319);320);321}322table(,, 147026880);323table(147026880,5040, 6983776800);324*/325326/* assume C < 20003.8 */327static ulong328compute_t_small(double C)329{330if (C < 17.94) return 6;331if (C < 31.99) return 12;332if (C < 33.99) return 24;333if (C < 54.07) return 36;334if (C < 65.32) return 60;335if (C < 68.45) return 72;336if (C < 70.78) return 108;337if (C < 78.04) return 120;338if (C < 102.41) return 180;339if (C < 127.50) return 360;340if (C < 136.68) return 420;341if (C < 153.44) return 540;342if (C < 165.67) return 840;343if (C < 169.18) return 1008;344if (C < 178.53) return 1080;345if (C < 192.69) return 1200;346if (C < 206.35) return 1260;347if (C < 211.96) return 1620;348if (C < 222.10) return 1680;349if (C < 225.12) return 2016;350if (C < 244.20) return 2160;351if (C < 270.31) return 2520;352if (C < 279.52) return 3360;353if (C < 293.64) return 3780;354if (C < 346.70) return 5040;355if (C < 348.73) return 6480;356if (C < 383.37) return 7560;357if (C < 396.71) return 8400;358if (C < 426.08) return 10080;359if (C < 458.38) return 12600;360if (C < 527.20) return 15120;361if (C < 595.43) return 25200;362if (C < 636.34) return 30240;363if (C < 672.58) return 42840;364if (C < 684.96) return 45360;365if (C < 708.84) return 55440;366if (C < 771.37) return 60480;367if (C < 775.93) return 75600;368if (C < 859.69) return 85680;369if (C < 893.24) return 100800;370if (C < 912.35) return 110880;371if (C < 966.22) return 128520;372if (C < 1009.18) return 131040;373if (C < 1042.04) return 166320;374if (C < 1124.98) return 196560;375if (C < 1251.09) return 257040;376if (C < 1375.13) return 332640;377if (C < 1431.11) return 393120;378if (C < 1483.46) return 514080;379if (C < 1546.46) return 655200;380if (C < 1585.94) return 665280;381if (C < 1661.44) return 786240;382if (C < 1667.67) return 831600;383if (C < 1677.07) return 917280;384if (C < 1728.17) return 982800;385if (C < 1747.57) return 1081080;386if (C < 1773.76) return 1179360;387if (C < 1810.81) return 1285200;388if (C < 1924.66) return 1310400;389if (C < 2001.27) return 1441440;390if (C < 2096.51) return 1663200;391if (C < 2166.02) return 1965600;392if (C < 2321.86) return 2162160;393if (C < 2368.45) return 2751840;394if (C < 2377.39) return 2827440;395if (C < 2514.97) return 3326400;396if (C < 2588.72) return 3341520;397if (C < 2636.84) return 3603600;398if (C < 2667.46) return 3931200;399if (C < 3028.92) return 4324320;400if (C < 3045.76) return 5654880;401if (C < 3080.78) return 6652800;402if (C < 3121.88) return 6683040;403if (C < 3283.38) return 7207200;404if (C < 3514.94) return 8648640;405if (C < 3725.71) return 10810800;406if (C < 3817.49) return 12972960;407if (C < 3976.57) return 14414400;408if (C < 3980.72) return 18378360;409if (C < 4761.70) return 21621600;410if (C < 5067.62) return 36756720;411if (C < 5657.30) return 43243200;412if (C < 5959.24) return 64864800;413if (C < 6423.60) return 73513440;414if (C < 6497.01) return 86486400;415if (C < 6529.89) return 113097600;416if (C < 6899.19) return 122522400;417if (C < 7094.26) return 129729600;418if (C < 7494.60) return 147026880;419if (C < 7606.21) return 172972800;420if (C < 7785.10) return 183783600;421if (C < 7803.68) return 216216000;422if (C < 8024.18) return 220540320;423if (C < 8278.12) return 245044800;424if (C < 8316.48) return 273873600;425if (C < 8544.02) return 294053760;426if (C < 8634.14) return 302702400;427if (C < 9977.69) return 367567200;428if (C < 10053.06) return 514594080;429if (C < 10184.29) return 551350800;430if (C < 11798.33) return 735134400;431if (C < 11812.60) return 821620800;432if (C < 11935.31) return 1029188160;433if (C < 12017.99) return 1074427200;434if (C < 12723.99) return 1102701600;435if (C < 13702.71) return 1470268800;436if (C < 13748.76) return 1643241600;437if (C < 13977.37) return 2058376320;438if (C < 14096.03) return 2148854400UL;439if (C < 15082.25) return 2205403200UL;440if (C < 15344.18) return 2572970400UL;441if (C < 15718.37) return 2940537600UL;442if (C < 15868.65) return 3491888400UL;443if (C < 15919.88) return 3675672000UL;444if (C < 16217.23) return 4108104000UL;445#ifdef LONG_IS_64BIT446if (C < 17510.32) return 4410806400UL;447if (C < 18312.87) return 5145940800UL;448return 6983776800UL;449#else450pari_err_IMPL("APRCL for large numbers on 32bit arch");451return 0;452#endif453}454455/* return t such that e(t) > sqrt(N), set *faet = odd prime divisors of e(t) */456static ulong457compute_t(GEN N, GEN *e, GEN *faet)458{ /* 2^e b <= N < 2^e (b+1), where b >= 2^52. Approximating log_2 N by459* log2(gtodouble(N)) ~ e+log2(b), the error is less than log(1+1/b) < 1e-15*/460double C = dbllog2(N) + 1e-10; /* > log_2 N at least for N < 2^(2^21) */461ulong t;462/* Return "smallest" t such that f(t) >= C, which implies e(t) > sqrt(N) */463/* For N < 2^20003.8 ~ 5.5 10^6021 */464if (C < 20003.8)465{466t = compute_t_small(C);467*e = compute_e(t, faet);468}469else470{471#ifdef LONG_IS_64BIT472GEN B = sqrti(N);473for (t = 6983776800UL+5040UL;; t+=5040)474{475pari_sp av = avma;476*e = compute_e(t, faet);477if (cmpii(*e, B) > 0) break;478set_avma(av);479}480#else481*e = NULL; /* LCOV_EXCL_LINE */482t = 0; /* LCOV_EXCL_LINE */483#endif484}485return t;486}487488/* T[i] = discrete log of i in (Z/q)^*, q odd prime489* To save on memory, compute half the table: T[q-x] = T[x] + (q-1)/2 */490static GEN491computetabdl(ulong q)492{493ulong g, a, i, qs2 = q>>1; /* (q-1)/2 */494GEN T = cgetg(qs2+2,t_VECSMALL);495496g = pgener_Fl(q); a = 1;497for (i=1; i < qs2; i++) /* g^((q-1)/2) = -1 */498{499a = Fl_mul(g,a,q);500if (a > qs2) T[q-a] = i+qs2; else T[a] = i;501}502T[qs2+1] = T[qs2] + qs2;503T[1] = 0; return T;504}505506/* Return T: T[x] = dl of x(1-x) */507static GEN508compute_g(ulong q)509{510const ulong qs2 = q>>1; /* (q-1)/2 */511ulong x, a;512GEN T = computetabdl(q); /* updated in place to save on memory */513a = 0; /* dl[1] */514for (x=2; x<=qs2+1; x++)515{ /* a = dl(x) */516ulong b = T[x]; /* = dl(x) */517T[x] = b + a + qs2; /* dl(x) + dl(x-1) + dl(-1) */518a = b;519}520return T;521}522523/* x a nonzero VECSMALL with >= 0 entries */524static GEN525zv_to_ZX(GEN x)526{527long i,j, lx = lg(x);528GEN y;529530while (lx-- && x[lx]==0) /* empty */;531i = lx+2; y = cgetg(i,t_POL); y[1] = evalsigne(1);532for (j=2; j<i; j++) gel(y,j) = utoi(x[j-1]);533return y;534}535/* p odd prime */536static GEN537get_jac(GEN C, ulong q, long pk, GEN tabg)538{539ulong x, qs2 = q>>1; /* (q-1)/2 */540GEN vpk = zero_zv(pk);541542for (x=2; x<=qs2; x++) vpk[ tabg[x]%pk + 1 ] += 2;543vpk[ tabg[x]%pk + 1 ]++; /* x = (q+1)/2 */544return ZX_rem(zv_to_ZX(vpk), cache_cyc(C));545}546547/* p = 2 */548static GEN549get_jac2(GEN N, ulong q, long k, GEN *j2q, GEN *j3q)550{551GEN jpq, vpk, T = computetabdl(q);552ulong x, pk, i, qs2;553554/* could store T[x+1] + T[x] + qs2 (cf compute_g).555* Recompute instead, saving half the memory. */556pk = 1UL << k;;557vpk = zero_zv(pk);558559qs2 = q>>1; /* (q-1)/2 */560561for (x=2; x<=qs2; x++) vpk[ (T[x]+T[x-1]+qs2)%pk + 1 ] += 2;562vpk[ (T[x]+T[x-1]+qs2)%pk + 1 ]++;563jpq = u_red_cyclo2n_ip(vpk, k);564565if (k == 2) return jpq;566567if (mod8(N) >= 5)568{569GEN v8 = cgetg(9,t_VECSMALL);570for (x=1; x<=8; x++) v8[x] = 0;571for (x=2; x<=qs2; x++) v8[ ((3*T[x]+T[x-1]+qs2)&7) + 1 ]++;572for ( ; x<=q-1; x++) v8[ ((3*T[q-x]+T[q-x+1]-3*qs2)&7) + 1 ]++;573*j2q = RgX_inflate(ZX_sqr(u_red_cyclo2n_ip(v8,3)), pk>>3);574*j2q = red_cyclo2n_ip(*j2q, k);575}576for (i=1; i<=pk; i++) vpk[i] = 0;577for (x=2; x<=qs2; x++) vpk[ (2*T[x]+T[x-1]+qs2)%pk + 1 ]++;578for ( ; x<=q-1; x++) vpk[ (2*T[q-x]+T[q-x+1]-2*qs2)%pk + 1 ]++;579*j3q = ZX_mul(jpq, u_red_cyclo2n_ip(vpk,k));580*j3q = red_cyclo2n_ip(*j3q, k);581return jpq;582}583584/* N = 1 mod p^k, return an elt of order p^k in (Z/N)^* */585static GEN586finda(GEN Cp, GEN N, long pk, long p)587{588GEN a, pv;589if (Cp && !isintzero(cache_a(Cp))) {590a = cache_a(Cp);591pv = cache_pk(Cp);592}593else594{595GEN ph, b, q;596ulong u = 2;597long v = Z_lvalrem(subiu(N,1), p, &q);598ph = powuu(p, v-1); pv = muliu(ph, p); /* N - 1 = p^v q */599if (p > 2)600{601for (;;u++)602{603a = Fp_pow(utoipos(u), q, N);604b = Fp_pow(a, ph, N);605if (!gequal1(b)) break;606}607}608else609{610while (krosi(u,N) >= 0) u++;611a = Fp_pow(utoipos(u), q, N);612b = Fp_pow(a, ph, N);613}614/* checking b^p = 1 mod N done economically in caller */615b = gcdii(subiu(b,1), N);616if (!gequal1(b)) return NULL;617618if (Cp) {619cache_a(Cp) = a; /* a has order p^v */620cache_pk(Cp) = pv;621}622}623return Fp_pow(a, divis(pv, pk), N);624}625626/* return 0: N not a prime, 1: no problem so far */627static long628filltabs(GEN C, GEN Cp, Red *R, long p, long pk, long ltab)629{630pari_sp av;631long i, j;632long e;633GEN tabt, taba, m;634635cache_cyc(C) = polcyclo(pk,0);636637if (p > 2)638{639long LE = pk - pk/p + 1;640GEN E = cgetg(LE, t_VECSMALL), eta = cgetg(pk+1,t_VEC);641for (i=1,j=0; i<pk; i++)642if (i%p) E[++j] = i;643cache_E(C) = E;644645for (i=1; i<=pk; i++)646{647GEN z = FpX_rem(pol_xn(i-1, 0), cache_cyc(C), R->N);648gel(eta,i) = FpX_center_i(z, R->N, R->N2);649}650cache_eta(C) = eta;651}652else if (pk >= 8)653{654long LE = (pk>>2) + 1;655GEN E = cgetg(LE, t_VECSMALL);656for (i=1,j=0; i<pk; i++)657if ((i%8)==1 || (i%8)==3) E[++j] = i;658cache_E(C) = E;659}660661if (pk > 2 && umodiu(R->N,pk) == 1)662{663GEN vpa, p1, p2, p3, a2 = NULL, a = finda(Cp, R->N, pk, p);664long jj, ph;665666if (!a) return 0;667ph = pk - pk/p;668vpa = cgetg(ph+1,t_COL); gel(vpa,1) = a;669if (pk > p) a2 = modZ(sqri(a), R);670jj = 1;671for (i=2; i<pk; i++) /* vpa = { a^i, (i,p) = 1 } */672if (i%p) {673GEN z = mulii((i%p==1) ? a2 : a, gel(vpa,jj));674gel(vpa,++jj) = modZ(z , R);675}676if (!gequal1( modZ( mulii(a, gel(vpa,ph)), R) )) return 0;677p1 = cgetg(ph+1,t_MAT);678p2 = cgetg(ph+1,t_COL); gel(p1,1) = p2;679for (i=1; i<=ph; i++) gel(p2,i) = gen_1;680j = 2; gel(p1,j) = vpa; p3 = vpa;681for (j++; j <= ph; j++)682{683p2 = cgetg(ph+1,t_COL); gel(p1,j) = p2;684for (i=1; i<=ph; i++)685gel(p2,i) = modZ(mulii(gel(vpa,i),gel(p3,i)), R);686p3 = p2;687}688cache_mat(C) = p1;689cache_matinv(C) = FpM_inv(p1, R->N);690}691692tabt = cgetg(ltab+1, t_VECSMALL);693taba = cgetg(ltab+1, t_VECSMALL);694av = avma; m = divis(R->N, pk);695for (e=1; e<=ltab && signe(m); e++)696{697long s = vali(m); m = shifti(m,-s);698tabt[e] = e==1? s: s + R->k;699taba[e] = signe(m)? ((mod2BIL(m) & R->mask)+1)>>1: 0;700m = shifti(m, -R->k);701}702setlg(taba, e); cache_aall(C) = taba;703setlg(tabt, e); cache_tall(C) = tabt;704return gc_long(av,1);705}706707static GEN708calcglobs(Red *R, ulong t, long *plpC, long *pltab, GEN *pP)709{710GEN fat, P, E, PE;711long lv, i, k, b;712GEN pC;713714b = expi(R->N)+1;715k = 3; while (((k+1)*(k+2) << (k-1)) < b) k++;716*pltab = (b/k)+2;717R->k = k;718R->lv = 1L << (k-1);719R->mask = (1UL << k) - 1;720721fat = factoru_pow(t);722P = gel(fat,1);723E = gel(fat,2);724PE= gel(fat,3);725*plpC = lv = vecsmall_max(PE); /* max(p^e, p^e | t) */726pC = zerovec(lv);727gel(pC,1) = zerovec(9); /* to be used as temp in step5() */728for (i = 2; i <= lv; i++) gel(pC,i) = gen_0;729for (i=1; i<lg(P); i++)730{731long pk, p = P[i], e = E[i];732pk = p;733for (k=1; k<=e; k++, pk*=p)734{735gel(pC,pk) = zerovec(9);736if (!filltabs(gel(pC,pk), gel(pC,p), R, p,pk, *pltab)) return NULL;737}738}739*pP = P; return pC;740}741742/* sig_a^{-1}(z) for z in Q(zeta_pk) and sig_a: zeta -> zeta^a. Assume743* a reduced mod pk := p^k*/744static GEN745aut(long pk, GEN z, long a)746{747GEN v;748long b, i, dz = degpol(z);749if (a == 1 || dz < 0) return z;750v = cgetg(pk+2,t_POL); v[1] = evalvarn(0); b = 0;751gel(v,2) = gel(z,2); /* i = 0 */752for (i = 1; i < pk; i++)753{754b += a; if (b > pk) b -= pk; /* b = (a*i) % pk */755gel(v,i+2) = b > dz? gen_0: gel(z,b+2);756}757return normalizepol_lg(v, pk+2);758}759760/* z^v for v in Z[G], represented by couples [sig_x^{-1},x] */761static GEN762autvec_TH(long pk, GEN z, GEN v, GEN C)763{764pari_sp av = avma;765long i, lv = lg(v);766GEN s = pol_1(varn(C));767for (i=1; i<lv; i++)768{769long y = v[i];770if (y) s = ZXQ_mul(s, ZXQ_powu(aut(pk,z, y), y, C), C);771}772return gerepileupto(av,s);773}774775static GEN776autvec_AL(long pk, GEN z, GEN v, Red *R)777{778pari_sp av = avma;779const long r = umodiu(R->N, pk);780GEN s = pol_1(varn(R->C));781long i, lv = lg(v);782for (i=1; i<lv; i++)783{784long y = (r*v[i]) / pk;785if (y) s = RgXQ_mul(s, ZXQ_powu(aut(pk,z, v[i]), y, R->C), R->C);786}787return gerepileupto(av,s);788}789790/* 0 <= i < pk, such that x^i = z mod polcyclo(pk), -1 if no such i exist */791static long792look_eta(GEN eta, long pk, GEN z)793{794long i;795for (i=1; i<=pk; i++)796if (ZX_equal(z, gel(eta,i))) return i-1;797return -1;798}799/* same pk = 2^k */800static long801look_eta2(long k, GEN z)802{803long d, s;804if (typ(z) != t_POL) d = 0; /* t_INT */805else806{807if (!RgX_is_monomial(z)) return -1;808d = degpol(z);809z = gel(z,d+2); /* leading term */810}811s = signe(z);812if (!s || !is_pm1(z)) return -1;813return (s > 0)? d: d + (1L<<(k-1));814}815816static long817step4a(GEN C, Red *R, ulong q, long p, long k, GEN tabg)818{819const long pk = upowuu(p,k);820long ind;821GEN jpq, s1, s2, s3;822823if (!tabg) tabg = compute_g(q);824jpq = get_jac(C, q, pk, tabg);825s1 = autvec_TH(pk, jpq, cache_E(C), cache_cyc(C));826s2 = powpolmod(C,R, p,k, s1);827s3 = autvec_AL(pk, jpq, cache_E(C), R);828s3 = _red(gmul(s3,s2), R);829830ind = look_eta(cache_eta(C), pk, s3);831if (ind < 0) return -1;832return (ind%p) != 0;833}834835/* x == -1 mod N ? */836static long837is_m1(GEN x, GEN N)838{839return equalii(addiu(x,1), N);840}841842/* p=2, k>=3 */843static long844step4b(GEN C, Red *R, ulong q, long k)845{846const long pk = 1L << k;847long ind;848GEN s1, s2, s3, j2q = NULL, j3q = NULL;849850(void)get_jac2(R->N,q,k, &j2q,&j3q);851852s1 = autvec_TH(pk, j3q, cache_E(C), cache_cyc(C));853s2 = powpolmod(C,R, 2,k, s1);854s3 = autvec_AL(pk, j3q, cache_E(C), R);855s3 = _red(gmul(s3,s2), R);856if (j2q) s3 = _red(gmul(j2q, s3), R);857858ind = look_eta2(k, s3);859if (ind < 0) return -1;860if ((ind&1)==0) return 0;861s3 = Fp_pow(utoipos(q), R->N2, R->N);862return is_m1(s3, R->N);863}864865/* p=2, k=2 */866static long867step4c(GEN C, Red *R, ulong q)868{869long ind;870GEN s0,s1,s3, jpq = get_jac2(R->N,q,2, NULL,NULL);871872s0 = sqrmod4(jpq, R);873s1 = gmulsg(q,s0);874s3 = powpolmod(C,R, 2,2, s1);875if (mod4(R->N) == 3) s3 = _red(gmul(s0,s3), R);876877ind = look_eta2(2, s3);878if (ind < 0) return -1;879if ((ind&1)==0) return 0;880s3 = Fp_pow(utoipos(q), R->N2, R->N);881return is_m1(s3, R->N);882}883884/* p=2, k=1 */885static long886step4d(Red *R, ulong q)887{888GEN s1 = Fp_pow(utoipos(q), R->N2, R->N);889if (is_pm1(s1)) return 0;890if (is_m1(s1, R->N)) return (mod4(R->N) == 1);891return -1;892}893894/* return 1 [OK so far] or 0 [not a prime] */895static long896step5(GEN pC, Red *R, long p, GEN et, ulong ltab, long lpC)897{898pari_sp av;899ulong q;900long pk, k, fl = -1;901GEN C, Cp;902forprime_t T;903904(void)u_forprime_arith_init(&T, 3, ULONG_MAX, 1,p);905while( (q = u_forprime_next(&T)) )906{ /* q = 1 (mod p) */907if (umodiu(et,q) == 0) continue;908if (umodiu(R->N,q) == 0) return 0;909k = u_lval(q-1, p);910pk = upowuu(p,k);911if (pk <= lpC && !isintzero(gel(pC,pk))) {912C = gel(pC,pk);913Cp = gel(pC,p);914} else {915C = gel(pC,1);916Cp = NULL;917cache_mat(C) = gen_0; /* re-init */918}919av = avma;920if (!filltabs(C, Cp, R, p, pk, ltab)) return 0;921R->C = cache_cyc(C);922if (p >= 3) fl = step4a(C,R, q,p,k, NULL);923else if (k >= 3) fl = step4b(C,R, q,k);924else if (k == 2) fl = step4c(C,R, q);925else fl = step4d(R, q);926if (fl == -1) return 0;927if (fl == 1) return 1; /*OK*/928set_avma(av);929}930pari_err_BUG("aprcl test fails! This is highly improbable");931return 0;/*LCOV_EXCL_LINE*/932}933934GEN935aprcl_step6_worker(GEN r, long t, GEN N, GEN N1, GEN et)936{937long i;938pari_sp av = avma;939for (i=1; i<=t; i++)940{941r = remii(mulii(r,N1), et);942if (equali1(r)) break;943if (dvdii(N,r) && !equalii(r,N)) return gen_0; /* not prime */944if ((i & 0x1f) == 0) r = gerepileuptoint(av, r);945}946return cgetg(1,t_VECSMALL);947}948949/* return 1 if N prime, else 0 */950static long951step6(GEN N, ulong t, GEN et)952{953GEN worker, r, rk, N1 = remii(N, et);954ulong k = 10000;955ulong i;956long pending = 0, res = 1;957struct pari_mt pt;958pari_sp btop;959worker = snm_closure(is_entry("_aprcl_step6_worker"), mkvec3(N, N1, et));960r = gen_1;961rk = Fp_powu(N1, k, et);962mt_queue_start_lim(&pt, worker, (t-1+k-1)/k);963btop = avma;964for (i=1; (i<t && res) || pending; i+=k)965{966GEN done;967mt_queue_submit(&pt, i, (i<t && res)? mkvec2(r, utoi(minss(k,t-i))): NULL);968done = mt_queue_get(&pt, NULL, &pending);969if (res && done && typ(done) != t_VECSMALL) res = 0; /* not a prime */970r = Fp_mul(r, rk, et);971if (gc_needed(btop, 2))972{973if(DEBUGMEM>1) pari_warn(warnmem,"APRCL: i = %ld",i);974r = gerepileupto(btop, r);975}976}977mt_queue_end(&pt);978return res;979}980981GEN982aprcl_step4_worker(ulong q, GEN pC, GEN N, GEN v)983{984pari_sp av1 = avma, av2 = avma;985long j, k;986Red R;987GEN faq = factoru_pow(q-1), tabg = compute_g(q);988GEN P = gel(faq,1), E = gel(faq,2), PE = gel(faq,3);989long lfaq = lg(P);990GEN flags = cgetg(lfaq, t_VECSMALL);991R.N = N;992R.N2= shifti(N, -1);993R.k = v[1]; R.lv = v[2]; R.mask = uel(v,3); R.n = v[4];994av2 = avma;995for (j=1, k=1; j<lfaq; j++, set_avma(av2))996{997long p = P[j], e = E[j], pe = PE[j], fl;998GEN C = gel(pC,pe);999R.C = cache_cyc(C);1000if (p >= 3) fl = step4a(C,&R, q,p,e, tabg);1001else if (e >= 3) fl = step4b(C,&R, q,e);1002else if (e == 2) fl = step4c(C,&R, q);1003else fl = step4d(&R, q);1004if (fl == -1) return gen_0; /* not prime */1005if (fl == 1) flags[k++] = p;1006}1007setlg(flags, k);1008return gerepileuptoleaf(av1, flags); /* OK so far */1009}10101011/* return 1 if prime, else 0 */1012static long1013aprcl(GEN N)1014{1015GEN pC, worker, et, fat, flaglp, faet = NULL; /*-Wall*/1016long i, j, l, ltab, lfat, lpC, workid, pending = 0, res = 1;1017ulong t;1018Red R;1019struct pari_mt pt;10201021if (typ(N) != t_INT) pari_err_TYPE("aprcl",N);1022if (cmpis(N,12) <= 0)1023switch(itos(N))1024{1025case 2: case 3: case 5: case 7: case 11: return 1;1026default: return 0;1027}1028if (Z_issquare(N)) return 0;1029t = compute_t(N, &et, &faet);1030if (DEBUGLEVEL) err_printf("Starting APRCL with t = %ld\n",t);1031if (cmpii(sqri(et),N) < 0) pari_err_BUG("aprcl: e(t) too small");1032if (!equali1(gcdii(N,mului(t,et)))) return 0;10331034R.N = N;1035R.N2= shifti(N, -1);1036pC = calcglobs(&R, t, &lpC, <ab, &fat);1037if (!pC) return 0;1038lfat = lg(fat);1039flaglp = cgetg(lfat, t_VECSMALL);1040flaglp[1] = 0;1041for (i=2; i<lfat; i++)1042{1043ulong p = fat[i];1044flaglp[i] = absequaliu(Fp_powu(N, p-1, sqru(p)), 1);1045}1046vecsmall_sort(faet);1047l = lg(faet);1048worker = snm_closure(is_entry("_aprcl_step4_worker"),1049mkvec3(pC, N, mkvecsmall4(R.k, R.lv, R.mask, R.n)));1050if (DEBUGLEVEL>2) err_printf("Step4: %ld q-values\n", l-1);1051mt_queue_start_lim(&pt, worker, l-1);1052for (i=l-1; (i>0 && res) || pending; i--)1053{1054GEN done;1055ulong q = i>0 ? faet[i]: 0;1056mt_queue_submit(&pt, q, q>0? mkvec(utoi(q)): NULL);1057done = mt_queue_get(&pt, &workid, &pending);1058if (res && done)1059{1060long lf = lg(done);1061if (typ(done) != t_VECSMALL) { res = 0; continue; } /* not prime */1062for (j=1; j<lf; j++) flaglp[ zv_search(fat, done[j]) ] = 0;1063if (DEBUGLEVEL>2) err_printf("testing Jacobi sums for q = %ld...OK\n", workid);1064}1065}1066mt_queue_end(&pt);1067if (!res) return 0;1068if (DEBUGLEVEL>2) err_printf("Step5: testing conditions lp\n");1069for (i=2; i<lfat; i++) /*skip fat[1] = 2*/1070{1071pari_sp av = avma;1072long p = fat[i];1073if (flaglp[i] && !step5(pC, &R, p, et, ltab, lpC)) return 0;1074set_avma(av);1075}1076if (DEBUGLEVEL>2)1077err_printf("Step6: testing potential divisors\n");1078return step6(N, t, et);1079}10801081long1082isprimeAPRCL(GEN N)1083{ pari_sp av = avma; return gc_long(av, aprcl(N)); }10841085/*******************************************************************/1086/* DIVISORS IN RESIDUE CLASSES (LENSTRA) */1087/*******************************************************************/1088/* This would allow to replace e(t) > N^(1/2) by e(t) > N^(1/3), but step61089* becomes so expensive that, at least up to 6000 bits, this is useless1090* in this application. */1091static void1092set_add(hashtable *H, void *d)1093{1094ulong h = H->hash(d);1095if (!hash_search2(H, d, h)) hash_insert2(H, d, NULL, h);1096}1097static GEN1098GEN_hash_keys(hashtable *H)1099{ GEN v = hash_keys(H); settyp(v, t_VEC); return ZV_sort(v); }1100static void1101add(hashtable *H, GEN t1, GEN t2, GEN a, GEN b, GEN r, GEN s)1102{1103GEN ra, qa = dvmdii(t1, a, &ra);1104if (!signe(ra) && dvdii(t2, b) && equalii(modii(qa, s), r))1105set_add(H, (void*)qa);1106}1107/* T^2 - B*T + C has integer roots ? */1108static void1109check_t(hashtable *H, GEN B, GEN C4, GEN a, GEN b, GEN r, GEN s)1110{1111GEN d, t1, t2, D = subii(sqri(B), C4);1112if (!Z_issquareall(D, &d)) return;1113t1 = shifti(addii(B, d), -1); /* >= 0 */1114t2 = subii(B, t1);1115add(H, t1,t2, a,b,r,s);1116if (signe(t2) >= 0) add(H, t2,t1, a,b,r,s);1117}1118/* N > s > r >= 0, (r,s) = 1 */1119GEN1120divisorslenstra(GEN N, GEN r, GEN s)1121{1122pari_sp av = avma;1123GEN u, Ns2, rp, a0, a1, b0, b1, c0, c1, s2;1124hashtable *H = hash_create(11, (ulong(*)(void*))&hash_GEN,1125(int(*)(void*,void*))&equalii, 1);1126long j;1127if (typ(N) != t_INT) pari_err_TYPE("divisorslenstra", N);1128if (typ(r) != t_INT) pari_err_TYPE("divisorslenstra", r);1129if (typ(s) != t_INT) pari_err_TYPE("divisorslenstra", s);1130u = Fp_inv(r, s);1131rp = Fp_mul(u, N, s); /* r' */1132s2 = sqri(s);1133a0 = s;1134b0 = gen_0;1135c0 = gen_0;1136if (dvdii(N, r)) set_add(H, (void*)r); /* case i = 0 */1137a1 = Fp_mul(u, rp, s); if (!signe(a1)) a1 = s; /* 0 < a1 <= s */1138b1 = gen_1;1139c1 = Fp_mul(u, diviiexact(subii(N,mulii(r,rp)), s), s);1140Ns2 = divii(N, s2);1141j = 1;1142for (;;)1143{1144GEN Cs, q, c, ab = mulii(a1,b1);1145long i, lC;1146if (j == 0) /* i even, a1 >= 0 */1147{1148if (!signe(c1)) Cs = mkvec(gen_0);1149else1150{1151GEN cs = mulii(c1, s);1152Cs = mkvec2(subii(cs,s2), cs);1153}1154}1155else1156{ /* i odd, a1 > 0 */1157GEN X = shifti(ab,1);1158c = c1;1159/* smallest c >= 2ab, c = c1 (mod s) */1160if (cmpii(c, X) < 0)1161{1162GEN rX, qX = dvmdii(subii(X,c), s, &rX);1163if (signe(rX)) qX = addiu(qX,1); /* ceil((X-c)/s) */1164c = addii(c, mulii(s, qX));1165}1166Cs = (cmpii(c, addii(Ns2,ab)) <= 0)? mkvec(mulii(c,s)): cgetg(1,t_VEC);1167}1168lC = lg(Cs);1169if (signe(a1))1170{1171GEN abN4 = shifti(mulii(ab, N), 2);1172GEN B = addii(mulii(a1,r), mulii(b1,rp));1173for (i = 1; i < lC; i++)1174check_t(H, addii(B, gel(Cs,i)), abN4, a1, b1, r, s);1175}1176else1177{ /* a1 = 0, last batch */1178for (i = 1; i < lC; i++)1179{1180GEN ry, ys = dvmdii(gel(Cs,i), b1, &ry);1181if (!signe(ry))1182{1183GEN d = addii(ys, rp);1184if (signe(d) > 0)1185{1186d = dvmdii(N, d, &ry);1187if (!signe(ry)) set_add(H, (void*)d);1188}1189}1190}1191break; /* DONE */1192}1193j = 1-j;1194q = dvmdii(a0, a1, &c);1195if (j == 1 && !signe(c)) { q = subiu(q,1); c = a1; }1196a0 = a1; a1 = c;1197if (equali1(q)) /* frequent */1198{1199c = subii(b0, b1); b0 = b1; b1 = c;1200c = Fp_sub(c0, c1, s); c0 = c1; c1 = c;1201}1202else1203{1204c = subii(b0, mulii(q,b1)); b0 = b1; b1 = c;1205c = modii(subii(c0, mulii(q,c1)), s); c0 = c1; c1 = c;1206}1207}1208return gerepileupto(av, GEN_hash_keys(H));1209}121012111212