Math-Prime-Util-GMP-0.52/0000755000175000017500000000000013674072603013337 5ustar danadanaMath-Prime-Util-GMP-0.52/primality.c0000644000175000017500000013147313663067455015535 0ustar danadana#include #include "ptypes.h" #include "primality.h" #include "gmp_main.h" /* primality_pretest */ #include "bls75.h" #include "ecpp.h" #include "factor.h" #define FUNC_is_perfect_square 1 #define FUNC_mpz_logn #include "utility.h" #define NSMALLPRIMES 54 static const unsigned char sprimes[NSMALLPRIMES] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251}; /* 0 fail, 1 pass, -1 nothing. Modifies base a */ static int _preprocess_base(mpz_t n, mpz_t a) { if (mpz_cmp_ui(a, 1) <= 0) croak("Base %ld is invalid", mpz_get_si(a)); if (mpz_cmp_ui(n, 3) <= 0) return (mpz_cmp_ui(n, 2) >= 0); if (mpz_cmp_ui(a, 2) > 0) { if (mpz_cmp(a, n) >= 0) { mpz_mod(a, a, n); if (mpz_cmp_ui(a, 1) <= 0) return mpz_sgn(a); } } return -1; } int is_pseudoprime(mpz_t n, mpz_t a) { mpz_t nm1; int res; if ((res = _preprocess_base(n, a)) >= 0) return res; mpz_init(nm1); mpz_sub_ui(nm1, n, 1); mpz_powm(nm1, a, nm1, n); res = (mpz_cmp_ui(nm1, 1) == 0); mpz_clear(nm1); return res; } int is_euler_pseudoprime(mpz_t n, mpz_t a) { mpz_t nm1, ap; int res; if (mpz_even_p(n)) return (mpz_cmp_ui(n,2) == 0); if ((res = _preprocess_base(n, a)) >= 0) return res; mpz_init(ap); if (mpz_gcd(ap, a, n), mpz_cmp_ui(ap, 1) != 0) { mpz_clear(ap); return 0; } mpz_init(nm1); mpz_sub_ui(nm1, n, 1); mpz_tdiv_q_2exp(ap, nm1, 1); mpz_powm(ap, a, ap, n); if (mpz_cmp_ui(ap, 1) && mpz_cmp(ap, nm1)) res = 0; else if (mpz_kronecker(a, n) >= 0) res = (mpz_cmp_ui(ap, 1) == 0); else res = (mpz_cmp(ap, nm1) == 0); mpz_clear(nm1); mpz_clear(ap); return res; } static int mrx(/*destroyed*/mpz_t x, /*destroyed*/ mpz_t d, mpz_t n, UV s) { UV r; mpz_powm(x, x, d, n); mpz_sub_ui(d, n, 1); if (!mpz_cmp_ui(x, 1) || !mpz_cmp(x, d)) return 1; for (r = 1; r < s; r++) { mpz_powm_ui(x, x, 2, n); if (!mpz_cmp_ui(x, 1)) break; if (!mpz_cmp(x, d)) return 1; } return 0; } int miller_rabin(mpz_t n, mpz_t a) { mpz_t d, x; int cmpr, rval = 1; cmpr = mpz_cmp_ui(n, 2); if (cmpr == 0) return 1; /* 2 is prime */ if (cmpr < 0) return 0; /* below 2 is composite */ if (mpz_even_p(n)) return 0; /* multiple of 2 is composite */ if (mpz_cmp_ui(a, 1) <= 0) croak("Base %ld is invalid", mpz_get_si(a)); mpz_init_set(x, a); mpz_init_set(d, n); mpz_sub_ui(d, d, 1); /* Handle large and small bases. Use x so we don't modify their input a. */ if (mpz_cmp(x, n) >= 0) mpz_mod(x, x, n); if ( (mpz_cmp_ui(x, 1) > 0) && (mpz_cmp(x, d) < 0) ) { UV s = mpz_scan1(d, 0); mpz_tdiv_q_2exp(d, d, s); rval = mrx(x, d, n, s); } mpz_clear(d); mpz_clear(x); return rval; } int miller_rabin_ui(mpz_t n, unsigned long a) { mpz_t d, x; int cmpr, rval = 1; cmpr = mpz_cmp_ui(n, 2); if (cmpr == 0) return 1; /* 2 is prime */ if (cmpr < 0) return 0; /* below 2 is composite */ if (mpz_even_p(n)) return 0; /* multiple of 2 is composite */ if (a <= 1) croak("Base %lu is invalid", a); mpz_init_set_ui(x, a); mpz_init_set(d, n); mpz_sub_ui(d, d, 1); if (mpz_cmp(x, n) >= 0) mpz_mod(x, x, n); if ( (mpz_cmp_ui(x, 1) > 0) && (mpz_cmp(x, d) < 0) ) { UV s = mpz_scan1(d, 0); mpz_tdiv_q_2exp(d, d, s); rval = mrx(x, d, n, s); } mpz_clear(d); mpz_clear(x); return rval; } int is_miller_prime(mpz_t n, int assume_grh) { mpz_t d, x, D; UV s, maxa, a; int rval; { int cmpr = mpz_cmp_ui(n, 2); if (cmpr == 0) return 1; /* 2 is prime */ if (cmpr < 0) return 0; /* below 2 is composite */ if (mpz_even_p(n)) return 0; /* multiple of 2 is composite */ } if (mpz_cmp_ui(n, 1373653) < 0) { maxa = 3; } else if (assume_grh) { double logn = mpz_logn(n); double dmaxa = 2 * logn * logn; /* Bach (1990) */ /* Wedeniwski (2001) claims the following, but it might be wrong * double dmaxa = 1.5L * logn * logn - 44.0L/5.0L * logn + 13; */ if (dmaxa >= (double)ULONG_MAX) croak("is_miller_prime: n is too large for GRH DMR"); maxa = ceil(dmaxa); } else { /* Bober and Goldmakher 2015 (http://arxiv.org/abs/1311.7556) */ /* n_p < p^(1/(4*sqrt(e))+epsilon). Do it with logs */ double dmaxa = exp( (1.0L/6.5948850828L) * mpz_logn(n) ); if (dmaxa >= (double)ULONG_MAX) croak("is_miller_prime: n is too large for unconditional DMR"); maxa = ceil(dmaxa); } if (mpz_cmp_ui(n, maxa) <= 0) maxa = mpz_get_ui(n) - 1; if (get_verbose_level() > 1) printf("Deterministic Miller-Rabin testing bases from 2 to %"UVuf"\n", maxa); mpz_init_set(d, n); mpz_sub_ui(d, d, 1); s = mpz_scan1(d, 0); mpz_tdiv_q_2exp(d, d, s); mpz_init(D); mpz_init(x); for (a = 2, rval = 1; rval && a <= maxa; a++) { mpz_set_ui(x, a); mpz_set(D, d); rval = mrx(x, D, n, s); } mpz_clear(x); mpz_clear(D); mpz_clear(d); return rval; } int miller_rabin_random(mpz_t n, UV numbases, char* seedstr) { gmp_randstate_t randstate; mpz_t t, base; UV i; if (numbases == 0) return 1; if (mpz_cmp_ui(n, 100) < 0) /* tiny n */ return (_GMP_is_prob_prime(n) > 0); /* See if they've asked for a ludicrous number of bases */ mpz_init(t); mpz_mul_ui(t, n, 3); mpz_div_ui(t, t, 4); if (mpz_cmp_ui(t, numbases) <= 0) { int res = is_bpsw_dmr_prime(n); if (res != 1) { mpz_clear(t); return !!res; } numbases = mpz_get_ui(t); } mpz_init(base); mpz_sub_ui(t, n, 3); if (seedstr == 0) { /* Normal case with no seed string. Use our CSPRNG. */ for (i = 0; i < numbases; i++) { mpz_isaac_urandomm(base, t); /* base 0 .. (n-3)-1 */ mpz_add_ui(base, base, 2); /* base 2 .. n-2 */ if (miller_rabin(n, base) == 0) break; } } else { gmp_randinit_default(randstate); mpz_set_str(base, seedstr, 0); gmp_randseed(randstate, base); for (i = 0; i < numbases; i++) { mpz_urandomm(base, randstate, t); /* base 0 .. (n-3)-1 */ mpz_add_ui(base, base, 2); /* base 2 .. n-2 */ if (miller_rabin(n, base) == 0) break; } gmp_randclear(randstate); } mpz_clear(base); mpz_clear(t); return (i >= numbases); } int is_euler_plumb_pseudoprime(mpz_t n) { unsigned int nmod8; mpz_t x, two; int result = 0; if (mpz_cmp_ui(n,5) < 0) return (mpz_cmp_ui(n,2) == 0 || mpz_cmp_ui(n,3) == 0); if (mpz_even_p(n)) return 0; nmod8 = mpz_fdiv_ui(n, 8); mpz_init(x); mpz_init_set_ui(two,2); mpz_sub_ui(x, n, 1); mpz_fdiv_q_2exp(x, x, 1 + (nmod8 == 1)); mpz_powm(x, two, x, n); if (mpz_cmp_ui(x,1) == 0) { result = (nmod8 == 1 || nmod8 == 7); } else { mpz_add_ui(x,x,1); result = (mpz_cmp(x,n) == 0 && (nmod8 == 1 || nmod8 == 3 || nmod8 == 5)); } mpz_clear(two); mpz_clear(x); return result; } /* Returns Lucas sequence U_k mod n and V_k mod n defined by P,Q */ void lucas_seq(mpz_t U, mpz_t V, mpz_t n, IV P, IV Q, mpz_t k, mpz_t Qk, mpz_t t) { UV b = mpz_sizeinbase(k, 2); IV D = P*P - 4*Q; if (mpz_cmp_ui(n, 2) < 0) croak("Lucas sequence modulus n must be > 1"); MPUassert( mpz_cmp_ui(k, 0) >= 0, "lucas_seq: k is negative" ); MPUassert( mpz_cmp_si(n,(P>=0) ? P : -P) > 0, "lucas_seq: P is out of range"); MPUassert( mpz_cmp_si(n,(Q>=0) ? Q : -Q) > 0, "lucas_seq: Q is out of range"); MPUassert( D != 0, "lucas_seq: D is zero" ); if (mpz_cmp_ui(k, 0) <= 0) { mpz_set_ui(U, 0); mpz_set_ui(V, 2); return; } if (mpz_even_p(n)) { /* If n is even, then we can't divide by 2. Do it differently. */ alt_lucas_seq(U, V, n, P, Q, k, Qk, t); return; } mpz_set_ui(U, 1); mpz_set_si(V, P); mpz_set_si(Qk, Q); if (Q == 1) { /* Use the fast V method if possible. Much faster with small n. */ mpz_set_si(t, P*P-4); if (P > 2 && mpz_invert(t, t, n)) { /* Compute V_k and V_{k+1}, then computer U_k from them. */ mpz_set_si(V, P); mpz_set_si(U, P*P-2); while (b > 1) { b--; if (mpz_tstbit(k, b-1)) { mpz_mul(V, V, U); mpz_sub_ui(V, V, P); mpz_mod(V, V, n); mpz_mul(U, U, U); mpz_sub_ui(U, U, 2); mpz_mod(U, U, n); } else { mpz_mul(U, V, U); mpz_sub_ui(U, U, P); mpz_mod(U, U, n); mpz_mul(V, V, V); mpz_sub_ui(V, V, 2); mpz_mod(V, V, n); } } mpz_mul_ui(U, U, 2); mpz_submul_ui(U, V, P); mpz_mul(U, U, t); } else { /* Fast computation of U_k and V_k, specific to Q = 1 */ while (b > 1) { mpz_mulmod(U, U, V, n, t); /* U2k = Uk * Vk */ mpz_mul(V, V, V); mpz_sub_ui(V, V, 2); mpz_mod(V, V, n); /* V2k = Vk^2 - 2 Q^k */ b--; if (mpz_tstbit(k, b-1)) { mpz_mul_si(t, U, D); /* U: U2k+1 = (P*U2k + V2k)/2 */ mpz_mul_si(U, U, P); mpz_add(U, U, V); if (mpz_odd_p(U)) mpz_add(U, U, n); mpz_fdiv_q_2exp(U, U, 1); /* V: V2k+1 = (D*U2k + P*V2k)/2 */ mpz_mul_si(V, V, P); mpz_add(V, V, t); if (mpz_odd_p(V)) mpz_add(V, V, n); mpz_fdiv_q_2exp(V, V, 1); } } } } else { while (b > 1) { mpz_mulmod(U, U, V, n, t); /* U2k = Uk * Vk */ mpz_mul(V, V, V); mpz_submul_ui(V, Qk, 2); mpz_mod(V, V, n); /* V2k = Vk^2 - 2 Q^k */ mpz_mul(Qk, Qk, Qk); /* Q2k = Qk^2 */ b--; if (mpz_tstbit(k, b-1)) { mpz_mul_si(t, U, D); /* U: U2k+1 = (P*U2k + V2k)/2 */ mpz_mul_si(U, U, P); mpz_add(U, U, V); if (mpz_odd_p(U)) mpz_add(U, U, n); mpz_fdiv_q_2exp(U, U, 1); /* V: V2k+1 = (D*U2k + P*V2k)/2 */ mpz_mul_si(V, V, P); mpz_add(V, V, t); if (mpz_odd_p(V)) mpz_add(V, V, n); mpz_fdiv_q_2exp(V, V, 1); mpz_mul_si(Qk, Qk, Q); } mpz_mod(Qk, Qk, n); } } mpz_mod(U, U, n); mpz_mod(V, V, n); } void alt_lucas_seq(mpz_t Uh, mpz_t Vl, mpz_t n, IV P, IV Q, mpz_t k, mpz_t Ql, mpz_t t) { mpz_t Vh, Qh; int j, s = mpz_scan1(k,0), b = mpz_sizeinbase(k,2); if (mpz_sgn(k) <= 0) { mpz_set_ui(Uh, 0); mpz_set_ui(Vl, 2); return; } mpz_set_ui(Uh, 1); mpz_set_ui(Vl, 2); mpz_set_ui(Ql, 1); mpz_init_set_si(Vh,P); mpz_init_set_ui(Qh,1); for (j = b; j > s; j--) { mpz_mul(Ql, Ql, Qh); mpz_mod(Ql, Ql, n); if (mpz_tstbit(k, j)) { mpz_mul_si(Qh, Ql, Q); mpz_mul(Uh, Uh, Vh); mpz_mul_si(t, Ql, P); mpz_mul(Vl, Vl, Vh); mpz_sub(Vl, Vl, t); mpz_mul(Vh, Vh, Vh); mpz_sub(Vh, Vh, Qh); mpz_sub(Vh, Vh, Qh); } else { mpz_set(Qh, Ql); mpz_mul(Uh, Uh, Vl); mpz_sub(Uh, Uh, Ql); mpz_mul_si(t, Ql, P); mpz_mul(Vh, Vh, Vl); mpz_sub(Vh, Vh, t); mpz_mul(Vl, Vl, Vl); mpz_sub(Vl, Vl, Ql); mpz_sub(Vl, Vl, Ql); } mpz_mod(Qh, Qh, n); mpz_mod(Uh, Uh, n); mpz_mod(Vh, Vh, n); mpz_mod(Vl, Vl, n); } mpz_mul(Ql, Ql, Qh); mpz_mul_si(Qh, Ql, Q); mpz_mul(Uh, Uh, Vl); mpz_sub(Uh, Uh, Ql); mpz_mul_si(t, Ql, P); mpz_mul(Vl, Vl, Vh); mpz_sub(Vl, Vl, t); mpz_mul(Ql, Ql, Qh); mpz_clear(Qh); mpz_clear(Vh); mpz_mod(Ql, Ql, n); mpz_mod(Uh, Uh, n); mpz_mod(Vl, Vl, n); for (j = 0; j < s; j++) { mpz_mul(Uh, Uh, Vl); mpz_mul(Vl, Vl, Vl); mpz_sub(Vl, Vl, Ql); mpz_sub(Vl, Vl, Ql); mpz_mul(Ql, Ql, Ql); mpz_mod(Ql, Ql, n); mpz_mod(Uh, Uh, n); mpz_mod(Vl, Vl, n); } } void lucasuv(mpz_t Uh, mpz_t Vl, IV P, IV Q, mpz_t k) { mpz_t Vh, Ql, Qh, t; int j, s, n; if (mpz_sgn(k) <= 0) { mpz_set_ui(Uh, 0); mpz_set_ui(Vl, 2); return; } mpz_set_ui(Uh, 1); mpz_set_ui(Vl, 2); mpz_init_set_si(Vh,P); mpz_init(t); s = mpz_scan1(k, 0); /* number of zero bits at the end */ n = mpz_sizeinbase(k,2); /* It is tempting to try to pull out the various Q operations when Q=1 or * Q=-1. This doesn't lead to any immediate savings. Don't bother unless * there is a way to reduce the actual operations involving U and V. */ mpz_init_set_ui(Ql,1); mpz_init_set_ui(Qh,1); for (j = n; j > s; j--) { mpz_mul(Ql, Ql, Qh); if (mpz_tstbit(k, j)) { mpz_mul_si(Qh, Ql, Q); mpz_mul(Uh, Uh, Vh); mpz_mul_si(t, Ql, P); mpz_mul(Vl, Vl, Vh); mpz_sub(Vl, Vl, t); mpz_mul(Vh, Vh, Vh); mpz_sub(Vh, Vh, Qh); mpz_sub(Vh, Vh, Qh); } else { mpz_set(Qh, Ql); mpz_mul(Uh, Uh, Vl); mpz_sub(Uh, Uh, Ql); mpz_mul_si(t, Ql, P); mpz_mul(Vh, Vh, Vl); mpz_sub(Vh, Vh, t); mpz_mul(Vl, Vl, Vl); mpz_sub(Vl, Vl, Ql); mpz_sub(Vl, Vl, Ql); } } mpz_mul(Ql, Ql, Qh); mpz_mul_si(Qh, Ql, Q); mpz_mul(Uh, Uh, Vl); mpz_sub(Uh, Uh, Ql); mpz_mul_si(t, Ql, P); mpz_mul(Vl, Vl, Vh); mpz_sub(Vl, Vl, t); mpz_mul(Ql, Ql, Qh); mpz_clear(Qh); mpz_clear(t); mpz_clear(Vh); for (j = 0; j < s; j++) { mpz_mul(Uh, Uh, Vl); mpz_mul(Vl, Vl, Vl); mpz_sub(Vl, Vl, Ql); mpz_sub(Vl, Vl, Ql); mpz_mul(Ql, Ql, Ql); } mpz_clear(Ql); } int lucas_lehmer(UV p) { UV k, tlim; int res, pbits; mpz_t V, mp, t; if (p == 2) return 1; if (!(p&1)) return 0; mpz_init_set_ui(t, p); if (!_GMP_is_prob_prime(t)) /* p must be prime */ { mpz_clear(t); return 0; } if (p < 23) { mpz_clear(t); return (p != 11); } pbits = mpz_sizeinbase(t,2); mpz_init(mp); mpz_setbit(mp, p); mpz_sub_ui(mp, mp, 1); /* If p=3 mod 4 and p,2p+1 both prime, then 2p+1 | 2^p-1. Cheap test. */ if (p > 3 && p % 4 == 3) { mpz_mul_ui(t, t, 2); mpz_add_ui(t, t, 1); if (_GMP_is_prob_prime(t) && mpz_divisible_p(mp, t)) { mpz_clear(mp); mpz_clear(t); return 0; } } /* Do a little trial division first. Saves quite a bit of time. */ tlim = (p < 1500) ? p/2 : (p < 5000) ? p : 2*p; if (tlim > UV_MAX/(2*p)) tlim = UV_MAX/(2*p); for (k = 1; k < tlim; k++) { UV q = 2*p*k+1; if ( (q%8==1 || q%8==7) && /* factor must be 1 or 7 mod 8 */ q % 3 && q % 5 && q % 7 && q % 11 && q % 13) { /* and must be prime */ if (1 && q < (UVCONST(1) << (BITS_PER_WORD/2)) ) { UV b = 1, j = pbits; while (j--) { b = (b*b) % q; if (p & (UVCONST(1) << j)) { b *= 2; if (b >= q) b -= q; } } if (b == 1) { mpz_clear(mp); mpz_clear(t); return 0; } } else { if( mpz_divisible_ui_p(mp, q) ) { mpz_clear(mp); mpz_clear(t); return 0; } } } } /* We could do some specialized p+1 factoring here. */ mpz_init_set_ui(V, 4); for (k = 3; k <= p; k++) { mpz_mul(V, V, V); mpz_sub_ui(V, V, 2); /* mpz_mod(V, V, mp) but more efficiently done given mod 2^p-1 */ if (mpz_sgn(V) < 0) mpz_add(V, V, mp); /* while (n > mp) { n = (n >> p) + (n & mp) } if (n==mp) n=0 */ /* but in this case we can have at most one loop plus a carry */ mpz_tdiv_r_2exp(t, V, p); mpz_tdiv_q_2exp(V, V, p); mpz_add(V, V, t); while (mpz_cmp(V, mp) >= 0) mpz_sub(V, V, mp); } res = !mpz_sgn(V); mpz_clear(t); mpz_clear(mp); mpz_clear(V); return res; } /* Returns: -1 unknown, 0 composite, 2 definitely prime */ int llr(mpz_t N) { mpz_t v, k, V, U, Qk, t; UV i, n, P; int res = -1; if (mpz_cmp_ui(N,100) <= 0) return (_GMP_is_prob_prime(N) ? 2 : 0); if (mpz_even_p(N) || mpz_divisible_ui_p(N, 3)) return 0; mpz_init(v); mpz_init(k); mpz_add_ui(v, N, 1); n = mpz_scan1(v, 0); mpz_tdiv_q_2exp(k, v, n); /* N = k * 2^n - 1 */ if (mpz_cmp_ui(k,1) == 0) { res = lucas_lehmer(n) ? 2 : 0; goto DONE_LLR; } if (mpz_sizeinbase(k,2) > n) goto DONE_LLR; mpz_init(V); mpz_init(U); mpz_init(Qk); mpz_init(t); if (!mpz_divisible_ui_p(k, 3)) { /* Select V for 3 not divis k */ lucas_seq(U, V, N, 4, 1, k, Qk, t); } else if ((n % 4 == 0 || n % 4 == 3) && mpz_cmp_ui(k,3)==0) { mpz_set_ui(V, 5778); } else { /* Öystein J. Rödseth: http://www.uib.no/People/nmaoy/papers/luc.pdf */ for (P=5; P < 1000; P++) { mpz_set_ui(t, P-2); if (mpz_jacobi(t, N) == 1) { mpz_set_ui(t, P+2); if (mpz_jacobi(t, N) == -1) { break; } } } if (P >= 1000) { mpz_clear(t); mpz_clear(Qk); mpz_clear(U); mpz_clear(V); goto DONE_LLR; } lucas_seq(U, V, N, P, 1, k, Qk, t); } mpz_clear(t); mpz_clear(Qk); mpz_clear(U); for (i = 3; i <= n; i++) { mpz_mul(V, V, V); mpz_sub_ui(V, V, 2); mpz_mod(V, V, N); } res = mpz_sgn(V) ? 0 : 2; mpz_clear(V); DONE_LLR: if (res != -1 && get_verbose_level() > 1) printf("N shown %s with LLR\n", res ? "prime" : "composite"); mpz_clear(k); mpz_clear(v); return res; } /* Returns: -1 unknown, 0 composite, 2 definitely prime */ int proth(mpz_t N) { mpz_t v, k, a; UV n; int i, res = -1; /* TODO: Should have a flag to skip pretests */ if (mpz_cmp_ui(N,100) <= 0) return (_GMP_is_prob_prime(N) ? 2 : 0); if (mpz_even_p(N) || mpz_divisible_ui_p(N, 3)) return 0; mpz_init(v); mpz_init(k); mpz_sub_ui(v, N, 1); n = mpz_scan1(v, 0); mpz_tdiv_q_2exp(k, v, n); /* N = k * 2^n + 1 */ if (mpz_sizeinbase(k,2) <= n) { mpz_init(a); for (i = 0; i < 25 && res == -1; i++) { mpz_set_ui(a, sprimes[i]); if (mpz_jacobi(a, N) == -1) res = 0; } /* (a,N) = -1 if res=0. Do Proth primality test. */ if (res == 0) { mpz_tdiv_q_2exp(k, v, 1); mpz_powm(a, a, k, N); if (mpz_cmp(a, v) == 0) res = 2; } mpz_clear(a); } /* TODO: look into Rao (2018): k*2^n+1 for n>1, k prime */ /* if (n > 1 && res == -1 && _GMP_BPSW(k)) { ... } */ mpz_clear(k); mpz_clear(v); if (res != -1 && get_verbose_level() > 1) printf("N shown %s with Proth\n", res ? "prime" : "composite"); fflush(stdout); return res; } int is_proth_form(mpz_t N) { mpz_t v, k; UV n; int res = 0; if (mpz_cmp_ui(N,100) <= 0) return (_GMP_is_prob_prime(N) ? 2 : 0); if (mpz_even_p(N) || mpz_divisible_ui_p(N, 3)) return 0; mpz_init(v); mpz_init(k); mpz_sub_ui(v, N, 1); n = mpz_scan1(v, 0); mpz_tdiv_q_2exp(k, v, n); /* N = k * 2^n + 1 */ if (mpz_sizeinbase(k,2) <= n) res = 1; mpz_clear(k); mpz_clear(v); return res; } static int lucas_selfridge_params(IV* P, IV* Q, mpz_t n, mpz_t t) { IV D = 5; UV Dui = (UV) D; while (1) { UV gcd = mpz_gcd_ui(NULL, n, Dui); if ((gcd > 1) && mpz_cmp_ui(n, gcd) != 0) return 0; mpz_set_si(t, D); if (mpz_jacobi(t, n) == -1) break; if (Dui == 21 && mpz_perfect_square_p(n)) return 0; Dui += 2; D = (D > 0) ? -Dui : Dui; if (Dui > 1000000) croak("lucas_selfridge_params: D exceeded 1e6"); } if (P) *P = 1; if (Q) *Q = (1 - D) / 4; return 1; } static int lucas_extrastrong_params(IV* P, IV* Q, mpz_t n, mpz_t t, UV inc) { UV tP = 3; if (inc < 1 || inc > 256) croak("Invalid lucas parameter increment: %"UVuf"\n", inc); while (1) { UV D = tP*tP - 4; UV gcd = mpz_gcd_ui(NULL, n, D); if (gcd > 1 && mpz_cmp_ui(n, gcd) != 0) return 0; mpz_set_ui(t, D); if (mpz_jacobi(t, n) == -1) break; if (tP == (3+20*inc) && mpz_perfect_square_p(n)) return 0; tP += inc; if (tP > 65535) croak("lucas_extrastrong_params: P exceeded 65535"); } if (P) *P = (IV)tP; if (Q) *Q = 1; return 1; } /* This code was verified against Feitsma's psps-below-2-to-64.txt file. * is_strong_pseudoprime reduced it from 118,968,378 to 31,894,014. * all three variations of the Lucas test reduce it to 0. * The test suite should check that they generate the correct pseudoprimes. * * The standard and strong versions use the method A (Selfridge) parameters, * while the extra strong version uses Baillie's parameters from OEIS A217719. * * Using the strong version, we can implement the strong BPSW test as * specified by Baillie and Wagstaff, 1980, page 1401. * * Testing on my x86_64 machine, the strong Lucas code is over 35% faster than * T.R. Nicely's implementation, and over 40% faster than David Cleaver's. */ int _GMP_is_lucas_pseudoprime(mpz_t n, int strength) { mpz_t d, U, V, Qk, t; IV P, Q; UV s = 0; int rval; int _verbose = get_verbose_level(); { int cmpr = mpz_cmp_ui(n, 2); if (cmpr == 0) return 1; /* 2 is prime */ if (cmpr < 0) return 0; /* below 2 is composite */ if (mpz_even_p(n)) return 0; /* multiple of 2 is composite */ } mpz_init(t); rval = (strength < 2) ? lucas_selfridge_params(&P, &Q, n, t) : lucas_extrastrong_params(&P, &Q, n, t, 1); if (!rval) { mpz_clear(t); return 0; } if (_verbose>3) gmp_printf("N: %Zd D: %"IVdf" P: %"UVuf" Q: %"IVdf"\n", n, P*P-4*Q, P, Q); mpz_init(U); mpz_init(V); mpz_init(Qk); mpz_init_set(d, n); mpz_add_ui(d, d, 1); if (strength > 0) { s = mpz_scan1(d, 0); mpz_tdiv_q_2exp(d, d, s); } lucas_seq(U, V, n, P, Q, d, Qk, t); mpz_clear(d); rval = 0; if (strength == 0) { /* Standard checks U_{n+1} = 0 mod n. */ rval = (mpz_sgn(U) == 0); } else if (strength == 1) { if (mpz_sgn(U) == 0) { rval = 1; } else { while (s--) { if (mpz_sgn(V) == 0) { rval = 1; break; } if (s) { mpz_mul(V, V, V); mpz_submul_ui(V, Qk, 2); mpz_mod(V, V, n); mpz_mulmod(Qk, Qk, Qk, n, t); } } } } else { mpz_sub_ui(t, n, 2); if ( mpz_sgn(U) == 0 && (mpz_cmp_ui(V, 2) == 0 || mpz_cmp(V, t) == 0) ) { rval = 1; } else { s--; /* The extra strong test tests r < s-1 instead of r < s */ while (s--) { if (mpz_sgn(V) == 0) { rval = 1; break; } if (s) { mpz_mul(V, V, V); mpz_sub_ui(V, V, 2); mpz_mod(V, V, n); } } } } mpz_clear(Qk); mpz_clear(V); mpz_clear(U); mpz_clear(t); return rval; } /* Pari's clever method. It's an extra-strong Lucas test, but without * computing U_d. This makes it faster, but yields more pseudoprimes. * * increment: 1 for Baillie OEIS, 2 for Pari. * * With increment = 1, these results will be a subset of the extra-strong * Lucas pseudoprimes. With increment = 2, we produce Pari's results (we've * added the necessary GCD with D so we produce somewhat fewer). */ int _GMP_is_almost_extra_strong_lucas_pseudoprime(mpz_t n, UV increment) { mpz_t d, V, W, t; UV P, s; int rval; { int cmpr = mpz_cmp_ui(n, 2); if (cmpr == 0) return 1; /* 2 is prime */ if (cmpr < 0) return 0; /* below 2 is composite */ if (mpz_even_p(n)) return 0; /* multiple of 2 is composite */ } mpz_init(t); { IV PP; if (! lucas_extrastrong_params(&PP, 0, n, t, increment) ) { mpz_clear(t); return 0; } P = (UV) PP; } mpz_init(d); mpz_add_ui(d, n, 1); s = mpz_scan1(d, 0); mpz_tdiv_q_2exp(d, d, s); /* Calculate V_d */ { UV b = mpz_sizeinbase(d, 2); mpz_init_set_ui(V, P); mpz_init_set_ui(W, P*P-2); /* V = V_{k}, W = V_{k+1} */ while (b > 1) { b--; if (mpz_tstbit(d, b-1)) { mpz_mul(V, V, W); mpz_sub_ui(V, V, P); mpz_mul(W, W, W); mpz_sub_ui(W, W, 2); } else { mpz_mul(W, V, W); mpz_sub_ui(W, W, P); mpz_mul(V, V, V); mpz_sub_ui(V, V, 2); } mpz_mod(V, V, n); mpz_mod(W, W, n); } } mpz_clear(d); rval = 0; mpz_sub_ui(t, n, 2); #if 0 /* According to Stan Wagon's 1999 "Mathematica in Action", this method, * equivalent to our Extra Strong test, is used, though with a different * (unspecified) parameter selection method. I'm not convinced Mathematica * actually uses this method, without any confirmation from Wolfram. */ { /* V must be all 2 or x,x,-2,2,2,2. First V=+/-2 must have a W=P. */ int must_have_2 = 0, bad = 0; if (mpz_cmp_ui(V,2) == 0) { must_have_2 = 1; if (mpz_cmp_ui(W, P) != 0) bad = 1; } while (s-- && !bad) { if (must_have_2) { if (mpz_cmp_ui(V,2) != 0) bad = 1; } else { if (mpz_cmp(V,t) == 0) { /* Found -2. Check W=-P. Look for 2's. */ mpz_sub(W, n, W); if (mpz_cmp_ui(W, P) != 0) bad = 1; must_have_2 = 1; } else { /* Keep looking for a -2. */ mpz_mul(W, V, W); mpz_sub_ui(W, W, P); mpz_mod(W, W, n); } } mpz_mul(V, V, V); mpz_sub_ui(V, V, 2); mpz_mod(V, V, n); } /* Fail if bad val found or didn't have a 2 at the end */ rval = !bad && must_have_2 && !mpz_cmp_ui(V,2); } #else if ( mpz_cmp_ui(V, 2) == 0 || mpz_cmp(V, t) == 0 ) { rval = 1; } else { s--; /* The extra strong test tests r < s-1 instead of r < s */ while (s--) { if (mpz_sgn(V) == 0) { rval = 1; break; } if (s) { mpz_mul(V, V, V); mpz_sub_ui(V, V, 2); mpz_mod(V, V, n); } } } #endif mpz_clear(W); mpz_clear(V); mpz_clear(t); return rval; } int is_perrin_pseudoprime(mpz_t n, int restricted) { mpz_t S[6], T[6], T01, T34, T45, t; int cmpr, i, j, rval; cmpr = mpz_cmp_ui(n, 2); if (cmpr == 0) return 1; /* 2 is prime */ if (cmpr < 0) return 0; /* below 2 is composite */ if (restricted > 2 && mpz_even_p(n)) return 0; { /* Simple filter for composites */ uint32_t n32 = mpz_fdiv_ui(n, 2762760); if (!(n32& 1) && !(( 22 >> (n32% 7)) & 1)) return 0; if (!(n32% 3) && !(( 523 >> (n32%13)) & 1)) return 0; if (!(n32% 5) && !((65890 >> (n32%24)) & 1)) return 0; if (!(n32% 4) && !(( 514 >> (n32%14)) & 1)) return 0; if (!(n32%23) && !(( 2 >> (n32%22)) & 1)) return 0; } /* Calculate signature using Adams/Shanks doubling rule. */ mpz_init(t); mpz_init_set_ui(S[0], 1); mpz_init(S[1]); mpz_sub_ui(S[1], n, 1); mpz_init_set_ui(S[2], 3); mpz_init_set_ui(S[3], 3); mpz_init_set_ui(S[4], 0); mpz_init_set_ui(S[5], 2); for (i=0; i < 6; i++) mpz_init(T[i]); mpz_init(T01); mpz_init(T34); mpz_init(T45); for (i = mpz_sizeinbase(n,2)-2; i >= 0; i--) { mpz_mul(t,S[0],S[0]); mpz_sub(t,t,S[5]); mpz_sub(t,t,S[5]); mpz_mod(T[0],t,n); mpz_mul(t,S[1],S[1]); mpz_sub(t,t,S[4]); mpz_sub(t,t,S[4]); mpz_mod(T[1],t,n); mpz_mul(t,S[2],S[2]); mpz_sub(t,t,S[3]); mpz_sub(t,t,S[3]); mpz_mod(T[2],t,n); mpz_mul(t,S[3],S[3]); mpz_sub(t,t,S[2]); mpz_sub(t,t,S[2]); mpz_mod(T[3],t,n); mpz_mul(t,S[4],S[4]); mpz_sub(t,t,S[1]); mpz_sub(t,t,S[1]); mpz_mod(T[4],t,n); mpz_mul(t,S[5],S[5]); mpz_sub(t,t,S[0]); mpz_sub(t,t,S[0]); mpz_mod(T[5],t,n); mpz_sub(t,T[2],T[1]); mpz_mod(T01,t,n); mpz_sub(t,T[5],T[4]); mpz_mod(T34,t,n); mpz_add(t,T34, T[3]); mpz_mod(T45,t,n); if (mpz_tstbit(n, i)) { mpz_set(S[0],T[0]); mpz_set(S[1],T01); mpz_set(S[2],T[1]); mpz_set(S[3],T[4]); mpz_set(S[4],T45); mpz_set(S[5],T[5]); } else { mpz_add(t,T01,T[0]); mpz_set(S[0],T01); mpz_set(S[1],T[1]); mpz_mod(S[2],t,n); mpz_set(S[3],T34); mpz_set(S[4],T[4]); mpz_set(S[5],T45); } } for (i=0; i < 6; i++) mpz_clear(T[i]); mpz_clear(T01); mpz_clear(T34); mpz_clear(T45); rval = !mpz_sgn(S[4]); if (rval == 0 || restricted == 0) goto DONE_PERRIN; mpz_sub_ui(t,n,1); rval = !mpz_cmp(S[1],t); if (rval == 0 || restricted == 1) goto DONE_PERRIN; /* Adams/Shanks or Arno,Grantham full signature test */ rval = 0; j = mpz_si_kronecker(-23, n); if (j == -1) { mpz_t A, B, C; mpz_init_set(B, S[2]); mpz_init(A); mpz_init(C); mpz_mul(t,B,B); mpz_mod(t,t,n); mpz_mul_ui(A,B,3); mpz_add_ui(A,A,1); mpz_sub(A,A,t); mpz_mod(A,A,n); mpz_mul_ui(C,t,3); mpz_sub_ui(C,C,2); mpz_mod(C,C,n); mpz_mul(t,t,B); mpz_sub(t,t,B); mpz_mod(t,t,n); rval = !mpz_cmp(S[0],A) && !mpz_cmp(S[2],B) && !mpz_cmp(S[3],B) && !mpz_cmp(S[5],C) && mpz_cmp_ui(B,3) && !mpz_cmp_ui(t,1); } else if (restricted > 2 && j == 0 && mpz_cmp_ui(n,23)) { /* Jacobi symbol says 23|n. n is composite if != 23 */ rval = 0; } else { if (!mpz_cmp(S[2],S[3])) { rval = !mpz_cmp_ui(S[0],1) && !mpz_cmp_ui(S[2],3) && !mpz_cmp_ui(S[3],3) && !mpz_cmp_ui(S[5],2); } else { mpz_sub_ui(t, n, 1); rval = !mpz_cmp_ui(S[0],0) && !mpz_cmp(S[5],t) && (mpz_add(t,S[2],S[3]),mpz_add_ui(t,t,3),mpz_mod(t,t,n),!mpz_sgn(t)) && (mpz_sub(t,S[2],S[3]),mpz_mul(t,t,t),mpz_add_ui(t,t,23),mpz_mod(t,t,n),!mpz_sgn(t)); } } DONE_PERRIN: for (i=0; i < 6; i++) mpz_clear(S[i]); mpz_clear(t); return rval; } int is_frobenius_pseudoprime(mpz_t n, IV P, IV Q) { mpz_t t, Vcomp, d, U, V, Qk; IV D; int k = 0; int rval; { int cmpr = mpz_cmp_ui(n, 2); if (cmpr == 0) return 1; /* 2 is prime */ if (cmpr < 0) return 0; /* below 2 is composite */ if (mpz_even_p(n)) return 0; /* multiple of 2 is composite */ } mpz_init(t); if (P == 0 && Q == 0) { P = 1; Q = 2; do { P += 2; if (P == 3) P = 5; /* P=3,Q=2 -> D=9-8=1 => k=1, so skip */ if (P == 21 && mpz_perfect_square_p(n)) { mpz_clear(t); return 0; } D = P*P-4*Q; if (mpz_cmp_ui(n, P >= 0 ? P : -P) <= 0) break; if (mpz_cmp_ui(n, D >= 0 ? D : -D) <= 0) break; mpz_set_si(t, D); k = mpz_jacobi(t, n); } while (k == 1); } else { D = P*P-4*Q; if (is_perfect_square( D >= 0 ? D : -D, 0 )) croak("Frobenius invalid P,Q: (%"IVdf",%"IVdf")", P, Q); mpz_set_si(t, D); k = mpz_jacobi(t, n); } /* Check initial conditions */ { UV Pu = P >= 0 ? P : -P; UV Qu = Q >= 0 ? Q : -Q; UV Du = D >= 0 ? D : -D; /* If abs(P) or abs(Q) or abs(D) >= n, exit early. */ if (mpz_cmp_ui(n, Pu) <= 0 || mpz_cmp_ui(n, Qu) <= 0 || mpz_cmp_ui(n, Du) <= 0) { mpz_clear(t); return _GMP_trial_factor(n, 2, Du+Pu+Qu) ? 0 : 1; } /* If k = 0, then D divides n */ if (k == 0) { mpz_clear(t); return 0; } /* If n is not coprime to P*Q*D then we found a factor */ if (mpz_gcd_ui(NULL, n, Du*Pu*Qu) > 1) { mpz_clear(t); return 0; } } mpz_init(Vcomp); if (k == 1) { mpz_set_si(Vcomp, 2); } else { mpz_set_si(Vcomp, Q); mpz_mul_ui(Vcomp, Vcomp, 2); mpz_mod(Vcomp, Vcomp, n); } mpz_init(U); mpz_init(V); mpz_init(Qk); mpz_init(d); if (k == 1) mpz_sub_ui(d, n, 1); else mpz_add_ui(d, n, 1); lucas_seq(U, V, n, P, Q, d, Qk, t); rval = ( mpz_sgn(U) == 0 && mpz_cmp(V, Vcomp) == 0 ); mpz_clear(d); mpz_clear(Qk); mpz_clear(V); mpz_clear(U); mpz_clear(Vcomp); mpz_clear(t); return rval; } /* Use Crandall/Pomerance, steps from Loebenberger 2008 */ int is_frobenius_cp_pseudoprime(mpz_t n, UV ntests) { mpz_t t, a, b, d, w1, wm, wm1, m; UV tn; int j; int result = 1; if (mpz_cmp_ui(n, 100) < 0) /* tiny n */ return (_GMP_is_prob_prime(n) > 0); if (mpz_even_p(n)) return 0; mpz_init(t); mpz_init(a); mpz_init(b); mpz_init(d); mpz_init(w1); mpz_init(wm); mpz_init(wm1); mpz_init(m); for (tn = 0; tn < ntests; tn++) { /* Step 1: choose a and b in 1..n-1 and d=a^2-4b not square and coprime */ do { mpz_sub_ui(t, n, 1); mpz_isaac_urandomm(a, t); mpz_add_ui(a, a, 1); mpz_isaac_urandomm(b, t); mpz_add_ui(b, b, 1); /* Check d and gcd */ mpz_mul(d, a, a); mpz_mul_ui(t, b, 4); mpz_sub(d, d, t); } while (mpz_perfect_square_p(d)); mpz_mul(t, a, b); mpz_mul(t, t, d); mpz_gcd(t, t, n); if (mpz_cmp_ui(t, 1) != 0 && mpz_cmp(t, n) != 0) { result = 0; break; } /* Step 2: W1 = a^2b^-1 - 2 mod n */ if (!mpz_invert(t, b, n)) { result = 0; break; } mpz_mul(w1, a, a); mpz_mul(w1, w1, t); mpz_sub_ui(w1, w1, 2); mpz_mod(w1, w1, n); /* Step 3: m = (n-(d|n))/2 */ j = mpz_jacobi(d, n); if (j == -1) mpz_add_ui(m, n, 1); else if (j == 0) mpz_set(m, n); else if (j == 1) mpz_sub_ui(m, n, 1); mpz_tdiv_q_2exp(m, m, 1); /* Step 8 here: B = b^(n-1)/2 mod n (stored in d) */ mpz_sub_ui(t, n, 1); mpz_tdiv_q_2exp(t, t, 1); mpz_powm(d, b, t, n); /* Quick Euler test */ mpz_sub_ui(t, n, 1); if (mpz_cmp_ui(d, 1) != 0 && mpz_cmp(d, t) != 0) { result = 0; break; } /* Step 4: calculate Wm,Wm+1 */ mpz_set_ui(wm, 2); mpz_set(wm1, w1); { UV bit = mpz_sizeinbase(m, 2); while (bit-- > 0) { if (mpz_tstbit(m, bit)) { mpz_mul(t, wm, wm1); mpz_sub(wm, t, w1); mpz_mul(t, wm1, wm1); mpz_sub_ui(wm1, t, 2); } else { mpz_mul(t, wm, wm1); mpz_sub(wm1, t, w1); mpz_mul(t, wm, wm); mpz_sub_ui(wm, t, 2); } mpz_mod(wm, wm, n); mpz_mod(wm1, wm1, n); } } /* Step 5-7: compare w1/wm */ mpz_mul(t, w1, wm); mpz_mod(t, t, n); mpz_mul_ui(wm1, wm1, 2); mpz_mod(wm1, wm1, n); if (mpz_cmp(t, wm1) != 0) { result = 0; break; } /* Step 8 was earlier */ /* Step 9: See if Bwm = 2 mod n */ mpz_mul(wm, wm, d); mpz_mod(wm, wm, n); if (mpz_cmp_ui(wm, 2) != 0) { result = 0; break; } } mpz_clear(w1); mpz_clear(wm); mpz_clear(wm1); mpz_clear(m); mpz_clear(t); mpz_clear(a); mpz_clear(b); mpz_clear(d); return result; } /* New code based on draft paper */ int _GMP_is_frobenius_underwood_pseudoprime(mpz_t n) { mpz_t temp1, temp2, n_plus_1, s, t; unsigned long a, ap2, len; int bit, j, rval = 0; int _verbose = get_verbose_level(); { int cmpr = mpz_cmp_ui(n, 2); if (cmpr == 0) return 1; /* 2 is prime */ if (cmpr < 0) return 0; /* below 2 is composite */ if (mpz_even_p(n)) return 0; /* multiple of 2 is composite */ } mpz_init(temp1); for (a = 0; a < 1000000; a++) { if (a==2 || a==4 || a==7 || a==8 || a==10 || a==14 || a==16 || a==18) continue; mpz_set_si(temp1, (long)(a*a) - 4); j = mpz_jacobi(temp1, n); if (j == -1) break; if (j == 0 || (a == 20 && mpz_perfect_square_p(n))) { mpz_clear(temp1); return 0; } } if (a >= 1000000) { mpz_clear(temp1); croak("FU test failure, unable to find suitable a"); } if (mpz_gcd_ui(NULL, n, (a+4)*(2*a+5)) != 1) { mpz_clear(temp1); return 0; } mpz_init(temp2); mpz_init(n_plus_1), ap2 = a+2; mpz_add_ui(n_plus_1, n, 1); len = mpz_sizeinbase(n_plus_1, 2); mpz_init_set_ui(s, 1); mpz_init_set_ui(t, 2); for (bit = len-2; bit >= 0; bit--) { mpz_add(temp2, t, t); if (a != 0) { mpz_mul_ui(temp1, s, a); mpz_add(temp2, temp1, temp2); } mpz_mul(temp1, temp2, s); mpz_sub(temp2, t, s); mpz_add(s, s, t); mpz_mul(t, s, temp2); mpz_mod(t, t, n); mpz_mod(s, temp1, n); if ( mpz_tstbit(n_plus_1, bit) ) { if (a == 0) mpz_add(temp1, s, s); else mpz_mul_ui(temp1, s, ap2); mpz_add(temp1, temp1, t); mpz_add(temp2, t, t); mpz_sub(t, temp2, s); mpz_set(s, temp1); } } /* n+1 always has an even last bit, so s and t always modded */ mpz_set_ui(temp1, 2*a+5); mpz_mod(temp1, temp1, n); if (mpz_cmp_ui(s, 0) == 0 && mpz_cmp(t, temp1) == 0) rval = 1; if (_verbose>1) { gmp_printf("%Zd is %s with a = %"UVuf"\n", n, (rval) ? "probably prime" : "composite", a); fflush(stdout); } mpz_clear(temp1); mpz_clear(temp2); mpz_clear(n_plus_1); mpz_clear(s); mpz_clear(t); return rval; } int _GMP_is_frobenius_khashin_pseudoprime(mpz_t n) { mpz_t t, ta, tb, ra, rb, a, b, n_minus_1; unsigned long c = 1; int bit, len, k, rval = 0; { int cmpr = mpz_cmp_ui(n, 2); if (cmpr == 0) return 1; /* 2 is prime */ if (cmpr < 0) return 0; /* below 2 is composite */ if (mpz_even_p(n)) return 0; /* multiple of 2 is composite */ } if (mpz_perfect_square_p(n)) return 0; mpz_init(t); do { c += 2; mpz_set_ui(t, c); k = mpz_jacobi(t, n); } while (k == 1); if (k == 0) { mpz_clear(t); return 0; } mpz_init_set_ui(ra, 1); mpz_init_set_ui(rb, 1); mpz_init_set_ui(a, 1); mpz_init_set_ui(b, 1); mpz_init(ta); mpz_init(tb); mpz_init(n_minus_1); mpz_sub_ui(n_minus_1, n, 1); len = mpz_sizeinbase(n_minus_1, 2); for (bit = 0; bit < len; bit++) { if ( mpz_tstbit(n_minus_1, bit) ) { mpz_mul(ta, ra, a); mpz_mul(tb, rb, b); mpz_add(t, ra, rb); mpz_add(rb, a, b); mpz_mul(rb, rb, t); mpz_sub(rb, rb, ta); mpz_sub(rb, rb, tb); mpz_mod(rb, rb, n); mpz_mul_ui(tb, tb, c); mpz_add(ra, ta, tb); mpz_mod(ra, ra, n); } if (bit < len-1) { mpz_mul(t, b, b); mpz_mul_ui(t, t, c); mpz_mul(b, b, a); mpz_add(b, b, b); mpz_mod(b, b, n); mpz_mul(a, a, a); mpz_add(a, a, t); mpz_mod(a, a, n); } } if ( (mpz_cmp_ui(ra,1) == 0) && (mpz_cmp(rb, n_minus_1) == 0) ) rval = 1; mpz_clear(n_minus_1); mpz_clear(ta); mpz_clear(tb); mpz_clear(a); mpz_clear(b); mpz_clear(ra); mpz_clear(rb); mpz_clear(t); return rval; } int _GMP_BPSW(mpz_t n) { if (mpz_cmp_ui(n, 4) < 0) return (mpz_cmp_ui(n, 1) <= 0) ? 0 : 2; if (miller_rabin_ui(n, 2) == 0) /* Miller Rabin with base 2 */ return 0; if (_GMP_is_lucas_pseudoprime(n, 2 /*extra strong*/) == 0) return 0; if (mpz_sizeinbase(n, 2) <= 64) /* BPSW is deterministic below 2^64 */ return 2; return 1; } /* Assume n is a BPSW PRP, return 1 (no result), 0 (composite), 2 (prime) */ int is_deterministic_miller_rabin_prime(mpz_t n) { mpz_t t; int i, res = 1, maxp = 0; if (mpz_sizeinbase(n, 2) <= 82) { mpz_init(t); /* n < 3825123056546413051 => maxp=9, but BPSW should have handled */ if (mpz_set_str(t, "318665857834031151167461",10), mpz_cmp(n,t) < 0) maxp = 12; else if (mpz_set_str(t,"3317044064679887385961981",10), mpz_cmp(n,t) < 0) maxp = 13; if (maxp > 0) { for (i = 1; i < maxp && res; i++) { res = miller_rabin_ui(n, sprimes[i]); } if (res == 1) res = 2; } mpz_clear(t); } return res; } /* * is_prob_prime BPSW -- fast, no known counterexamples * is_prime is_prob_prime + a little extra * is_provable_prime really prove it, which could take a very long time * * They're all identical for numbers <= 2^64. * * The extra M-R test in is_prime start actually costing something after * 1000 bits or so. Primality proving will get quite a bit slower as the * number of bits increases. * * Both is_prime and is_provable prime start with some trial division * followed by an extra strong BPSW test, just like is_prob_prime. For * 65+ bit inputs, they do more. A single extra random-base M-R test is * next done. In the worst case this has a 1/4 chance of rejecting the * composite, but an average change of < 1e-12. is_prime will return at * this point. is_provable_prime tries various special proofs, followed * by ECPP. ECPP returns either: * 2 "definitely prime", * 0 "definitely composite, or * 1 "probably prime" * where the latter doesn't really tell us anything. It's unusual, but * possible. If this even happs, we do a couple Frobenius-type tests, so * even an answer of 1 (not proven) will have less chance of false results. * A composite would have to have no small factors, be the first known * counterexample to each of three different and distinct tests, pass a * random-base M-R test, and manage to have the ECPP implementation not * find it a composite. */ int _GMP_is_prob_prime(mpz_t n) { /* Step 1: Look for small divisors. This is done purely for performance. * It is *not* a requirement for the BPSW test. */ int res = primality_pretest(n); if (res != 1) return res; /* We'd like to do the LLR test here, but it screws with certificates. */ /* Step 2: The BPSW test. spsp base 2 and slpsp. */ return _GMP_BPSW(n); } int is_bpsw_dmr_prime(mpz_t n) { int prob_prime = _GMP_BPSW(n); if (prob_prime == 1) { prob_prime = is_deterministic_miller_rabin_prime(n); if (prob_prime == 0) gmp_printf("\n\n**** BPSW counter-example found? ****\n**** N = %Zd ****\n\n", n); } return prob_prime; } int _GMP_is_prime(mpz_t n) { UV nbits; /* Similar to is_prob_prime, but put LLR before BPSW, then do more testing */ /* First, simple pretesting */ int prob_prime = primality_pretest(n); if (prob_prime != 1) return prob_prime; /* If the number is of form N=k*2^n-1 and we have a fast proof, do it. */ prob_prime = llr(n); if (prob_prime == 0 || prob_prime == 2) return prob_prime; /* If the number is of form N=k*2^n+1 and we have a fast proof, do it. */ prob_prime = proth(n); if (prob_prime == 0 || prob_prime == 2) return prob_prime; /* Start with BPSW */ prob_prime = _GMP_BPSW(n); nbits = mpz_sizeinbase(n, 2); /* Use Sorenson/Webster 2015 deterministic M-R if possible */ if (prob_prime == 1) { prob_prime = is_deterministic_miller_rabin_prime(n); if (prob_prime == 0) gmp_printf("\n\n**** BPSW counter-example found? ****\n**** N = %Zd ****\n\n", n); } /* n has passed the ES BPSW test, making it quite unlikely it is a * composite (and it cannot be if n < 2^64). */ /* For small numbers, try a quick BLS75 proof. */ if (prob_prime == 1) { if (is_proth_form(n)) prob_prime = _GMP_primality_bls_nm1(n, 2 /* effort */, 0 /* cert */); else if (nbits <= 150) prob_prime = _GMP_primality_bls_nm1(n, 0 /* effort */, 0 /* cert */); /* We could do far better by calling bls75_hybrid, especially with a * larger effort. But that takes more time. I've decided it isn't worth * the extra time here. We'll still try a very quick N-1 proof. */ } /* If prob_prime is still 1, let's run some extra tests. * Argument against: Nobody has yet found a BPSW counterexample, so * this is wasted time. They can make a call to one of * the other tests themselves if they care. * Argument for: is_prime() should be as correct as reasonably possible. * They can call is_prob_prime() to skip extra tests. * * Choices include: * * - A number of fixed-base Miller-Rabin tests. * - A number of random-base Miller-Rabin tests. * - A Frobenius-Underwood test. * - A Frobenius-Khashin test. * * The Miller-Rabin tests have better performance. * * We will use random bases to make it more difficult to get a false * result even if someone has a way to generate BPSW pseudoprimes. * * We can estimate probabilities of random odd 'k'-bit composites passing * 't' random-base Miller-Rabin tests using papers such as Kim and * Pomerance; Damg??rd, Landrock, and Pomerance; Lichtman and Pomerance. * We can also perform random sampling to get empirical data, which shows * a probability of less than 1e-12 at 65 bits, and lowering as the number * of bits increases. One extra test is all that is necessary. */ if (prob_prime == 1) { UV ntests = 1; prob_prime = miller_rabin_random(n, ntests, 0); /* prob_prime = _GMP_is_frobenius_underwood_pseudoprime(n); */ /* prob_prime = _GMP_is_frobenius_khashin_pseudoprime(n); */ } /* We have now done trial division, an SPSP-2 test, an extra-strong Lucas * test, and a random-base Miller-Rabin test. We have exceeded the testing * done in most math packages. Any composites will have no small factors, * be the first known BPSW counterexample, and gotten past the random-base * Miller-Rabin test. */ return prob_prime; } int _GMP_is_provable_prime(mpz_t n, char** prooftext) { int prob_prime = primality_pretest(n); if (prob_prime != 1) return prob_prime; /* Try LLR and Proth if they don't need a proof certificate. */ if (prooftext == 0) { prob_prime = llr(n); if (prob_prime == 0 || prob_prime == 2) return prob_prime; prob_prime = proth(n); if (prob_prime == 0 || prob_prime == 2) return prob_prime; } /* Start with BPSW */ prob_prime = _GMP_BPSW(n); if (prob_prime != 1) return prob_prime; /* Use Sorenson/Webster 2015 deterministic M-R if possible */ if (prooftext == 0) { prob_prime = is_deterministic_miller_rabin_prime(n); if (prob_prime != 1) return prob_prime; } /* Run one more M-R test, just in case. */ prob_prime = miller_rabin_random(n, 1, 0); if (prob_prime != 1) return prob_prime; /* We can choose a primality proving algorithm: * AKS _GMP_is_aks_prime really slow, don't bother * N-1 _GMP_primality_bls_nm1 small or special numbers * ECPP _GMP_ecpp fastest in general */ /* Give n-1 a small go */ prob_prime = _GMP_primality_bls_nm1(n, is_proth_form(n) ? 3 : 1, prooftext); if (prob_prime != 1) return prob_prime; /* ECPP */ prob_prime = _GMP_ecpp(n, prooftext); /* While extremely unusual, it is not impossible for our ECPP implementation * to give up. If this happens, we won't return 2 with a proof, but let's * at least run some more tests. */ if (prob_prime == 1) prob_prime = _GMP_is_frobenius_underwood_pseudoprime(n); if (prob_prime == 1) prob_prime = _GMP_is_frobenius_khashin_pseudoprime(n); return prob_prime; } Math-Prime-Util-GMP-0.52/ecm.h0000644000175000017500000000063313025437621014251 0ustar danadana#ifndef MPU_ECM_H #define MPU_ECM_H #include #include "ptypes.h" struct ec_affine_point { mpz_t x, y; }; extern int ec_affine_multiply( mpz_t a, mpz_t k, mpz_t n, struct ec_affine_point P, struct ec_affine_point *R, mpz_t d); extern int _GMP_ecm_factor_affine(mpz_t n, mpz_t f, UV BMax, UV ncurves); extern int _GMP_ecm_factor_projective(mpz_t n, mpz_t f, UV B1, UV B2, UV ncurves); #endif Math-Prime-Util-GMP-0.52/lib/0000755000175000017500000000000013674072603014105 5ustar danadanaMath-Prime-Util-GMP-0.52/lib/Math/0000755000175000017500000000000013674072603014776 5ustar danadanaMath-Prime-Util-GMP-0.52/lib/Math/Prime/0000755000175000017500000000000013674072603016052 5ustar danadanaMath-Prime-Util-GMP-0.52/lib/Math/Prime/Util/0000755000175000017500000000000013674072603016767 5ustar danadanaMath-Prime-Util-GMP-0.52/lib/Math/Prime/Util/GMP.pm0000644000175000017500000027065213663067455017773 0ustar danadanapackage Math::Prime::Util::GMP; use strict; use warnings; use Carp qw/croak confess carp/; BEGIN { $Math::Prime::Util::GMP::AUTHORITY = 'cpan:DANAJ'; $Math::Prime::Util::GMP::VERSION = '0.52'; } # parent is cleaner, and in the Perl 5.10.1 / 5.12.0 core, but not earlier. # use parent qw( Exporter ); use base qw( Exporter ); our @EXPORT_OK = qw( is_prime is_prob_prime is_bpsw_prime is_provable_prime is_provable_prime_with_cert is_aks_prime is_nminus1_prime is_nplus1_prime is_bls75_prime is_ecpp_prime is_pseudoprime is_euler_pseudoprime is_euler_plumb_pseudoprime is_strong_pseudoprime is_lucas_pseudoprime is_strong_lucas_pseudoprime is_extra_strong_lucas_pseudoprime is_almost_extra_strong_lucas_pseudoprime is_perrin_pseudoprime is_frobenius_pseudoprime is_frobenius_underwood_pseudoprime is_frobenius_khashin_pseudoprime is_mersenne_prime is_llr_prime is_proth_prime is_miller_prime miller_rabin_random is_gaussian_prime lucas_sequence lucasu lucasv primes sieve_primes sieve_twin_primes sieve_prime_cluster sieve_range next_prime prev_prime surround_primes next_twin_prime trial_factor prho_factor pbrent_factor pminus1_factor pplus1_factor holf_factor squfof_factor ecm_factor qs_factor factor divisors sigma chinese moebius prime_count prime_count_lower prime_count_upper primorial pn_primorial factorial subfactorial multifactorial factorial_sum factorialmod consecutive_integer_lcm partitions bernfrac bernreal harmfrac harmreal stirling zeta li ei riemannr lambertw addreal subreal mulreal divreal logreal expreal powreal rootreal agmreal gcd lcm kronecker valuation binomial gcdext hammingweight invmod sqrtmod addmod mulmod divmod powmod vecsum vecprod exp_mangoldt liouville totient jordan_totient carmichael_lambda sqrtint rootint logint powint mulint addint subint divint modint divrem tdivrem negint absint is_power is_prime_power is_semiprime is_square is_carmichael is_fundamental is_totient is_primitive_root is_polygonal polygonal_nth znorder znprimroot ramanujan_tau Pi Euler todigits random_prime random_nbit_prime random_ndigit_prime random_safe_prime random_strong_prime random_maurer_prime random_shawe_taylor_prime random_maurer_prime_with_cert random_shawe_taylor_prime_with_cert seed_csprng is_csprng_well_seeded irand irand64 drand urandomb urandomm urandomr random_bytes permtonum numtoperm ); # Should add: # nth_prime our %EXPORT_TAGS = (all => [ @EXPORT_OK ]); sub _init_random { use Fcntl; my($file, $nbytes, $s, $buffer, $nread) = ("/dev/urandom", 256, '', '', 0); return if $^O eq 'MSWin32'; return unless -r $file; sysopen(my $fh, $file, O_RDONLY); binmode $fh; while ($nread < $nbytes) { my $thisread = sysread $fh, $buffer, $nbytes-$nread; last unless defined $thisread && $thisread > 0; $s .= $buffer; $nread += length($buffer); } return unless $nbytes == length($s); seed_csprng($nbytes, $s); } BEGIN { eval { require XSLoader; XSLoader::load(__PACKAGE__, $Math::Prime::Util::GMP::VERSION); _GMP_init(); _init_random(); 1; } or do { die $@; }; } END { _GMP_destroy(); } sub _validate_positive_integer { my($n, $min, $max) = @_; croak "Parameter must be defined" if !defined $n; if (ref($n) eq 'Math::BigInt' && $n->can("sign")) { croak "Parameter '$n' must be a positive integer" unless $n->sign() eq '+'; } else { my $sn = "$n"; croak "Parameter '$sn' must be a positive integer" if $sn eq '' || $sn =~ tr/0123456789//c; } croak "Parameter '$n' must be >= $min" if defined $min && $n < $min; croak "Parameter '$n' must be <= $max" if defined $max && $n > $max; 1; } sub is_provable_prime { my ($n) = @_; return 0 if $n < 2; return _is_provable_prime($n); } sub is_provable_prime_with_cert { my ($n) = @_; my @composite = (0, ''); return @composite if $n < 2; my ($result, $text) = _is_provable_prime($n, 1); return @composite if $result == 0; return ($result, '') if $result != 2; $text = "Type Small\nN $n\n" if !defined $text || $text eq ''; $text =~ s/\n$//; $text = "[MPU - Primality Certificate]\nVersion 1.0\n\nProof for:\nN $n\n\n$text"; return ($result, $text); } sub primes { my($low,$high) = (scalar(@_) == 1) ? (2,$_[0]) : ($_[0], $_[1]); _validate_positive_integer($low); _validate_positive_integer($high); [ sieve_primes($low, $high, 0) ]; } 1; __END__ # ABSTRACT: Utilities related to prime numbers and factoring, using GMP =pod =encoding utf8 =for stopwords Möbius Deléglise Bézout s-gonal gcdext vecsum vecprod moebius totient liouville znorder znprimroot bernfrac bernreal harmfrac harmreal addreal subreal mulreal divreal logreal expreal powreal rootreal agmreal stirling zeta li ei riemannr lambertw lucasu lucasv OpenPFGW gmpy2 nonresidue chinese tuplets sqrtmod addmod mulmod powmod divmod superset sqrtint rootint logint powint mulint addint subint divint modint divrem tdivrem negint absint todigits urandomb urandomr =head1 NAME Math::Prime::Util::GMP - Utilities related to prime numbers and factoring, using GMP =head1 VERSION Version 0.52 =head1 SYNOPSIS use Math::Prime::Util::GMP ':all'; my $n = "115792089237316195423570985008687907853269984665640564039457584007913129639937"; # This doesn't impact the operation of the module at all, but does let you # enter big number arguments directly as well as enter (e.g.): 2**2048 + 1. use bigint; # These return 0 for composite, 2 for prime, and 1 for probably prime # Numbers under 2^64 will return 0 or 2. # is_prob_prime does a BPSW primality test for numbers > 2^64 # is_prime adds some MR tests and a quick test to try to prove the result # is_provable_prime will spend a lot of effort on proving primality say "$n is probably prime" if is_prob_prime($n); say "$n is ", qw(composite prob_prime def_prime)[is_prime($n)]; say "$n is definitely prime" if is_provable_prime($n) == 2; # Miller-Rabin and strong Lucas-Selfridge pseudoprime tests say "$n is a prime or spsp-2/7/61" if is_strong_pseudoprime($n, 2, 7, 61); say "$n is a prime or slpsp" if is_strong_lucas_pseudoprime($n); say "$n is a prime or eslpsp" if is_extra_strong_lucas_pseudoprime($n); # Return array reference to primes in a range. my $aref = primes( 10 ** 200, 10 ** 200 + 10000 ); $next = next_prime($n); # next prime > n $prev = prev_prime($n); # previous prime < n # Primorials and lcm say "23# is ", primorial(23); say "The product of the first 47 primes is ", pn_primorial(47); say "lcm(1..1000) is ", consecutive_integer_lcm(1000); # Find prime factors of big numbers @factors = factor(5465610891074107968111136514192945634873647594456118359804135903459867604844945580205745718497); # Finer control over factoring. # These stop after finding one factor or exceeding their limit. # # optional arguments o1, o2, ... @factors = trial_factor($n); # test up to o1 @factors = prho_factor($n); # no more than o1 rounds @factors = pbrent_factor($n); # no more than o1 rounds @factors = holf_factor($n); # no more than o1 rounds @factors = squfof_factor($n); # no more than o1 rounds @factors = pminus1_factor($n); # o1 = smoothness limit, o2 = stage 2 limit @factors = ecm_factor($n); # o1 = B1, o2 = # of curves @factors = qs_factor($n); # (no arguments) =head1 DESCRIPTION A module for number theory in Perl using GMP. This includes primality tests, getting primes in a range, factoring, and more. While it certainly can be used directly, the main purpose of this module is for L. That module will automatically load this one if it is installed, greatly speeding up many of its operations on big numbers. Inputs and outputs for big numbers are via strings, so you do not need to use a bigint package in your program. However if you do use bigints, inputs will be converted internally so there is no need to convert before a call. Output results are returned as either Perl scalars (for native-size) or strings (for bigints). L tries to reconvert all strings back into the callers bigint type if possible, which makes it more convenient for calculations. The various C tests are more appropriately called C or C. They return 1 if the input is a probable prime based on their test. The naming convention is historical and follows Pari, L, and some other math packages. The modern definition of pseudoprime is a I that passes the test, rather than any number. =head1 FUNCTIONS =head2 is_prob_prime my $prob_prime = is_prob_prime($n); # Returns 0 (composite), 2 (prime), or 1 (probably prime) Takes a positive number as input and returns back either 0 (composite), 2 (definitely prime), or 1 (probably prime). For inputs below C<2^64> the test is deterministic, so the possible return values are 0 (composite) or 2 (definitely prime). For inputs above C<2^64>, a probabilistic test is performed. Only 0 (composite) and 1 (probably prime) are returned. The current implementation uses the Baillie-PSW (BPSW) test. There is a possibility that composites may be returned marked prime, but since the test was published in 1980, not a single BPSW pseudoprime has been found, so it is extremely likely to be prime. While we believe (Pomerance 1984) that an infinite number of counterexamples exist, there is a weak conjecture (Martin) that none exist under 10000 digits. In more detail, we are using the extra-strong Lucas test (Grantham 2000) using the Baillie parameter selection method (see OEIS A217719). Previous versions of this module used the strong Lucas test with Selfridge parameters, but the extra-strong version produces fewer pseudoprimes while running 1.2 - 1.5x faster. It is slightly stronger than the test used in L. =head2 is_prime say "$n is prime!" if is_prime($n); Takes a positive number as input and returns back either 0 (composite), 2 (definitely prime), or 1 (probably prime). Composites will act exactly like C, as will numbers less than C<2^64>. For numbers larger than C<2^64>, some additional tests are performed on probable primes to see if they can be proven by another means. This call walks the line between the performance of L and the certainty of L. Those calls may be more appropriate in some cases. What this function does is give most of the performance of the former, while adding more certainty. For finer tuning of this tradeoff, you may instead use L followed by additional probable prime tests such as L and/or L. As with L, a BPSW test is first performed. This is deterministic for all 64-bit numbers. Next, if the number is a Proth or LLR form, then a proof is constructed. If the result is still "probably prime" and the input is smaller than the Sorenson/Webster (2015) deterministic Miller-Rabin limit (approximately 82 bits) then the 11 or 12 Miller-Rabin tests are performed and the result is confirmed. For larger inputs that are still "probably prime" but under 200 bits, a quick BLS75 C primality proof is attempted. This is tuned to give up if the result cannot be quickly determined, and results in success rates of ~80% at 80 bits, ~30% at 128 bits, and ~13% at 160 bits. Lastly, for results still "probably prime", an additional random-base Miller-Rabin test is performed. The result is that many numbers will return 2 (definitely prime), and the numbers that return 1 (probably prime) have gone through more tests than L while not taking too long. For cryptographic key generation, you may want even more testing for probable primes (NIST recommends a few more additional M-R tests than we perform). The function L is made for this. Alternately, a different test such as L can be used. Even better, use L which should be reasonably fast for sizes under 2048 bits. Typically for key generation one wants random primes, and there are many functions for that. =head2 is_provable_prime say "$n is definitely prime!" if is_provable_prime($n) == 2; Takes a positive number as input and returns back either 0 (composite), 2 (definitely prime), or 1 (probably prime). A great deal of effort is taken to return either 0 or 2 for all numbers. The current method first uses BPSW to find composites and provide a deterministic answer for tiny numbers (under C<2^64>). If no certificate is required, LLR and Proth tests can be run, and small numbers (under approximately C<2^82>) can be satisfied with a deterministic Miller-Rabin test. If the result is still not determined, a quick BLS75 C test is attempted, followed by ECPP. The time required for primes of different input sizes on a circa-2009 workstation averages about C<3ms> for 30-digits, C<5ms> for 40-digit, C<20ms> for 60-digit, C<50ms> for 80-digit, C<100ms> for 100-digit, C<2s> for 200-digit, and 400-digit inputs about a minute. Expect a lot of time variation for larger inputs. You can see progress indication if verbose is turned on (some at level 1, and a lot at level 2). A certificate can be obtained along with the result using the L method. There is no appreciable extra performance cost for returning a certificate. =head2 is_provable_prime_with_cert Takes a positive number as input and returns back an array with two elements. The result will be one of: (0, '') The input is composite. (1, '') The input is probably prime but we could not prove it. This is a failure in our ability to factor some necessary element in a reasonable time, not a significant proof failure (in other words, it remains a probable prime). (2, '...') The input is prime, and the certificate contains all the information necessary to verify this. The certificate is a text representation containing all the necessary information to verify the primality of the input in a reasonable time. The result can be used with L for verification. Proof types used include: ECPP BLS3 BLS15 BLS5 Small =head2 is_pseudoprime Takes a positive number C and one or more non-zero positive bases as input. Returns C<1> if the input is a probable prime to each base, C<0> if not. This is the simple Fermat primality test. Removing primes, given base 2 this produces the sequence L. =head2 is_euler_pseudoprime Takes a positive number C and one or more non-zero positive bases as input. Returns C<1> if the input is an Euler probable prime to each base, C<0> if not. This is the Euler test, sometimes called the Euler-Jacobi test. Removing primes, given base 2 this produces the sequence L. =head2 is_strong_pseudoprime my $maybe_prime = is_strong_pseudoprime($n, 2); my $probably_prime = is_strong_pseudoprime($n, 2, 3, 5, 7, 11, 13, 17); Takes a positive number C and one or more non-zero positive bases as input. Returns C<1> if the input is a strong probable prime to each base, C<0> if not. This is often called the Miller-Rabin test. If 0 is returned, then the number really is a composite. If 1 is returned, then it is either a prime or a strong pseudoprime to all the given bases. Given enough distinct bases, the chances become very strong that the number is actually prime. Both the input number and the bases may be big integers. If base modulo n E= 1 or base modulo n = n-1, then the result will be 1. This allows the bases to be larger than n if desired, while still returning meaningful results. For example, is_strong_pseudoprime(367, 1101) would incorrectly return 0 if this was not done properly. A 0 result should be returned only if n is composite, regardless of the base. This is usually used in combination with other tests to make either stronger tests (e.g. the strong BPSW test) or deterministic results for numbers less than some verified limit (e.g. Jaeschke showed in 1993 that no more than three selected bases are required to give correct primality test results for any 32-bit number). Given the small chances of passing multiple bases, there are some math packages that just use multiple MR tests for primality testing, though in the early 1990s almost all serious software switched to the BPSW test. Even numbers other than 2 will always return 0 (composite). While the algorithm works with even input, most sources define it only on odd input. Returning composite for all non-2 even input makes the function match most other implementations including L's C function. =head2 miller_rabin_random my $maybe_prime = miller_rabin_random($n, 10); # 10 random bases Takes a positive number (C) as input and a positive number (C) of bases to use. Performs C Miller-Rabin tests using uniform random bases between 2 and C. This is the correct way to perform C Miller-Rabin tests, rather than the common but broken method of using the first C primes. An optional third argument may be given, which is a seed to use. The seed should be a number either in decimal, binary with a leading C<0b>, hex with a leading C<0x>, or octal with a leading C<0>. It will be converted to a GMP integer, so may be large. Typically this is not necessary, but cryptographic applications may prefer the ability to use this, and it allows repeatable test results. There is no check for duplicate bases. Input sizes below 65 bits make little sense for this function since L is deterministic at that size. For numbers of 65+ bits, the chance of duplicate bases is quite small. The exponentiation approximation for the birthday problem gives a probability of less than 2e-16 for 100 random bases to have a duplicate with a 65-bit input, and less than 2e-35 with a 128-bit input. =head2 is_lucas_pseudoprime =head2 is_strong_lucas_pseudoprime Takes a positive number as input, and returns 1 if the input is a standard or strong Lucas probable prime. The Selfridge method of choosing D, P, and Q are used (some sources call this a Lucas-Selfridge test). This is one half of the BPSW primality test (the Miller-Rabin strong probable prime test with base 2 being the other half). The canonical BPSW test (page 1401 of Baillie and Wagstaff (1980)) uses the strong Lucas test with Selfridge parameters, but in practice a variety of Lucas tests with different parameters are used by tests calling themselves BPSW. The standard Lucas test implemented here corresponds to the Lucas test described in FIPS 186-4 section C.3.3, though uses a slightly more efficient calculation. Since the standard Lucas-Selfridge test is a subset of the strong Lucas-Selfridge test, I recommend using the strong test rather than the standard test for cryptographic purposes. It is often slightly faster, has over 4x fewer pseudoprimes, and is the method recommended by Baillie and Wagstaff in their 1980 paper. =head2 is_extra_strong_lucas_pseudoprime Takes a positive number as input, and returns 1 if the input is an extra-strong Lucas probable prime. This is defined in Grantham (2000), and is a slightly more stringent test than the strong Lucas test, though because different parameters are used the pseudoprimes are not a subset. As expected by the extra conditions, the number of pseudoprimes is less than 2/3 that of the strong Lucas-Selfridge test. Runtime performance is 1.2 to 1.5x faster than the strong Lucas test. The parameters are selected using the Baillie-OEIS method: P = 3; Q = 1; while ( jacobi( P*P-4, n ) != -1 ) P += 1; =head2 is_almost_extra_strong_lucas_pseudoprime Takes a positive number as input and returns 1 if the input is an "almost" extra-strong Lucas probable prime. This is the classic extra-strong Lucas test but without calculating the U sequence. This makes it very fast, although as the input increases in size the time converges to the conventional extra-strong implementation: at 30 digits this routine is about 15% faster, at 300 digits it is only 2% faster. With the current implementations, there is little reason to prefer this unless trying to reproduce specific results. The extra-strong implementation has been optimized to use similar features, removing most of the performance advantage. An optional second argument (must be between 1 and 256) indicates the increment amount for P parameter selection. The default value of one yields the method described in L. A value of 2 yields the method used in L. Because the C condition is ignored, this produces about 5% more pseudoprimes than the extra-strong Lucas test. However this is still only 66% of the number produced by the strong Lucas-Selfridge test. No BPSW counterexamples have been found with any of the Lucas tests described. =head2 is_euler_plumb_pseudoprime Takes a positive number C as input and returns 1 if C passes Colin Plumb's Euler Criterion primality test. Pseudoprimes to this test are a subset of the base 2 Fermat and Euler tests, but a superset of the base 2 strong pseudoprime (Miller-Rabin) test. The main reason for this test is that is a bit more efficient than other probable prime tests. =head2 is_perrin_pseudoprime Takes a positive number C as input and returns 1 if C divides C where C is the Perrin number of C. The Perrin sequence is defined by C with C. This is not a commonly used test, as it runs slower than most of the other probable prime tests and offers little benefit, especially over combined tests like L, L, and L. An optional second argument C indicates whether to run additional tests. With C, C is also verified, creating the "minimal restricted" test. With C, the full signature is also tested using the Adams and Shanks (1982) rules (without the quadratic form test). With C, the full signature is tested using the Grantham (2000) test, which additionally does not allow pseudoprimes to be divisible by 2 or 23. The minimal restricted pseudoprime sequence is L. =head2 is_frobenius_pseudoprime Takes a positive number C as input, and two optional parameters C and C, and returns 1 if the C is a Frobenius probable prime with respect to the polynomial C. Without the parameters, C and C is the least positive odd number such that C<(a^2-4b|n) = -1>. This selection has no pseudoprimes below C<2^64> and none known. In any case, the discriminant C must not be a perfect square. =head2 is_frobenius_underwood_pseudoprime Takes a positive number as input, and returns 1 if the input passes the efficient Frobenius test of Paul Underwood. This selects a parameter C as the least non-negative integer such that C<(a^2-4|n)=-1>, then verifies that C<(x+2)^(n+1) = 2a + 5 mod (x^2-ax+1,n)>. This combines a Fermat and Lucas test at a computational cost of about 2.5x a strong pseudoprime test. This makes it similar to, but faster than, a standard Frobenius test. This test is deterministic (no randomness is used). There are no known pseudoprimes to this test. This test also has no overlap with the BPSW test, making it a very effective method for adding additional certainty. =head2 is_frobenius_khashin_pseudoprime Takes a positive number as input, and returns 1 if the input passes the Frobenius test of Sergey Khashin. This ensures C is not a perfect square, selects the parameter C as the smallest odd prime such that C<(c|n)=-1>, then verifies that C<(1+D)^n = (1-D) mod n> where C. This test is deterministic (no randomness is used). There are no known pseudoprimes to this test. =head2 is_bpsw_prime Given a positive number input, returns 0 (composite), 2 (definitely prime), or 1 (probably prime), using the BPSW primality test (extra-strong variant). This function does the extra-strong BPSW test and nothing more. That is, it will skip all pretests and any extra work that the L test may add. This saves some time if the input has no small factors, such as testing results that have been sieved. =head2 is_aks_prime say "$n is definitely prime" if is_aks_prime($n); Takes a positive number as input, and returns 1 if the input passes the Agrawal-Kayal-Saxena (AKS) primality test. This is a deterministic unconditional primality test which runs in polynomial time for general input. The particular method used is theorem 4.1 from Bernstein (2003). This is substantially faster than the original AKS publication, the later version with improvements by Lenstra (sometimes called the V6 paper), or the later improvements of Voloch and Bornemann. It is, by a large order, faster than any other known implementation as of early 2017. For theoretical analysis of the primality task, AKS is extremely important. In practice, it is essentially useless. Estimated run time for a 150 digit input is over 2 days, making the case that while the algorithmic complexity I is polynomial, the constants are extremely high. It will take years for for numbers that ECPP or APR-CL can prove in seconds. With the C option set to 1, the chosen C and C values are printed before the test starts. With C set to 2 or higher, each of the C tests results in a C<.> output as the test runs, allowing progress to be monitored. Typically you should use L and let it decide the method. =head2 is_mersenne_prime say "2^607-1 (M607) is a Mersenne prime" if is_mersenne_prime(607); Takes a positive number C

as input and returns 1 if C<2^p-1> is prime. After some pre-testing, the Lucas-Lehmer test is performed. This is a deterministic unconditional test that runs very fast compared to other primality methods for numbers of comparable size, and vastly faster than any known general-form primality proof methods. =head2 is_llr_prime Takes a positive number C as input and returns one of: 0 (definitely composite), 2 (definitely prime), or -1 (test does not indicate anything). This implements the Lucas-Lehmer-Riesel test for fast deterministic primality testing on numbers of the form C. If the input is not of this form or if C= 2^n> then C<-1> will be returned as the test does not apply. If C then this is a Mersenne number and the Lucas-Lehmer test is used. Otherwise, the LLR test is performed. While not as fast as the Lucas-Lehmer test for Mersenne numbers, it is almost as fast as a single strong pseudoprime test (i.e. Miller-Rabin test) while giving a certain answer. =head2 is_proth_prime Takes a positive number C as input and returns one of: 0 (definitely composite), 2 (definitely prime), or -1 (test does not indicate anything). This applies Proth's theorem for fast Las Vegas primality testing on numbers of the form C. If the input is not of this form or if C= 2^n> then C<-1> will be returned as the test does not apply. Otherwise, a search is performed to find a quadratic nonresidue modulo C. If none can be found after a brief search, C<-1> is returned as no conclusion can be reached. Otherwise, Proth's theorem is checked which conclusively indicates primality. While not as fast as the Lucas-Lehmer test for Mersenne numbers, it is almost as fast as a single strong pseudoprime test (i.e. Miller-Rabin test) while giving a certain answer. =head2 is_gaussian_prime Given two integers C and C as input, returns 0 (definitely composite), 1 (probably prime), or 2 (definitely prime) to indicate whether the complex number C is a Guassian prime. The L function is used internally to make the determination. =head2 is_miller_prime say "$n is definitely prime" if is_miller_prime($n); say "$n is definitely prime assuming the GRH" if is_miller_prime($n, 1); Takes a positive number as input, and returns 1 if the input passes the deterministic Miller test. An optional second argument indicates whether the Generalized Riemann Hypothesis should be assumed, and defaults to 0. Setting the verbose flag to 2 or higher will show how many bases are used. The unconditional test is exponential time, while the conditional test (assuming the GRH) is polynomial time. This is a very slow method in practice, and generally should not be used. The asymptotic complexity of the GRH version is good in theory, matching ECPP, but in practice it is much slower. The number of bases used by the unconditional test grows quite rapidly, impractically many past about 160 bits, and overflows a 64-bit integer at 456 bits -- sizes that are trivial for the unconditional APR-CL and ECPP tests. =head2 is_nminus1_prime say "$n is definitely prime" if is_nminus1_prime($n); Takes a positive number as input, and returns 1 if the input passes either theorem 5 or theorem 7 of the Brillhart-Lehmer-Selfridge primality test. This is a deterministic unconditional primality test which requires factoring C to a linear factor less than the cube root of the input. For small inputs (under 40 digits) this is typically very easy, and some numbers will naturally lead to this being very fast. As the input grows, this method slows down rapidly. This method is most appropriate for numbers of the form C where C can be easily factored. Typically you should use L and let it decide the method. =head2 is_nplus1_prime Takes a positive number as input, and returns 1 if the input passes either theorem 17 or theorem 19 of the Brillhart-Lehmer-Selfridge primality test. This is a deterministic unconditional primality test which requires factoring C to a linear factor less than the cube root of the input. For small inputs (under 40 digits) this is typically very easy, and some numbers will naturally lead to this being very fast. As the input grows, this method slows down rapidly. Disregarding factoring, this is slightly slower than the C methods. It is most appropriate for numbers of the form C where C can be easily factored. =head2 is_bls75_prime Takes a positive number as input, and returns 1 if the input passes one of the tests from the Brillhart-Lehmer-Selfridge (1975) paper. These use partial factoring of C and C. Currently the implementation will use one of: N-1 Corollary 1, Theorem 5, Theorem 7 N+1 Corollary 8, Theorem 17, Theorem 19 Comb Theorem 20 This is appropriate for cases where either C or C can be easily factored, or when both of them have many small factors. =head2 is_ecpp_prime say "$n is definitely prime" if is_ecpp_prime($n); Takes a positive number as input, and returns 1 if the input passes the ECPP primality test. This is the Atkin-Morain Elliptic Curve Primality Proving algorithm. It is the fastest primality proving method in Math::Prime::Util. This implementation uses a "factor all strategy" (FAS) with backtracking. A limited set of about 500 precalculated discriminants are used, which works well for inputs up to 300 digits, and for many inputs up to one thousand digits. Having a larger set will help with large numbers (a set of 2650 is available on github in the C directory). A future implementation may include code to generate class polynomials as needed. Typically you should use L and let it decide the method. =head2 primes my $aref1 = primes( 1_000_000 ); my $aref2 = primes( 2 ** 448, 2 ** 448 + 10000 ); say join ",", @{primes( 2**2048, 2**2048 + 10000 )}; Returns all the primes between the lower and upper limits (inclusive), with a lower limit of C<2> if none is given. An array reference is returned, matching the signature of the function of the same name in L. Values above 64-bit are extra-strong BPSW probable primes. =head2 prime_count Returns the number of primes between 2 and C (single argument) or C and C given two arguments. The values are inclusive. The method is simple sieving followed by primality testing. This is appropriate for small ranges and is useful for very large arguments. The L module has much more sophisticated methods for 64-bit arguments. =head2 prime_count_lower =head2 prime_count_upper Returns lower or upper bounds for the prime count of the input C. Bounds use Dusart 2010, Büthe 2014, Büthe 2015, and Axler 2017. =head2 sieve_primes my @primes = sieve_primes(2**100, 2**100 + 10000); my @candidates = sieve_primes(2**1000, 2**1000 + 10000, 40000); Given two arguments C and C, this returns the primes in the interval (inclusive) as a list. It operates similar to L, though must always have an lower and upper bound and returns a list. With three arguments C, C, and C, this does a partial sieve over the inclusive range and returns the list that pass the sieve. If C is less than C<2> then it is identical to the two-argument version, in that a primality test will be performed after sieving. Otherwise, sieving is performed up to C. The two-argument version is typically only used internally and adds little functionality. The three-argument version is quite useful for applications that want to apply their own primality or other tests, and wish to have a list of values in the range with no small factors. This is quite common for applications involving prime gaps. Also see L. =head2 sieve_range my @candidates = sieve_range(2**1000, 10000, 40000); Given a start value C, and native unsigned integers C and C, a sieve of maximum depth C is done for the C consecutive numbers beginning with C. An array of offsets from the start is returned. The returned list contains those offsets in the range C to C where C has no prime factors less than C. This function is very similar to the three argument form of L. The differences are using C<(n,width)> instead of C<(low,high)>, and most importantly returning small offsets from the start value rather than the values themselves. This can substantially reduce overhead for multi-thousand digit numbers. =head2 sieve_twin_primes my @primes = sieve_twin_primes(2**1000, 2**1000 + 500000); Given two arguments C and C, this returns each lower twin prime in the interval (inclusive). The result is a list, not a reference. This does a partial sieve of the range, removes any non-twin candidates, then checks that each pair are both BPSW probable primes. This is substantially more efficient than sieving for all primes followed by removing those that are not twin primes. =head2 sieve_prime_cluster # Find some prime septuplets my @s = sieve_prime_cluster(2**100, 2**100+1e12, 2,6,8,12,18,20); Efficiently finds prime clusters between the first two arguments C and C (inclusive). The remaining arguments describe the cluster. The cluster values must be even, less than 31 bits, and strictly increasing. Given a cluster set C, the returned values are all primes in the range where C is prime for all C in the cluster set C. The cluster is described as offsets from 0, with the implicit prime at 0. Hence an empty list is asking for all primes (the cluster C). A list with the single value C<2> will find all twin primes (the cluster where C and C are prime). The list C<2,6,8> will find prime quadruplets. Note that there is no requirement that the list denote a constellation (a cluster with minimal distance) -- the list C<42,92,606> is just fine. For long clusters, e.g. L prime 12-tuplets, this will be immensely more efficient than filtering out the cluster from a list of primes. For that example, a range of C<10^13> takes less than a second to search -- thousands of times faster than filtering results from primes or twin primes. Shorter clusters are not quite this efficient, and the overhead for returning large arrays should not be ignored. =head2 next_prime $n = next_prime($n); Returns the prime following the input number (the smallest prime number that is greater than the input number). The function L is used to determine when a prime is found, hence the result is a probable prime (using BPSW). For large inputs this function is quite a bit faster than GMP's C or Pari's C. =head2 prev_prime $n = prev_prime($n); Returns the prime preceding the input number (the largest prime number that is less than the input number). 0 is returned if the input is C<2> or lower. The function L is used to determine when a prime is found, hence the result is a probable prime (using BPSW). =head2 surround_primes ($dprev, $dnext) = surround_primes($n); Returns the distances to the previous and next primes of the input C. This is slightly more efficient than calling both L and L, and returning the distances as native integers is more efficient with large inputs. If an optional second argument C is given, and the input C is larger than C<2^64>, then if a SPSP-2 is found in the range C to C (inclusive) then it will be returned with the other argument set to C<0>. Otherwise, the first SPSP-2 values found are returned. This feature is especially useful for prime gap searches as well as finding the nearest prime to a value. Note that with a non-zero second argument, the values returned have not undergone a full BPSW test; just sieving and a SPSP-2 test. =head2 next_twin_prime Returns the start of the next twin prime after the input C. The returned value will always be greater than the input. For a return value of C, both C and C will be a probable prime (using BPSW). =head2 random_nbit_prime say "random 512-bit prime: ", random_nbit_prime(512); Returns a randomly selected prime of exactly C bits. C is returned if C is less than C<2>. The returned prime has passed the C (extra strong BPSW) test. =head2 random_safe_prime Returns a randomly selected safe prime of exactly C bits. C must be at least C<3>. The returned value C

will be of the form C<2q+1> where C has passed the extra strong BPSW test. C

is guaranteed to be a prime if C is prime. Setting verbose level to 3 or higher will produce progress output not unlike openssl. A C<.> for each candidate that passes pretests, a C<+> for those where one is likely prime, and C<*> when both are likely prime with only confirmation tests remaining. This generates safe primes about 4-10x faster than openssl's dhparam. =head2 random_strong_prime say "random 512-bit strong prime: ", random_strong_prime(512); Returns a randomly selected strong prime of exactly C bits. C must be at least C<256>. The returned prime has passed the C (extra strong BPSW) test. Given the returned prime C

, C, C, and C will all have a large factor. This makes using factoring methods such as p-1 and p+1 much harder. Gordon's algorithm is used. The value of using strong primes is questionable over proper random primes when the number of bits is at least 1024. =head2 random_ndigit_prime say "random 200-digit prime: ", random_ndigit_prime(200); Returns a randomly selected prime of exactly C digits. C is returned if C is less than C<1>. The returned prime has passed the C (extra strong BPSW) test. =head2 random_prime say random_prime(1000, 2000); # prime between 1000 and 2000 inclusive Returns a random prime in the interval C<[a,b]> or C if no prime is in the range. The returned prime has passed the C (extra strong BPSW) test. The random prime functions use the internal CSPRNG for randomness. This is currently ISAAC-32 but will likely change to ChaCha20 in a later release. This corresponds to Mathematica's C function. This is a superset of Pari's C function, where our interval API is more convenient for cryptographic functions. =head2 random_maurer_prime say "random 512-bit proven prime: ", random_maurer_prime(512); Returns an n-bit proven prime using Ueli Maurer's FastPrime algorithm (1995). This results in uniform random selection of a proven prime, though not every n-bit prime can be generated with this algorithm. C is returned if C is less than C<2>. As a safety check, internally the extra strong BPSW test is additionally run on each intermediate and the final result. =head2 random_shawe_taylor_prime say "random 512-bit proven prime: ", random_shawe_taylor_prime(512); Returns an n-bit proven prime using the Shawe-Taylor algorithm (1986) from section C.6 of FIPS 186-4, although using our CSPRNG rather than SHA-256. This is a slightly simpler and older (1986) method than Maurer's algorithm. It is a bit faster than Maurer's method but has a smaller subset of returned primes. C is returned if C is less than C<2>. As a safety check, internally the extra strong BPSW test is additionally run on each intermediate and the final result. =head2 random_maurer_prime_with_cert Like L but also returns a string certificate. =head2 random_shawe_taylor_prime_with_cert Like L but also returns a string certificate. =head2 lucasu say "Fibonacci($_) = ", lucasu(1,-1,$_) for 0..100; Given integers C

, C, and the non-negative integer C, computes C for the Lucas sequence defined by C

,C. These include the Fibonacci numbers (C<1,-1>), the Pell numbers (C<2,-1>), the Jacobsthal numbers (C<1,-2>), the Mersenne numbers (C<3,2>), and more. This corresponds to OpenPFGW's C function and gmpy2's C function. =head2 lucasv say "Lucas($_) = ", lucasv(1,-1,$_) for 0..100; Given integers C

, C, and the non-negative integer C, computes C for the Lucas sequence defined by C

,C. These include the Lucas numbers (C<1,-1>). This corresponds to OpenPFGW's C function and gmpy2's C function. =head2 lucas_sequence my($U, $V, $Qk) = lucas_sequence($n, $P, $Q, $k) Computes C, C, and C for the Lucas sequence defined by C

,C, modulo C. The modular Lucas sequence is used in a number of primality tests and proofs. The following conditions must hold: - C<< D = P*P - 4*Q != 0 >> - C<< P > 0 >> - C<< P < n >> - C<< Q < n >> - C<< k >= 0 >> - C<< n >= 2 >> =head2 primorial $p = primorial($n); Given an unsigned integer argument, returns the product of the prime numbers which are less than or equal to C. This definition of C follows L and L. =head2 pn_primorial $p = pn_primorial($n) Given an unsigned integer argument, returns the product of the first C prime numbers. This definition of C follows L and L. The two are related with the relationships: pn_primorial($n) == primorial( nth_prime($n) ) primorial($n) == pn_primorial( prime_count($n) ) =head2 factorial Given positive integer argument C, returns the factorial of C, defined as the product of the integers 1 to C with the special case of C. This corresponds to Pari's C and Mathematica's C functions. =head2 multifactorial Given two positive integer arguments C and C, returns C, the multifactorial. C is the standard L while C is the double factorial. While the factorial is the product of all integers C and below, the multifactorial skips those without the same parity as C. Hence multifactorial(n,2) = n * (n-2) * (n-4) * ... The multifactorials are the OEIS series (m=1) L, (m=2) L, (m=3) L, (m=4) L, ... Also see L. =head2 factorialmod Given two positive integer arguments C and C, returns C. This is much faster than computing the large C followed by a mod operation. =head2 factorial_sum Given positive integer argument C, returns the factorial sum of C. This is defined as the sum of C for C<0 .. n-1>. These are equivalent, though this function is faster: factorial_sum($n) == vecsum(map{ factorial($_) } 0..$n-1) This is sometimes called the left factorial, confusingly also used for L. This is L. =head2 subfactorial Given positive integer argument C, returns the subfactorial of C. This is also called the derangement number, and occasionally the left factorial. This is L. This corresponds to Mathematica's C function. =head2 gcd Given a list of integers, returns the greatest common divisor. This is often used to test for L. =head2 lcm Given a list of integers, returns the least common multiple. =head2 gcdext Given two integers C and C, returns C such that C and C. This uses the extended Euclidian algorithm to compute the values satisfying Bézout's Identity. This corresponds to Pari's C function, which was renamed from C in Pari 2.6. The results will hence match L. =head2 chinese say chinese( [14,643], [254,419], [87,733] ); # 87041638 Solves a system of simultaneous congruences using the Chinese Remainder Theorem (with extension to non-coprime moduli). A list of C<[a,n]> pairs are taken as input, each representing an equation C. If no solution exists, C is returned. If a solution is returned, the modulus is equal to the lcm of all the given moduli (see L. In the standard case where all values of C are coprime, this is just the product. The C values must be positive integers, while the C values are integers. =head2 vecsum Returns the sum of all arguments, each of which must be an integer. =head2 vecprod Returns the product of all arguments, each of which must be an integer. =head2 kronecker Returns the Kronecker symbol C<(a|n)> for two integers. The possible return values with their meanings for odd positive C are: 0 a = 0 mod n 1 a is a quadratic residue modulo n (a = x^2 mod n for some x) -1 a is a quadratic non-residue modulo n The Kronecker symbol is an extension of the Jacobi symbol to all integer values of C from the latter's domain of positive odd values of C. The Jacobi symbol is itself an extension of the Legendre symbol, which is only defined for odd prime values of C. This corresponds to Pari's C function and Mathematica's C function. =head2 binomial Given integer arguments C and C, returns the binomial coefficient C, also known as the choose function. Negative arguments use the L. This corresponds to Mathematica's C function, Pari's C function, and GMP's C function. For negative arguments, this matches Mathematica. Pari does not implement the C 0, k E= n> extension and instead returns C<0> for this case. GMP's API does not allow negative C but otherwise matches. L does not implement any extensions and the results for C 0, k E 0> are undefined. =head2 addreal =head2 subreal =head2 mulreal =head2 divreal Returns the corresponding basic math operation applied to the two inputs. An optional third argument indicates the number of significant digits (default 40) with the result rounded. =head2 logreal Returns the natural logarithm of the input C. An optional second argument indicates the number of significant digits (default 40) with the result rounded. For C we use Formula 25 from Gourdon and Sebah (2010). For other values we use AGM (Sasaki and Kanada theta method). Performance is 100-1000x faster than Math::BigFloat's GMP backend. It is 10x slower than Pari/GP 2.10 and MPFR. Negative inputs are returned as C<-log(-n)>, which matches L. Pari/GP and Mathematica return C. =head2 expreal Returns C for the input C. An optional second argument indicates the number of significant digits (default 40) with the result rounded. The implementation computes C, then C from that. =head2 powreal Returns C for the inputs C and C. An optional third argument indicates the number of significant digits (default 40) with the result rounded. Like L and L, this is a basic math function that is not available from the GMP library but implemented in MPFR. Since the latter is not always available, this can be useful to have. =head2 rootreal Returns the C-th root of C for the inputs C and C. An optional third argument indicates the number of significant digits (default 40) with the result rounded. This is just C, but allows C to be easily specified in full precision. =head2 agmreal Returns the Arithmetic-Geometric mean (AGM) of C and C. An optional third argument indicates the number of significant digits (default 40) with the result rounded. Examples of use include elementary constants (e.g. C and C), logs, exponentials, trigonometric functions, elliptic integrals, computing pendulum periods, and more. This corresponds to Pari's C function, limited to positive reals (Pari also handles negative, complex, p-adic, and power series arguments). =head2 bernfrac Returns the Bernoulli number C for an integer argument C, as a rational number. Two values are returned, the numerator and denominator. B_1 = 1/2. This corresponds to Pari's C and Mathematica's C functions. =head2 bernreal Returns the Bernoulli number C for an integer argument C, as a string floating point. An optional second argument indicates the number of significant digits to be used, with the result rounded. The default is 40 digits. This corresponds to Pari's C function and. =head2 harmfrac Returns the Harmonic number C for an integer argument C, as a rational number. Two values are returned, the numerator and denominator. numbers are the sum of reciprocals of the first C natural numbers: C<1 + 1/2 + 1/3 + ... + 1/n>. This corresponds to Mathematica's C function. =head2 harmreal Returns the Harmonic number C for an integer argument C, as a string floating point. An optional second argument indicates the number of digits to be preserved past the decimal place, with a default of 40. =head2 stirling say "s(14,2) = ", stirling(14, 2); say "S(14,2) = ", stirling(14, 2, 2); Returns the Stirling numbers of either the first kind (default), the second kind, or the third kind (the unsigned Lah numbers), with the kind selected as an optional third argument. It takes two non-negative integer arguments C and C plus the optional C. This corresponds to Pari's C function and Mathematica's C / C functions. Stirling numbers of the first kind are C<-1^(n-k)> times the number of permutations of C symbols with exactly C cycles. Stirling numbers of the second kind are the number of ways to partition a set of C elements into C non-empty subsets. The Lah numbers are the number of ways to split a set of C elements into C non-empty lists. =head2 zeta Given a positive integer or float C, returns the real Riemann Zeta value as a string floating point. An optional second argument indicates the number of digits past the decimal point (default 40). The implementation is algorithm 2 of Borwein (1991). Performance with integer inputs is good, but floating point arguments with high precision will be slower than methods using MPFR. L will try to use L if possible. =head2 li Given a positive integer or float C, returns the real Logarithmic Integral as a string floating point. An optional second argument indicates the number of significant digits (default 40) with the result rounded. The implementation uses Ramanjan's series. This corresponds to Mathematica's C

  • function. =head2 ei Given a positive integer or float C, returns the real Exponential Integral as a string floating point. An optional second argument indicates the number of significant digits (default 40) with the result rounded. The implementation is simply li(exp(x)). =head2 riemannr Given a positive integer or float C, returns the real Riemann R function as a string floating point. An optional second argument indicates the number of significant digits (default 40) with the result rounded. The implementation is the standard Gram series. This corresponds to Mathematica's C function. =head2 lambertw Given a float C, returns the principal branch of the Lambert W function. This solves for C in the equation C. The input must not be less than C<-1/e>. This corresponds to Pari's C function and Mathematica's C / C function. =head2 znorder $order = znorder(17, "100000000000000000000000065"); Given two positive integers C and C, returns the multiplicative order of C modulo C. This is the smallest positive integer C such that C. Returns 1 if C. Returns undef if C or if C and C are not coprime, since no value will result in 1 mod n. This corresponds to Pari's C function and Mathematica's C function. =head2 znprimroot Given a positive integer C, returns the smallest primitive root of C<(Z/nZ)^*>, or C if no root exists. A root exists when C, which will be true for all prime C and some composites. L is a sequence of integers where the primitive root exists, while L is a list of the smallest primitive roots, which is what this function produces. =head2 is_primitive_root Given two non-negative numbers C and C, returns C<1> if C is a primitive root modulo C, and C<0> if not. If C is a primitive root, then C is the smallest C for which C. =head2 is_semiprime Given a positive integer C, returns 1 if C is a semiprime, 0 otherwise. A semiprime is the product of exactly two primes. The boolean result is the same as C, but this function performs shortcuts that can greatly speed up the operation. =head2 is_carmichael Given a positive integer C, returns 1 if C is a Carmichael number, 0 otherwise. These are composites that satisfy C for all C<1 E b E n> relatively prime to C. Alternately Korselt's theorem says these are composites such that C is square-free and C divides C for all prime divisors C

    of C. Inputs greater than 50 digits use a probabilistic test to avoid fully factoring the input. =head2 is_fundamental Given a positive integer C, returns 1 if C is a fundamental discriminant, 0 otherwise. =head2 is_totient Given an integer C, returns 1 if there exists an integer C where C. =head2 is_polygonal Given integers C and C, return 1 if x is an s-gonal number, 0 otherwise. C must be greater than 2. =head2 polygonal_nth Given integers C and C, return N if C is the C s-gonal number, 0 otherwise. =head2 sigma say "Sum of divisors of $n:", sigma( $n ); say "sigma_2($n) = ", sigma($n, 2); say "Number of divisors: sigma_0($n) = ", sigma($n, 0); This function takes a positive integer as input and returns the sum of its divisors, including 1 and itself. An optional second argument C may be given, which will result in the sum of the C powers of the divisors to be returned. This is known as the sigma function (see Hardy and Wright section 16.7, or OEIS A000203). The API is identical to Pari/GP's C function. This function is useful for calculating things like aliquot sums, abundant numbers, perfect numbers, etc. =head2 ramanujan_tau Takes a positive integer as input and returns the value of Ramanujan's tau function. The result is a signed integer. This corresponds to Mathematica's C function and Pari's C function. =head2 valuation say "$n is divisible by 2 ", valuation($n,2), " times."; Given integers C and C, returns the numbers of times C is divisible by C. This is a very limited version of the algebraic valuation meaning, just applied to integers. This corresponds to Pari's C function. C<0> is returned if C or C is one of the values C<-1>, C<0>, or C<1>. =head2 hammingweight Given an integer C, returns the binary Hamming weight of C. This is also called the population count, and is the number of 1s in the binary representation. This corresponds to Pari's C function for C arguments. =head2 moebius say "$n is square free" if moebius($n) != 0; $sum += moebius($_) for (1..200); say "Mertens(200) = $sum"; say "Mertens(2000) = ", vecsum(moebius(0,2000)); Returns μ(n), the Möbius function (also known as the Moebius, Mobius, or MoebiusMu function) for an integer input. This function is 1 if C, 0 if C is not square free (i.e. C has a repeated factor), and C<-1^t> if C is a product of C distinct primes. This is an important function in prime number theory. Like SAGE, we define C for convenience. If called with two arguments, they define a range C to C, and the function returns an array with the value of the Möbius function for every n from low to high inclusive. =head2 invmod say "The inverse of 42 mod 2017 = ", invmod(42,2017); Given two integers C and C, return the inverse of C modulo C. If not defined, undef is returned. If defined, then the return value multiplied by C equals C<1> modulo C. =head2 sqrtmod Given two integers C and C

    , return the square root of C mod C

    . If no square root exists, undef is returned. If defined, the return value C will always satisfy C. If C

    is not a prime, it is possible no result will be returned even though a modular root exists. Only one root is returned, even though there are at least two. In the case of C

    a prime and a return value C, then both C<+s mod n> and C<-s mod n> are roots. The least C will be returned. In the case of composites, many roots may exist, but only one will be returned. =head2 addmod Given three integers C, C, and C where C and C are unsigned, return C<(a+b) mod n>. This is particularly useful when dealing with numbers that are larger than a half-word but still native size. No bigint package is needed and this can be 10-200x faster than using one. =head2 mulmod Given three integers C, C, and C where C and C are unsigned, return C<(a*b) mod n>. This is particularly useful when C fits in a native integer. No bigint package is needed and this can be 10-200x faster than using one. =head2 powmod Given three integers C, C, and C where C and C are unsigned, return C<(a ** b) mod n>. Typically binary exponentiation is used, so the process is very efficient. With native size inputs, no bigint library is needed. =head2 divmod Given three integers C, C, and C where C and C are unsigned, return C<(a/b) mod n>. This is done as C<(a * (1/b mod n)) mod n>. If no inverse of C mod C exists then undef if returned. =head2 consecutive_integer_lcm $lcm = consecutive_integer_lcm($n); Given an unsigned integer argument, returns the least common multiple of all integers from 1 to C. This can be done by manipulation of the primes up to C, resulting in much faster and memory-friendly results than using factorials. =head2 partitions Calculates the partition function p(n) for a non-negative integer input. This is the number of ways of writing the integer n as a sum of positive integers, without restrictions. This corresponds to Pari's C function and Mathematica's C function. The values produced in order are L. This uses a combinatorial calculation, which means it will not be very fast compared to Pari, Mathematica, or FLINT which use the Rademacher formula using multi-precision floating point. In 10 seconds, the pure Perl version can produce C while with L it can do C. In contrast, in about 10 seconds Pari can solve C. If you want the enumerated partitions, see L or L. These are fast and memory efficient iterators, but not practical for producing the partition I for values over 100 or so. =head2 numtoperm @p = numtoperm(10,654321); # @p=(1,8,2,7,6,5,3,4,9,0) Given a non-negative integer C and integer C, return the rank C lexicographic permutation of C elements. C will be interpreted as mod C. =head2 permtonum $k = permtonum([1,8,2,7,6,5,3,4,9,0]); # $k = 654321 Given an array reference containing integers from C<0> to C, returns the lexicographic permutation rank of the set. This is the inverse of the L function. All integers up to C must be present. The result will be between C<0> and C. =head2 Pi Takes a positive integer argument C and returns the constant Pi with that many digits (including the leading 3). Rounding is performed. The implementation uses either AGM or Ramanujan/Chudnovsky with binary splitting, depending on the number of digits. It is a little over 2x faster than MPFR, similar in speed to Pari/GP, but about 1.5x slower than Xue's Chudnovsky demo from the GMP web site. Specialized programs such as C are even faster. Note there is a non-trivial amount of overhead in turning the result into a string, as well as even more if using the L module which further converts the result into a Math::BigFloat object. Called in void context, this just calculates and caches the result. =head2 Euler Takes a positive integer argument C and returns Euler's constant with that many digits. Rounding is performed. The implementation is Brent-McMillan algorithm B, just like Pari/GP. Performance is about 3x faster than Pari/GP, but 2-10x slower than MPFR which uses binary splitting. Called in void context, this just calculates and caches the result. =head2 exp_mangoldt say "exp(lambda($_)) = ", exp_mangoldt($_) for 1 .. 100; Returns EXP(Λ(n)), the exponential of the Mangoldt function (also known as von Mangoldt's function) for an integer value. The Mangoldt function is equal to log p if n is prime or a power of a prime, and 0 otherwise. We return the exponential so all results are integers. Hence the return value for C is: p if n = p^m for some prime p and integer m >= 1 1 otherwise. =head2 totient say "The Euler totient of $n is ", totient($n); Returns φ(n), the Euler totient function (also called Euler's phi or phi function) for an integer value. This is an arithmetic function which counts the number of positive integers less than or equal to C that are relatively prime to C. Given the definition used, C will return 0 for all C 1>. This follows the logic used by SAGE. Mathematica and Pari return C for C 0>. Mathematica returns 0 for C, Pari pre-2.6.2 raises and exception, and Pari 2.6.2 and newer returns 2. =head2 jordan_totient say "Jordan's totient J_$k($n) is ", jordan_totient($k, $n); Returns Jordan's totient function for a given integer value. Jordan's totient is a generalization of Euler's totient, where C This counts the number of k-tuples less than or equal to n that form a coprime tuple with n. As with C, 0 is returned for all C 1>. This function can be used to generate some other useful functions, such as the Dedekind psi function, where C. =head2 carmichael_lambda Returns the Carmichael function (also called the reduced totient function, or Carmichael λ(n)) of a positive integer argument. It is the smallest positive integer C such that C for every integer C coprime to C. This is L. =head2 liouville Returns λ(n), the Liouville function for a non-negative integer input. This is -1 raised to Ω(n) (the total number of prime factors). =head2 is_power say "$n is a perfect square" if is_power($n, 2); say "$n is a perfect cube" if is_power($n, 3); say "$n is a ", is_power($n), "-th power"; Given a single positive integer input C, returns k if C for some integer C

    1, k E 1>, and 0 otherwise. The k returned is the largest possible. This can be used in a boolean statement to determine if C is a perfect power. If given two arguments C and C, returns 1 if C is a C power, and 0 otherwise. For example, if C then this detects perfect squares. This corresponds to Pari/GP's C function, with the limitations of only integer arguments and no third argument may be given to return the root. =head2 is_square Given a positive integer C, returns 1 if C is a perfect square, 0 otherwise. This is identical to C. This corresponds to Pari/GP's C function. =head2 is_prime_power Given an integer input C, returns C if C for some prime p, and zero otherwise. This corresponds to Pari/GP's C function. =head2 sqrtint Returns the truncated integer part of the square root of C. This corresponds to Pari/GP's C function. =head2 rootint Given C and C, returns the truncated integer part of the C root of C. This corresponds to Pari/GP's C function. =head2 logint Given C and C, returns the integer base-C logarithm of C. This is the largest integer C such that C= n>. This corresponds to Pari/GP's C function. =head2 powint Given integers C and C, returns C. For <0^0> we return 1. The exponent C is converted into an unsigned long. =head2 mulint Given integers C and C, returns C. =head2 addint Given integers C and C, returns C. =head2 subint Given integers C and C, returns C. =head2 divint Given integers C and C, returns the quotient C. Floor division is used, so q is rounded towards -inf and the remainder has the same sign as the divisor C. This is the same as modern L and the GMP C functions, but not the same as Pari/GP's C<\\> operator. =head2 modint Given integers C and C, returns the modulo C. C Floor division is used, so q is rounded towards -inf and r has the same sign as the divisor C.. This is the same as modern L and the GMP C functions, but not the same as Pari/GP's C<%> operator. =head2 divrem my($quo, $rem) = divrem($a, $b); Given integers C and C, returns a list of two items: the Euclidean quotient and the Euclidean remainder. This corresponds to Pari/GP's C function. There is no explicit function in L that gives this division method for signed inputs. =head2 tdivrem Given integers C and C, returns a list of two items: the truncated quotient and the truncated remainder. The resulting pair will match L and L. =head2 absint Given integer C, return C<|n|>, i.e. the absolute value of C. =head2 negint Given integer C, return C<-n>. =head2 factor @factors = factor(640552686568398413516426919223357728279912327120302109778516984973296910867431808451611740398561987580967216226094312377767778241368426651540749005659); # Returns an array of 11 factors Returns a list of prime factors of a positive number, in numerical order. The special cases of C and C will return C. Like most advanced factoring programs, a mix of methods is used. This includes trial division for small factors, perfect power detection, Pollard's Rho, Pollard's P-1 with various smoothness and stage settings, Hart's OLF (a Fermat variant), ECM (elliptic curve method), and QS (quadratic sieve). Certainly improvements could be designed for this algorithm (suggestions are welcome). In practice, this factors 26-digit semiprimes in under C<100ms>, 36-digit semiprimes in under one second. Arbitrary integers are factored faster. It is many orders of magnitude faster than any other factoring module on CPAN circa 2013. It is comparable in speed to Math::Pari's C for most inputs. If you want better factoring in general, I recommend looking at the standalone programs L, L, L, and L. =head2 divisors my @divisors = divisors(30); # returns (1, 2, 3, 5, 6, 10, 15, 30) Produces all the divisors of a positive number input, including 1 and the input number. The divisors are a power set of multiplications of the prime factors, returned as a sorted list with no duplications. The result is identical to that of Pari's C and Mathematica's C functions. In scalar context this returns the sigma0 function (OEIS A000005), and is the same result as evaluating the returned array in scalar context (but much more efficient). The result then corresponds to Pari's C and Mathematica's C functions. =head2 trial_factor my @factors = trial_factor($n); my @factors = trial_factor($n, 1000); Given a positive number input, tries to discover a factor using trial division. The resulting array will contain either two factors (it succeeded) or the original number (no factor was found). In either case, multiplying @factors yields the original input. An optional divisor limit may be given as the second parameter. Factoring will stop when the input is a prime, one factor is found, or the input has been tested for divisibility with all primes less than or equal to the limit. If no limit is given, then C<2**31-1> will be used. This is a good and fast initial test, and will be very fast for small numbers (e.g. under 1 million). For larger numbers, faster methods for complete factoring have been known since the 17th century. For inputs larger than about 1000 digits, a dynamic product/remainder tree is used, which is faster than GMP's native methods. This helps when pruning composites or looking for very small factors. =head2 prho_factor my @factors = prho_factor($n); my @factors = prho_factor($n, 100_000_000); Given a positive number input, tries to discover a factor using Pollard's Rho method. The resulting array will contain either two factors (it succeeded) or the original number (no factor was found). In either case, multiplying @factors yields the original input. An optional number of rounds may be given as the second parameter. Factoring will stop when the input is a prime, one factor has been found, or the number of rounds has been exceeded. This is the Pollard Rho method with C and default rounds 64M. It is very good at finding small factors. Typically L will be preferred as it behaves similarly but runs quite a bit faster. They use different parameters however, so are not completely identical. =head2 pbrent_factor my @factors = pbrent_factor($n); my @factors = pbrent_factor($n, 100_000_000); Given a positive number input, tries to discover a factor using Pollard's Rho method with Brent's algorithm. The resulting array will contain either two factors (it succeeded) or the original number (no factor was found). In either case, multiplying @factors yields the original input. An optional number of rounds may be given as the second parameter. Factoring will stop when the input is a prime, one factor has been found, or the number of rounds has been exceeded. This is the Pollard Rho method using Brent's modified cycle detection, delayed C computations, and backtracking. It is essentially Algorithm P''2 from Brent (1980). Parameters used are C and default rounds 64M. It is very good at finding small factors. =head2 pminus1_factor my @factors = pminus1_factor($n); # Set B1 smoothness to 10M, second stage automatically set. my @factors = pminus1_factor($n, 10_000_000); # Run p-1 with B1 = 10M, B2 = 100M. my @factors = pminus1_factor($n, 10_000_000, 100_000_000); Given a positive number input, tries to discover a factor using Pollard's C method. The resulting array will contain either two factors (it succeeded) or the original number (no factor was found). In either case, multiplying @factors yields the original input. An optional first stage smoothness factor (B1) may be given as the second parameter. This will be the smoothness limit B1 for the first stage, and will use C<10*B1> for the second stage limit B2. If a third parameter is given, it will be used as the second stage limit B2. Factoring will stop when the input is a prime, one factor has been found, or the algorithm fails to find a factor with the given smoothness. This is Pollard's C method using a default smoothness of 5M and a second stage of C. It can quickly find a factor C

    of the input C if the number C factors into small primes. For example C has the factor C

    , where C, so this method will find a factor in the first stage if C= 703499> or in the second stage if C= 3137> and C= 703499>. The implementation is written from scratch using the basic algorithm including a second stage as described in Montgomery 1987. It is faster than most simple implementations I have seen (many of which are written assuming native precision inputs), but slower than Ben Buhrow's code used in earlier versions of L, and nowhere close to the speed of the version included with modern GMP-ECM with large B values (it is actually quite a bit faster than GMP-ECM with small smoothness values). =head2 pplus1_factor my @factors = pplus1_factor($n); Given a positive number input, tries to discover a factor using Williams' C method. The resulting array will contain either two factors (it succeeded) or the original number (no factor was found). In either case, multiplying @factors yields the original input. An optional first stage smoothness factor (B1) may be given as the second parameter. This will be the smoothness limit B1 for the first stage. Factoring will stop when the input is a prime, one factor has been found, or the algorithm fails to find a factor with the given smoothness. =head2 holf_factor my @factors = holf_factor($n); my @factors = holf_factor($n, 100_000_000); Given a positive number input, tries to discover a factor using Hart's OLF method. The resulting array will contain either two factors (it succeeded) or the original number (no factor was found). In either case, multiplying @factors yields the original input. An optional number of rounds may be given as the second parameter. Factoring will stop when the input is a prime, one factor has been found, or the number of rounds has been exceeded. This is Hart's One Line Factorization method, which is a variant of Fermat's algorithm. A premultiplier of 480 is used. It is very good at factoring numbers that are close to perfect squares, or small numbers. Very naive methods of picking RSA parameters sometimes yield numbers in this form, so it can be useful to run a few rounds to check. For example, the number: 18548676741817250104151622545580576823736636896432849057 \ 10984160646722888555430591384041316374473729421512365598 \ 29709849969346650897776687202384767704706338162219624578 \ 777915220190863619885201763980069247978050169295918863 was proposed by someone as an RSA key. It is indeed composed of two distinct prime numbers of similar bit length. Most factoring methods will take a B long time to break this. However one factor is almost exactly 5x larger than the other, allowing HOLF to factor this 222-digit semiprime in only a few milliseconds. =head2 squfof_factor my @factors = squfof_factor($n); my @factors = squfof_factor($n, 100_000_000); Given a positive number input, tries to discover a factor using Shanks' square forms factorization method (usually known as SQUFOF). The resulting array will contain either two factors (it succeeded) or the original number (no factor was found). In either case, multiplying @factors yields the original input. An optional number of rounds may be given as the second parameter. Factoring will stop when the input is a prime, one factor has been found, or the number of rounds has been exceeded. This is Daniel Shanks' SQUFOF (square forms factorization) algorithm. The particular implementation is a non-racing multiple-multiplier version, based on code ideas of Ben Buhrow and Jason Papadopoulos as well as many others. SQUFOF is often the preferred method for small numbers, and L as well as many other packages use it was the default method for native size (e.g. 32-bit or 64-bit) numbers after trial division. The GMP version used in this module will work for larger values, but my testing indicates it is generally slower than the C and C implementations. =head2 ecm_factor my @factors = ecm_factor($n); my @factors = ecm_factor($n, 12500); # B1 = 12500 my @factors = ecm_factor($n, 12500, 10); # B1 = 12500, curves = 10 Given a positive number input, tries to discover a factor using ECM. The resulting array will contain either two factors (it succeeded) or the original number (no factor was found). In either case, multiplying @factors yields the original input. An optional maximum smoothness may be given as the second parameter, which relates to the size of factor to search for. An optional third parameter indicates the number of random curves to use at each smoothness value being searched. This is an implementation of Hendrik Lenstra's elliptic curve factoring method, usually referred to as ECM. The implementation is reasonable, using projective coordinates, Montgomery's PRAC heuristic for EC multiplication, and two stages. It is much slower than the latest GMP-ECM, but still quite useful for factoring reasonably sized inputs. =head2 qs_factor my @factors = qs_factor($n); Given a positive number input, tries to discover factors using QS (the quadratic sieve). The resulting array will contain one or more numbers such that multiplying @factors yields the original input. Typically multiple factors will be produced, unlike the other C<..._factor> routines. The current implementation is a modified version of SIMPQS, a predecessor to the QS in FLINT, and was written by William Hart in 2006. It will not operate on input less than 30 digits. The memory use for large inputs is more than desired, so other methods such as L, L, and L are recommended to begin with to filter out small factors. However, it is substantially faster than the other methods on large inputs having large factors, and is the method of choice for 35+ digit semiprimes. =head2 todigits Given an integer C, return an array of digits of C<|n|>. An optional second integer argument specifies a base (default 10). For example, given a base of 2, this returns an array of binary digits of C. An optional third argument specifies a length for the returned array. The result will be either have upper digits truncated or have leading zeros added. C returns an empty array. The base must be at least 2, and is limited to an int. Length must be at least zero and is limited to an int. =head2 seed_csprng Takes a non-negative integer C and a string C as input. These are used to seed the internal CSPRNG used for random functions, including the random prime functions. Ideally this is 16-256 bytes of good entropy. Currently the CSPRNG is ISAAC-32, and the maximum number of seed bytes used is 1024. The CSPRNG will likely change to ChaCha20 in a later release. =head2 is_csprng_well_seeded Returns true if the CSPRNG has been seeded with 16 or more bytes (128 bits). There is no measurement of how "good" the input was. On startup the module will attempt to seed the CSPRNG from C, so this function will return true if that was successful, but false otherwise. =head2 urandomb $n32 = urandomb(32); # Classic irand32, returns a UV $n = urandomb(1024); # Random integer less than 2^1024 Given a number of bits C, returns a random unsigned integer less than C<2^b>. The result will be uniformly distributed between C<0> and C<2^b-1> inclusive. This is similar to the GMP function C. =head2 urandomm $n = urandomm(100); # random integer in [0,99] $n = urandomm(1024); # random integer in [0,1023] Given a positive integer C, returns a random unsigned integer less than C. The results will be uniformly distributed between C<0> and C inclusive. This is similar to the GMP function C. =head2 urandomr $n = urandomr(100, 110); # Random number [100,110] $nb = urandomr(2**24,2**25-1); # Random 25-bit number $nd = urandomr(10**24,10**25-1); # Random 25-digit number Given values C and C, returns a uniform random unsigned integer in the range C<[low,high]>. Both inputs must be non-negative. If C high> then function will return C. Note that the range is inclusive, so C, C, and each integer between them have an equal probability of appearing. =head2 irand $n32 = irand; # random 32-bit integer Returns a random 32-bit integer using the CSPRNG. Performance is similar to L and L. It is somewhat faster than casting system C to a 32-bit int. It is noticeably faster than L, L, L, L, and L. =head2 irand64 $n64 = irand64; # random 64-bit integer Returns a random 64-bit integer using the CSPRNG (on 64-bit Perl). =head2 drand $f = drand; # random floating point value in [0,1) $r = drand(25); # random floating point value in [0,25) Returns a random NV (Perl's native floating point) using the CSPRNG. The number of bits returned is equal to the mantissa bits of the NV type used for the Perl build, with a max of 64. By default Perl uses doubles and the returned values have 53 bits. If Perl is built with long double support and the long doubles have a larger mantissa, then more bits are used. This gives I better quality random numbers than the default Perl C function. Among other things, on modern Perl's, C uses drand48, which gives 32 bits of decent random values and 16 more bits of known patterns (e.g. the 48th bit alternates, the 47th has a period of 4, etc.). There are much better choices for standard random number generators, such as the Mersenne Twister from L. Performance is similar to L and L. It is 1.5 - 2x slower than core C (as are the other modules). =head2 random_bytes $str = random_bytes(32); # 32 random bytes Given an unsigned number C of bytes, returns a binary string filled with random data from the CSPRNG. Performance for getting 256 byte strings: Module/Method Rate Type ------------- --------- ---------------------- Data::Entropy::Algorithms 2027/s CSPRNG - AES Counter Crypt::Random 6649/s CSPRNG - /dev/urandom Bytes::Random 9217/s drand48 Bytes::Random::Secure 23043/s CSPRNG - ISAAC Math::Random::ISAAC::XS 58377/s CSPRNG - ISAAC rand+pack 82977/s drand48 Crypt::PRNG 298567/s CSPRNG - Fortuna Bytes::Random::XS 383354/s drand48 ntheory 770364/s CSPRNG - ChaCha20 Math::Random::MTwist 1890151/s Mersenne Twister Math::Prime::Util::GMP 2045715/s CSPRNG - ISAAC Each of the CSPRNG modules should be high quality. There are no known flaws in any of ISAAC, AES CTR, ChaCha20, or Fortuna. The industry seems to be standardizing on ChaCha20 (e.g. BSD, Linux, TLS). =head1 SEE ALSO =over 4 =item L Has many more functions, lots of fast code for dealing with native-precision arguments (including much faster primes using sieves), and will use this module when needed for big numbers. Using L rather than this module directly is recommended. =item L (version 0.08) A Perl module with support for the strong Miller-Rabin test, strong Lucas-Selfridge test, the BPSW probable prime test, next_prime / prev_prime, the AKS primality test, and prime_count. It uses L to do all the calculations, so is faster than pure Perl bignums, but a lot slower than XS+GMP. The prime_count function is only usable for very small inputs, but the other functions are quite good for big numbers. Make sure to use version 0.05 or newer. =item L Supports quite a bit of the same functionality (and much more). See L for more detailed information on how the modules compare. =item L, L, L, L Good general purpose factoring utilities. These will be faster than this module, and B better as the factor increases in size. =item L is the state of the art in freely available (though not open source!) primality proving programs. If you have 1000+ digit numbers to prove, you want to use this. =item L Open source APR-CL primality proof implementation. Fast primality proving, though without certificates. =back =head1 REFERENCES =over 4 =item Robert Baillie and Samuel S. Wagstaff, Jr., "Lucas Pseudoprimes", Mathematics of Computation, v35 n152, October 1980, pp 1391-1417. L =item Daniel J. Bernstein, "Proving Primality After Agrawal-Kayal-Saxena", preprint, Jan 2003. L =item Jon Grantham, "Frobenius Pseudoprimes", Mathematics of Computation, v70 n234, March 2000, pp 873-891. L =item John Brillhart, D. H. Lehmer, and J. L. Selfridge, "New Primality Criteria and Factorizations of 2^m +/- 1", Mathematics of Computation, v29, n130, Apr 1975, pp 620-647. L =item Richard P. Brent, "An improved Monte Carlo factorization algorithm", BIT 20, 1980, pp. 176-184. L =item Peter L. Montgomery, "Speeding the Pollard and Elliptic Curve Methods of Factorization", Mathematics of Computation, v48, n177, Jan 1987, pp 243-264. L =item Richard P. Brent, "Parallel Algorithms for Integer Factorisation", in Number Theory and Cryptography, Cambridge University Press, 1990, pp 26-37. L =item Richard P. Brent, "Some Parallel Algorithms for Integer Factorisation", in Proc. Third Australian Supercomputer Conference, 1999. (Note: there are multiple versions of this paper) L =item William B. Hart, "A One Line Factoring Algorithm", preprint. L =item Daniel Shanks, "SQUFOF notes", unpublished notes, transcribed by Stephen McMath. L =item Jason E. Gower and Samuel S. Wagstaff, Jr, "Square Form Factorization", Mathematics of Computation, v77, 2008, pages 551-588. L =item A.O.L. Atkin and F. Morain, "Elliptic Curves and primality proving", Mathematics of Computation, v61, 1993, pages 29-68. L =item R.G.E. Pinch, "Some Primality Testing Algorithms", June 1993. Describes the primality testing methods used by many CAS systems and how most were compromised. Gives recommendations for primality testing APIs. L =back =head1 AUTHORS Dana Jacobsen Edana@acm.orgE Jason Papadopoulos wrote the tinyqs code which is basically unchanged. William Hart wrote SIMPQS which is the basis for the QS code. =head1 ACKNOWLEDGEMENTS Obviously none of this would be possible without the mathematicians who created and published their work. Eratosthenes, Gauss, Euler, Riemann, Fermat, Lucas, Baillie, Pollard, Brent, Montgomery, Shanks, Hart, Wagstaff, Dixon, Pomerance, A.K. Lenstra, H. W. Lenstra Jr., Atkin, Knuth, etc. The GNU GMP team, whose product allows me to concentrate on coding high-level algorithms and not worry about any of the details of how modular exponentiation and the like happen, and still get decent performance for my purposes. Ben Buhrow and Jason Papadopoulos deserve special mention for their open source factoring tools, which are both readable and fast. In particular I am leveraging their work on SQUFOF in the current implementation. They are a huge resource to the community. Jonathan Leto and Bob Kuo, who wrote and distributed the L module on CPAN. Their implementation of BPSW provided the motivation I needed to do it in this module and L. I also used their module quite a bit for testing against. Paul Zimmermann's papers and GMP-ECM code were of great value for my projective ECM implementation, as well as the many papers by Brent and Montgomery. =head1 COPYRIGHT Copyright 2011-2019 by Dana Jacobsen Edana@acm.orgE This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. SIMPQS Copyright 2006, William Hart. SIMPQS is distributed under GPL v2+. =cut Math-Prime-Util-GMP-0.52/tinyqs.h0000644000175000017500000000026413663067455015050 0ustar danadana#ifndef MPU_COFACTORIZE_H_ #define MPU_COFACTORIZE_H_ #include #include "ptypes.h" unsigned int tinyqs(mpz_t n, mpz_t factor); #endif /* !MPU_COFACTORIZE_H_ */ Math-Prime-Util-GMP-0.52/inc/0000755000175000017500000000000013674072603014110 5ustar danadanaMath-Prime-Util-GMP-0.52/inc/Devel/0000755000175000017500000000000013674072603015147 5ustar danadanaMath-Prime-Util-GMP-0.52/inc/Devel/CheckLib.pm0000644000175000017500000003544113025437621017153 0ustar danadana# $Id: CheckLib.pm,v 1.25 2008/10/27 12:16:23 drhyde Exp $ package # Devel::CheckLib; use 5.00405; #postfix foreach use strict; use vars qw($VERSION @ISA @EXPORT); $VERSION = '1.01'; use Config qw(%Config); use Text::ParseWords 'quotewords'; use File::Spec; use File::Temp; require Exporter; @ISA = qw(Exporter); @EXPORT = qw(assert_lib check_lib_or_exit check_lib); # localising prevents the warningness leaking out of this module local $^W = 1; # use warnings is a 5.6-ism _findcc(); # bomb out early if there's no compiler =head1 NAME Devel::CheckLib - check that a library is available =head1 DESCRIPTION Devel::CheckLib is a perl module that checks whether a particular C library and its headers are available. =head1 SYNOPSIS use Devel::CheckLib; check_lib_or_exit( lib => 'jpeg', header => 'jpeglib.h' ); check_lib_or_exit( lib => [ 'iconv', 'jpeg' ] ); # or prompt for path to library and then do this: check_lib_or_exit( lib => 'jpeg', libpath => $additional_path ); =head1 USING IT IN Makefile.PL or Build.PL If you want to use this from Makefile.PL or Build.PL, do not simply copy the module into your distribution as this may cause problems when PAUSE and search.cpan.org index the distro. Instead, use the use-devel-checklib script. =head1 HOW IT WORKS You pass named parameters to a function, describing to it how to build and link to the libraries. It works by trying to compile some code - which defaults to this: int main(void) { return 0; } and linking it to the specified libraries. If something pops out the end which looks executable, it gets executed, and if main() returns 0 we know that it worked. That tiny program is built once for each library that you specify, and (without linking) once for each header file. If you want to check for the presence of particular functions in a library, or even that those functions return particular results, then you can pass your own function body for main() thus: check_lib_or_exit( function => 'foo();if(libversion() > 5) return 0; else return 1;' incpath => ... libpath => ... lib => ... header => ... ); In that case, it will fail to build if either foo() or libversion() don't exist, and main() will return the wrong value if libversion()'s return value isn't what you want. =head1 FUNCTIONS All of these take the same named parameters and are exported by default. To avoid exporting them, C. =head2 assert_lib This takes several named parameters, all of which are optional, and dies with an error message if any of the libraries listed can not be found. B: dying in a Makefile.PL or Build.PL may provoke a 'FAIL' report from CPAN Testers' automated smoke testers. Use C instead. The named parameters are: =over =item lib Must be either a string with the name of a single library or a reference to an array of strings of library names. Depending on the compiler found, library names will be fed to the compiler either as C<-l> arguments or as C<.lib> file names. (E.g. C<-ljpeg> or C) =item libpath a string or an array of strings representing additional paths to search for libraries. =item LIBS a C-style space-seperated list of libraries (each preceded by '-l') and directories (preceded by '-L'). This can also be supplied on the command-line. =item debug If true - emit information during processing that can be used for debugging. =back And libraries are no use without header files, so ... =over =item header Must be either a string with the name of a single header file or a reference to an array of strings of header file names. =item incpath a string or an array of strings representing additional paths to search for headers. =item INC a C-style space-seperated list of incpaths, each preceded by '-I'. This can also be supplied on the command-line. =back =head2 check_lib_or_exit This behaves exactly the same as C except that instead of dieing, it warns (with exactly the same error message) and exits. This is intended for use in Makefile.PL / Build.PL when you might want to prompt the user for various paths and things before checking that what they've told you is sane. If any library or header is missing, it exits with an exit value of 0 to avoid causing a CPAN Testers 'FAIL' report. CPAN Testers should ignore this result -- which is what you want if an external library dependency is not available. =head2 check_lib This behaves exactly the same as C except that it is silent, returning false instead of dieing, or true otherwise. =cut sub check_lib_or_exit { eval 'assert_lib(@_)'; if($@) { warn $@; exit; } } sub check_lib { eval 'assert_lib(@_)'; return $@ ? 0 : 1; } sub assert_lib { my %args = @_; my (@libs, @libpaths, @headers, @incpaths); # FIXME: these four just SCREAM "refactor" at me @libs = (ref($args{lib}) ? @{$args{lib}} : $args{lib}) if $args{lib}; @libpaths = (ref($args{libpath}) ? @{$args{libpath}} : $args{libpath}) if $args{libpath}; @headers = (ref($args{header}) ? @{$args{header}} : $args{header}) if $args{header}; @incpaths = (ref($args{incpath}) ? @{$args{incpath}} : $args{incpath}) if $args{incpath}; # work-a-like for Makefile.PL's LIBS and INC arguments # if given as command-line argument, append to %args for my $arg (@ARGV) { for my $mm_attr_key (qw(LIBS INC)) { if (my ($mm_attr_value) = $arg =~ /\A $mm_attr_key = (.*)/x) { # it is tempting to put some \s* into the expression, but the # MM command-line parser only accepts LIBS etc. followed by =, # so we should not be any more lenient with whitespace than that $args{$mm_attr_key} .= " $mm_attr_value"; } } } # using special form of split to trim whitespace if(defined($args{LIBS})) { foreach my $arg (split(' ', $args{LIBS})) { die("LIBS argument badly-formed: $arg\n") unless($arg =~ /^-[lLR]/); push @{$arg =~ /^-l/ ? \@libs : \@libpaths}, substr($arg, 2); } } if(defined($args{INC})) { foreach my $arg (split(' ', $args{INC})) { die("INC argument badly-formed: $arg\n") unless($arg =~ /^-I/); push @incpaths, substr($arg, 2); } } my ($cc, $ld) = _findcc(); my @missing; my @wrongresult; my @use_headers; # first figure out which headers we can't find ... for my $header (@headers) { push @use_headers, $header; my($ch, $cfile) = File::Temp::tempfile( 'assertlibXXXXXXXX', SUFFIX => '.c' ); my $ofile = $cfile; $ofile =~ s/\.c$/$Config{_o}/; print $ch qq{#include <$_>\n} for @use_headers; print $ch qq{int main(void) { return 0; }\n}; close($ch); my $exefile = File::Temp::mktemp( 'assertlibXXXXXXXX' ) . $Config{_exe}; my @sys_cmd; # FIXME: re-factor - almost identical code later when linking if ( $Config{cc} eq 'cl' ) { # Microsoft compiler require Win32; @sys_cmd = ( @$cc, $cfile, "/Fe$exefile", (map { '/I'.Win32::GetShortPathName($_) } @incpaths), "/link", @$ld ); } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( @$cc, @$ld, (map { "-I$_" } @incpaths), "-o$exefile", $cfile ); } else { # Unix-ish: gcc, Sun, AIX (gcc, cc), ... @sys_cmd = ( @$cc, @$ld, $cfile, (map { "-I$_" } @incpaths), "-o", "$exefile" ); } warn "# @sys_cmd\n" if $args{debug}; my $rv = $args{debug} ? system(@sys_cmd) : _quiet_system(@sys_cmd); push @missing, $header if $rv != 0 || ! -x $exefile; _cleanup_exe($exefile); unlink $ofile if -e $ofile; unlink $cfile; } # now do each library in turn with headers my($ch, $cfile) = File::Temp::tempfile( 'assertlibXXXXXXXX', SUFFIX => '.c' ); my $ofile = $cfile; $ofile =~ s/\.c$/$Config{_o}/; print $ch qq{#include <$_>\n} foreach (@headers); print $ch "int main(void) { ".($args{function} || 'return 0;')." }\n"; close($ch); for my $lib ( @libs ) { my $exefile = File::Temp::mktemp( 'assertlibXXXXXXXX' ) . $Config{_exe}; my @sys_cmd; if ( $Config{cc} eq 'cl' ) { # Microsoft compiler require Win32; my @libpath = map { q{/libpath:} . Win32::GetShortPathName($_) } @libpaths; # this is horribly sensitive to the order of arguments @sys_cmd = ( @$cc, $cfile, "${lib}.lib", "/Fe$exefile", (map { '/I'.Win32::GetShortPathName($_) } @incpaths), "/link", @$ld, (map {'/libpath:'.Win32::GetShortPathName($_)} @libpaths), ); } elsif($Config{cc} eq 'CC/DECC') { # VMS } elsif($Config{cc} =~ /bcc32(\.exe)?/) { # Borland @sys_cmd = ( @$cc, @$ld, "-o$exefile", (map { "-I$_" } @incpaths), (map { "-L$_" } @libpaths), "-l$lib", $cfile); } else { # Unix-ish # gcc, Sun, AIX (gcc, cc) @sys_cmd = ( @$cc, @$ld, $cfile, "-o", "$exefile", (map { "-I$_" } @incpaths), (map { "-L$_" } @libpaths), "-l$lib", ); } warn "# @sys_cmd\n" if $args{debug}; my $rv = $args{debug} ? system(@sys_cmd) : _quiet_system(@sys_cmd); push @missing, $lib if $rv != 0 || ! -x $exefile; my $absexefile = File::Spec->rel2abs($exefile); $absexefile = '"'.$absexefile.'"' if $absexefile =~ m/\s/; push @wrongresult, $lib if $rv == 0 && -x $exefile && system($absexefile) != 0; unlink $ofile if -e $ofile; _cleanup_exe($exefile); } unlink $cfile; my $miss_string = join( q{, }, map { qq{'$_'} } @missing ); die("Can't link/include C library $miss_string, aborting.\n") if @missing; my $wrong_string = join( q{, }, map { qq{'$_'} } @wrongresult); die("wrong result: $wrong_string\n") if @wrongresult; } sub _cleanup_exe { my ($exefile) = @_; my $ofile = $exefile; $ofile =~ s/$Config{_exe}$/$Config{_o}/; unlink $exefile if -f $exefile; unlink $ofile if -f $ofile; unlink "$exefile\.manifest" if -f "$exefile\.manifest"; if ( $Config{cc} eq 'cl' ) { # MSVC also creates foo.ilk and foo.pdb my $ilkfile = $exefile; $ilkfile =~ s/$Config{_exe}$/.ilk/; my $pdbfile = $exefile; $pdbfile =~ s/$Config{_exe}$/.pdb/; unlink $ilkfile if -f $ilkfile; unlink $pdbfile if -f $pdbfile; } return } # return ($cc, $ld) # where $cc is an array ref of compiler name, compiler flags # where $ld is an array ref of linker flags sub _findcc { # Need to use $keep=1 to work with MSWin32 backslashes and quotes my $Config_ccflags = $Config{ccflags}; # use copy so ASPerl will compile my @Config_ldflags = (); for my $config_val ( @Config{qw(ldflags perllibs)} ){ push @Config_ldflags, $config_val if ( $config_val =~ /\S/ ); } my @ccflags = grep { length } quotewords('\s+', 1, $Config_ccflags||''); my @ldflags = grep { length } quotewords('\s+', 1, @Config_ldflags); my @paths = split(/$Config{path_sep}/, $ENV{PATH}); my @cc = split(/\s+/, $Config{cc}); return ( [ @cc, @ccflags ], \@ldflags ) if -x $cc[0]; foreach my $path (@paths) { my $compiler = File::Spec->catfile($path, $cc[0]) . $Config{_exe}; return ([ $compiler, @cc[1 .. $#cc], @ccflags ], \@ldflags) if -x $compiler; } die("Couldn't find your C compiler\n"); } # code substantially borrowed from IPC::Run3 sub _quiet_system { my (@cmd) = @_; # save handles local *STDOUT_SAVE; local *STDERR_SAVE; open STDOUT_SAVE, ">&STDOUT" or die "CheckLib: $! saving STDOUT"; open STDERR_SAVE, ">&STDERR" or die "CheckLib: $! saving STDERR"; # redirect to nowhere local *DEV_NULL; open DEV_NULL, ">" . File::Spec->devnull or die "CheckLib: $! opening handle to null device"; open STDOUT, ">&" . fileno DEV_NULL or die "CheckLib: $! redirecting STDOUT to null handle"; open STDERR, ">&" . fileno DEV_NULL or die "CheckLib: $! redirecting STDERR to null handle"; # run system command my $rv = system(@cmd); # restore handles open STDOUT, ">&" . fileno STDOUT_SAVE or die "CheckLib: $! restoring STDOUT handle"; open STDERR, ">&" . fileno STDERR_SAVE or die "CheckLib: $! restoring STDERR handle"; return $rv; } =head1 PLATFORMS SUPPORTED You must have a C compiler installed. We check for C<$Config{cc}>, both literally as it is in Config.pm and also in the $PATH. It has been tested with varying degrees on rigourousness on: =over =item gcc (on Linux, *BSD, Mac OS X, Solaris, Cygwin) =item Sun's compiler tools on Solaris =item IBM's tools on AIX =item SGI's tools on Irix 6.5 =item Microsoft's tools on Windows =item MinGW on Windows (with Strawberry Perl) =item Borland's tools on Windows =item QNX =back =head1 WARNINGS, BUGS and FEEDBACK This is a very early release intended primarily for feedback from people who have discussed it. The interface may change and it has not been adequately tested. Feedback is most welcome, including constructive criticism. Bug reports should be made using L or by email. When submitting a bug report, please include the output from running: perl -V perl -MDevel::CheckLib -e0 =head1 SEE ALSO L L =head1 AUTHORS David Cantrell Edavid@cantrell.org.ukE David Golden Edagolden@cpan.orgE Yasuhiro Matsumoto Emattn@cpan.orgE Thanks to the cpan-testers-discuss mailing list for prompting us to write it in the first place; to Chris Williams for help with Borland support; to Tony Cook for help with Microsoft compiler command-line options =head1 COPYRIGHT and LICENCE Copyright 2007 David Cantrell. Portions copyright 2007 David Golden. This module is free-as-in-speech software, and may be used, distributed, and modified under the same conditions as perl itself. =head1 CONSPIRACY This module is also free-as-in-mason software. =cut 1; Math-Prime-Util-GMP-0.52/bls75.h0000644000175000017500000000250313025437621014437 0ustar danadana#ifndef MPU_BLS75_H #define MPU_BLS75_H #include #include "ptypes.h" /* extern int _GMP_primality_pocklington(mpz_t n, int do_quick); */ /* Note that the theorem 3 and 15 checks, as well as the splitters: * 1) do not do a full proof. You must verify q. * 2) do not indicate compositeness on failure. */ /* These will check the theorem conditions for given n and factor. */ /* Check BLS75 theorem 3 conditions */ extern int _GMP_primality_bls_3(mpz_t n, mpz_t p, UV* a); /* Check BLS75 theorem 15 conditions */ extern int _GMP_primality_bls_15(mpz_t n, mpz_t q, IV* lp, IV* lq); /* These will try to factor and check the theorem conditions. */ /* BLS75 theorem 3, you must verify q for a proof */ extern int _GMP_primality_bls_nm1_split(mpz_t n, int effort, mpz_t q, UV* a); /* BLS75 theorem 15, you must verify q for a proof */ extern int _GMP_primality_bls_np1_split(mpz_t n, int effort, mpz_t q, IV* lp, IV* lq); /* This does a complete recursive proof */ /* BLS75 theorem 5/7 complete proof */ extern int _GMP_primality_bls_nm1(mpz_t n, int effort, char ** prooftextptr); /* BLS75 theorem 17 complete proof (N+1) */ extern int _GMP_primality_bls_np1(mpz_t n, int effort, char** prooftextptr); /* BLS75 theorem 20 complete proof (N-1 and N+1) */ extern int bls75_hybrid(mpz_t n, int effort, char** prooftextptr); #endif Math-Prime-Util-GMP-0.52/prime_iterator.c0000644000175000017500000004762313663067455016553 0ustar danadana#include #include #include #include #include "ptypes.h" #define FUNC_isqrt 1 #include "utility.h" #include "prime_iterator.h" /* Add this to a number and you'll ensure you're on a wheel location */ static const unsigned char distancewheel30[30] = {1,0,5,4,3,2,1,0,3,2,1,0,1,0,3,2,1,0,1,0,3,2,1,0,5,4,3,2,1,0}; /* The bit mask within a byte */ static const unsigned char masktab30[30] = { 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 4, 0, 8, 0, 0, 0, 16, 0, 32, 0, 0, 0, 64, 0, 0, 0, 0, 0,128 }; static const unsigned char nextwheel30[30] = { 1, 7, 7, 7, 7, 7, 7, 11, 11, 11, 11, 13, 13, 17, 17, 17, 17, 19, 19, 23, 23, 23, 23, 29, 29, 29, 29, 29, 29, 1 }; #if 0 static const unsigned char prevwheel30[30] = { 29, 29, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 11, 11, 13, 13, 13, 13, 17, 17, 19, 19, 19, 19, 23, 23, 23, 23, 23, 23 }; #endif static INLINE UV next_prime_in_segment( const unsigned char* sieve, UV segment_start, UV segment_bytes, UV p) { UV d, m; if (p < segment_start) return 0; d = (p-segment_start)/30; if (d >= segment_bytes) return 0; m = (p-segment_start) - d*30; do { if (m==29) { d++; m = 1; if (d >= segment_bytes) return 0; } else { m = nextwheel30[m]; } } while (sieve[d] & masktab30[m]); return (segment_start + d*30 + m); } static INLINE int is_prime_in_segment( const unsigned char* sieve, UV segment_start, UV segment_bytes, UV p) { UV d, m, mtab; if (p < segment_start) return -1; d = (p-segment_start)/30; if (d >= segment_bytes) return -1; m = (p-segment_start) - d*30; mtab = masktab30[m]; if (mtab == 0) return 0; return ((sieve[d] & mtab) == 0); } #define next_prime_in_sieve(sieve, p) next_prime_in_segment(sieve, 0, UV_MAX, p) /* 1001 bytes of presieved mod-30 bytes. If the area to be sieved is * appropriately filled with this data, then 7, 11, and 13 do not have * to be sieved. It wraps, so multiple memcpy's can be used. Do be * aware that if you start at 0, you'll have to correct the first byte. */ #define PRESIEVE_SIZE (7*11*13) static const unsigned char presieve13[PRESIEVE_SIZE] = { 0x0e,0x20,0x10,0x81,0x49,0x24,0xc2,0x06,0x2a,0x90,0xa1,0x0c,0x14, 0x58,0x02,0x61,0x11,0xc3,0x28,0x0c,0x44,0x22,0xa4,0x10,0x91,0x18, 0x4d,0x40,0x82,0x21,0x58,0xa1,0x28,0x04,0x42,0x92,0x20,0x51,0x91, 0x8a,0x04,0x48,0x03,0x60,0x34,0x81,0x1c,0x06,0xc1,0x02,0xa2,0x10, 0x89,0x08,0x24,0x45,0x42,0x30,0x10,0xc5,0x0a,0x86,0x40,0x0a,0x30, 0x38,0x85,0x08,0x15,0x40,0x63,0x20,0x96,0x83,0x88,0x04,0x60,0x16, 0x28,0x10,0x81,0x49,0x44,0xe2,0x02,0x2c,0x12,0xa1,0x0c,0x04,0x50, 0x0a,0x61,0x10,0x83,0x48,0x2c,0x40,0x26,0x26,0x90,0x91,0x08,0x55, 0x48,0x82,0x20,0x19,0xc1,0x28,0x04,0x44,0x12,0xa0,0x51,0x81,0x9a, 0x0c,0x48,0x02,0x21,0x54,0xa1,0x18,0x04,0x43,0x82,0xa2,0x10,0x99, 0x08,0x24,0x44,0x03,0x70,0x30,0xc1,0x0c,0x86,0xc0,0x0a,0x20,0x30, 0x8d,0x08,0x14,0x41,0x43,0x20,0x92,0x85,0x0a,0x84,0x60,0x06,0x30, 0x18,0x81,0x49,0x05,0xc2,0x22,0x28,0x14,0xa3,0x8c,0x04,0x50,0x12, 0x69,0x10,0x83,0x09,0x4c,0x60,0x22,0x24,0x12,0x91,0x08,0x45,0x50, 0x8a,0x20,0x18,0x81,0x68,0x24,0x40,0x16,0x22,0xd1,0x81,0x8a,0x14, 0x48,0x02,0x20,0x15,0xc1,0x38,0x04,0x45,0x02,0xa2,0x10,0x89,0x18, 0x2c,0x44,0x02,0x31,0x50,0xe1,0x08,0x86,0x42,0x8a,0x20,0x30,0x95, 0x08,0x14,0x40,0x43,0x60,0xb2,0x81,0x0c,0x06,0xe0,0x06,0x20,0x10, 0x89,0x49,0x04,0xc3,0x42,0x28,0x10,0xa5,0x0e,0x84,0x50,0x02,0x71, 0x18,0x83,0x08,0x0d,0x40,0x22,0x24,0x14,0x93,0x88,0x45,0x40,0x92, 0x28,0x18,0x81,0x29,0x44,0x60,0x12,0x24,0x53,0x81,0x8a,0x04,0x58, 0x0a,0x20,0x14,0x81,0x58,0x24,0x41,0x06,0xa2,0x90,0x89,0x08,0x34, 0x4c,0x02,0x30,0x11,0xc1,0x28,0x86,0x44,0x0a,0xa0,0x30,0x85,0x18, 0x1c,0x40,0x43,0x21,0xd2,0xa1,0x08,0x04,0x62,0x86,0x20,0x10,0x91, 0x49,0x04,0xc2,0x03,0x68,0x30,0xa1,0x0c,0x06,0xd0,0x02,0x61,0x10, 0x8b,0x08,0x0c,0x41,0x62,0x24,0x10,0x95,0x0a,0xc5,0x40,0x82,0x30, 0x18,0x81,0x28,0x05,0x40,0x32,0x20,0x55,0x83,0x8a,0x04,0x48,0x12, 0x28,0x14,0x81,0x19,0x44,0x61,0x02,0xa6,0x12,0x89,0x08,0x24,0x54, 0x0a,0x30,0x10,0xc1,0x48,0xa6,0x40,0x0e,0x22,0xb0,0x85,0x08,0x14, 0x48,0x43,0x20,0x93,0xc1,0x28,0x04,0x64,0x06,0xa0,0x10,0x81,0x59, 0x0c,0xc2,0x02,0x29,0x50,0xa1,0x0c,0x04,0x52,0x82,0x61,0x10,0x93, 0x08,0x0c,0x40,0x23,0x64,0x30,0x91,0x0c,0x47,0xc0,0x82,0x20,0x18, 0x89,0x28,0x04,0x41,0x52,0x20,0x51,0x85,0x8a,0x84,0x48,0x02,0x30, 0x1c,0x81,0x18,0x05,0x41,0x22,0xa2,0x14,0x8b,0x88,0x24,0x44,0x12, 0x38,0x10,0xc1,0x09,0xc6,0x60,0x0a,0x24,0x32,0x85,0x08,0x14,0x50, 0x4b,0x20,0x92,0x81,0x48,0x24,0x60,0x06,0x22,0x90,0x81,0x49,0x14, 0xca,0x02,0x28,0x11,0xe1,0x2c,0x04,0x54,0x02,0xe1,0x10,0x83,0x18, 0x0c,0x40,0x22,0x25,0x50,0xb1,0x08,0x45,0x42,0x82,0x20,0x18,0x91, 0x28,0x04,0x40,0x13,0x60,0x71,0x81,0x8e,0x06,0xc8,0x02,0x20,0x14, 0x89,0x18,0x04,0x41,0x42,0xa2,0x10,0x8d,0x0a,0xa4,0x44,0x02,0x30, 0x18,0xc1,0x08,0x87,0x40,0x2a,0x20,0x34,0x87,0x88,0x14,0x40,0x53, 0x28,0x92,0x81,0x09,0x44,0x60,0x06,0x24,0x12,0x81,0x49,0x04,0xd2, 0x0a,0x28,0x10,0xa1,0x4c,0x24,0x50,0x06,0x63,0x90,0x83,0x08,0x1c, 0x48,0x22,0x24,0x11,0xd1,0x28,0x45,0x44,0x82,0xa0,0x18,0x81,0x38, 0x0c,0x40,0x12,0x21,0x51,0xa1,0x8a,0x04,0x4a,0x82,0x20,0x14,0x91, 0x18,0x04,0x41,0x03,0xe2,0x30,0x89,0x0c,0x26,0xc4,0x02,0x30,0x10, 0xc9,0x08,0x86,0x41,0x4a,0x20,0x30,0x85,0x0a,0x94,0x40,0x43,0x30, 0x9a,0x81,0x08,0x05,0x60,0x26,0x20,0x14,0x83,0xc9,0x04,0xc2,0x12, 0x28,0x10,0xa1,0x0d,0x44,0x70,0x02,0x65,0x12,0x83,0x08,0x0c,0x50, 0x2a,0x24,0x10,0x91,0x48,0x65,0x40,0x86,0x22,0x98,0x81,0x28,0x14, 0x48,0x12,0x20,0x51,0xc1,0xaa,0x04,0x4c,0x02,0xa0,0x14,0x81,0x18, 0x0c,0x41,0x02,0xa3,0x50,0xa9,0x08,0x24,0x46,0x82,0x30,0x10,0xd1, 0x08,0x86,0x40,0x0b,0x60,0x30,0x85,0x0c,0x16,0xc0,0x43,0x20,0x92, 0x89,0x08,0x04,0x61,0x46,0x20,0x10,0x85,0x4b,0x84,0xc2,0x02,0x38, 0x18,0xa1,0x0c,0x05,0x50,0x22,0x61,0x14,0x83,0x88,0x0c,0x40,0x32, 0x2c,0x10,0x91,0x09,0x45,0x60,0x82,0x24,0x1a,0x81,0x28,0x04,0x50, 0x1a,0x20,0x51,0x81,0xca,0x24,0x48,0x06,0x22,0x94,0x81,0x18,0x14, 0x49,0x02,0xa2,0x11,0xc9,0x28,0x24,0x44,0x02,0xb0,0x10,0xc1,0x18, 0x8e,0x40,0x0a,0x21,0x70,0xa5,0x08,0x14,0x42,0xc3,0x20,0x92,0x91, 0x08,0x04,0x60,0x07,0x60,0x30,0x81,0x4d,0x06,0xc2,0x02,0x28,0x10, 0xa9,0x0c,0x04,0x51,0x42,0x61,0x10,0x87,0x0a,0x8c,0x40,0x22,0x34, 0x18,0x91,0x08,0x45,0x40,0xa2,0x20,0x1c,0x83,0xa8,0x04,0x40,0x12, 0x28,0x51,0x81,0x8b,0x44,0x68,0x02,0x24,0x16,0x81,0x18,0x04,0x51, 0x0a,0xa2,0x10,0x89,0x48,0x24,0x44,0x06,0x32,0x90,0xc1,0x08,0x96, 0x48,0x0a,0x20,0x31,0xc5,0x28,0x14,0x44,0x43,0xa0,0x92,0x81,0x18, 0x0c,0x60,0x06,0x21,0x50,0xa1,0x49,0x04,0xc2,0x82,0x28,0x10,0xb1, 0x0c,0x04,0x50,0x03,0x61,0x30,0x83,0x0c,0x0e,0xc0,0x22,0x24,0x10, 0x99,0x08,0x45,0x41,0xc2,0x20,0x18,0x85,0x2a,0x84,0x40,0x12,0x30, 0x59,0x81,0x8a,0x05,0x48,0x22,0x20,0x14,0x83,0x98,0x04,0x41,0x12, 0xaa,0x10,0x89,0x09,0x64,0x64,0x02,0x34,0x12,0xc1,0x08,0x86,0x50, 0x0a,0x20,0x30,0x85,0x48,0x34,0x40,0x47,0x22,0x92,0x81,0x08,0x14, 0x68,0x06,0x20,0x11,0xc1,0x69,0x04,0xc6,0x02,0xa8,0x10,0xa1,0x1c, 0x0c,0x50,0x02,0x61,0x50,0xa3,0x08,0x0c,0x42,0xa2,0x24,0x10,0x91, 0x08,0x45,0x40,0x83,0x60,0x38,0x81,0x2c,0x06,0xc0,0x12,0x20,0x51, 0x89,0x8a,0x04,0x49,0x42,0x20,0x14,0x85,0x1a,0x84,0x41,0x02,0xb2, 0x18,0x89,0x08,0x25,0x44,0x22,0x30,0x14,0xc3,0x88,0x86,0x40,0x1a, 0x28,0x30,0x85,0x09,0x54,0x60,0x43,0x24,0x92,0x81,0x08,0x04,0x70}; static void sieve_prefill(unsigned char* mem, UV startd, UV endd) { UV nbytes = endd - startd + 1; MPUassert( (mem != 0) && (endd >= startd), "sieve_prefill bad arguments"); /* Walk the memory, tiling in the presieve area using memcpy. * This is pretty fast, but it might still benefit from using copy * doubling (where we copy to the memory, then copy memory to memory * doubling in size each time), as memcpy usually loves big chunks. */ while (startd <= endd) { UV pstartd = startd % PRESIEVE_SIZE; UV sieve_bytes = PRESIEVE_SIZE - pstartd; UV bytes = (nbytes > sieve_bytes) ? sieve_bytes : nbytes; memcpy(mem, presieve13 + pstartd, bytes); if (startd == 0) mem[0] = 0x01; /* Correct first byte */ startd += bytes; mem += bytes; nbytes -= bytes; } } /* Marking primes is done the same way we used to do with tables, but * now uses heavily unrolled code based on Kim Walisch's mod-30 sieve. */ #define set_bit(s,n) *(s) |= (1 << n); static const unsigned char masknum30[30] = {0,0,0,0,0,0,0,1,0,0,0,2,0,3,0,0,0,4,0,5,0,0,0,6,0,0,0,0,0,7}; static const unsigned char qinit30[30] = {0,0,1,1,1,1,1,1,2,2,2,2,3,3,4,4,4,4,5,5,6,6,6,6,7,7,7,7,7,7}; static const UV max_sieve_prime = (BITS_PER_WORD==64) ? 4294967291U : 65521U; #define CROSS_INDEX(v, b0,b1,b2,b3,b4,b5,b6,b7, i0,i1,i2,i3,i4,i5,i6,i7, it) \ while (1) { \ case (v+0): if (s >= send) break; set_bit(s,b0); s += r*6+i0; \ case (v+1): if (s >= send) break; set_bit(s,b1); s += r*4+i1; \ case (v+2): if (s >= send) break; set_bit(s,b2); s += r*2+i2; \ case (v+3): if (s >= send) break; set_bit(s,b3); s += r*4+i3; \ case (v+4): if (s >= send) break; set_bit(s,b4); s += r*2+i4; \ case (v+5): if (s >= send) break; set_bit(s,b5); s += r*4+i5; \ case (v+6): if (s >= send) break; set_bit(s,b6); s += r*6+i6; \ case (v+7): if (s >= send) break; set_bit(s,b7); s += r*2+i7; \ while (s + r*28 + it-1 < send) { \ set_bit(s + r * 0 + 0, b0); \ set_bit(s + r * 6 + i0, b1); \ set_bit(s + r * 10 + i0+i1, b2); \ set_bit(s + r * 12 + i0+i1+i2, b3); \ set_bit(s + r * 16 + i0+i1+i2+i3, b4); \ set_bit(s + r * 18 + i0+i1+i2+i3+i4, b5); \ set_bit(s + r * 22 + i0+i1+i2+i3+i4+i5, b6); \ set_bit(s + r * 28 + i0+i1+i2+i3+i4+i5+i6, b7); \ s += r*30 + it; \ } \ } static void mark_primes(unsigned char* s, const unsigned char* send, UV startp, UV endp, UV prime) { UV p2, q, r; int index; q = prime; p2 = prime * prime; if (p2 < startp) { q = 1+(startp-1)/prime; q += distancewheel30[q % 30]; p2 = prime * q; } if (p2 > endp || p2 < startp) return; s += (p2-startp) / 30; r = prime / 30; index = qinit30[q % 30] + 8*masknum30[prime % 30]; switch (index) { CROSS_INDEX( 0, 0,1,2,3,4,5,6,7, 0,0,0,0,0,0,0,1, 1); break; CROSS_INDEX( 8, 1,5,4,0,7,3,2,6, 1,1,1,0,1,1,1,1, 7); break; CROSS_INDEX(16, 2,4,0,6,1,7,3,5, 2,2,0,2,0,2,2,1, 11); break; CROSS_INDEX(24, 3,0,6,5,2,1,7,4, 3,1,1,2,1,1,3,1, 13); break; CROSS_INDEX(32, 4,7,1,2,5,6,0,3, 3,3,1,2,1,3,3,1, 17); break; CROSS_INDEX(40, 5,3,7,1,6,0,4,2, 4,2,2,2,2,2,4,1, 19); break; CROSS_INDEX(48, 6,2,3,7,0,4,5,1, 5,3,1,4,1,3,5,1, 23); break; CROSS_INDEX(56, 7,6,5,4,3,2,1,0, 6,4,2,4,2,4,6,1, 29); break; } } /* Monolithic mod-30 wheel sieve */ static unsigned char* sieve_erat30(UV end) { unsigned char *mem; UV max_buf, limit, prime; max_buf = (end/30) + ((end%30) != 0); /* Round up to a word */ max_buf = ((max_buf + sizeof(UV) - 1) / sizeof(UV)) * sizeof(UV); New(0, mem, max_buf, unsigned char); /* Fill buffer with marked 7, 11, and 13 */ sieve_prefill(mem, 0, max_buf-1); limit = isqrt(end); /* prime*prime can overflow */ for (prime = 17; prime <= limit; prime = next_prime_in_sieve(mem,prime)) { mark_primes(mem, mem+max_buf, 0, end, prime); } return mem; } /* Segmented mod-30 wheel sieve */ static int sieve_segment(unsigned char* mem, UV startd, UV endd, const unsigned char* prim_sieve, UV prim_limit) { const unsigned char* sieve; UV limit, p; UV startp = 30*startd; UV endp = (endd >= (UV_MAX/30)) ? UV_MAX-2 : 30*endd+29; MPUassert( (mem != 0) && (endd >= startd) && (endp >= startp), "sieve_segment bad arguments"); /* Fill buffer with marked 7, 11, and 13 */ sieve_prefill(mem, startd, endd); limit = isqrt(endp); if (limit > max_sieve_prime) limit = max_sieve_prime; sieve = (prim_sieve != 0 && limit <= prim_limit) ? prim_sieve : sieve_erat30(limit); MPUassert( sieve != 0, "Could not generate base sieve" ); for (p = 17; p <= limit; p = next_prime_in_sieve(sieve,p)) { mark_primes(mem, mem+endd-startd+1, startp, endp, p); } if (sieve != prim_sieve) Safefree(sieve); return 1; } /*****************************************************************************/ /* Prime iterator */ /*****************************************************************************/ /* These sizes are a tradeoff. For better memory use I think 16k,4k is good. * For performance, 32k,16k or 64k,16k is better. To avoid threading hell, * this is just decided statically. At 24k,16k we handle 736800 numbers in * the primary sieve and won't redo for segments until after 5*10^11. Each * segment will store a range of 30*(16384-16) = 491040 numbers. */ #define PRIMARY_SIZE (32768-16) #define SEGMENT_SIZE (24576-16) #define NSMALL_PRIMES (83970-180) static const unsigned char* primary_sieve = 0; static const UV primary_limit = (30 * PRIMARY_SIZE)-1; static const uint32_t* small_primes = 0; static UV num_small_primes = 0; void prime_iterator_global_startup(void) { primary_sieve = sieve_erat30(primary_limit); #ifdef NSMALL_PRIMES { UV p; uint32_t *primes32; UV *primes64 = sieve_to_n(NSMALL_PRIMES + 180, &num_small_primes); New(0, primes32, num_small_primes, uint32_t); for (p = 0; p < num_small_primes; p++) primes32[p] = primes64[p]; Safefree(primes64); small_primes = primes32; } #endif } void prime_iterator_global_shutdown(void) { if (primary_sieve != 0) Safefree(primary_sieve); if (small_primes != 0) Safefree(small_primes); primary_sieve = 0; small_primes = 0; } #if 0 void prime_iterator_init(prime_iterator *iter) { iter->p = 2; iter->segment_start = 0; iter->segment_bytes = 0; iter->segment_mem = 0; } prime_iterator prime_iterator_default(void) { prime_iterator iter = {2, 0, 0, 0}; return iter; } #endif void prime_iterator_destroy(prime_iterator *iter) { if (iter->segment_mem != 0) Safefree(iter->segment_mem); iter->segment_mem = 0; iter->segment_start = 0; iter->segment_bytes = 0; iter->p = 0; } #ifdef NSMALL_PRIMES static UV pcount(UV n) { UV lo = 0 + (n >> 4); UV hi = (n >> 3) - (n >> 6) + ( (n<503) ? 40 : (n<1669) ? 80 : 139 ); if (hi > num_small_primes) hi = num_small_primes; while (lo < hi) { UV mid = lo + (hi-lo)/2; if (small_primes[mid] <= n) lo = mid+1; else hi = mid; } return lo; /* Because 2 is stored at location 0 */ } #endif void prime_iterator_setprime(prime_iterator *iter, UV n) { /* Is it inside the current segment? */ if ( (iter->segment_mem != 0) && (n >= iter->segment_start) && (n <= iter->segment_start + 30*iter->segment_bytes - 1) ) { iter->p = n; return; } prime_iterator_destroy(iter); #ifdef NSMALL_PRIMES /* In small area? */ if (n < NSMALL_PRIMES) { UV pc = pcount(n); iter->segment_start = pc-1; iter->p = (pc == 0) ? 2 : small_primes[pc-1]; } else #endif if (n <= primary_limit) { /* Is it inside the primary cache range? */ iter->p = n; } else { /* Sieve this range */ UV lod, hid; lod = n/30; hid = lod + SEGMENT_SIZE; New(0, iter->segment_mem, SEGMENT_SIZE, unsigned char ); iter->segment_start = lod * 30; iter->segment_bytes = SEGMENT_SIZE; if (!sieve_segment((unsigned char*)iter->segment_mem, lod, hid, primary_sieve, primary_limit)) croak("Could not segment sieve"); iter->p = n; } } UV prime_iterator_next(prime_iterator *iter) { UV lod, hid, seg_beg, seg_end; const unsigned char* sieve; UV n = iter->p; #ifdef NSMALL_PRIMES if (n < NSMALL_PRIMES) { iter->p = small_primes[++iter->segment_start]; return iter->p; } #else if (n < 11) { switch (n) { case 0: case 1: iter->p = 2; break; case 2: iter->p = 3; break; case 3: case 4: iter->p = 5; break; case 5: case 6: iter->p = 7; break; default: iter->p = 11; break; } return iter->p; } #endif /* Primary sieve */ if (primary_sieve != 0 && n < 30*PRIMARY_SIZE) { n = next_prime_in_segment(primary_sieve, 0, PRIMARY_SIZE, iter->p); if (n > 0) { iter->p = n; return n; } } sieve = iter->segment_mem; /* Current segment */ if (sieve != 0) { seg_beg = iter->segment_start; seg_end = iter->segment_start + 30*iter->segment_bytes - 1; n = next_prime_in_segment(sieve, seg_beg, iter->segment_bytes, iter->p); if (n > 0) { iter->p = n; return n; } /* Not found in this segment */ lod = (seg_end+1)/30; } else { lod = PRIMARY_SIZE; New(0, sieve, SEGMENT_SIZE, unsigned char ); } hid = lod + SEGMENT_SIZE - 1; iter->segment_start = lod * 30; iter->segment_bytes = SEGMENT_SIZE; seg_beg = iter->segment_start; seg_end = iter->segment_start + 30*iter->segment_bytes - 1; if (!sieve_segment((unsigned char*)sieve, lod, hid, primary_sieve, primary_limit)) croak("Could not segment sieve from %"UVuf" to %"UVuf, seg_beg, seg_end); iter->segment_mem = sieve; n = next_prime_in_segment(sieve, seg_beg, iter->segment_bytes, seg_beg); if (n > 0) { iter->p = n; return n; } croak("MPU: segment size too small, could not find prime\n"); } static int _is_trial_prime(UV n) { UV i = 7; UV limit = (UV)sqrt(n); while (1) { /* trial division, skipping multiples of 2/3/5 */ if (i > limit) break; if ((n % i) == 0) return 0; i += 4; if (i > limit) break; if ((n % i) == 0) return 0; i += 2; if (i > limit) break; if ((n % i) == 0) return 0; i += 4; if (i > limit) break; if ((n % i) == 0) return 0; i += 2; if (i > limit) break; if ((n % i) == 0) return 0; i += 4; if (i > limit) break; if ((n % i) == 0) return 0; i += 6; if (i > limit) break; if ((n % i) == 0) return 0; i += 2; if (i > limit) break; if ((n % i) == 0) return 0; i += 6; } return 1; } int prime_iterator_isprime(prime_iterator *iter, UV n) { if (n < 11) { switch (n) { case 2: case 3: case 5: case 7: return 1; break; default: break; } return 0; } /* Primary sieve */ if (primary_sieve != 0 && n <= primary_limit) { UV d = n/30; UV m = n - d*30; unsigned char mtab = masktab30[m]; return mtab && !(primary_sieve[d] & mtab); } /* Current segment */ if (iter->segment_mem != 0) { int isp = is_prime_in_segment(iter->segment_mem, iter->segment_start, iter->segment_bytes, n); if (isp >= 0) return isp; } /* Out of segment range, can't answer. Try simple divisibility */ { UV d = n/30; UV m = n - d*30; unsigned char mtab = masktab30[m]; if (mtab == 0) return 0; return _is_trial_prime(n); } } UV* sieve_to_n(UV n, UV* count) { UV pi_max, max_buf, i, p, pi; const unsigned char* sieve; UV* primes; #ifdef NSMALL_PRIMES if (small_primes != 0 && n < NSMALL_PRIMES) { pi = pcount(n); New(0, primes, pi, UV); for (i = 0; i < pi; i++) primes[i] = small_primes[i]; if (count != 0) *count = pi; return primes; } #endif pi_max = (n < 67) ? 18 : (n < 355991) ? 15+(n/(log(n)-1.09)) : (n/log(n)) * (1.0+1.0/log(n)+2.51/(log(n)*log(n))); New(0, primes, pi_max + 10, UV); pi = 0; primes[pi++] = 2; primes[pi++] = 3; primes[pi++] = 5; primes[pi++] = 7; primes[pi++] = 11; primes[pi++] = 13; primes[pi++] = 17; primes[pi++] = 19; primes[pi++] = 23; primes[pi++] = 29; if (primary_sieve != 0 && n < 30*PRIMARY_SIZE) sieve = primary_sieve; else sieve = sieve_erat30(n); max_buf = (n/30) + ((n%30) != 0); for (i = 1, p = 30; i < max_buf; i++, p += 30) { UV c = sieve[i]; if (!(c & 1)) primes[pi++] = p+ 1; if (!(c & 2)) primes[pi++] = p+ 7; if (!(c & 4)) primes[pi++] = p+11; if (!(c & 8)) primes[pi++] = p+13; if (!(c & 16)) primes[pi++] = p+17; if (!(c & 32)) primes[pi++] = p+19; if (!(c & 64)) primes[pi++] = p+23; if (!(c & 128)) primes[pi++] = p+29; } while (pi > 0 && primes[pi-1] > n) pi--; if (sieve != primary_sieve) Safefree(sieve); if (count != 0) *count = pi; return primes; } Math-Prime-Util-GMP-0.52/aks.c0000644000175000017500000003207613663067455014300 0ustar danadana#include #include #include "ptypes.h" /***************************************************************************** * * The AKS polynomial-time deterministic primality test. * * Multiple variants are implemented. The original algorithm as shown in * articles such as Rotella (2005) is not here as it is much slower than * the essentially identical algorithm in the updated (V6) AKS paper. The * updated paper uses improved theorems based on Lenstra et al. which allows * loweing some limits used in the algorithm. * * All versions have a relatively similar O(log^{6.x}(n)) asymptotic growth, * which is what we expect from AKS. * * A version with improvements from Voloch and Bornemann is included, and * is similar to Bornemann's 2002 Pari/GP implementation. It is *much* faster * than the V6 algorithm, and to the best of my knowledge is the fastest * publicly available AKS implementation in early 2016. * * The Bernstein 4.1 algorithm implements theorem 4.1 from Bernstein's 2003 * paper, which has the Voloch improvements as well as many more. It is * another 10-20x faster than the Bornemann version, hence is substantially * faster than any other known implementation in mid 2016. * * Copyright (2012-2016) Dana Jacobsen. * *****************************************************************************/ /* In approximate order of performance. */ #define AKS_VARIANT_V6 1 /* The V6 paper with Lenstra impr */ #define AKS_VARIANT_BERN21 2 /* AKS-Bernstein-Morain theorem 2.1 */ #define AKS_VARIANT_BERN22 3 /* AKS-Bernstein-Morain theorem 2.2 */ #define AKS_VARIANT_BERN23 4 /* AKS-Bernstein-Morain theorem 2.3 */ #define AKS_VARIANT_BORNEMANN 5 /* Based on Folkmar Bornemann's impl */ #define AKS_VARIANT_BERN41 6 /* Bernstein 2003, theorem 4.1 */ #define AKS_VARIANT AKS_VARIANT_BERN41 #include "aks.h" #include "prime_iterator.h" #include "factor.h" #if AKS_VARIANT == AKS_VARIANT_BORNEMANN #define FUNC_mpz_logn 1 #endif #define FUNC_mpz_log2 1 #include "utility.h" static int test_anr(UV a, mpz_t n, UV r, mpz_t* px, mpz_t* py) { int retval = 1; UV i, n_mod_r; mpz_t t; for (i = 0; i < r; i++) mpz_set_ui(px[i], 0); mpz_set_ui(px[0], a); mpz_set_ui(px[1], 1); poly_mod_pow(py, px, n, r, n); mpz_init(t); n_mod_r = mpz_fdiv_ui(n, r); mpz_sub_ui(t, py[n_mod_r], 1); mpz_mod(py[n_mod_r], t, n); mpz_sub_ui(t, py[0], a); mpz_mod(py[0], t, n); mpz_clear(t); for (i = 0; i < r; i++) if (mpz_sgn(py[i])) retval = 0; return retval; } #if AKS_VARIANT != AKS_VARIANT_V6 static int is_primitive_root_uiprime(mpz_t n, UV r) { int res; mpz_t zr; mpz_init_set_ui(zr, r); res = is_primitive_root(n, zr, 1); mpz_clear(zr); return res; } #endif #if AKS_VARIANT == AKS_VARIANT_BERN21 static UV largest_factor(UV n) { UV p = 2; PRIME_ITERATOR(iter); while (n >= p*p && !prime_iterator_isprime(&iter, n)) { while ( (n % p) == 0 && n >= p*p ) { n /= p; } p = prime_iterator_next(&iter); } prime_iterator_destroy(&iter); return n; } #endif #if AKS_VARIANT == AKS_VARIANT_BERN41 int bern41_acceptable(mpz_t n, UV r, UV s, mpz_t t1, mpz_t t2) { double scmp = ceil(sqrt( (r-1)/3.0 )) * mpz_log2(n); UV d = (UV) (0.5 * (r-1)); UV i = (UV) (0.475 * (r-1)); UV j = i; /* Ensure conditions are correct */ if (d > r-2) d = r-2; if (i > d) i = d; if (j > (r-2-d)) j = r-2-d; mpz_bin_uiui(t2, 2*s, i); mpz_bin_uiui(t1, d, i); mpz_mul(t2, t2, t1); mpz_bin_uiui(t1, 2*s-i, j); mpz_mul(t2, t2, t1); mpz_bin_uiui(t1, r-2-d, j); mpz_mul(t2, t2, t1); return (mpz_log2(t2) >= scmp); } #endif int is_aks_prime(mpz_t n) { mpz_t *px, *py; int retval; UV i, s, r, a; UV starta = 1; int _verbose = get_verbose_level(); if (mpz_cmp_ui(n, 4) < 0) return (mpz_cmp_ui(n, 1) <= 0) ? 0 : 1; /* Just for performance: check small divisors: 2*3*5*7*11*13*17*19*23 */ if (mpz_gcd_ui(0, n, 223092870UL) != 1 && mpz_cmp_ui(n, 23) > 0) return 0; if (mpz_perfect_power_p(n)) return 0; #if AKS_VARIANT == AKS_VARIANT_V6 /* From the V6 AKS paper */ { mpz_t sqrtn, t; double log2n; UV limit, startr; PRIME_ITERATOR(iter); mpz_init(sqrtn); mpz_sqrt(sqrtn, n); log2n = mpz_log2(n); limit = (UV) floor( log2n * log2n ); if (_verbose>1) gmp_printf("# AKS checking order_r(%Zd) to %"UVuf"\n", n, (unsigned long) limit); /* Using a native r limits us to ~2000 digits in the worst case (r ~ log^5n) * but would typically work for 100,000+ digits (r ~ log^3n). This code is * far too slow to matter either way. Composite r is ok here, but it will * always end up prime, so save time and just check primes. */ retval = 0; /* Start order search at a good spot. Idea from Nemana and Venkaiah. */ startr = (mpz_sizeinbase(n,2)-1) * (mpz_sizeinbase(n,2)-1); startr = (startr < 1002) ? 2 : startr - 100; for (r = 2; /* */; r = prime_iterator_next(&iter)) { if (mpz_divisible_ui_p(n, r) ) /* r divides n. composite. */ { retval = 0; break; } if (mpz_cmp_ui(sqrtn, r) <= 0) /* no r <= sqrtn divides n. prime. */ { retval = 1; break; } if (r < startr) continue; if (mpz_order_ui(r, n, limit) > limit) { retval = 2; break; } } prime_iterator_destroy(&iter); mpz_clear(sqrtn); if (retval != 2) return retval; /* Since r is prime, phi(r) = r-1. */ s = (UV) floor( sqrt(r-1) * log2n ); } #elif AKS_VARIANT == AKS_VARIANT_BORNEMANN /* Bernstein + Voloch */ { UV slim; double c2, x; /* small t = few iters of big poly. big t = many iters of small poly */ double const t = (mpz_sizeinbase(n, 2) <= 64) ? 32 : 40; double const t1 = (1.0/((t+1)*log(t+1)-t*log(t))); double const dlogn = mpz_logn(n); mpz_t tmp; PRIME_ITERATOR(iter); mpz_init(tmp); prime_iterator_setprime(&iter, (UV) (t1*t1 * dlogn*dlogn) ); r = prime_iterator_next(&iter); while (!is_primitive_root_uiprime(n,r)) r = prime_iterator_next(&iter); prime_iterator_destroy(&iter); slim = (UV) (2*t*(r-1)); c2 = dlogn * floor(sqrt(r)); { /* Binary search for first s in [1,slim] where x >= 0 */ UV bi = 1; UV bj = slim; while (bi < bj) { s = bi + (bj-bi)/2; mpz_bin_uiui(tmp, r+s-1, s); x = mpz_logn(tmp) / c2 - 1.0; if (x < 0) bi = s+1; else bj = s; } s = bi-1; } s = (s+3) >> 1; /* Bornemann checks factors up to (s-1)^2, we check to max(r,s) */ /* slim = (s-1)*(s-1); */ slim = (r > s) ? r : s; if (_verbose > 1) printf("# aks trial to %"UVuf"\n", slim); if (_GMP_trial_factor(n, 2, slim) > 1) { mpz_clear(tmp); return 0; } mpz_sqrt(tmp, n); if (mpz_cmp_ui(tmp, slim) <= 0) { mpz_clear(tmp); return 1; } mpz_clear(tmp); } #elif AKS_VARIANT == AKS_VARIANT_BERN21 { /* Bernstein 2003, theorem 2.1 (simplified) */ UV q; double slim, scmp, x; mpz_t t, t2; PRIME_ITERATOR(iter); mpz_init(t); mpz_init(t2); r = s = 0; while (1) { /* todo: Check r|n and r >= sqrt(n) here instead of waiting */ if (mpz_cmp_ui(n, r) <= 0) break; r = prime_iterator_next(&iter); q = largest_factor(r-1); mpz_set_ui(t, r); mpz_powm_ui(t, n, (r-1)/q, t); if (mpz_cmp_ui(t, 1) <= 0) continue; scmp = 2 * floor(sqrt(r)) * mpz_log2(n); slim = 20 * (r-1); /* Check viability */ mpz_bin_uiui(t, q+slim-1, slim); if (mpz_log2(t) < scmp) continue; for (s = 2; s < slim; s++) { mpz_bin_uiui(t, q+s-1, s); if (mpz_log2(t) > scmp) break; } if (s < slim) break; } mpz_clear(t); mpz_clear(t2); prime_iterator_destroy(&iter); if (_GMP_trial_factor(n, 2, s) > 1) return 0; } #elif AKS_VARIANT == AKS_VARIANT_BERN22 { /* Bernstein 2003, theorem 2.2 (simplified) */ UV q; double slim, scmp, x; mpz_t t, t2; PRIME_ITERATOR(iter); mpz_init(t); mpz_init(t2); r = s = 0; while (1) { /* todo: Check r|n and r >= sqrt(n) here instead of waiting */ if (mpz_cmp_ui(n, r) <= 0) break; r = prime_iterator_next(&iter); if (!is_primitive_root_uiprime(n,r)) continue; q = r-1; /* Since r is prime, phi(r) = r-1 */ scmp = 2 * floor(sqrt(r-1)) * mpz_log2(n); slim = 20 * (r-1); /* Check viability */ mpz_bin_uiui(t, q+slim-1, slim); if (mpz_log2(t) < scmp) continue; for (s = 2; s < slim; s++) { mpz_bin_uiui(t, q+s-1, s); if (mpz_log2(t) > scmp) break; } if (s < slim) break; } mpz_clear(t); mpz_clear(t2); prime_iterator_destroy(&iter); if (_GMP_trial_factor(n, 2, s) > 1) return 0; } #elif AKS_VARIANT == AKS_VARIANT_BERN23 { /* Bernstein 2003, theorem 2.3 (simplified) */ UV q, d, limit; double slim, scmp, sbin, x, log2n; mpz_t t, t2; PRIME_ITERATOR(iter); mpz_init(t); mpz_init(t2); log2n = mpz_log2(n); limit = (UV) floor( log2n * log2n ); r = 2; s = 0; while (1) { /* todo: Check r|n and r >= sqrt(n) here instead of waiting */ if (mpz_cmp_ui(n, r) <= 0) break; r++; UV gcd = mpz_gcd_ui(NULL, n, r); if (gcd != 1) { mpz_clear(t); mpz_clear(t2); return 0; } UV v = mpz_order_ui(r, n, limit); if (v >= limit) continue; mpz_set_ui(t2, r); totient(t, t2); q = mpz_get_ui(t); UV phiv = q/v; /* printf("phi(%lu)/v = %lu/%lu = %lu\n", r, q, v, phiv); */ /* This is extremely inefficient. */ /* Choose an s value we'd be happy with */ slim = 20 * (r-1); /* Quick check to see if it could work with s=slim, d=1 */ mpz_bin_uiui(t, q+slim-1, slim); sbin = mpz_log2(t); if (sbin < 2*floor(sqrt(q))*log2n) continue; for (s = 2; s < slim; s++) { mpz_bin_uiui(t, q+s-1, s); sbin = mpz_log2(t); if (sbin < 2*floor(sqrt(q))*log2n) continue; /* d=1 */ /* Check each number dividing phi(r)/v */ for (d = 2; d < phiv; d++) { if ((phiv % d) != 0) continue; scmp = 2 * d * floor(sqrt(q/d)) * log2n; if (sbin < scmp) break; } /* if we did not exit early, this s worked for each d. This s wins. */ if (d >= phiv) break; } if (s < slim) break; } mpz_clear(t); mpz_clear(t2); prime_iterator_destroy(&iter); if (_GMP_trial_factor(n, 2, s) > 1) return 0; } #elif AKS_VARIANT == AKS_VARIANT_BERN41 { double const log2n = mpz_log2(n); /* Tuning: Initial 'r' selection */ double const r0 = 0.008 * log2n * log2n; /* Tuning: Try a larger 'r' if 's' looks very large */ UV const rmult = 8; UV slim; mpz_t tmp, tmp2; PRIME_ITERATOR(iter); mpz_init(tmp); mpz_init(tmp2); /* r has to be at least 3. */ prime_iterator_setprime(&iter, (r0 < 2) ? 2 : (UV) r0); r = prime_iterator_next(&iter); /* r must be a primitive root. For performance, skip if s looks too big. */ while ( !is_primitive_root_uiprime(n, r) || !bern41_acceptable(n, r, rmult*(r-1), tmp, tmp2) ) r = prime_iterator_next(&iter); prime_iterator_destroy(&iter); { /* Binary search for first s in [1,lim] where conditions met */ UV bi = 1; UV bj = rmult * (r-1); while (bi < bj) { s = bi + (bj-bi)/2; if (!bern41_acceptable(n,r,s,tmp,tmp2)) bi = s+1; else bj = s; } s = bj; /* Our S goes from 2 to s+1. */ starta = 2; s = s+1; } /* printf("chose r=%lu s=%lu d = %lu i = %lu j = %lu\n", r, s, d, i, j); */ /* Check divisibility to s(s-1) to cover both gcd conditions */ slim = s * (s-1); if (_verbose > 1) printf("# aks trial to %"UVuf"\n", slim); if (_GMP_trial_factor(n, 2, slim) > 1) { mpz_clear(tmp); mpz_clear(tmp2); return 0; } /* If we checked divisibility to sqrt(n), then it is prime. */ mpz_sqrt(tmp, n); if (mpz_cmp_ui(tmp, slim) <= 0) { mpz_clear(tmp); mpz_clear(tmp2); return 1; } /* Check b^(n-1) = 1 mod n for b in [2..s] */ if (_verbose > 1) printf("# aks checking fermat to %"UVuf"\n", s); mpz_sub_ui(tmp2, n, 1); for (i = 2; i <= s; i++) { mpz_set_ui(tmp, i); mpz_powm(tmp, tmp, tmp2, n); if (mpz_cmp_ui(tmp, 1) != 0) { mpz_clear(tmp); mpz_clear(tmp2); return 0; } } mpz_clear(tmp); mpz_clear(tmp2); } #endif if (_verbose) gmp_printf("# AKS %Zd. r = %"UVuf" s = %"UVuf"\n", n, (unsigned long) r, (unsigned long) s); /* Create the three polynomials we will use */ New(0, px, r, mpz_t); New(0, py, r, mpz_t); if ( !px || !py ) croak("allocation failure\n"); for (i = 0; i < r; i++) { mpz_init(px[i]); mpz_init(py[i]); } retval = 1; for (a = starta; a <= s; a++) { retval = test_anr(a, n, r, px, py); if (!retval) break; if (_verbose>1) { printf("."); fflush(stdout); } } if (_verbose>1) { printf("\n"); fflush(stdout); }; /* Free the polynomials */ for (i = 0; i < r; i++) { mpz_clear(px[i]); mpz_clear(py[i]); } Safefree(px); Safefree(py); return retval; } Math-Prime-Util-GMP-0.52/Changes0000644000175000017500000007501313674066376014652 0ustar danadanaRevision history for Perl module Math::Prime::Util::GMP 0.52 2020-06-22 [ADDED] - powint(a,b) integer a^b - mulint(a,b) integer a*b - addint(a,b) integer a+b - subint(a,b) integer a-b - divint(a,b) integer a/b quotient (floor) - modint(a,b) integer a/b modulo (floor) - divrem(a,b) integer a/b quo + rem (Euclidian) - tdivrem(a,b) integer a/b quo + rem (truncated) - absint(n) integer absolute value - negint(n) integer negate: returns -n - is_gaussian_prime(a,b) is a+bi a Gaussian prime - random_safe_prime(b) random b-bit safe prob prime - next_twin_prime(n) returns start of twin prime > n [FIXES] - Remove a mod in the AKS test that was in code since 2012. - squfof126 was not portable. GMP 6.2.0 changed to lazy allocation causing the code to fail. Rewrote function to be more portable. - is_totient for powers of 2 was returning 0. Thanks Trizen. - LambertW could fault if given inputs very near the branch point. [PERFORMANCE] - Trizen suggested binary splitting LCM. Much faster for big lists. - Trizen improved speed of lucas sequence for large n and even modulus. - todigits uses a subquadratic algorithm. Thanks to Trizen for request. - sieving depth for large sizes wasn't optimal on 32-bit machines. Thanks to Seth Troisi. - LambertW is about 2x faster due to a better and faster initial estimate. 0.51 2018-08-27 [ADDED] - rootreal(x,n[,digits]) nth root of x: x^(1/n) - addreal(x,y[,digits]) x+y - subreal(x,y[,digits]) x-y - mulreal(x,y[,digits]) x*y - divreal(x,y[,digits]) x/y - subfactorial(n) !n (derangements) - factorial_sum(n) !n (sum of factorials) - multifactorial(x,n) x!, x!!, x!!!, etc. [FIXES] - Some memory leaks squashed. - Trizen reported a factor bug. Fixed with patch to tinyqs.c init code. [OTHER] - Work around a bug in NetBSD. - Standalone ecpp creation fixed. - Allow Ramanujan polynomials (D = 11 mod 24) for ECPP, reducing sizes. - Some new code for ei(). - is_primitive_root quite a bit faster. 0.50 2017-11-28 [FIXES] - real.h mismatched types on machines where unsigned long != UV. 0.49 2017-11-27 [ADDED] - Euler([digits]) Euler's constant with this many digits - li(x[,digits]) Logarithmic Integral of x (x floating point) - ei(x[,digits]) Exponential Integral of x (x floating point) - logreal(x[,digits]) Natural logarithm of x - expreal(x[,digits]) e^x - powreal(x,n[,digits]) x^n - agmreal(a,b[,digits]) AGM(a,b) - arithmetic-geometric mean - prime_count_lower(n) lower bounds for prime count - prime_count_upper(n) upper bounds for prime count [FIXES] - When real functions rounded 0.999... to 1.0 and were given too few digits, they could return .0 instead of 1.0. [OTHER] - moebius handles negative inputs - Added Jason P's cofactorize-tinyqs, which handles up to 126 bit. This gives us faster and more consistent timing when factoring 20 to 38 digit inputs. - Rewrite internal log and exp functions. Among other things, this speeds up LambertW and non-integer Zeta by 10x. - Use Ramanujan/Chudnovsky Pi algorithm. 2x faster with many digits. - Constants Euler, Pi, and Log2 are cached, just like Pari/GP, MPFR, etc. All three are used quite a bit internally. - Calling Pi or Euler in void context just calculates (and caches) the value. This saves the expensive string conversion. 0.48 2017-10-05 [FIXES] - Issues with 32-bit GMP on 64-bit platforms. - Use log instead of logl. 0.47 2017-10-04 [ADDED] - is_square(n) Returns 1 if n is a perfect square - is_carmichael(n) Returns 1 if n is a Carmichael number - is_fundamental(n) Returns 1 if n is a fundamental discriminant - is_totient(n) Returns 1 if euler_phi(x) == n for some x - is_polygonal(n,k) Returns 1 if n is a k-gonal number - polygonal_nth(n,k) Returns N if n is the Nth k-gonal number - logint(n,base) Integer log: largest e s.t. b^e <= n - factorialmod(n,m) Returns n! mod m - permtonum([...]) Returns rank of permutation array ref - numtoperm(n,k) Returns kth permutation of n elems - hammingweight(n) Returns bitwise population count of n [FIXES] - Random stream is identical on big-endian machines. RT 122718 [PERFORMANCE] - Use new sieve marking for prime_iterator. Should give a very small speedup to many functions. - Remove unnecessary variable copy in AKS (is_primitive_root_uiprime). - Slightly faster twin prime sieve by splitting BPSW test. - Factoring is faster with new SQUFOF and native pbrent. [OTHER] - is_primitive_root internal func doesn't modify inputs. - non-exported factor methods (e.g. squfof_factor, ecm_factor, etc.) now always return smallest factor first. - old native SQUFOF and GMP SQUFOF removed. - On x86-64 use a very fast Pollard Rho Brent for 63-bit. - On 64-bit platforms (long = 64-bit), use new SQUFOF126 which can handle up to 126-bit inputs using only native math in the core. This is about 10x faster than our old SQUFOF. 0.46 2017-04-17 [FIXES] - Allow single argument to miller_rabin_random (implies one test). - AKS on small inputs wasn't correctly calculating primitive roots. 0.45 2017-04-16 [FIXES] - Remove use of exp2 which is C99 only. - Trap negative bases sent to miller_rabin_random 0.44 2017-04-13 [ADDED] - irand() Returns uniform random 32-bit integer - irand64() Returns uniform random 64-bit integer - drand([fmax]) Returns uniform random NV (floating point) - urandomm(n) Returns uniform random integer in [0, hi-1] - random_bytes(nbytes) Return a string of CSPRNG bytes [FIXES] - miller_rabin_random wasn't initializing a variable. Fixed and test added. Thanks to Alexandr Ciornii for timely reporting. - Fixed is_primitive_root behavior with negative values. [PERFORMANCE] - sieve_prime_cluster up to 2x faster. [OTHER] - prime_count(), random_prime(), urandomr() can be used with one arg. 0.43 2017-03-12 [ADDED] - random_strong_prime(nbits) random strong prob prime of nbits bits - random_maurer_prime(nbits) random nbits-bits proven prime - random_shawe_taylor_prime(nbits) random nbits-bits proven prime - random_maurer_prime_with_cert(nbits) - random_shawe_taylor_prime_with_cert(nbits) - urandomb(n) random number between 0 and 2^n-1 - urandomr(lo,hi) random number in [lo,hi], inclusive. [PERFORMANCE] - sieve_primes with small widths should perform much better. 0.42 2017-02-27 [ADDED] - lambertw(x[,digits]) Lambert W function - random_prime(a,b) random prob prime in range [a,b] - random_nbit_prime(nbits) random prob prime of exactly nbits bits - random_ndigit_prime(ndigs) random prob prime of exactly ndigs digits - seed_csprng(bytes,data) supply a seed to the internal CSPRNG - is_csprng_well_seeded() returns 1 if the CSPRNG has a proper seed - is_semiprime(n) does n have exactly two prime factors [FIXES] - is_power behaviour for 1 and -1. - is_nminus1_prime could assert on some inputs. Fix. - chinese([3,0],[2,3]) made GMP go belly up. Found by Trizen. - divisors(1) in list context would segfault. Found by Trizen. [PERFORMANCE] - Adjust zeta algorithm crossover for large precision. Makes a huge difference for bern{frac/real} with values > 53000. Thanks to Trizen for pointing this out. - zeta works for all real values, returns undef for 1. It has issues below -10 or so that need to be dealt with in a later release. - is_primitive_root a bit faster with large inputs. - stirling about 40% faster. Thanks to Karim Belabas. [OTHER] - The ISAAC CSPRNG has been added internally and all functions call it. While it is quite fast it is slower than GMP's Mersenne Twister. - On startup, we attempt to seed ISAAC with 256 bytes from /dev/urandom. Callers can call is_csprng_well_seeded() to check if this succeeded, and call as needed seed_csprng() to seed or reseed. 0.41 2016-10-09 [API CHANGES] - bernreal and harmreal will use the second argument to mean the digits of precision to use, rather than the number of digits past the decimal place. - is_pseudoprime and is_strong_pseudoprime act like Math::Prime::Util. [ADDED] - todigits(n[,base[,len]]) Convert number to digit array - zeta(s[,digits]) Riemann Zeta of integer or FP s - riemannr(s[,digits]) Riemann R function of integer or FP s - divisors(n) Returns list of divisors - is_euler_pseudoprime(n,@a) Euler-Jacobi primality test [OTHER] - With verbose >= 3, prints factors found in partial sieve. - factor(1) returns empty list, just like non-GMP code. - factor() went through a Perl layer for obsolete reasons. Removed. - bernreal and bernfrac will use the Zeta/Pi method for large values, making it orders of magnitude faster for large sizes. - Added internal FP log, exp, pow functions, which are not in GMP. - is_prime will do one extra M-R test for probable primes, down from 1-5. Also, if is_provable_prime adds two Frobenius tests if returning a 1. - Removed Perl layer from is_strong_pseudoprime. - is_pseudoprime and is_strong_pseudoprime take a list of bases, and there is no default base. - sieve_primes with small n and large range (e.g. 10^20 to 10^20+8e9) is much faster. This tunes the full vs. partial sieve crossover. 0.40 2016-08-01 [ADDED] - sqrtint(n) Integer square root of n - rootint(n,k) Integer k-th root of n - is_prime_power(n) Returns k if n=p^k for p a prime. [OTHER] - is_perrin_pseudoprime 2x faster. Takes optional second argument for additional restrictions. 0.39 2016-07-24 [ADDED] - bernreal returns float value of Bernoulli number - is_euler_plumb_pseudoprime Colin Plumb's Euler Criterion test - surround_primes returns offsets of prev and next primes [PERFORMANCE] - prev/next/surround prime sieve is slightly deeper - Add very simple composite filter for is_perrin_pseudoprime. - Internal refactor of Miller-Rabin code to remove one mpz variable. [OTHER] - Add option for restricted Perrin pseudoprimes. 0.38 2016-06-18 [FIXES] - Minor updates for Kwalitee. - Rewrite of BLS75 internals, rewrite BLS75 hybrid. - Remove two small memory leaks. [PERFORMANCE] - Less effort to prove primality in is_prime(). 0.37 2016-06-06 [ADDED] - is_nplus1_prime(n) BLS75 N+1 deterministic primality test - is_bls75_prime(n) BLS75 N-1, N+1, combined primality tests [FIXES] - Fixed primorial on systems with not-new GMP, 8-byte UV, and 4-byte long. - sieve_range should work with >32-bit depths on 64-bit Perl + 32-bit GMP. 0.36 2016-05-21 [ADDED] - addmod (a + b) % n - mulmod (a * b) % n - divmod (a / b) % n - powmod (a ^ b) % n - invmod (1 / b) % n - sqrtmod square root modulo a prime - is_primitive_root(a,n) return 1 if 'a' is a primitive root mod n - sieve_range(n,width,depth) sieve from n, returning candidate offsets [FIXES] - Allow a leading '+' in inputs. [PERFORMANCE] - znprimroot is much faster with large inputs. - Speedup partial sieve with large input. - next_prime and prev_prime sieve deeper. ~5% faster with large inputs. - AKS using Bernstein (2003) theorem 4.1. 10-20x faster. - Speedup for large pn_primorial and primorial. Much faster for very large values, though it will all get swamped by the overhead in returning the large value. This is a great reason to return mpz objects. [OTHER] - Split out factor, primality, and AKS code into separate source files. 0.35 2015-12-13 [FIXES] - gcdext done manually for old GMP. - fix memory leak in chinese 0.34 2015-10-14 [ADDED] - sieve_prime_cluster(low,high,...) sieve clusters/constellations [PERFORMANCE] - Speedup partial sieve with large range. [OTHER] - Remove _GMP_trial_primes(), which was never exported. - Internal restructuring of sieve_primes and sieve_twin_primes. - is_frobenius_pseudoprime with arguments doesn't check for perfect square, and works for small primes plus large params. 0.33 2015-09-04 [ADDED] - sieve_twin_primes(low,high) sieve for twin primes - is_miller_prime(n[,assumeGRH]) deterministic Miller test [PERFORMANCE] - New results from Sorenson and Webster let us give faster deterministic results for 65-82 bits. is_prime always returns {0,2} for this range. 0.32 2015-08-16 [ADDED] - chinese chinese remainder theorem - sigma divisor sums - ramanujan_tau Ramanujan's Tau function 0.31 2015-06-21 [PERFORMANCE] - Minor speedup to partial sieve. [OTHER] - Allow working on old GMP versions. 0.30 2015-06-15 [ADDED] - harmfrac returns (num,den) of Harmonic number - harmreal returns float value of Harmonic number - is_proth_prime(p) For k*2^n+1, returns -1, 0, or 2 - is_frobenius_khashin_pseudoprime returns 1 if Frob-Khashin prob prime [FIXES] - lucas sequence with even n fixed. [PERFORMANCE] - A Proth test was added to quickly prove numbers of the form k*2^n+1. - LLR testing was improved using a method by Rödseth. This allows proofs of k*2^n-1. The old method is still used, but was unable to quickly test cases where k was divisible by 3. The new method handles these. - BLS75-5 proof: use an expanding stack, allowing it to work on inputs like: 'k * n# + 1'. - BLS75-5 proof: remove some redundant computations. 0.29 2014-11-26 [ADDED] - is_llr_prime(p) For k*2^n-1, returns -1, 0, or 2 - lucasu(P, Q, k) U_k for Lucas(P,Q) - lucasv(P, Q, k) V_k for Lucas(P,Q) [PERFORMANCE] - is_prime will prove many Proth-form (h*2^n+1) numbers. - is_provable_prime tries less hard to make a BLS75-T5 proof. Certs may be longer, but performance is better. - is_power is more efficient (recursion removed, only prime powers checked). 0.28 2014-11-17 [ADDED] - is_mersenne_prime(p) returns 1 iff 2^p-1 is prime [PERFORMANCE] - is_prime will do a LLR test, as will is_provable_prime if not returning a certificate. This means many primes of the form k*2^n-1 will run faster and return 2 rather than 1. - Update UV SQUFOF factoring code, faster factoring once reduced in size. - Slightly better P-1 stage 2 performance. - Slightly deeper trial division in general factoring. - Big reduction in average depth of unfactored stack. We work on smaller composite factors first, and add repeated factors all at once. This fixes some pathological inputs such as: vecprod( map { $_*($_+2)**17 } @{twin_primes(100000,115000)} ) which has 2574 factors and would overflow the 256-element stack. With the new code it has a maximum stack depth of 3. [OTHER] - is_power works with negative powers, although doesn't return root. 0.27 2014-10-07 [PERFORMANCE] - Minor changes to factor recipe, should give a little speedup. - Cache ~32k worth of small primes to give a little speedup in many places. - Switch to my original AGM code, slightly faster for large values. - Add Goetgheluck binomial code, and switch to mpz_bin_uiui for builtin. For large inputs this can be thousands of times faster than mpz_bin_ui. [OTHER] - Don't use mp_bitcnt_t -- old GMPs don't have this type. 0.26 2014-09-26 [ADDED] - stirling(n,m,[type]) Stirling numbers of first,second,third kind - vecprod(list) product of a list of integers [OTHER] - Cleanup invmod, etc. XS parser. Smaller code. - Fixed some leaked mpz_t / mpz_f objects. 0.25 2014-09-23 - Fixed compiler warning (error for some compilers). - prev_prime uses a sieve for 200+ bits. 20% speedup for large inputs. 0.24 2014-09-22 [ADDED] - sieve_primes(low,high[,k]) sieve for primes, partial or BPSW - is_frobenius_pseudoprime(n,[a,b]) Frobenius quadratic primality test - is_perrin_pseudoprime(n) Perrin primality test - factorial(n) n! - bernfrac returns (num,den) of Bernoulli number - Pi([digits]) Pi with requested number of digits [OTHER] - next_prime will use a partial sieve for 120+ bit inputs. For large inputs this is a 15-30% speedup. For 2469*2617#/93030-12182 I get: = 392.2s OpenPFGW 3.7.7 = 220.6s Pari/GP 2.6.2 = 128.4s GMP 5.0.2 mpz_nextprime = 57.6s old MPU = 45.5s new MPU - New version of Frobenius-Underwood test to match the 2014 draft paper. This is just a code refresh and has no other effect. - BLS75 with effort 1 toned down. This makes is_prime with 65- to 200-bit inputs faster, though a bit less likely to return with the value 2 rather than 1. It's a couple percent fewer, but 10-60% faster. 0.23 2014-08-16 - Fat comma isn't fat for numbers, garbled test hashes on 32-bit. 0.22 2014-08-16 [ADDED] - moebius(n[,nhi]) Moebius function (single or ranged) - liouville(n) Liouville function - totient(n) Euler's Totient function (single) - jordan_totient(k, n) Jordan totient - carmichael_lambda(n) Carmichael Lambda (reduced totient) - znorder(a, n) multiplicative order of a mod n - znprimroot(n) least primitive root of n [OTHER] - Moved factoring loop out of XS file. - factor does much better power splitting, similar to MPU 0.38's code: time mpu 'use bigint; my $n = next_prime(10**20)**200; say join(" ", map {"[@$_]"} factor_exp($n));' time mpu 'use bigint; my $n = next_prime(10**21)**200 * next_prime(10**20)**200; say join(" ", map {"[@$_]"} factor_exp($n));' - Fix spelling of Paul Zimmermann's name (thanks to Mathew @ mersenneforum) - Standalone ECPP now does expression parsing using the GMP 6.0.0a demo code. Version bumped to 1.04. 0.21 2014-06-19 - Used a bare 64-bit in a test. Wrap in quotes. 0.20 2014-06-18 [ADDED] - valuation(a,b) how many times does b divide a? - invmod(a,n) inverse of a modulo n - is_pseudoprime(n,base) Simple Fermat test - binomial(n,k) binomial coefficient - gcdext(a,b) extended Euclidian algorithm - vecsum(...) sum list of integers [OTHER] - 10%-ish speedup for next/prev prime with 38-950 digit inputs. 0.19 2014-04-21 [ADDED] - is_power - exp_mangoldt [FIXES] - Fixed string shortcut for simple divisibility. is_prime and related functions are a bit faster when given inputs divisible by 2 or 5. [OTHER] - Add improved AKS parameter selection. About 200x faster, though still thousands of times slower than APR-CL or ECPP. Updated times for the example in the v0.10 entry: Timing for 10**100+267: AKS: ~5 days. BLS75 n-1: ~3 minutes. APR-CL: 0.09 seconds ECPP: 0.05 seconds. - ECPP performance adjustments, version 1.03 of standalone ECPP. - Updated ECPP class polynomial data. Default "tiny" table had very minor changes. The "big" table (in the github xt/ directory, default for standalone ECPP) removed some large coefficient 17-24 degree polys to make room for many more higher-degree polys. For some ranges this may mean more backtracking, but should expand the input size that is able to find good discriminants without high factoring effort. "prob" below is summing the estimate 1/2H: 9x more polys and 66x larger size gives on average about 3x more candidates. Default "tiny" table: OLD: 30373 bytes 604 polys 24 maxdeg 42.0 prob 1450 prob/MB NEW: 30422 bytes 611 polys 25 maxdeg 42.8 prob 1475 prob/MB "big" table at www.probableprime.org/ecpp/cpd/big/class_poly_data.h.gz OLD: 2032376 bytes 3197 polys 117 maxdeg 104.5 prob 54 prob/MB NEW: 2005072 bytes 5271 polys 85 maxdeg 125.2 prob 65 prob/MB "huge" table at www.probableprime.org/ecpp/cpd/huge/class_poly_data.h.gz 15724395 bytes 14571 polys 128 maxdeg 207.9 prob 14 prob/MB 0.18 2014-01-27 [FIXES] - Fix for 5.6.2 (undefined symbol). - Fix for unsigned long != UV, reported by CHORNY. 0.17 2014-01-24 [ADDED] - is_bpsw_prime specific BPSW-only test - gcd 20-50x faster than Math::BigInt - lcm 3-800x faster than Math::BigInt - kronecker [FIXES] - Factoring with a number or intermediate near the word boundary would hang or run very slow. Thanks to Hugo van der Sanden for the report. - Next version of vcert.c, which handles some new Primo changes. 0.16 2013-10-28 [ADDED] - partitions partition function p(n), OEIS A000041 [FIXES] - Fixed memory leak in Lucas sequence (is_prime, next_prime, etc.). - is_aks_prime wasn't properly checking divisibility for composites. [Scripts and Programs Added] - verify_primegap.pl parallel prime gap verification 0.15 2013-09-30 [Functions Added] - miller_rabin_random - A tree sieve is done in trial factor for large (900+ digits) inputs. This improves performance greatly for very large inputs. - is_prob_prime uses more trial division for large inputs. For very large inputs (e.g. 50,000+ digits) this can greatly speed up probable prime testing, for instance in next_prime or similar sieving. Time for next_prime(99992 * 10**10101 - 100): 1m 4s MPUGMP 0.15 3m 34s Pari/GP (needs 450MB of stack!) 4m 1s mpz_nextprime 9m 33s Math::Primality - Use shallow product tree for primorials. Large primorials are 2 to 12 times faster. Break consecutive_integer_lcm into four sub-products so it runs 2-4x faster for large inputs. - Trim ECPP and adjust its heuristics. - Standalone ECPP now has consistent return codes, making it easier to use in applications without having to parse return text. The return codes are consistent with the certificate verifier. - factor() in scalar context is now consistent. 0.14 2013-08-07 - Fix small certificates leaving out the "N " for small numbers. 0.13 2013-08-06 [API Changes] - Primality proofs now use a text certificate. This is nicer for external interaction, but is a change from previous behavior. You will need to use Math::Prime::Util 0.30 or newer. [Functions Added] - lucas_sequence - is_almost_extra_strong_lucas_pseudoprime - is_frobenius_underwood_pseudoprime - pplus1_factor [Enhancements] - is_prob_prime now uses the extra-strong Lucas test instead of the strong Lucas test. This gives better performance. is_prime and is_provable_prime also incorporate the change. - Added more trial division to is_prob_prime for big (100+ digit) numbers. This is a significant speedup for next_prime in many cases. Pari/gp 2.6.0 nextprime(10^4000) 19 minutes MPU:GMP 0.12 next_prime(10**4000) 15 minutes MPU:GMP 0.13 next_prime(10**4000) 8 minutes - ECPP now tries partial n-1 and n+1 proofs (BLS theorem 3 / 15) at each step, and adds a couple additional quick factoring tests. This mainly helps lower the time variability with large inputs. - Updated ECPP polynomials. Should give better performance with larger inputs. [Scripts and Programs Added] - convert-primo-cert.pl convert a Primo certificate to MPU format. - verify-cert.pl Verify a Primo or MPU certificate. - vcert.c Verify a Primo or MPU certificate. 0.12 2013-06-12 - add standard and extra strong Lucas probable prime tests. - Rearrange C code to allow standalone build of ECPP. - Speedups for ECPP. 0.11 2013-05-20 - is_prob_prime is faster at finding composites. - rewrote Lucas inner loop for ~20% speedup. - The previous two changes make is_prob_prime a bit faster, which means a small speedup to almost all functions. - Lower is_prime proving effort. Proves ~30% of 128-bit primes instead of 50%, but runs about 4x faster. - Change ECPP to factor all strategy with backtracking. Not much difference below 200 digits, but a big help after that. Certificates are identical. 0.10 2013-05-07 - ECPP -- a much faster primality prover. BLS75 n-1 works well to about 40 digits, then slows down rapidly. This ECPP implementation is good to 300-500 digits. Timing for 10**100+267: AKS: ~1 year. BLS75 n-1: 1.5-5 minutes. ECPP: 0.1 seconds. - is_prime does an additional 4 random-base M-R tests. - is_provable_prime will try a quick n-1 then do ECPP. - is_nminus1_prime added to give access to that specific method, in case someone has reason to insist on that proof type. - Change polynomial multiplication to use binary segmentation. Huge speed improvement for AKS primality proving (20-100x faster). AKS is now faster in GMP than MPU's C code. It's still not nearly as fast as other methods: proving 100000000003 takes 65 seconds, while this would take a couple milliseconds at most for an n-1 proof. The one year estimate in the first paragraph is with the _new_ code. - Compile-time support to BLS75 theorem 7, which reduces the amount of n-1 we need to factor. Not enabling because it just doesn't help enough, and ECPP is a better place to spend development effort. - Lots of new internal functions to support ECPP, which could be used for future projects. 0.09 2013-04-21 - Add primality certificate generation. 0.08 2013-04-05 - Switch to a projective ECM with a stage 2. Much better results, but note that it doesn't build up to B1 like the old version. This has a big impact on factoring and primality proving. - Add a QS based on William Hart's SIMPQS (a simple QS that is a predecessor to what went into FLINT). Not the fastest by a long shot (yafu and msieve take that prize), but it's quite small and works pretty well. Eventually this will get replaced with a home-built QS. Meanwhile some improvements from version 2.0 that remain are (1) no partial relations, (2) uses too much memory, and (3) uses GE instead of jasonp's block Lanczos. - The new ECM and QS make factoring much faster, especially for 30+ digit inputs. Factoring should give reasonable times out to 70+ digits now. Time is competitive with Math::Pari now, and often faster (noting that Math::Pari uses a fairly old version of Pari). - Factoring mix redone given the big changes in ECM and QS. - Primality proofs adjusted to better use p-1 and ECM. The quick proof in is_prime has a higher success rate for all input sizes and is a little faster for small numbers. is_provable_prime is 10-50x faster. 0.07 2013-03-19 - Tiny speedup when passing in bigints. - Some speedups in pbrent, pbrent usage, and small prime iterator. Factoring small (< ~30 digit) numbers is faster. - Handle large and small M-R bases just like MPU does -- mod with n, then return 1 if base <= 1 or base >= n-1. 0.06 2012-12-17 - Fix 1-byte memory overrun (thanks to CPAN Testers, Solaris, Valgrind). - Add factoring of small numbers. Helps a little when the input gets reduced enough to fit into a UV. 0.05 2012-12-15 - Add AKS primality test. Super slow, but nice to have around. - ECM is faster. - Add a small prime iterator, which means _much_ less memory and faster operation for big smoothness factors in pminus1 and ecm factoring. 0.04 2012-11-11 - Add simple prime_count function. It uses next_prime so is terribly slow for big ranges. However it's a lot faster than the PP code when given a large base and small range e.g. (10**96, 10**96 + 2**18). - Add primorial, pn_primorial, and consecutive_integer_lcm functions. - Factoring: Add a perfect power test. Add a simple ECM factoring method. Speed up SQUFOF a bit. Complete p-1 rewrite. Much faster and finds more factors. Adjust general factor() mix. - Add Pocklington-Lehmer and BLS primality tests. is_prime() uses the BLS test with a quick factoring attempt for numbers less than 2^200, though the chances of success drop off as the size increases. The point is not to cull mismarked probable primes (we use BPSW so this is highly unlikely for these small sizes), but to quickly mark more numbers as definitely prime. Remember to use is_prob_prime if you do not care about this distinction and want the result slightly faster. - add is_provable_prime function that calls BLS with much more aggressive factoring. 0.03 2012-07-16 - XS callable: _lcm_of_consecutive_integers(B) which is a better alternative for B! for many factoring algorithms. - Fix some minor compile issues. 0.02 2012-07-15 - Factoring tests assumed 64-bit. Rewrite. 0.01 2012-07-15 - Initial release Math-Prime-Util-GMP-0.52/ecpp.c0000644000175000017500000011400613663067455014443 0ustar danadana/***************************************************************************** * * ECPP - Elliptic Curve Primality Proving * * Copyright (c) 2013-2014 Dana Jacobsen (dana@acm.org). * This is free software; you can redistribute it and/or modify it under * the same terms as the Perl 5 programming language system itself. * * This file is part of the Math::Prime::Util::GMP Perl module. A script * is included to build this as a standalone program (see the README file). * * This is pretty good for numbers less than 800 digits. Over that, it needs * larger discriminant sets. Comparing to other contemporary software: * * - Primo is much faster for inputs over 300 digits. Not open source. * - mpz_aprcl 1.1 (APR-CL). Nearly the same speed to ~600 digits, with * very little speed variation. Faster over 800 digits. No certificate. * - GMP-ECPP is much slower at all sizes, and nearly useless > 300 digits. * - AKS is stupendously slow, even with Bernstein and Voloch improvements. * - François Morain's 10-20 year old work describes optimizations not * present here, but his (very old!) binaries run slower than this code at * all sizes. Not open source. * * A set of fixed discriminants are used, rather than calculating them as * needed. Having a way to calculate values as needed would be a big help. * In the interests of space for the MPU package, I've chosen ~600 values which * compile into about 35k of data. This is about 1/5 of the entire code size * for the MPU package. The github repository includes an expanded set of 5271 * discriminants that compile to 2MB. This is recommended if proving 300+ * digit numbers is a regular occurrence. There is a set available for download * with almost 15k polys, taking 15.5MB. * * This version uses the FAS "factor all strategy", meaning it first constructs * the entire factor chain, with backtracking if necessary, then will do the * elliptic curve proof as it recurses back. * * If your goal is primality proofs for very large numbers, use Primo. It's * free, it is very fast, it is widely used, it can process batch results, * and it makes independently verifiable certificates (including the verifier * included in this package). MPU's ECPP (this software) is an open source * alternative with many of the same features for "small" numbers of <1000 * digits. Improvements are possible since it is open source. * * Another open source alternative if one does not need certificates is the * mpz_aprcl code from David Cleaver. To about 600 digits the speeds are * very similar, but past that this ECPP code starts slowing down. * * Thanks to H. Cohen, R. Crandall & C. Pomerance, and H. Riesel for their * text books. Thanks to the authors of open source software who allow me * to compare and contrast (GMP-ECM, GMP-ECPP). Thanks to the authors of GMP. * Thanks to Schoof, Goldwasser, Kilian, Atkin, Morain, Lenstra, etc. for all * the math and publications. Thanks to Gauss, Euler, et al. * * The ECM code in ecm.c was heavily influenced by early GMP-ECM work by Paul * Zimmermann, as well as all the articles of Montgomery, Bosma, Lentra, * Cohen, and others. */ #include #include #include #include #include #include "ptypes.h" #include "ecpp.h" #include "gmp_main.h" /* primorial */ #include "ecm.h" #include "utility.h" #include "prime_iterator.h" #include "bls75.h" #include "factor.h" #include "primality.h" #define MAX_SFACS 1000 #ifdef USE_LIBECM #include #endif #ifdef USE_APRCL #include "mpz_aprcl.h" #include "mpz_aprcl.c" #endif /*********** big primorials and lcm for divisibility tests **********/ static int _gcdinit = 0; static mpz_t _gcd_small; static mpz_t _gcd_large; void init_ecpp_gcds(UV nsize) { if (_gcdinit == 0) { mpz_init(_gcd_small); mpz_init(_gcd_large); _GMP_pn_primorial(_gcd_small, 3000); /* This is never re-adjusted -- first number proved sets the size */ nsize *= 20; if (nsize < 20000) nsize = 20000; else if (nsize > 500000) nsize = 500000; _GMP_pn_primorial(_gcd_large, nsize); mpz_divexact(_gcd_large, _gcd_large, _gcd_small); mpz_divexact_ui(_gcd_small, _gcd_small, 2*3*5); _gcdinit = 1; } } void destroy_ecpp_gcds(void) { if (!_gcdinit) return; mpz_clear(_gcd_small); mpz_clear(_gcd_large); _gcdinit = 0; } /* We could use a function with a prefilter here, but my tests are showing * that adding a Fermat test (ala GMP's is_probab_prime) is slower than going * straight to the base-2 Miller-Rabin test we use in BPSW. */ #define is_bpsw_prime(n) _GMP_BPSW(n) static int check_for_factor(mpz_t f, mpz_t inputn, mpz_t fmin, mpz_t n, int stage, mpz_t* sfacs, int* nsfacs, int degree) { int success, sfaci; UV B1; /* Use this so we don't modify their input value */ mpz_set(n, inputn); if (mpz_cmp(n, fmin) <= 0) return 0; #if 0 /* Use this to really encourage n-1 / n+1 proof types */ if (degree <= 0) { if (stage == 1) return -1; if (stage == 0) stage = 1; } #endif /* Utilize GMP's fast gcd algorithms. Trial to 224737+ with two gcds. */ mpz_tdiv_q_2exp(n, n, mpz_scan1(n, 0)); while (mpz_divisible_ui_p(n, 3)) mpz_divexact_ui(n, n, 3); while (mpz_divisible_ui_p(n, 5)) mpz_divexact_ui(n, n, 5); if (mpz_cmp(n, fmin) <= 0) return 0; mpz_gcd(f, n, _gcd_small); while (mpz_cmp_ui(f, 1) > 0) { mpz_divexact(n, n, f); mpz_gcd(f, f, n); } if (mpz_cmp(n, fmin) <= 0) return 0; mpz_gcd(f, n, _gcd_large); while (mpz_cmp_ui(f, 1) > 0) { mpz_divexact(n, n, f); mpz_gcd(f, f, n); } sfaci = 0; success = 1; while (success) { UV nsize = mpz_sizeinbase(n, 2); const int do_pm1 = 1; const int do_pp1 = 1; const int do_pbr = 0; const int do_ecm = 0; if (mpz_cmp(n, fmin) <= 0) return 0; if (is_bpsw_prime(n)) { mpz_set(f, n); return (mpz_cmp(f, fmin) > 0); } success = 0; B1 = 300 + 3 * nsize; if (degree <= 2) B1 += nsize; /* D1 & D2 are cheap to prove. */ if (degree <= 0) B1 += 2*nsize; /* N-1 and N+1 are really cheap. */ if (degree > 20 && stage <= 1) B1 -= nsize; /* Less time on big polys. */ if (degree > 40) B1 -= nsize/2; /* Less time on big polys. */ if (stage == 0) { /* A relatively small performance hit, makes slightly smaller proofs. */ if (nsize < 900 && degree <= 2) B1 *= 1.8; /* We need to try a bit harder for the large sizes :( */ if (nsize > 1400) B1 *= 2; if (nsize > 2000) B1 *= 2; if (!success) success = _GMP_pminus1_factor(n, f, 100+B1/8, 100+B1); } else if (stage >= 1) { /* P-1 */ if ((!success && do_pm1)) success = _GMP_pminus1_factor(n, f, B1, 6*B1); /* Pollard's Rho */ if ((!success && do_pbr && nsize < 500)) success = _GMP_pbrent_factor(n, f, nsize % 53, 1000-nsize); /* P+1 */ if ((!success && do_pp1)) { UV ppB = (nsize < 2000) ? B1/4 : B1/16; success = _GMP_pplus1_factor(n, f, 0, ppB, ppB); } if ((!success && do_ecm)) success = _GMP_ecm_factor_projective(n, f, 400, 2000, 1); #ifdef USE_LIBECM /* TODO: LIBECM in other stages */ /* Note: this will be substantially slower than our code for small sizes * and the small B1/B2 values we're using. */ if (!success && degree <= 2 && nsize > 600) { ecm_params params; ecm_init(params); params->method = ECM_ECM; mpz_set_ui(params->B2, 10*B1); mpz_set_ui(params->sigma, 0); success = ecm_factor(f, n, B1/4, params); ecm_clear(params); if (mpz_cmp(f, n) == 0) success = 0; if (success) { printf("ECM FOUND FACTOR\n"); } } #endif } /* Try any factors found in previous stage 2+ calls */ while (!success && sfaci < *nsfacs) { if (mpz_divisible_p(n, sfacs[sfaci])) { mpz_set(f, sfacs[sfaci]); success = 1; } sfaci++; } if (stage > 1 && !success) { if (stage == 2) { /* if (!success) success = _GMP_pbrent_factor(n, f, nsize-1, 8192); */ if (!success) success = _GMP_pminus1_factor(n, f, 6*B1, 60*B1); /* p+1 with different initial point and searching farther */ if (!success) success = _GMP_pplus1_factor(n, f, 1, B1/2, B1/2); if (!success) success = _GMP_ecm_factor_projective(n, f, 250, 2500, 8); } else if (stage == 3) { if (!success) success = _GMP_pbrent_factor(n, f, nsize+1, 16384); if (!success) success = _GMP_pminus1_factor(n, f, 60*B1, 600*B1); /* p+1 with a third initial point and searching farther */ if (!success) success = _GMP_pplus1_factor(n, f, 2, 1*B1, 1*B1); if (!success) success = _GMP_ecm_factor_projective(n, f, B1/4, B1*4, 5); } else if (stage == 4) { if (!success) success = _GMP_pminus1_factor(n, f, 300*B1, 300*20*B1); if (!success) success = _GMP_ecm_factor_projective(n, f, B1/2, B1*8, 4); } else if (stage >= 5) { UV B = B1 * (stage-4) * (stage-4) * (stage-4); if (!success) success = _GMP_ecm_factor_projective(n, f, B, 10*B, 8+stage); } } if (success) { if (mpz_cmp_ui(f, 1) == 0 || mpz_cmp(f, n) == 0) { gmp_printf("factoring %Zd resulted in factor %Zd\n", n, f); croak("internal error in ECPP factoring"); } /* Add the factor to the saved factors list */ if (stage > 1 && *nsfacs < MAX_SFACS) { /* gmp_printf(" ***** adding factor %Zd ****\n", f); */ mpz_init_set(sfacs[*nsfacs], f); nsfacs[0]++; } /* Is the factor f what we want? */ if ( mpz_cmp(f, fmin) > 0 && is_bpsw_prime(f) ) return 1; /* Divide out f */ mpz_divexact(n, n, f); } } /* n is larger than fmin and not prime */ mpz_set(f, n); return -1; } /* See: * (1) Kaltofen, Valente, Yui 1989 * (2) Valente 1992 (Thesis) * (3) Konstantinou, Stamatiou, and Zaroliagis (CHES 2002) * This code is performing table 1 of reference 3. */ static void weber_root_to_hilbert_root(mpz_t r, mpz_t N, long D) { mpz_t A, t; if (D < 0) D = -D; D = ((D % 4) == 0) ? D/4 : D; if ( (D % 8) == 0 ) return; mpz_init(A); mpz_init(t); switch (D % 8) { case 1: if ((D % 3) != 0) mpz_powm_ui(t, r, 12, N); else mpz_powm_ui(t, r, 4, N); mpz_mul_ui(A, t, 64); mpz_sub_ui(t, A, 16); break; case 2: case 6: if ((D % 3) != 0) mpz_powm_ui(t, r, 12, N); else mpz_powm_ui(t, r, 4, N); mpz_mul_ui(A, t, 64); mpz_add_ui(t, A, 16); break; case 5: if ((D % 3) != 0) mpz_powm_ui(t, r, 6, N); else mpz_powm_ui(t, r, 2, N); mpz_mul_ui(A, t, 64); mpz_sub_ui(t, A, 16); break; case 7: if (!mpz_invert(t, r, N)) mpz_set_ui(t, 0); if ((D % 3) != 0) mpz_powm_ui(A, t, 24, N); else mpz_powm_ui(A, t, 8, N); mpz_sub_ui(t, A, 16); break; /* Results in degree 3x Hilbert, so typically not used */ case 3: if (!mpz_invert(t, r, N)) mpz_set_ui(t, 0); if ((D % 3) != 0) { mpz_powm_ui(t, t, 24, N); mpz_mul_2exp(A, t, 12); } else { mpz_powm_ui(t, t, 8, N); mpz_mul_2exp(A, t, 4); } mpz_sub_ui(t, A, 16); break; default: break; } /* r = t^3 / A */ mpz_powm_ui(t, t, 3, N); if ( ! mpz_divmod(r, t, A, N, r) ) mpz_set_ui(r, 0); mpz_clear(A); mpz_clear(t); } /* See: * Konstantinou and Kontogeorgis (2008) https://arxiv.org/abs/0804.1652 * http://www.math.leidenuniv.nl/~psh/konto5.pdf */ static void ramanujan_root_to_hilbert_root(mpz_t r, mpz_t N, long D) { mpz_t A, t; if (D < 0) D = -D; if (D % 24 != 11) return; /* croak("Bad Ramanujan root D: %ld", D); */ mpz_init(A); mpz_init(t); if (!mpz_invert(t, r, N)) mpz_set_ui(t, 0); mpz_powm_ui(A, t, 6, N); mpz_mul_ui(A, A, 27); mpz_powm_ui(t, r, 6, N); mpz_sub(A, t, A); mpz_sub_ui(A, A, 6); mpz_powm_ui(r, A, 3, N); /* mpz_powm_ui(t, A, 3, N); * gmp_printf("Converted Ramanujan root %Zd to Hilbert %Zd\n", r, t); * mpz_set(r, t); */ mpz_clear(A); mpz_clear(t); } static int find_roots(long D, int poly_index, mpz_t N, mpz_t** roots, int maxroots) { mpz_t* T; UV degree; long dT, i, nroots; int poly_type; if (D == -3 || D == -4) { *roots = 0; return 1; } degree = poly_class_poly_num(poly_index, NULL, &T, &poly_type); if (degree == 0 || (poly_type != 1 && poly_type != 2 && poly_type != 3)) return 0; dT = degree; polyz_mod(T, T, &dT, N); polyz_roots_modp(roots, &nroots, maxroots, T, dT, N); if (nroots == 0) { gmp_printf("N = %Zd\n", N); croak("Failed to find roots for D = %ld\n", D); } for (i = 0; i <= dT; i++) mpz_clear(T[i]); Safefree(T); #if 0 if (nroots != dT && get_verbose_level()) printf(" found %ld roots of the %ld degree poly\n", nroots, dT); #endif /* Convert Weber and Ramanujan roots to Hilbert roots */ if (poly_type == 2) for (i = 0; i < nroots; i++) weber_root_to_hilbert_root((*roots)[i], N, D); if (poly_type == 3) for (i = 0; i < nroots; i++) ramanujan_root_to_hilbert_root((*roots)[i], N, D); return nroots; } static void select_curve_params(mpz_t a, mpz_t b, mpz_t g, long D, mpz_t *roots, long i, mpz_t N, mpz_t t) { int N_is_not_1_congruent_3; mpz_set_ui(a, 0); mpz_set_ui(b, 0); if (D == -3) { mpz_set_si(b, -1); } else if (D == -4) { mpz_set_si(a, -1); } else { mpz_sub_ui(t, roots[i], 1728); mpz_mod(t, t, N); /* c = (j * inverse(j-1728)) mod n */ if (mpz_divmod(b, roots[i], t, N, b)) { mpz_mul_si(a, b, -3); /* r = -3c */ mpz_mul_si(b, b, 2); /* s = 2c */ } } mpz_mod(a, a, N); mpz_mod(b, b, N); /* g: 1 < g < Ni && (g/Ni) != -1 && (g%3!=1 || cubic non-residue) */ N_is_not_1_congruent_3 = ! mpz_congruent_ui_p(N, 1, 3); for ( mpz_set_ui(g, 2); mpz_cmp(g, N) < 0; mpz_add_ui(g, g, 1) ) { if (mpz_jacobi(g, N) != -1) continue; if (N_is_not_1_congruent_3) break; mpz_sub_ui(t, N, 1); mpz_tdiv_q_ui(t, t, 3); mpz_powm(t, g, t, N); /* t = g^((Ni-1)/3) mod Ni */ if (mpz_cmp_ui(t, 1) == 0) continue; if (D == -3) { mpz_powm_ui(t, t, 3, N); if (mpz_cmp_ui(t, 1) != 0) /* Additional check when D == -3 */ continue; } break; } if (mpz_cmp(g, N) >= 0) /* No g can be found: N is composite */ mpz_set_ui(g, 0); } static void select_point(mpz_t x, mpz_t y, mpz_t a, mpz_t b, mpz_t N, mpz_t t, mpz_t t2) { mpz_t Q, t3, t4; mpz_init(Q); mpz_init(t3); mpz_init(t4); mpz_set_ui(y, 0); while (mpz_sgn(y) == 0) { /* select a Q s.t. (Q,N) != -1 */ do { do { /* mpz_urandomm(x, *p_randstate, N); */ mpz_isaac_urandomb(x, 32); /* May as well make x small */ mpz_mod(x, x, N); } while (mpz_sgn(x) == 0); mpz_mul(t, x, x); mpz_add(t, t, a); mpz_mul(t, t, x); mpz_add(t, t, b); mpz_mod(Q, t, N); } while (mpz_jacobi(Q, N) == -1); /* Select Y */ sqrtmod_t(y, Q, N, t, t2, t3, t4); /* TODO: if y^2 mod Ni != t, return composite */ if (mpz_sgn(y) == 0) croak("y == 0 in point selection\n"); } mpz_clear(Q); mpz_clear(t3); mpz_clear(t4); } /* Returns 0 (composite), 1 (didn't find a point), 2 (found point) */ int ecpp_check_point(mpz_t x, mpz_t y, mpz_t m, mpz_t q, mpz_t a, mpz_t N, mpz_t t, mpz_t t2) { struct ec_affine_point P, P1, P2; int result = 1; mpz_init_set(P.x, x); mpz_init_set(P.y, y); mpz_init(P1.x); mpz_init(P1.y); mpz_init(P2.x); mpz_init(P2.y); mpz_tdiv_q(t, m, q); if (!ec_affine_multiply(a, t, N, P, &P2, t2)) { mpz_tdiv_q(t, m, q); /* P2 should not be (0,1) */ if (!(mpz_cmp_ui(P2.x, 0) == 0 && mpz_cmp_ui(P2.y, 1) == 0)) { mpz_set(t, q); if (!ec_affine_multiply(a, t, N, P2, &P1, t2)) { /* P1 should be (0,1) */ if (mpz_cmp_ui(P1.x, 0) == 0 && mpz_cmp_ui(P1.y, 1) == 0) { result = 2; } } else result = 0; } } else result = 0; mpz_clear(P.x); mpz_clear(P.y); mpz_clear(P1.x); mpz_clear(P1.y); mpz_clear(P2.x); mpz_clear(P2.y); return result; } static void update_ab(mpz_t a, mpz_t b, long D, mpz_t g, mpz_t N) { if (D == -3) { mpz_mul(b, b, g); } else if (D == -4) { mpz_mul(a, a, g); } else { mpz_mul(a, a, g); mpz_mul(a, a, g); mpz_mul(b, b, g); mpz_mul(b, b, g); mpz_mul(b, b, g); } mpz_mod(a, a, N); mpz_mod(b, b, N); } /* Once we have found a D and q, this will find a curve and point. * Returns: 0 (composite), 1 (didn't work), 2 (success) * It's debatable what to do with a 1 return. */ static int find_curve(mpz_t a, mpz_t b, mpz_t x, mpz_t y, long D, int poly_index, mpz_t m, mpz_t q, mpz_t N, int maxroots) { long nroots, npoints, i, rooti, unity, result; mpz_t g, t, t2; mpz_t* roots = 0; /* TODO: A better way to do this, I believe, would be to have the root * finder set up as an iterator. That way we'd get the first root, * try to find a curve, and probably we'd be done. Only if we tried * 10+ points on that root would we get another root. This would * probably be set up as a stack (array) of polynomials plus one * saved root (for when we solve a degree 2 poly). */ /* Step 1: Get the roots of the Hilbert class polynomial. */ nroots = find_roots(D, poly_index, N, &roots, maxroots); if (nroots == 0) return 1; /* Step 2: Loop selecting curves and trying points. * On average it takes about 3 points, but we'll try 100+. */ mpz_init(g); mpz_init(t); mpz_init(t2); npoints = 0; result = 1; for (rooti = 0; result == 1 && rooti < 50*nroots; rooti++) { /* Given this D and root, select curve a,b */ select_curve_params(a, b, g, D, roots, rooti % nroots, N, t); if (mpz_sgn(g) == 0) { result = 0; break; } /* See Cohen 5.3.1, page 231 */ unity = (D == -3) ? 6 : (D == -4) ? 4 : 2; for (i = 0; result == 1 && i < unity; i++) { if (i > 0) update_ab(a, b, D, g, N); npoints++; select_point(x, y, a, b, N, t, t2); result = ecpp_check_point(x, y, m, q, a, N, t, t2); } } if (npoints > 10 && get_verbose_level() > 0) printf(" # point finding took %ld points\n", npoints); if (roots != 0) { for (rooti = 0; rooti < nroots; rooti++) mpz_clear(roots[rooti]); Safefree(roots); } mpz_clear(g); mpz_clear(t); mpz_clear(t2); return result; } /* Select the 2, 4, or 6 numbers we will try to factor. */ static void choose_m(mpz_t* mlist, long D, mpz_t u, mpz_t v, mpz_t N, mpz_t t, mpz_t Nplus1) { int i, j; mpz_add_ui(Nplus1, N, 1); mpz_sub(mlist[0], Nplus1, u); /* N+1-u */ mpz_add(mlist[1], Nplus1, u); /* N+1+u */ for (i = 2; i < 6; i++) mpz_set_ui(mlist[i], 0); if (D == -3) { /* If reading Cohen, be sure to see the errata for page 474. */ mpz_mul_si(t, v, 3); mpz_add(t, t, u); mpz_tdiv_q_2exp(t, t, 1); mpz_sub(mlist[2], Nplus1, t); /* N+1-(u+3v)/2 */ mpz_add(mlist[3], Nplus1, t); /* N+1+(u+3v)/2 */ mpz_mul_si(t, v, -3); mpz_add(t, t, u); mpz_tdiv_q_2exp(t, t, 1); mpz_sub(mlist[4], Nplus1, t); /* N+1-(u-3v)/2 */ mpz_add(mlist[5], Nplus1, t); /* N+1+(u-3v)/2 */ } else if (D == -4) { mpz_mul_ui(t, v, 2); mpz_sub(mlist[2], Nplus1, t); /* N+1-2v */ mpz_add(mlist[3], Nplus1, t); /* N+1+2v */ } /* m must not be prime */ for (i = 0; i < 6; i++) if (mpz_sgn(mlist[i]) && _GMP_is_prob_prime(mlist[i])) mpz_set_ui(mlist[i], 0); /* Sort the m values so we test the smallest first */ for (i = 0; i < 5; i++) if (mpz_sgn(mlist[i])) for (j = i+1; j < 6; j++) if (mpz_sgn(mlist[j]) && mpz_cmp(mlist[i],mlist[j]) > 0) mpz_swap( mlist[i], mlist[j] ); } /* This is the "factor all strategy" FAS version, which ends up being a lot * simpler than the FPS code. * * It should have a little more smarts for not repeating work when repeating * steps. This could be complicated trying to save all state, but I think we * could get most of the benefit by keeping a simple list of all factors * found after stage 1, and we just try each of them. */ #define VERBOSE_PRINT_N(step, ndigits, maxH, factorstage) \ if (verbose) { \ printf("%*sN[%d] (%d dig)", i, "", step, ndigits); \ if (factorstage > 1) printf(" [FS %d]", factorstage); \ fflush(stdout); \ } /* Recursive routine to prove via ECPP */ static int ecpp_down(int i, mpz_t Ni, int facstage, int *pmaxH, int* dilist, mpz_t* sfacs, int* nsfacs, char** prooftextptr) { mpz_t a, b, u, v, m, q, minfactor, sqrtn, mD, t, t2; mpz_t mlist[6]; mpz_t qlist[6]; UV nm1a; IV np1lp, np1lq; struct ec_affine_point P; int k, dindex, pindex, nidigits, facresult, curveresult, downresult, stage, D; int verbose = get_verbose_level(); nidigits = mpz_sizeinbase(Ni, 10); downresult = _GMP_is_prob_prime(Ni); if (downresult == 0) return 0; if (downresult == 2) { if (mpz_sizeinbase(Ni,2) <= 64) { /* No need to put anything in the proof */ if (verbose) printf("%*sN[%d] (%d dig) PRIME\n", i, "", i, nidigits); return 2; } downresult = 1; } if (i == 0 && facstage == 2 && miller_rabin_random(Ni, 2, 0) == 0) { gmp_printf("\n\n**** BPSW counter-example found? ****\n**** N = %Zd ****\n\n", Ni); return 0; } VERBOSE_PRINT_N(i, nidigits, *pmaxH, facstage); mpz_init(a); mpz_init(b); mpz_init(u); mpz_init(v); mpz_init(m); mpz_init(q); mpz_init(mD); mpz_init(minfactor); mpz_init(sqrtn); mpz_init(t); mpz_init(t2); mpz_init(P.x);mpz_init(P.y); for (k = 0; k < 6; k++) { mpz_init(mlist[k]); mpz_init(qlist[k]); } /* Any factors q found must be strictly > minfactor. * See Atkin and Morain, 1992, section 6.4 */ mpz_root(minfactor, Ni, 4); mpz_add_ui(minfactor, minfactor, 1); mpz_mul(minfactor, minfactor, minfactor); mpz_sqrt(sqrtn, Ni); stage = 0; if (nidigits > 700) stage = 1; /* Too rare to find them */ if (i == 0 && facstage > 1) stage = facstage; for ( ; stage <= facstage; stage++) { int next_stage = (stage > 1) ? stage : 1; for (dindex = -1; dindex < 0 || dilist[dindex] != 0; dindex++) { int poly_type; /* just for debugging/verbose */ int poly_degree; int allq = (nidigits < 400); /* Do all q values together, or not */ if (dindex == -1) { /* n-1 and n+1 tests */ int nm1_success = 0; int np1_success = 0; const char* ptype = ""; mpz_sub_ui(m, Ni, 1); mpz_sub_ui(t2, sqrtn, 1); mpz_tdiv_q_2exp(t2, t2, 1); /* t2 = minfactor */ nm1_success = check_for_factor(u, m, t2, t, stage, sfacs, nsfacs, 0); mpz_add_ui(m, Ni, 1); mpz_add_ui(t2, sqrtn, 1); mpz_tdiv_q_2exp(t2, t2, 1); /* t2 = minfactor */ np1_success = check_for_factor(v, m, t2, t, stage, sfacs, nsfacs, 0); /* If both successful, pick smallest */ if (nm1_success > 0 && np1_success > 0) { if (mpz_cmp(u, v) <= 0) np1_success = 0; else nm1_success = 0; } if (nm1_success > 0) { ptype = "n-1"; mpz_set(q, u); D = 1; } else if (np1_success > 0) { ptype = "n+1"; mpz_set(q, v); D = -1; } else continue; if (verbose) { printf(" %s\n", ptype); fflush(stdout); } downresult = ecpp_down(i+1, q, next_stage, pmaxH, dilist, sfacs, nsfacs, prooftextptr); if (downresult == 0) goto end_down; /* composite */ if (downresult == 1) { /* nothing found at this stage */ VERBOSE_PRINT_N(i, nidigits, *pmaxH, facstage); continue; } if (verbose) { printf("%*sN[%d] (%d dig) %s", i, "", i, nidigits, ptype); fflush(stdout); } curveresult = (nm1_success > 0) ? _GMP_primality_bls_3(Ni, q, &nm1a) : _GMP_primality_bls_15(Ni, q, &np1lp, &np1lq); if (verbose) { printf(" %d\n", curveresult); fflush(stdout); } if ( ! curveresult ) { /* This ought not happen */ if (verbose) gmp_printf("\n Could not prove %s with N = %Zd\n", ptype, Ni); downresult = 1; continue; } goto end_down; } pindex = dilist[dindex]; if (pindex < 0) continue; /* We marked this for skip */ /* Get the values for D, degree, and poly type */ poly_degree = poly_class_poly_num(pindex, &D, NULL, &poly_type); if (poly_degree == 0) croak("Unknown value in dilist[%d]: %d\n", dindex, pindex); if ( (-D % 4) != 3 && (-D % 16) != 4 && (-D % 16) != 8 ) croak("Invalid discriminant '%d' in list\n", D); /* D must also be squarefree in odd divisors, but assume it. */ /* Make sure we can get a class polynomial for this D. */ if (poly_degree > 16 && stage == 0) { if (verbose) printf(" [1]"); break; } /* Make the continue-search vs. backtrack decision */ if (*pmaxH > 0 && poly_degree > *pmaxH) break; mpz_set_si(mD, D); /* (D/N) must be 1, and we have to have a u,v solution */ if (mpz_jacobi(mD, Ni) != 1) continue; if ( ! modified_cornacchia(u, v, mD, Ni) ) continue; if (verbose > 1) { printf(" %d", D); fflush(stdout); } /* We're going to factor all the values for this discriminant then pick * the smallest. This adds a little time, but it means we go down * faster. This makes smaller proofs, and might even save time. */ choose_m(mlist, D, u, v, Ni, t, t2); if (allq) { int x, y; /* We have 0 to 6 m values. Try to factor them, put in qlist. */ for (k = 0; k < 6; k++) { mpz_set_ui(qlist[k], 0); if (mpz_sgn(mlist[k])) { facresult = check_for_factor(qlist[k], mlist[k], minfactor, t, stage, sfacs, nsfacs, poly_degree); /* -1 = couldn't find, 0 = no big factors, 1 = found */ if (facresult <= 0) mpz_set_ui(qlist[k], 0); } } /* Sort any q values by size, so we work on the smallest first */ for (x = 0; x < 5; x++) if (mpz_sgn(qlist[x])) for (y = x+1; y < 6; y++) if (mpz_sgn(qlist[y]) && mpz_cmp(qlist[x],qlist[y]) > 0) { mpz_swap( qlist[x], qlist[y] ); mpz_swap( mlist[x], mlist[y] ); } } /* Try to make a proof with the first (smallest) q value. * Repeat for others if we have to. */ for (k = 0; k < 6; k++) { int maxH = *pmaxH; int minH = (nidigits <= 240) ? 7 : (nidigits+39)/40; if (allq) { if (mpz_sgn(qlist[k]) == 0) continue; mpz_set(m, mlist[k]); mpz_set(q, qlist[k]); } else { if (mpz_sgn(mlist[k]) == 0) continue; mpz_set(m, mlist[k]); facresult = check_for_factor(q, m, minfactor, t, stage, sfacs, nsfacs, poly_degree); if (facresult <= 0) continue; } if (verbose) { printf(" %d (%s %d)\n", D, poly_class_type_name(poly_type), poly_degree); fflush(stdout); } if (maxH == 0) { maxH = minH-1 + poly_degree; if (facstage > 1) /* We worked hard to get here, */ maxH = 2*maxH + 10; /* try hard to make use of it. */ } else if (maxH > minH && maxH > (poly_degree+2)) { maxH--; } /* Great, now go down. */ downresult = ecpp_down(i+1, q, next_stage, &maxH, dilist, sfacs, nsfacs, prooftextptr); /* Nothing found, look at more polys in the future */ if (downresult == 1 && *pmaxH > 0) *pmaxH = maxH; if (downresult == 0) goto end_down; /* composite */ if (downresult == 1) { /* nothing found at this stage */ VERBOSE_PRINT_N(i, nidigits, *pmaxH, facstage); continue; } /* Awesome, we found the q chain and are in STAGE 2 */ if (verbose) { printf("%*sN[%d] (%d dig) %d (%s %d)", i, "", i, nidigits, D, poly_class_type_name(poly_type), poly_degree); fflush(stdout); } /* Try with only one or two roots, then 8 if that didn't work. */ /* TODO: This should be done using a root iterator in find_curve() */ curveresult = find_curve(a, b, P.x, P.y, D, pindex, m, q, Ni, 1); if (curveresult == 1) { if (verbose) { printf(" [redo roots]"); fflush(stdout); } curveresult = find_curve(a, b, P.x, P.y, D, pindex, m, q, Ni, 8); } if (verbose) { printf(" %d\n", curveresult); fflush(stdout); } if (curveresult == 1) { /* Something is wrong. Very likely the class poly coefficients are incorrect. We've wasted lots of time, and need to try again. */ dilist[dindex] = -2; /* skip this D value from now on */ if (verbose) gmp_printf("\n Invalidated D = %d with N = %Zd\n", D, Ni); downresult = 1; continue; } /* We found it was composite or proved it */ goto end_down; } /* k loop for D */ } /* D */ } /* fac stage */ /* Nothing at this level */ if (downresult != 1) croak("ECPP internal error: downresult is %d at end\n", downresult); if (verbose) { if (*pmaxH > 0) printf(" (max %d)", *pmaxH); printf(" ---\n"); fflush(stdout); } if (*pmaxH > 0) *pmaxH = *pmaxH + 2; end_down: if (downresult == 2) { if (0 && verbose > 1) { gmp_printf("\n"); if (D == 1) { gmp_printf("Type BLS3\nN %Zd\nQ %Zd\nA %"UVuf"\n", Ni, q, nm1a); } else if (D == -1) { gmp_printf("Type BLS15\nN %Zd\nQ %Zd\nLP %"IVdf"\nLQ %"IVdf"\n", Ni, q, np1lp, np1lq); } else { gmp_printf("Type ECPP\nN %Zd\nA %Zd\nB %Zd\nM %Zd\nQ %Zd\nX %Zd\nY %Zd\n", Ni, a, b, m, q, P.x, P.y); } gmp_printf("\n"); fflush(stdout); } /* Prepend our proof to anything that exists. */ if (prooftextptr != 0) { char *proofstr, *proofptr; int curprooflen = (*prooftextptr == 0) ? 0 : strlen(*prooftextptr); if (D == 1) { int myprooflen = 20 + 2*(4 + mpz_sizeinbase(Ni, 10)) + 1*21; New(0, proofstr, myprooflen + curprooflen + 1, char); proofptr = proofstr; proofptr += gmp_sprintf(proofptr, "Type BLS3\nN %Zd\nQ %Zd\n", Ni,q); proofptr += sprintf(proofptr, "A %"UVuf"\n", nm1a); } else if (D == -1) { int myprooflen = 20 + 2*(4 + mpz_sizeinbase(Ni, 10)) + 2*21; New(0, proofstr, myprooflen + curprooflen + 1, char); proofptr = proofstr; /* It seems some testers have a sprintf bug with IVs. Try to handle. */ proofptr += gmp_sprintf(proofptr, "Type BLS15\nN %Zd\nQ %Zd\n", Ni,q); proofptr += sprintf(proofptr, "LP %d\nLQ %d\n", (int)np1lp, (int)np1lq); } else { int myprooflen = 20 + 7*(4 + mpz_sizeinbase(Ni, 10)) + 0; New(0, proofstr, myprooflen + curprooflen + 1, char); proofptr = proofstr; mpz_sub_ui(t, Ni, 1); if (mpz_cmp(a, t) == 0) mpz_set_si(a, -1); if (mpz_cmp(b, t) == 0) mpz_set_si(b, -1); proofptr += gmp_sprintf(proofptr, "Type ECPP\nN %Zd\nA %Zd\nB %Zd\nM %Zd\nQ %Zd\nX %Zd\nY %Zd\n", Ni, a, b, m, q, P.x, P.y); } if (*prooftextptr) { proofptr += gmp_sprintf(proofptr, "\n"); strcat(proofptr, *prooftextptr); Safefree(*prooftextptr); } *prooftextptr = proofstr; } } /* Ni passed BPSW, so it's highly unlikely to be composite */ if (downresult == 0) { if (mpz_probab_prime_p(Ni, 2) == 0) { gmp_printf("\n\n**** BPSW counter-example found? ****\n**** N = %Zd ****\n\n", Ni); } else { /* Q was composite, but we don't seem to be. */ downresult = 1; } } mpz_clear(a); mpz_clear(b); mpz_clear(u); mpz_clear(v); mpz_clear(m); mpz_clear(q); mpz_clear(mD); mpz_clear(minfactor); mpz_clear(sqrtn); mpz_clear(t); mpz_clear(t2); mpz_clear(P.x);mpz_clear(P.y); for (k = 0; k < 6; k++) { mpz_clear(mlist[k]); mpz_clear(qlist[k]); } return downresult; } /* returns 2 if N is proven prime, 1 if probably prime, 0 if composite */ int _GMP_ecpp(mpz_t N, char** prooftextptr) { int* dilist; mpz_t* sfacs; int i, fstage, result, nsfacs; UV nsize = mpz_sizeinbase(N,2); /* We must check gcd(N,6), let's check 2*3*5*7*11*13*17*19*23. */ if (nsize <= 64 || mpz_gcd_ui(NULL, N, 223092870UL) != 1) { result = _GMP_is_prob_prime(N); if (result != 1) return result; } init_ecpp_gcds( nsize ); if (prooftextptr) *prooftextptr = 0; New(0, sfacs, MAX_SFACS, mpz_t); dilist = poly_class_nums(); nsfacs = 0; result = 1; for (fstage = 1; fstage < 20; fstage++) { int maxH = 0; if (fstage == 3 && get_verbose_level()) gmp_printf("Working hard on: %Zd\n", N); result = ecpp_down(0, N, fstage, &maxH, dilist, sfacs, &nsfacs, prooftextptr); if (result != 1) break; } Safefree(dilist); for (i = 0; i < nsfacs; i++) mpz_clear(sfacs[i]); Safefree(sfacs); return result; } #ifdef STANDALONE_ECPP static void dieusage(char* prog) { printf("ECPP-DJ version 1.04. Dana Jacobsen, 2014.\n\n"); printf("Usage: %s [options] \n\n", prog); printf("Options:\n"); printf(" -v set verbose\n"); printf(" -V set extra verbose\n"); printf(" -q no output other than return code\n"); printf(" -c print certificate to stdout (redirect to save to a file)\n"); printf(" -bpsw use the extra strong BPSW test (probable prime test)\n"); printf(" -nm1 use n-1 proof only (BLS75 theorem 5/7)\n"); printf(" -np1 use n+1 proof only (BLS75 theorem 19)\n"); printf(" -bls use n-1 / n+1 proof (various BLS75 theorems)\n"); printf(" -ecpp use ECPP proof only\n"); printf(" -aks use AKS for proof\n"); #ifdef USE_APRCL printf(" -aprcl use APR-CL for proof\n"); #endif printf(" -help this message\n"); printf("\n"); printf("Return codes: 0 prime, 1 composite, 2 prp, 3 error\n"); exit(3); } #include "expr.h" #include "aks.h" #include "bls75.h" int main(int argc, char **argv) { mpz_t n; int isprime, i, do_printcert; int do_nminus1 = 0; int do_nplus1 = 0; int do_bls75 = 0; int do_aks = 0; int do_aprcl = 0; int do_ecpp = 0; int do_bpsw = 0; int be_quiet = 0; int retcode = 3; char* cert = 0; if (argc < 2) dieusage(argv[0]); _GMP_init(); mpz_init(n); set_verbose_level(0); do_printcert = 0; /* Braindead hacky option parsing */ for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { if (strcmp(argv[i], "-v") == 0) { set_verbose_level(1); } else if (strcmp(argv[i], "-V") == 0) { set_verbose_level(2); } else if (strcmp(argv[i], "-q") == 0) { be_quiet = 1; set_verbose_level(0); do_printcert = 0; } else if (strcmp(argv[i], "-c") == 0) { do_printcert = 1; } else if (strcmp(argv[i], "-nm1") == 0) { do_nminus1 = 1; } else if (strcmp(argv[i], "-np1") == 0) { do_nplus1 = 1; } else if (strcmp(argv[i], "-bls") == 0) { do_bls75 = 1; } else if (strcmp(argv[i], "-aks") == 0) { do_aks = 1; } else if (strcmp(argv[i], "-ecpp") == 0) { do_ecpp = 1; } else if (strcmp(argv[i], "-aprcl") == 0) { do_aprcl = 1; } else if (strcmp(argv[i], "-bpsw") == 0) { do_bpsw = 1; } else if (strcmp(argv[i], "-help") == 0 || strcmp(argv[i], "--help") == 0) { dieusage(argv[0]); } else { printf("Unknown option: %s\n\n", argv[i]); dieusage(argv[0]); } continue; } /* mpz_set_str(n, argv[i], 10); */ if (mpz_expr(n, 10, argv[i])) croak("Can't parse input: '%s'\n",argv[i]); if (get_verbose_level() > 1) gmp_printf("N: %Zd\n", n); isprime = _GMP_is_prob_prime(n); /* isprime = 2 either because BPSW/M-R passed and it is small, or it * went through a test like Lucas-Lehmer, Proth, or Lucas-Lehmer-Riesel. * We don't currently handle those tests, so just look for small values. */ if (isprime == 2 && mpz_sizeinbase(n, 2) > 64) isprime = 1; if (isprime == 2) { Newz(0, cert, 20 + mpz_sizeinbase(n, 10), char); gmp_sprintf(cert, "Type Small\nN %Zd\n", n); } else if (isprime == 1) { if (do_bpsw) { /* Done */ } else if (do_nminus1) { isprime = _GMP_primality_bls_nm1(n, 100, &cert); } else if (do_nplus1) { isprime = _GMP_primality_bls_np1(n, 100, &cert); } else if (do_bls75) { isprime = bls75_hybrid(n, 100, &cert); } else if (do_aks) { isprime = 2 * is_aks_prime(n); do_printcert = 0; } else if (do_aprcl) { #ifdef USE_APRCL /* int i; for (i = 0; i < 10000; i++) */ isprime = mpz_aprtcle(n, get_verbose_level()); do_printcert = 0; #else croak("Compiled without USE_APRCL. Sorry."); #endif } else { if (!do_ecpp) { /* Quick n-1 test */ isprime = _GMP_primality_bls_nm1(n, 1, &cert); } if (isprime == 1) isprime = _GMP_ecpp(n, &cert); } } /* printf("(%d digit) ", (int)mpz_sizeinbase(n, 10)); */ if (isprime == 0) { if (!be_quiet) printf("COMPOSITE\n"); retcode = 1; } else if (isprime == 1) { /* This would normally only be from BPSW */ if (!be_quiet) printf("PROBABLY PRIME\n"); retcode = 2; } else if (isprime == 2) { if (do_printcert) { gmp_printf("[MPU - Primality Certificate]\n"); gmp_printf("Version 1.0\n"); gmp_printf("\n"); gmp_printf("Proof for:\n"); gmp_printf("N %Zd\n", n); gmp_printf("\n"); printf("%s", cert); } else { if (!be_quiet) printf("PRIME\n"); } retcode = 0; } else { /* E.g. APRCL returns -1 for error */ croak("Unknown return code, probable error.\n"); } if (cert != 0) { Safefree(cert); cert = 0; } } mpz_clear(n); _GMP_destroy(); return retcode; } #endif Math-Prime-Util-GMP-0.52/factor.h0000644000175000017500000000235313054533725014770 0ustar danadana#ifndef MPU_FACTOR_H #define MPU_FACTOR_H #include #include "ptypes.h" extern void _init_factor(void); extern int factor(mpz_t n, mpz_t* factors[], int* exponents[]); extern void clear_factors(int nfactors, mpz_t* pfactors[], int* pexponents[]); extern void sigma(mpz_t res, mpz_t n, UV k); extern int moebius(mpz_t n); extern int liouville(mpz_t n); extern int is_semiprime(mpz_t n); extern void totient(mpz_t totient, mpz_t n); extern void jordan_totient(mpz_t tot, mpz_t n, unsigned long k); extern void carmichael_lambda(mpz_t lambda, mpz_t n); extern void znorder(mpz_t res, mpz_t a, mpz_t n); extern void znprimroot(mpz_t root, mpz_t n); extern void ramanujan_tau(mpz_t res, mpz_t n); extern UV _GMP_trial_factor(mpz_t n, UV from_n, UV to_n); extern int _GMP_prho_factor(mpz_t n, mpz_t f, UV a, UV rounds); extern int _GMP_pbrent_factor(mpz_t n, mpz_t f, UV a, UV rounds); extern int _GMP_pminus1_factor(mpz_t n, mpz_t f, UV B1, UV B2); extern int _GMP_pplus1_factor(mpz_t n, mpz_t f, UV P0, UV B1, UV B2); extern int _GMP_holf_factor(mpz_t n, mpz_t f, UV rounds); extern int _GMP_squfof_factor(mpz_t n, mpz_t f, UV rounds); extern UV power_factor(mpz_t n, mpz_t f); extern mpz_t* divisor_list(int* ndivisors, mpz_t n); #endif Math-Prime-Util-GMP-0.52/TODO0000644000175000017500000001414313674066200014026 0ustar danadana - prime_count - needs the pc(#) option as well as pc(#,#) - Do a GMP version of LMO prime_count. Possible versions: - 32-bit main, 16-bit support - 64-bit main, 32-bit support (using __uint64_t if necessary) - 128-bit main, 64-bit support (gcc only) - GMP main, 32-bit support (portable) - GMP main, 64-bit support (mostly portable) - nth_prime - GMP SQUFOF could use a better implementation, though low priority since it just isn't going to be the right algorithm for numbers > 2^64. Mainly what it needs is to pay attention to the rounds argument. Perhaps race. - Tune and improve SIMPQS for our uses. Check FLINT 2.3 for improvements. - Write our own QS. - The statics in ecm and QS won't play well with threading. - ECPP: Perhaps more HCPs/WCPs could be loaded if needed? - ECPP: Another idea is related to Atkin/Morain's EAS. When we have a large number, we can process more Ds, delaying the downrun. We then use the smallest q we found. Combine with lightened stage 1 factoring as above. This drops our q sizes faster, at the expense of more up-front time. I have this running, but for small numbers it doesn't matter much, and for large numbers it just highlights how much nicer FAS would be. - ECPP: All discriminants with D % 8 != 3 have been converted to Weber. We're still left with lots of those D values. Figure out a different invariant that will make smaller polynomials, along with a root conversion. - ECPP: Add a fast BLS5 to downrun? - Add BLS17 proof. Merge into BLS5 code since the end is the same. - Add tests for proofs, similar to MPU t/23. - Handle objects of type: Math::GMP Math::GMP::Fast Math::GMPz We should parse their mpz_t directly, do our processing, and output the result as one of these types. - Recognize Math::BigInt / Math::Pari objects. Shortcut validation. Create results as new objects of their type. - These functions should be added: legendre_phi znlog - Any fast primality pretest would be nice. I've tested: - Colin Plumb's Euler Criterion test - Fermat base 210, which is done in GMP's internal millerrabin.c. - Fermat base 2 also no faster than SPRP-2, though some claim it is. mpz_t e, r; int composite; mpz_init(e); mpz_init_set_ui(r, 2); mpz_sub_ui(e, n, 1); mpz_powm(r, r, e, n); composite = mpz_cmp_ui(r, 1) != 0; mpz_clear(r); mpz_clear(e); if (composite) return 0; None of these are faster on average than just doing BPSW. - merge the two frobenius tests. cp is faster, needs the deterministic version, we should switch to the two input version (allow GMP), etc. - tests for sieve_primes. - speed up range sieving. - fast prime printing routine. The following could be trivially 2x faster: $n = 10**20; say for Math::Prime::Util::GMP::sieve_primes($n,$n+8e9,0); About 3 minutes vs. 7-8 just by using gmp_printf. Using sieve_range doesn't help, as the issue is the massive return array. - More efficient version of ramanujan_tau? MPU has an hclassno implementation now. FLINT does an interesting method as well. - Consider ranged ramanujan_tau. See: https://cs.uwaterloo.ca/journals/JIS/VOL13/Lygeros/lygeros5.pdf Where we could compute a number of hclassno values, then generate the tau values. This might be more efficient. - We could do LLR and Proth in prob_prime and return 1 instead of 2, leaving certs possible. - consider probabilistic is_primitive_root for large inputs - Verify speed and memory use of GMP's two binomials for various versions and compare. Looks like Luschny sent his changes after 5.0.0. https://gmplib.org/list-archives/gmp-discuss/2010-February/004036.html - faster znprimroot - Identify places where 32-bit GMP on 64-bit Perl will trip us up. - BLS75 methods: check if we can return 0 instead of 1 in many cases. - Make a trial factor routine that returns all factors. This can be done with a single treesieve. ECPP could make use of this (since it is doing many calls, keeping the product tree around would be useful). All current calls are testing primality, so don't need multiple returns. Changing the XS call to return multiple values might be useful. - mpu 'use bigint; $n=14299; say is_prime($n); say Math::Prime::Util::GMP::is_nplus1_prime($n)' n=14299 F2=52 R2=275. s=3,r=-37. This passes theorem 17. qi=2 p=66,q=2,d=4348 qi=13 p=45,q=1,d=2021 5543 also all examples of this seem to be n+1 = 2 * [many small factors] n = 5543 = 23*241, n+1=5544 n+1 = F2 * R2 = 88 * 63. R2>1. gcd(F2,R2)=1. q_1 = 2 p=19,q=5,d=341 q_2 = 11 p=18,q=50,d=124 By Corollary 8, N is prime. By Theorem 17, N is prime. r2 = 63 p=11,q=29,d=5 By Corollary 10, N is prime By Theorem 19, N is prime - zeta below -20 or so is increasingly wrong. We should use reflection formula, but that requires some new functions. The MPU interface doesn't even allow negative inputs at all so it isn't critical. - random prime should be more efficient (use A2 instead of A1). - gamma, lngamma See http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.527.8519 https://www.researchgate.net/publication/272039164_A_new_fast_asymptotic_series_for_the_gamma_function - lambertw should use increasing precision. - Euler using: = binary splitting = B3 from Brent/McMillan (1980) = FLINT's B3 (b6ebd880cea55e6e6cf99d6c454607a5872b2c96) - Functions used in MPU that were MPFR. = (++) Pi is about 2x faster than MPFR = (--) li(10^17) is 2x slower than MPFR = (--) ei(0.5) is much slower than MPFR (20x and worse exponent) = (--) Euler is much slower than MPFR (10x and worse exponent) = (--) zeta is much slower than MPFR (10x and worse exponent) = harmreal, riemannr, prime_count_lower, prime_count_upper - tinyqs needs a destroy to clear all the init vars - maybe export rising_factorial and falling_factorial. - clean up dependencies links. We now have to include *every* C file to compile SIMPQS standalone. Completely unnecessary, but some utility functions are pulling in other things. - add sumliouville, prime_bigomega, prime_omega - smooth/rough number functions Math-Prime-Util-GMP-0.52/pbrent63.c0000644000175000017500000001074513663067455015164 0ustar danadana/* Native 63-bit Pollard-Rho-Brent for x86-64. */ #include #include "ptypes.h" #include "pbrent63.h" #if BITS_PER_WORD == 64 && HAVE_STD_U64 && defined(__GNUC__) && defined(__x86_64__) #define FUNC_gcd_ui 1 #include "utility.h" static INLINE UV mpz_getuv(mpz_t n) { UV v = mpz_getlimbn(n,0); if (GMP_LIMB_BITS < 64 || sizeof(mp_limb_t) < sizeof(UV)) v |= ((UV)mpz_getlimbn(n,1)) << 32; return v; } int pbrent63(mpz_t n, mpz_t f, UV rounds) { UV facs[2]; int nfactors; if (mpz_sizeinbase(n,2) > 63) return 0; nfactors = uvpbrent63(mpz_getuv(n), facs, rounds, 1); if (nfactors < 2) return 0; /* Smallest factor of 64-bit n always fits in 32-bit */ mpz_set_ui(f, (facs[0] < facs[1]) ? facs[0] : facs[1]); return 1; } /* Trimmed out all the extra stuff and the 64-bit variation */ #define mont_get1(n) _u64div(1,n) /* Must have npi = mont_inverse(n), mont1 = mont_get1(n) */ #define mont_geta(a,n) mulmod(a,mont1,n) #define mont_mulmod(a,b,n) _mulredc63(a,b,n,npi) static INLINE uint64_t mont_inverse(const uint64_t n) { uint64_t ret = (3*n) ^ 2; ret *= (uint64_t)2 - n * ret; ret *= (uint64_t)2 - n * ret; ret *= (uint64_t)2 - n * ret; ret *= (uint64_t)2 - n * ret; return (uint64_t)0 - ret; } /* MULREDC asm from Ben Buhrow */ static INLINE uint64_t _mulredc63(uint64_t a, uint64_t b, uint64_t n, uint64_t npi) { asm("mulq %2 \n\t" "movq %%rax, %%r10 \n\t" "movq %%rdx, %%r11 \n\t" "mulq %3 \n\t" "mulq %4 \n\t" "addq %%r10, %%rax \n\t" "adcq %%r11, %%rdx \n\t" "xorq %%rax, %%rax \n\t" "subq %4, %%rdx \n\t" "cmovc %4, %%rax \n\t" "addq %%rdx, %%rax \n\t" : "=a"(a) : "0"(a), "r"(b), "r"(npi), "r"(n) : "rdx", "r10", "r11", "cc"); return a; } static INLINE uint64_t _u64div(uint64_t c, uint64_t n) { asm("divq %4" : "=a"(c), "=d"(n) : "1"(c), "0"(0), "r"(n)); return n; } static INLINE UV mulmod(UV a, UV b, UV n) { UV d, dummy; /* d will get a*b mod c */ asm ("mulq %3\n\t" /* mul a*b -> rdx:rax */ "divq %4\n\t" /* (a*b)/c -> quot in rax remainder in rdx */ :"=a"(dummy), "=&d"(d) /* output */ :"a"(a), "r"(b), "r"(n) /* input */ :"cc" /* mulq and divq can set conditions */ ); return d; } static INLINE UV addmod(UV a, UV b, UV n) { UV t = a-n; a += b; asm ("add %2, %1\n\t" /* t := t + b */ "cmovc %1, %0\n\t" /* if (carry) a := t */ :"+r" (a), "+&r" (t) :"r" (b) :"cc" ); return a; } #define ABSDIFF(x,y) (x>y) ? x-y : y-x /* Brent's modifications to Pollard's Rho. */ int uvpbrent63(UV n, UV *factors, UV rounds, UV a) { UV const nbits = BITS_PER_WORD - __builtin_ctzll(n); const UV inner = (nbits <= 31) ? 32 : (nbits <= 35) ? 64 : (nbits <= 40) ? 160 : (nbits <= 52) ? 256 : 320; UV f, m, r, rleft, Xi, Xm, Xs; int irounds, fails = 6; const uint64_t npi = mont_inverse(n), mont1 = mont_get1(n); if (n <= 3) { factors[0] = n; return 1; } if (!(n&1)) { factors[0] = 2; factors[1] = n/2; return 2; } r = f = 1; Xi = Xm = Xs = mont1; a = mont_geta(a,n); while (rounds > 0) { rleft = (r > rounds) ? rounds : r; Xm = Xi; /* Do rleft rounds, inner at a time */ while (rleft > 0) { irounds = (rleft > (UV)inner) ? inner : rleft; rleft -= irounds; rounds -= irounds; Xs = Xi; Xi = mont_mulmod(Xi,Xi+a,n); m = ABSDIFF(Xi,Xm); while (--irounds > 0) { Xi = mont_mulmod(Xi,Xi+a,n); f = ABSDIFF(Xi,Xm); m = mont_mulmod(m, f, n); } f = gcd_ui(m, n); if (f != 1) break; } /* If f == 1, then we didn't find a factor. Move on. */ if (f == 1) { r *= 2; continue; } if (f == n) { /* back up, with safety */ Xi = Xs; do { Xi = mont_mulmod(Xi,Xi+a,n); m = ABSDIFF(Xi,Xm); f = gcd_ui(m, n); } while (f == 1 && r-- != 0); } if (f == 0 || f == n) { if (fails-- <= 0) break; Xi = Xm = mont1; a = addmod(a, mont_geta(11,n), n); continue; } factors[0] = f; factors[1] = n / f; MPUassert( factors[0] * factors[1] == n , "incorrect factoring"); return 2; } factors[0] = n; return 1; } #else /* no 64-bit gcc x86-64 */ int pbrent63(mpz_t n, mpz_t f, UV rounds) { return 0; } int uvpbrent63(UV n, UV *factors, UV rounds, UV a) { factors[0] = n; return 1; } #endif Math-Prime-Util-GMP-0.52/README0000644000175000017500000000511213663067455014225 0ustar danadanaMath::Prime::Util::GMP version 0.52 A module for number theory in Perl using GMP. This includes primality tests, getting primes in a range, factoring, and more. These use GMP directly, so should be quite fast for bignums. This module is mainly intended to be used within Math::Prime::Util, but most functions can be easily used in independent C programs. Some, like factoring and primality proving, have explicit ways of compiling as standalone programs. SYNOPSIS use bigint; use Math::Prime::Util::GMP qw/is_prime/; my $bignum = 27188762623694447842124996538064039444034480940561898523069471141322552613142248049662205275973369340310432664971214620312500867999795559094898390220747143052478910604268911012707898393728029267456459638286456542290811906119936040794792836567800517712998324001798156031927248728220625109007338679765933511619979774789836912923556217410691909195918721300495567162524824116421834972571058278049256235507898646245768556946276949788343519575161621940362646866507884693948582445313246609982609803440514973664475699712739781845803535392293307648102481184237357244142946254918813030632212409545324607906367812717102049454943; say "$bignum is ", is_prime($bignum) ? "prime" : "not prime"; See the POD module documentation for examples and more information on all the methods included. INSTALLATION To install this module type the following: perl Makefile.PL make make test make install You will need a C compiler compatible with the compiler used to build Perl, and the GMP development system installed. If you can install or have installed Math::BigInt::GMP or Math::GMPz then this module should have no issues. Fedora: sudo yum install gmp gmp-devel Ubuntu: sudo apt-get install libgmp3 libgmp3-dev Cygwin: install gmp, libgmp-devel, libgmp3 If you would like to make a standalone executable for ECPP, the easiest method is to run the xt/create-standalone.sh script, which will create a standalone/ directory with Makefile and README. You should make sure you have the large discrimiment set (https://github.com/danaj/Math-Prime-Util-GMP/tree/master/xt/). You may also simply compile it with: gcc -O3 -fomit-frame-pointer -DSTANDALONE -DSTANDALONE_ECPP ecpp.c bls75.c \ ecm.c simpqs.c prime_iterator.c gmp_main.c small_factor.c utility.c \ -lgmp -lm -o ecpp-dj DEPENDENCIES Perl 5.6.2 or later. No modules outside of Core have been used. COPYRIGHT AND LICENCE Copyright (C) 2011-2017 by Dana Jacobsen This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Math-Prime-Util-GMP-0.52/gmp_main.h0000644000175000017500000000330613666104127015277 0ustar danadana#ifndef MPU_GMPMAIN_H #define MPU_GMPMAIN_H #include #include "ptypes.h" extern void _GMP_init(void); extern void _GMP_destroy(void); extern void _GMP_memfree(void); extern int primality_pretest(mpz_t n); extern void _GMP_next_prime(mpz_t n); extern void _GMP_prev_prime(mpz_t n); extern void surround_primes(mpz_t n, UV* prev, UV* next, UV skip_width); extern void _GMP_pn_primorial(mpz_t prim, UV n); extern void _GMP_primorial(mpz_t prim, UV n); extern void consecutive_integer_lcm(mpz_t m, UV B); extern void stirling(mpz_t r, unsigned long n, unsigned long m, UV type); extern void binomial(mpz_t r, UV n, UV k); extern void partitions(mpz_t npart, UV n); extern void factorialmod(mpz_t r, UV n, mpz_t m); extern void multifactorial(mpz_t r, UV n, UV k); extern void factorial_sum(mpz_t r, UV n); extern void subfactorial(mpz_t r, UV n); extern void rising_factorial(mpz_t r, UV x, UV n); extern void falling_factorial(mpz_t r, UV x, UV n); extern int is_carmichael(mpz_t n); extern int is_fundamental(mpz_t n); extern int is_totient(mpz_t n); extern void polygonal_nth(mpz_t r, mpz_t n, UV k); extern void exp_mangoldt(mpz_t res, mpz_t n); extern uint32_t* partial_sieve(mpz_t start, UV length, UV maxprime); extern void prime_count_lower(mpz_t pc, mpz_t n); extern void prime_count_upper(mpz_t pc, mpz_t n); extern void count_primes(mpz_t count, mpz_t lo, mpz_t hi); extern UV* sieve_primes(mpz_t low, mpz_t high, UV k, UV *rn); extern UV* sieve_twin_primes(mpz_t low, mpz_t high, UV twin, UV *rn); extern UV* sieve_cluster(mpz_t low, mpz_t high, uint32_t* cl, UV nc, UV *rn); extern void next_twin_prime(mpz_t res, mpz_t n); extern uint32_t* todigits(uint32_t *ndigits, mpz_t n, uint32_t base); #endif Math-Prime-Util-GMP-0.52/Makefile.PL0000644000175000017500000000717413663067455015331 0ustar danadanause ExtUtils::MakeMaker; use lib 'inc'; # load our bundled version of Devel::CheckLib use Devel::CheckLib; check_lib_or_exit(lib => 'gmp', header => 'gmp.h'); WriteMakefile1( NAME => 'Math::Prime::Util::GMP', ABSTRACT => 'Utilities related to prime numbers, using GMP', VERSION_FROM => 'lib/Math/Prime/Util/GMP.pm', LICENSE => 'perl_5', AUTHOR => 'Dana A Jacobsen ', OBJECT => 'prime_iterator.o ' . 'utility.o ' . 'primality.o ' . 'factor.o ' . 'pbrent63.o ' . 'squfof126.o ' . 'ecm.o ' . 'tinyqs.o ' . 'simpqs.o ' . 'bls75.o ' . 'ecpp.o ' . 'aks.o ' . 'gmp_main.o ' . 'real.o ' . 'isaac.o ' . 'random_prime.o ' . 'XS.o', LIBS => ['-lgmp -lm'], TEST_REQUIRES=> { 'Math::BigInt' => '1.88', # try && bug fixes 'Test::More' => '0.45', }, PREREQ_PM => { 'Exporter' => '5.57', 'XSLoader' => '0.01', 'Fcntl' => 0, 'Carp' => 0, 'base' => 0, }, META_MERGE => { 'meta-spec' => { version => '2', url => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec', }, dynamic_config => 1, resources => { license => [ 'http://dev.perl.org/licenses/' ], homepage => 'https://github.com/danaj/Math-Prime-Util-GMP', repository => { url => 'https://github.com/danaj/Math-Prime-Util-GMP', }, }, prereqs => { runtime => { recommends => { 'Math::Prime::Util' => 0.68, }, }, }, provides => { 'Math::Prime::Util::GMP' => { version => '0.52', file => 'lib/Math/Prime/Util/GMP.pm', }, }, }, MIN_PERL_VERSION => 5.006002, ); sub WriteMakefile1 { # Cribbed from eumm-upgrade by Alexandr Ciornii my %params = @_; my $eumm_version = $ExtUtils::MakeMaker::VERSION; $eumm_version = eval $eumm_version; if ($params{TEST_REQUIRES} and $eumm_version < 6.6303) { $params{BUILD_REQUIRES}={ %{$params{BUILD_REQUIRES} || {}} , %{$params{TEST_REQUIRES}} }; delete $params{TEST_REQUIRES}; } if ($params{BUILD_REQUIRES} and $eumm_version < 6.5503) { #EUMM 6.5502 has problems with BUILD_REQUIRES $params{PREREQ_PM}={ %{$params{PREREQ_PM} || {}} , %{$params{BUILD_REQUIRES}} }; delete $params{BUILD_REQUIRES}; } delete $params{CONFIGURE_REQUIRES} if $eumm_version < 6.52; delete $params{MIN_PERL_VERSION} if $eumm_version < 6.48; delete $params{META_MERGE} if $eumm_version < 6.46; delete $params{META_ADD} if $eumm_version < 6.46; delete $params{LICENSE} if $eumm_version < 6.31; delete $params{AUTHOR} if $] < 5.005; delete $params{ABSTRACT_FROM} if $] < 5.005; delete $params{BINARY_LOCATION} if $] < 5.005; WriteMakefile(%params); } Math-Prime-Util-GMP-0.52/random_prime.h0000644000175000017500000000077413663067455016203 0ustar danadana#ifndef MPU_RANDOM_PRIME_H #define MPU_RANDOM_PRIME_H #include "ptypes.h" extern int mpz_random_prime(mpz_t p, mpz_t lo, mpz_t hi); extern void mpz_random_nbit_prime(mpz_t p, UV n); extern void mpz_random_ndigit_prime(mpz_t p, UV n); extern void mpz_random_safe_prime(mpz_t p, UV nbits); extern void mpz_random_strong_prime(mpz_t p, UV nbits); extern void mpz_random_maurer_prime(mpz_t p, UV nbits, char** proofptr); extern void mpz_random_shawe_taylor_prime(mpz_t p, UV nbits, char** proofptr); #endif Math-Prime-Util-GMP-0.52/isaac.c0000644000175000017500000001145313663067455014576 0ustar danadana/* * The ISAAC CSPRNG plus interface. * Slightly modified readable.c from Bob Jenkins 1996. */ #include #include #include #include "ptypes.h" #include "isaac.h" /* Ensure big-endian and little-endian get the same results */ #if __LITTLE_ENDIAN__ || (defined(BYTEORDER) && (BYTEORDER == 0x1234 || BYTEORDER == 0x12345678)) #define SWAPRSL(rsl, num) { } #define COPYRSL(data, rsl, start, bytes) \ memcpy(data, (unsigned char*) (rsl+start), bytes); #else #if !defined(__x86_64__) #undef U8TO32_LE #undef U32TO8_LE #endif #ifndef U32TO8_LE #define U32TO8_LE(p, v) \ do { uint32_t _v = v; \ (p)[0] = (((_v) ) & 0xFFU); \ (p)[1] = (((_v) >> 8) & 0xFFU); \ (p)[2] = (((_v) >> 16) & 0xFFU); \ (p)[3] = (((_v) >> 24) & 0xFFU); } while (0) #endif #define SWAPRSL(rsl, num) \ { unsigned char* rsc = (unsigned char*) rsl; \ uint32_t i; \ for (i = 0; i < num; i++) \ U32TO8_LE(rsc+4*i, rsl[i]); \ } #define COPYRSL(data, rsl, start, bytes) \ { \ unsigned char swapbuf[256*4]; \ uint32_t i; \ for (i = 0; i < (bytes+3)/4; i++) \ { U32TO8_LE(swapbuf+4*i, rsl[start+i]); } \ memcpy(data, swapbuf, bytes); \ } #endif static uint32_t randrsl[256]; static uint32_t randcnt; static int good_seed = 0; /* internal state */ static uint32_t mm[256]; static uint32_t aa = 0, bb = 0, cc = 0; static void isaac(void) { uint32_t i,x,y; cc = cc + 1; /* cc just gets incremented once per 256 results */ bb = bb + cc; /* then combined with bb */ for (i=0; i<256; ++i) { x = mm[i]; switch (i%4) { case 0: aa = aa^(aa<<13); break; case 1: aa = aa^(aa>>6); break; case 2: aa = aa^(aa<<2); break; case 3: aa = aa^(aa>>16); break; } aa = mm[(i+128)%256] + aa; mm[i] = y = mm[(x>>2)%256] + aa + bb; randrsl[i] = bb = mm[(y>>10)%256] + x; } randcnt = 0; } #define mix(a,b,c,d,e,f,g,h) \ { \ a^=b<<11; d+=a; b+=c; \ b^=c>>2; e+=b; c+=d; \ c^=d<<8; f+=c; d+=e; \ d^=e>>16; g+=d; e+=f; \ e^=f<<10; h+=e; f+=g; \ f^=g>>4; a+=f; g+=h; \ g^=h<<8; b+=g; h+=a; \ h^=a>>9; c+=h; a+=b; \ } static void randinit(void) { int i; uint32_t a,b,c,d,e,f,g,h; aa=bb=cc=0; a=b=c=d=e=f=g=h=0x9e3779b9; /* the golden ratio */ for (i=0; i<4; ++i) /* scramble it */ { mix(a,b,c,d,e,f,g,h); } for (i=0; i<256; i+=8) /* fill in mm[] with messy stuff */ { a+=randrsl[i ]; b+=randrsl[i+1]; c+=randrsl[i+2]; d+=randrsl[i+3]; e+=randrsl[i+4]; f+=randrsl[i+5]; g+=randrsl[i+6]; h+=randrsl[i+7]; mix(a,b,c,d,e,f,g,h); mm[i ]=a; mm[i+1]=b; mm[i+2]=c; mm[i+3]=d; mm[i+4]=e; mm[i+5]=f; mm[i+6]=g; mm[i+7]=h; } { /* do a second pass to make all of the seed affect all of mm */ for (i=0; i<256; i+=8) { a+=mm[i ]; b+=mm[i+1]; c+=mm[i+2]; d+=mm[i+3]; e+=mm[i+4]; f+=mm[i+5]; g+=mm[i+6]; h+=mm[i+7]; mix(a,b,c,d,e,f,g,h); mm[i ]=a; mm[i+1]=b; mm[i+2]=c; mm[i+3]=d; mm[i+4]=e; mm[i+5]=f; mm[i+6]=g; mm[i+7]=h; } } isaac(); /* fill in the first set of results */ randcnt=256; /* first use will run isaac() again */ } void isaac_init(uint32_t bytes, const unsigned char* data) { memset(mm, 0, 4*256); memset(randrsl, 0, 4*256); if (bytes > 0 && data != 0) { /* Replicate supplied seed as recommended by Bob Jenkins. */ unsigned char* rdata = (unsigned char*) randrsl; uint32_t n_fill_bytes = 1024; while (n_fill_bytes > 0) { uint32_t n_copy_bytes = (bytes > n_fill_bytes) ? n_fill_bytes : bytes; memcpy(rdata, data, n_copy_bytes); rdata += n_copy_bytes; n_fill_bytes -= n_copy_bytes; } SWAPRSL(randrsl, 256); } randinit(); good_seed = (bytes >= 16); } int isaac_seeded(void) { return good_seed; } void isaac_rand_bytes(uint32_t bytes, unsigned char* data) { if ( 4*(256-randcnt) >= bytes) { /* We have enough data, just copy it and leave */ COPYRSL(data, randrsl, randcnt, bytes); randcnt += (bytes+3)/4; } else { /* Loop copying up to 1024 bytes at a time */ uint32_t n_rand_bytes, n_copy_bytes; while (bytes > 0) { if (randcnt > 255) isaac(); n_rand_bytes = 4 * (256-randcnt); n_copy_bytes = (n_rand_bytes > bytes) ? bytes : n_rand_bytes; COPYRSL(data, randrsl, randcnt, n_copy_bytes); data += n_copy_bytes; randcnt += (n_copy_bytes+3)/4; bytes -= n_copy_bytes; } } } uint32_t isaac_rand32(void) { if (randcnt > 255) isaac(); return randrsl[randcnt++]; } /* Return rand 32-bit integer between 0 to n-1 inclusive */ uint32_t isaac_rand(uint32_t n) { uint32_t r, rmin; if (n <= 1) return 0; rmin = -n % n; while (1) { r = isaac_rand32(); if (r >= rmin) break; } return r % n; } Math-Prime-Util-GMP-0.52/utility.h0000644000175000017500000001356613663067455015235 0ustar danadana#ifndef MPU_UTILITY_H #define MPU_UTILITY_H #include #include #include "ptypes.h" extern int get_verbose_level(void); extern void set_verbose_level(int level); extern gmp_randstate_t* get_randstate(void); extern void init_randstate(unsigned long seed); extern void clear_randstate(void); extern void mpz_isaac_urandomb(mpz_t rop, int nbits); extern void mpz_isaac_urandomm(mpz_t rop, mpz_t n); extern UV irand64(int nbits); extern NV drand64(void); extern UV is_power(mpz_t n, UV a); extern UV prime_power(mpz_t prime, mpz_t n); extern int is_primitive_root(mpz_t a, mpz_t b, int nprime); /* tdiv_r is faster, but we'd need to guarantee the input is positive */ #define mpz_mulmod(r, a, b, n, t) \ do { mpz_mul(t, a, b); mpz_mod(r, t, n); } while (0) #undef mpz_divmod extern int mpz_divmod(mpz_t r, mpz_t a, mpz_t b, mpz_t n, mpz_t t); /* s = sqrt(a) mod p */ extern int sqrtmod(mpz_t s, mpz_t a, mpz_t p); extern int sqrtmod_t(mpz_t s, mpz_t a, mpz_t p, mpz_t t, mpz_t t2, mpz_t b, mpz_t g); /* 4 tmp variables */ extern unsigned long modinverse(unsigned long a, unsigned long p); #if __GNU_MP_VERSION < 5 /* Older versions left out a normalization step */ extern void gcdext(mpz_t g, mpz_t s, mpz_t t, const mpz_t a, const mpz_t b); #else #define gcdext(g,s,t,a,b) mpz_gcdext(g,s,t,a,b) #endif extern int chinese(mpz_t ret, mpz_t lcm, mpz_t *a, mpz_t *m, int items); extern UV mpz_order_ui(UV r, mpz_t n, UV limit); extern void mpz_arctan(mpz_t r, unsigned long base, mpz_t pow, mpz_t t1, mpz_t t2); extern void mpz_arctanh(mpz_t r, unsigned long base, mpz_t pow, mpz_t t1, mpz_t t2); extern void mpz_product(mpz_t* A, UV a, UV b); extern void mpz_veclcm(mpz_t* A, UV a, UV b); extern void poly_mod_mul(mpz_t* px, mpz_t* py, UV r, mpz_t mod, mpz_t t1, mpz_t t2, mpz_t t3); extern void poly_mod_pow(mpz_t *pres, mpz_t *pn, mpz_t power, UV r, mpz_t mod); extern void poly_mod(mpz_t *pres, mpz_t *pn, UV *dn, mpz_t mod); extern void polyz_mod(mpz_t *pres, mpz_t *pn, long *dn, mpz_t mod); extern void polyz_set(mpz_t* pr, long* dr, mpz_t* ps, long ds); extern void polyz_print(const char* header, mpz_t* pn, long dn); extern void polyz_mulmod(mpz_t* pr, mpz_t* px, mpz_t *py, long *dr, long dx, long dy, mpz_t mod); extern void polyz_div(mpz_t *pq, mpz_t *pr, mpz_t *pn, mpz_t *pd, long *dq, long *dr, long dn, long dd, mpz_t NMOD); extern void polyz_pow_polymod(mpz_t* pres, mpz_t* pn, mpz_t* pmod, long *dres, long dn, long dmod, mpz_t power, mpz_t NMOD); extern void polyz_gcd(mpz_t* pres, mpz_t* pa, mpz_t* pb, long* dres, long da, long db, mpz_t MODN); extern void polyz_root_deg1(mpz_t root, mpz_t* pn, mpz_t NMOD); extern void polyz_root_deg2(mpz_t root1, mpz_t root2, mpz_t* pn, mpz_t NMOD); /* Find roots of a polynomial mod a prime, slightly modified. */ /* We will stop if we've found at least maxroots unique roots. */ extern void polyz_roots_modp(mpz_t** roots, long *nroots, long maxroots, mpz_t *pP, long dP, mpz_t NMOD); /* Solve x^2 + |D|y^2 = p */ extern int cornacchia(mpz_t x, mpz_t y, mpz_t D, mpz_t p); /* Solve x^2 + |D|y^2 = 4p */ extern int modified_cornacchia(mpz_t x, mpz_t y, mpz_t D, mpz_t p); /* return a class poly (Hilbert [type 1] or Weber [type 2]) */ extern UV poly_class_poly(IV D, mpz_t**T, int* type); extern const char* poly_class_type_name(int type); /* return a 0 terminated list of all D's sorted by degree */ extern IV* poly_class_degrees(int insert_1s); /* List of class polynomial indices in order */ extern int* poly_class_nums(void); /* Given a class poly index, return the degree and fill in (if not null): * D the discriminant number * T the polynomial coefficients * type the poly type: 1 Hilber, 2 Weber */ extern UV poly_class_poly_num(int i, int *D, mpz_t**T, int* type); #define BITS2DIGS(bits) ceil(bits/3.3219281) #define DIGS2BITS(digs) ceil(digs*3.3219281) extern void mpf_log(mpf_t logx, mpf_t x); extern void mpf_exp(mpf_t expx, mpf_t x); extern void mpf_pow(mpf_t powx, mpf_t b, mpf_t x); extern void mpf_root(mpf_t rootx, mpf_t x, mpf_t n); extern void mpf_agm(mpf_t r, mpf_t a, mpf_t b); extern UV logint(mpz_t n, UV base); #if defined(FUNC_isqrt) || defined(FUNC_is_perfect_square) static UV isqrt(UV n) { UV root; #if BITS_PER_WORD == 32 if (n >= UVCONST(4294836225)) return UVCONST(65535); #else if (n >= UVCONST(18446744065119617025)) return UVCONST(4294967295); #endif root = (UV) sqrt((double)n); while (root*root > n) root--; while ((root+1)*(root+1) <= n) root++; return root; } #endif #if defined(FUNC_gcd_ui) || defined(FUNC_lcm_ui) static UV gcd_ui(UV x, UV y) { UV t; if (y < x) { t = x; x = y; y = t; } while (y > 0) { t = y; y = x % y; x = t; /* y1 <- x0 % y0 ; x1 <- y0 */ } return x; } #endif #ifdef FUNC_lcm_ui static UV lcm_ui(UV x, UV y) { /* Can overflow if lcm(x,y) > 2^64 (e.g. two primes each > 2^32) */ return x * (y / gcd_ui(x,y)); } #endif #ifdef FUNC_is_perfect_square /* Return 0 if n is not a perfect square. Set sqrtn to int(sqrt(n)) if so. * See: http://mersenneforum.org/showpost.php?p=110896 */ static int is_perfect_square(UV n, UV* sqrtn) { UV m; m = n & 127; if ((m*0x8bc40d7d) & (m*0xa1e2f5d1) & 0x14020a) return 0; /* This cuts out another 80%: */ m = n % 63; if ((m*0x3d491df7) & (m*0xc824a9f9) & 0x10f14008) return 0; /* m = n % 25; if ((m*0x1929fc1b) & (m*0x4c9ea3b2) & 0x51001005) return 0; */ m = isqrt(n); if (n != m*m) return 0; if (sqrtn != 0) *sqrtn = m; return 1; } #endif #ifdef FUNC_mpz_logn static double mpz_logn(mpz_t n) { long exp; double logn = mpz_get_d_2exp(&exp, n); logn = log(logn) + (log(2) * exp); return logn; } #endif #ifdef FUNC_mpz_log2 static double mpz_log2(mpz_t n) { long exp; double logn = mpz_get_d_2exp(&exp, n); logn = exp + log(logn)/log(2); return logn; } #endif #endif Math-Prime-Util-GMP-0.52/examples/0000755000175000017500000000000013674072603015155 5ustar danadanaMath-Prime-Util-GMP-0.52/examples/convert-primo-cert.pl0000755000175000017500000000452713025437621021257 0ustar danadana#!/usr/bin/env perl use warnings; use strict; use Math::BigInt try=>"GMP,Pari"; # Convert a Primo certificate to a MPU certificate. # Written by Dana Jacobsen, 2013. # This uses type ECPP3 and ECPP4 to make smaller files, letting the # MPU certificate prover handle the check and convert to ECPP type. print "[MPU - Primality Certificate]\n"; print "Version 1.0\n"; print "\n"; print "# Converted from Primo by convert-primo version 1.0\n"; print "\n"; my $n; while (<>) { if (/^N\$=(\S+)/) { $n = Math::BigInt->new('0x' . $1); print "Proof for:\n"; print "N $n\n"; print "\n"; } elsif (/^Type=(\d)/) { my $type = $1; if ($type == 4) { my ($s, $r, $j, $t) = read_vars('4', qw/S R J T/); print "Type ECPP4\n"; print "N $n\nS $s\nR $r\nJ $j\nT $t\n\n"; $n = $r; } elsif ($type == 3) { my ($s, $r, $a, $b, $t) = read_vars('3', qw/S R A B T/); print "Type ECPP3\n"; print "N $n\nS $s\nR $r\nA $a\nB $b\nT $t\n\n"; $n = $r; } elsif ($type == 2) { my ($s, $r, $q) = read_vars('2', qw/S R Q/); print "Type BLS15\n"; my $p = ($q->is_odd()) ? 2 : 1; print "N $n\nQ $r\nLP $p\nLQ $q\n\n"; $n = $r; } elsif ($type == 1) { my ($s, $r, $b) = read_vars('1', qw/S R B/); print "Type Pocklington\n"; print "N $n\nQ $r\nA $b\n\n"; $n = $r; } elsif ($type == 0) { # End } else { die "Unkown type: $type\n"; } } } sub read_vars { my $type = shift; my %vars = map { $_ => 1 } @_; my %return; while (scalar keys %vars) { my $line = <>; die "end of file during type $type\n" unless defined $line; # Skip comments and blank lines next if $line =~ /^\s*#/ or $line =~ /^\s*$/; chomp($line); die "Still missing values in type $type\n" if $line =~ /^Type/; if ($line =~ /^(\S+)\$\s*=\s*(\S+)/) { my ($var, $val) = ($1, $2); $var =~ tr/a-z/A-Z/; die "Type $type: repeated or inappropriate var: $line\n" unless defined $vars{$var}; $return{$var} = $val; delete $vars{$var}; } else { die "Unrecognized line: $line\n"; } } # Now return them in the order given, turned into bigints. my @ret; foreach my $var (@_) { my $sign = 1; $sign = -1 if $return{$var} =~ s/^-//; push @ret, Math::BigInt->new('0x' . $return{$var}) * $sign; } return @ret; } Math-Prime-Util-GMP-0.52/examples/convert-gmpecpp-cert.pl0000755000175000017500000000265013025437621021557 0ustar danadana#!/usr/bin/env perl use warnings; use strict; use Math::BigInt try=>"GMP,Pari"; # Convert the output of GMP-ECPP to a MPU certificate. # Written by Dana Jacobsen, 2013. # This does no error checking and is very simple. It's up to verify-cert.pl # to make sure the resulting MPU certificate is parsable and valid. It might # be nice to have this do a little more error checking just so any format # errors could get caught right away. # As an example, MPU certificates really don't care what order things arrive, # as it just follows the tree of "N is prime if [Q1,Q2,Q3,...] is prime" down. # PRIMO and GMP-ECPP both restrict the tree to a single child and in-order. # This converter ought to verify that each N is the previous step's Q. print "[MPU - Primality Certificate]\n"; print "Version 1.0\n"; print "\n"; print "# Converted from GMP-ECPP by convert-gmpecpp version 1.0\n"; print "\n"; while (<>) { if (/^N\[(\d+)\]\s*=\s*(\d+)/) { my($step, $n) = ($1, $2); if ($step == 0) { print "Proof for:\n"; print "N $n\n"; print "\n"; } print "Type ECPP\n"; print "N $n\n"; } elsif (/^a\s*=\s*(\d+)/) { print "A $1\n"; } elsif (/^b\s*=\s*(\d+)/) { print "B $1\n"; } elsif (/^m\s*=\s*(\d+)/) { print "M $1\n"; } elsif (/^q\s*=\s*(\d+)/) { print "Q $1\n"; } elsif (/^P\s*=\s*\(\s*(\d+)\s*,\s*(\d+)\s*\)/) { print "X $1\n"; print "Y $2\n"; print "\n"; } } Math-Prime-Util-GMP-0.52/examples/verify-cert.pl0000755000175000017500000004577613025437621017772 0ustar danadana#!/usr/bin/env perl use warnings; use strict; use Math::BigInt lib=>"GMP,Pari"; use Math::Prime::Util qw/:all/; use Time::HiRes qw(gettimeofday tv_interval); use Getopt::Long; $|++; # MPU and PRIMO certificate verification. # Written by Dana Jacobsen, 2013. # Requires Math::Prime::Util v0.30 or later. # Will be very slow without Math:::Prime::Util::GMP for EC operations. # Exits with: # 0 all numbers verified prime # 1 at least one number verified composite # 2 incorrect or incomplete conditions. Cannot verify. # 3 certificate file cannot be parsed or no number found # The candidate number is always checked against is_prime first. That # performs an extra-strong Lucas pseudoprime test followed by at least # one additional M-R test using a random base. my $verbose = 2; my $quiet; my $verb; my $timing; GetOptions("verbose+" => \$verb, "quiet" => \$quiet, "timing" => \$timing, ) or die "Error in option parsing\n"; $verbose = $verb if defined $verb; $verbose = 0 if $quiet; sub error ($) { my $message = shift; warn "\n$message\n" if $verbose; exit(3); # error in certificate } sub fail ($) { my $message = shift; warn "\n$message\n" if $verbose; exit(2); # Failed a condition } my $orig_N; my $N; my %parts; # Map of "N is prime if Q is prime" my %proof_funcs = ( ECPP => \&prove_ecpp, # Standard ECPP proof ECPP3 => \&prove_ecpp3, # Primo type 3 ECPP4 => \&prove_ecpp4, # Primo type 4 BLS15 => \&prove_bls15, # basic n+1, includes Primo type 2 BLS3 => \&prove_bls3, # basic n-1 BLS5 => \&prove_bls5, # much better n-1 SMALL => \&prove_small, # n <= 2^64 POCKLINGTON => \&prove_pock, # simple n-1, Primo type 1 LUCAS => \&prove_lucas, # n-1 completely factored ); my $smallval = Math::BigInt->new(2)->bpow(64); my $step = 1; my $base = 10; my $cert_type = 'Unknown'; my $start_time; while (<>) { next if /^\s*#/ or /^\s*$/; # Skip comments and blank lines chomp; if (/^\[(\S+) - Primality Certificate\]/) { error "Unknown certificate type: $1" unless $1 eq 'MPU' || $1 eq 'PRIMO'; $cert_type = $1; next; } if ( ($cert_type eq 'PRIMO' && /^\[Candidate\]/) || ($cert_type eq 'MPU' && /^Proof for:/) ) { if (defined $N) { # Done with this number, starting the next. print " " x 60, "\r" if $verbose == 2; if (final_verify($N)) { print "PRIME\n" if $verbose; } else { print "NOT PROVEN\n" if $verbose; exit(2); } undef $N; undef %parts; $step = 1; } if ($cert_type eq 'PRIMO') { ($N) = primo_read_vars('Candidate', qw/N/); } else { ($N) = read_vars('Proof for', qw/N/); } $start_time = [gettimeofday]; $orig_N = $N; if ($verbose == 1) { print "N $N"; } elsif ($verbose == 2) { print "$N\n"; } if (!is_prime($N)) { print "COMPOSITE\n" if $verbose; exit(1); } next; } if ($cert_type eq 'PRIMO') { if (/^Type\s*=\s*(\d+)/) { my $type = $1; error("Starting type without telling me the N value!") unless defined $N; if ($type == 4) { my ($n, $f) = verify_ecpp4( $N, primo_read_vars('4', qw/S R J T/) ); $N = $f; } elsif ($type == 3) { my ($n, $f) = verify_ecpp3( $N, primo_read_vars('3', qw/S R A B T/) ); $N = $f; } elsif ($type == 2) { my ($s, $r, $q) = primo_read_vars('2', qw/S R Q/); my $p = ($q->is_odd()) ? 2 : 1; my ($n, $f) = verify_bls15( $N, $r, $p, $q ); $N = $f; } elsif ($type == 1) { my ($s, $r, $b) = primo_read_vars('1', qw/S R B/); fail "Type 1: $N failed SR + 1 = N" unless $s*$r+1 == $N; my ($n, $f) = verify_pock( $N, $r, $b ); # S = (N-1)/r $N = $f; } elsif ($type == 0) { # Final } else { error "Unknown type: $type"; } if ($verbose == 1) { print "."; } elsif ($verbose == 2) { printf "step %2d: %4d digits type %d\r", $step++, length($N), $type; } } } elsif ($cert_type eq 'MPU') { if (/^Base (\d+)/) { $base = $1; error "Invalid base: $base" unless $base == 10 || $base == 16 || $base == 62; error "Sorry, only base 10 implemented in this version" unless $base == 10; } elsif (/^Type (.*?)\s*$/) { error("Starting type without telling me the N value!") unless defined $N; my $type = $1; $type =~ tr/a-z/A-Z/; error("Unknown type: $type") unless defined $proof_funcs{$type}; my ($n, @q) = $proof_funcs{$type}->(); $parts{$n} = [@q]; if ($verbose == 1) { print "."; } elsif ($verbose == 2) { printf "step %2d: %4d digits type %-12s\r", $step++, length($n), $type; } } } } error("No N found") unless defined $N; print " " x 60, "\r" if $verbose == 2; if (final_verify($N)) { print "PRIME\n" if $verbose; exit(0); } else { print "NOT PROVEN\n" if $verbose; exit(2); } sub final_verify { my $n = shift; die "Internal error: argument not defined" unless defined $n; if ($timing) { my $seconds = tv_interval($start_time); printf "%7.6f seconds for verification of %d digit number\n", $seconds, length($orig_N); } if ($cert_type eq 'PRIMO') { fail "Type 0: $n failed N > 18" unless $n > 18; fail "Type 0: $n failed N < 34 * 10^13" unless $n < (34*10**13); fail "Type 0: $n failed spsp(2,3,5,7,11,13,17)" unless is_strong_pseudoprime($n,2,3,5,7,11,13,17); return 1; } my @qs = ($n); while (@qs) { my $q = shift @qs; # Check that this q has a chain if (!defined $parts{$q}) { # Auto-small: handle small q right here. if ($q <= $smallval) { fail "Small n $q does not pass BPSW" unless is_prime($q); next; } else { error "q value $q has no proof\n"; } } die "Internal error: Invalid parts entry" unless ref($parts{$q}) eq 'ARRAY'; # q is prime if all it's chains are prime. push @qs, @{$parts{$q}}; } 1; } ############################################################################## # MPU Proof handlers ############################################################################## sub prove_ecpp { verify_ecpp( read_vars('ECPP', qw/N A B M Q X Y/) ); } sub prove_ecpp3 { verify_ecpp3( read_vars('ECPP3', qw/N S R A B T/) ); } sub prove_ecpp4 { verify_ecpp4( read_vars('ECPP4', qw/N S R J T/) ); } sub prove_bls15 { verify_bls15( read_vars('BLS15', qw/N Q LP LQ/) ); } sub prove_bls3 { verify_bls3( read_vars('BLS3', qw/N Q A/) ); } sub prove_pock { verify_pock( read_vars('POCKLINGTON', qw/N Q A/) ); } sub prove_small { verify_small( read_vars('Small', qw/N/) ); } sub prove_bls5 { # No good way to do this using read_vars my ($n, @Q, @A); my $index = 0; $Q[0] = Math::BigInt->new(2); # 2 is implicit while (1) { my $line = <>; error("end of file during type BLS5") unless defined $line; # Skip comments and blank lines next if $line =~ /^\s*#/ or $line =~ /^\s*$/; # Stop when we see a line starting with -. last if $line =~ /^-/; chomp($line); if ($line =~ /^N\s+(\d+)/) { error("BLS5: N redefined") if defined $n; $n = Math::BigInt->new("$1"); } elsif ($line =~ /^Q\[(\d+)\]\s+(\d+)/) { $index++; error("BLS5: Invalid index: $1") unless $1 == $index; $Q[$1] = Math::BigInt->new("$2"); } elsif ($line =~ /^A\[(\d+)\]\s+(\d+)/) { error("BLS5: Invalid index: A[$1]") unless $1 >= 0 && $1 <= $index; $A[$1] = Math::BigInt->new("$2"); } else { error("Unrecognized line: $line"); } } verify_bls5($n, \@Q, \@A); } sub prove_lucas { # No good way to do this using read_vars my ($n, @Q, $a); my $index = 0; while (1) { my $line = <>; error("end of file during type Lucas") unless defined $line; # Skip comments and blank lines next if $line =~ /^\s*#/ or $line =~ /^\s*$/; chomp($line); if ($line =~ /^N\s+(\d+)/) { error("Lucas: N redefined") if defined $n; $n = Math::BigInt->new("$1"); } elsif ($line =~ /^Q\[(\d+)\]\s+(\d+)/) { $index++; error("Lucas: Invalid index: $1") unless $1 == $index; $Q[$1] = Math::BigInt->new("$2"); } elsif ($line =~ /^A\s+(\d+)/) { $a = Math::BigInt->new("$1"); last; } else { error("Unrecognized line: $line"); } } verify_lucas($n, \@Q, $a); } ############################################################################## # Proof verifications ############################################################################## sub verify_ecpp { my ($n, $a, $b, $m, $q, $x, $y) = @_; $a %= $n if $a < 0; $b %= $n if $b < 0; fail "ECPP: $n failed N > 0" unless $n > 0; fail "ECPP: $n failed gcd(N, 6) = 1" unless Math::BigInt::bgcd($n, 6) == 1; fail "ECPP: $n failed gcd(4*a^3 + 27*b^2, N) = 1" unless Math::BigInt::bgcd(4*$a*$a*$a+27*$b*$b,$n) == 1; fail "ECPP: $n failed Y^2 = X^3 + A*X + B mod N" unless ($y*$y) % $n == ($x*$x*$x + $a*$x + $b) % $n; fail "ECPP: $n failed M >= N + 1 - 2*sqrt(N)" unless $m >= $n + 1 - $n->copy->bmul(4)->bsqrt(); fail "ECPP: $n failed M <= N + 1 + 2*sqrt(N)" unless $m <= $n + 1 + $n->copy->bmul(4)->bsqrt(); fail "ECPP: $n failed Q > (N^(1/4)+1)^2" unless $q > $n->copy->broot(4)->badd(1)->bpow(2); fail "ECPP: $n failed Q < N" unless $q < $n; fail "ECPP: $n failed M != Q" unless $m != $q; my ($mdivq, $rem) = $m->copy->bdiv($q); fail "ECPP: $n failed Q divides M" unless $rem == 0; # Now verify the elliptic curve my $correct_point = 0; if (prime_get_config->{'gmp'} && defined &Math::Prime::Util::GMP::_validate_ecpp_curve) { $correct_point = Math::Prime::Util::GMP::_validate_ecpp_curve($a, $b, $n, $x, $y, $m, $q); } else { if (!defined $Math::Prime::Util::ECAffinePoint::VERSION) { eval { require Math::Prime::Util::ECAffinePoint; 1; } or do { die "Cannot load Math::Prime::Util::ECAffinePoint"; }; } my $ECP = Math::Prime::Util::ECAffinePoint->new($a, $b, $n, $x, $y); # Compute U = (m/q)P, check U != point at infinity $ECP->mul( $m->copy->bdiv($q)->as_int ); if (!$ECP->is_infinity) { # Compute V = qU, check V = point at infinity $ECP->mul( $q ); $correct_point = 1 if $ECP->is_infinity; } } fail "ECPP: $n failed elliptic curve conditions" unless $correct_point; ($n, $q); } sub verify_ecpp3 { my ($n, $s, $r, $a, $b, $t) = @_; fail "ECPP3: $n failed |A| <= N/2" unless 2*abs($a) <= $n; fail "ECPP3: $n failed |B| <= N/2" unless 2*abs($b) <= $n; fail "ECPP3: $n failed T >= 0" unless $t >= 0; fail "ECPP3: $n failed T < N" unless $t < $n; my $l = ($t*$t*$t + $a*$t + $b) % $n; verify_ecpp( $n, ($a * $l*$l) % $n, ($b * $l*$l*$l) % $n, $r*$s, $r, ($t*$l) % $n, ($l*$l) % $n ); } sub verify_ecpp4 { my ($n, $s, $r, $j, $t) = @_; fail "ECPP4: $n failed |J| <= N/2" unless 2*abs($j) <= $n; fail "ECPP4: $n failed T >= 0" unless $t >= 0; fail "ECPP4: $n failed T < N" unless $t < $n; my $a = 3 * $j * (1728 - $j); my $b = 2 * $j * (1728 - $j) * (1728 - $j); my $l = ($t*$t*$t + $a*$t + $b) % $n; verify_ecpp( $n, ($a * $l*$l) % $n, ($b * $l*$l*$l) % $n, $r*$s, $r, ($t*$l) % $n, ($l*$l) % $n ); } sub verify_bls15 { my ($n, $q, $lp, $lq) = @_; fail "BLS15: $n failed Q odd" unless $q->is_odd(); fail "BLS15: $n failed Q > 2" unless $q > 2; my ($m, $rem) = ($n+1)->copy->bdiv($q); fail "BLS15: $n failed Q divides N+1" unless $rem == 0; fail "BLS15: $n failed MQ-1 = N" unless $m*$q-1 == $n; fail "BLS15: $n failed M > 0" unless $m > 0; fail "BLS15: $n failed 2Q-1 > sqrt(N)" unless 2*$q-1 > $n->copy->bsqrt(); my $D = $lp*$lp - 4*$lq; fail "BLS15: $n failed D != 0" unless $D != 0; fail "BLS15: $n failed jacobi(D,N) = -1" unless _jacobi($D,$n) == -1; fail "BLS15: $n failed V_{m/2} mod N != 0" unless (lucas_sequence($n, $lp, $lq, $m/2))[1] != 0; fail "BLS15: $n failed V_{(N+1)/2} mod N == 0" unless (lucas_sequence($n, $lp, $lq, ($n+1)/2))[1] == 0; ($n, $q); } sub verify_bls3 { my ($n, $q, $a) = @_; fail "BLS3: $n failed Q odd" unless $q->is_odd(); fail "BLS3: $n failed Q > 2" unless $q > 2; my ($m, $rem) = ($n-1)->copy->bdiv($q); fail "BLS3: $n failed Q divides N-1" unless $rem == 0; fail "BLS3: $n failed MQ+1 = N" unless $m*$q+1 == $n; fail "BLS3: $n failed M > 0" unless $m > 0; fail "BLS3: $n failed 2Q+1 > sqrt(n)" unless 2*$q+1 > $n->copy->bsqrt(); fail "BLS3: $n failed A^((N-1)/2) = N-1 mod N" unless $a->copy->bmodpow(($n-1)/2, $n) == $n-1; fail "BLS3: $n failed A^(M/2) != N-1 mod N" unless $a->copy->bmodpow($m/2,$n) != $n-1; ($n, $q); } sub verify_pock { my ($n, $q, $a) = @_; my ($m, $rem) = ($n-1)->copy->bdiv($q); fail "Pocklington: $n failed Q divides N-1" unless $rem == 0; fail "Pocklington: $n failed M is even" unless $m->is_even(); fail "Pocklington: $n failed M > 0" unless $m > 0; fail "Pocklington: $n failed M < Q" unless $m < $q; fail "Pocklington: $n failed MQ+1 = N" unless $m*$q+1 == $n; fail "Pocklington: $n failed A > 1" unless $a > 1; fail "Pocklington: $n failed A^(N-1) mod N = 1" unless $a->copy->bmodpow($n-1, $n) == 1; fail "Pocklington: $n failed gcd(A^M - 1, N) = 1" unless Math::BigInt::bgcd($a->copy->bmodpow($m, $n)-1, $n) == 1; ($n, $q); } sub verify_small { my ($n) = @_; fail "Small n $n is > 2^64\n" unless $n <= $smallval; fail "Small n $n does not pass BPSW" unless is_prime($n); ($n); } sub verify_bls5 { my ($n, $Qr, $Ar) = @_; my @Q = @{$Qr}; my @A = @{$Ar}; my $nm1 = $n - 1; my $F = Math::BigInt->bone; my $R = $nm1->copy; my $index = $#Q; foreach my $i (0 .. $index) { error "BLS5: $n failed Q[$i] doesn't exist" unless defined $Q[$i]; $A[$i] = Math::BigInt->new(2) unless defined $A[$i]; fail "BLS5: $n failed Q[$i] > 1" unless $Q[$i] > 1; fail "BLS5: $n failed Q[$i] < N-1" unless $Q[$i] < $nm1; fail "BLS5: $n failed A[$i] > 1" unless $A[$i] > 1; fail "BLS5: $n failed A[$i] < N" unless $A[$i] < $n; fail "BLS5: $n failed Q[$i] divides N-1" unless ($nm1 % $Q[$i]) == 0; while (($R % $Q[$i]) == 0) { $F *= $Q[$i]; $R /= $Q[$i]; } } die "BLS5: Internal error R != (N-1)/F\n" unless $R == $nm1/$F; fail "BLS5: $n failed F is even" unless $F->is_even(); fail "BLS5: $n failed gcd(F, R) = 1\n" unless Math::BigInt::bgcd($F,$R) == 1; my ($s, $r) = $R->copy->bdiv(2*$F); my $P = ($F+1) * (2 * $F * $F + ($r-1)*$F + 1); fail "BLS5: $n failed n < P" unless $n < $P; fail "BLS5: $n failed s=0 OR r^2-8s not a perfect square" unless $s == 0 or !_is_perfect_square($r*$r - 8*$s); foreach my $i (0 .. $index) { my $a = $A[$i]; my $q = $Q[$i]; fail "BLS5: $n failed A[i]^(N-1) mod N = 1" unless $a->copy->bmodpow($nm1, $n) == 1; fail "BLS5: $n failed gcd(A[i]^((N-1)/Q[i])-1, N) = 1" unless Math::BigInt::bgcd($a->copy->bmodpow($nm1/$q, $n)-1, $n) == 1; } ($n, @Q); } sub verify_lucas { my ($n, $Qr, $a) = @_; my @Q = @{$Qr}; my $index = $#Q; fail "Lucas: $n failed A > 1" unless $a > 1; fail "Lucas: $n failed A < N" unless $a < $n; my $nm1 = $n - 1; my $F = Math::BigInt->bone; my $R = $nm1->copy; fail "Lucas: $n failed A^(N-1) mod N = 1" unless $a->copy->bmodpow($nm1, $n) == 1; foreach my $i (1 .. $index) { error "Lucas: $n failed Q[$i] doesn't exist" unless defined $Q[$i]; fail "Lucas: $n failed Q[$i] > 1" unless $Q[$i] > 1; fail "Lucas: $n failed Q[$i] < N-1" unless $Q[$i] < $nm1; fail "Lucas: $n failed Q[$i] divides N-1" unless ($nm1 % $Q[$i]) == 0; fail "Lucas: $n failed A^((N-1)/Q[$i]) mod N != 1" unless $a->copy->bmodpow($nm1/$Q[$i], $n) != 1; while (($R % $Q[$i]) == 0) { $F *= $Q[$i]; $R /= $Q[$i]; } } fail("Lucas: $n failed N-1 has only factors Q") unless $R == 1 && $F == $nm1; shift @Q; # Remove Q[0] ($n, @Q); } ############################################################################## # Utility functions ############################################################################## sub read_vars { my $type = shift; my %vars = map { $_ => 1 } @_; my %return; while (scalar keys %vars) { my $line = <>; error("end of file during type $type") unless defined $line; # Skip comments and blank lines next if $line =~ /^\s*#/ or $line =~ /^\s*$/; chomp($line); error("Still missing values in type $type") if $line =~ /^Type /; if ($line =~ /^(\S+)\s+(-?\d+)/) { my ($var, $val) = ($1, $2); $var =~ tr/a-z/A-Z/; error("Type $type: repeated or inappropriate var: $line") unless defined $vars{$var}; $return{$var} = $val; delete $vars{$var}; } else { error("Unrecognized line: $line"); } } # Now return them in the order given, turned into bigints. return map { Math::BigInt->new("$return{$_}") } @_; } sub primo_read_vars { my $type = shift; my %vars = map { $_ => 1 } @_; my %return; while (scalar keys %vars) { my $line = <>; error("end of file during type $type") unless defined $line; error("blank line during type $type") if $line =~ /^\s*$/; chomp($line); error("Still missing values in type $type") if $line =~ /^Type=/; if ($line =~ /^(\S+)\s*=\s*(\S+)/) { my ($var, $val) = ($1, $2); $var =~ tr/a-z/A-Z/; $val = "0x$val" if $var =~ s/\$$//; # For Primo, just skip things we don't understand. next unless defined $vars{$var}; $return{$var} = $val; delete $vars{$var}; } else { error("Unrecognized line: $line"); } } # Now return them in the order given, turned into bigints. my @ret; foreach my $var (@_) { my $sign = 1; $sign = -1 if $return{$var} =~ s/^(0x)?-/$1/; push @ret, Math::BigInt->new($return{$var}) * $sign; } return @ret; } sub _is_perfect_square { my($n) = @_; if (ref($n) eq 'Math::BigInt') { my $mc = int(($n & 31)->bstr); if ($mc==0||$mc==1||$mc==4||$mc==9||$mc==16||$mc==17||$mc==25) { my $sq = $n->copy->bsqrt->bfloor; $sq->bmul($sq); return 1 if $sq == $n; } } else { my $mc = $n & 31; if ($mc==0||$mc==1||$mc==4||$mc==9||$mc==16||$mc==17||$mc==25) { my $sq = int(sqrt($n)); return 1 if ($sq*$sq) == $n; } } 0; } # Calculate Jacobi symbol (M|N) sub _jacobi { my($n, $m) = @_; return 0 if $m <= 0 || ($m % 2) == 0; my $j = 1; if ($n < 0) { $n = -$n; $j = -$j if ($m % 4) == 3; } # Split loop so we can reduce n/m to non-bigints after first iteration. if ($n != 0) { while (($n % 2) == 0) { $n >>= 1; $j = -$j if ($m % 8) == 3 || ($m % 8) == 5; } ($n, $m) = ($m, $n); $j = -$j if ($n % 4) == 3 && ($m % 4) == 3; $n = $n % $m; $n = int($n->bstr) if ref($n) eq 'Math::BigInt' && $n <= ''.~0; $m = int($m->bstr) if ref($m) eq 'Math::BigInt' && $m <= ''.~0; } while ($n != 0) { while (($n % 2) == 0) { $n >>= 1; $j = -$j if ($m % 8) == 3 || ($m % 8) == 5; } ($n, $m) = ($m, $n); $j = -$j if ($n % 4) == 3 && ($m % 4) == 3; $n = $n % $m; } return ($m == 1) ? $j : 0; } Math-Prime-Util-GMP-0.52/examples/bench-mp-psrp.pl0000755000175000017500000000176013025437621020167 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Math::Prime::Util; use Math::Prime::Util::GMP; use Math::Primality; use Benchmark qw/:all/; use List::Util qw/min max/; my $count = shift || -2; srand(29); # So we have repeatable results test_at_digits($_, 1000) for (5, 15, 25, 50, 200); sub test_at_digits { my($digits, $numbers) = @_; die "Digits must be > 0" unless $digits > 0; # We get a mix of primes and non-primes. my @nums = map { Math::Prime::Util::random_ndigit_prime($digits)+2 } 1 .. $numbers; print "is_strong_pseudoprime for $numbers random $digits-digit numbers", " (", min(@nums), " - ", max(@nums), ")\n"; cmpthese($count,{ 'MP' =>sub {Math::Primality::is_strong_pseudoprime($_,3) for @nums;}, 'MPU' =>sub {Math::Prime::Util::is_strong_pseudoprime($_,3) for @nums;}, #'MPU PP' =>sub {Math::Prime::Util::PP::is_strong_pseudoprime($_,3) for @nums;}, 'MPU GMP' =>sub {Math::Prime::Util::GMP::is_strong_pseudoprime($_,3) for @nums;}, }); } Math-Prime-Util-GMP-0.52/examples/verify_primegap.pl0000644000175000017500000000727713025437621020712 0ustar danadana#!/usr/bin/perl # Verify a prime gap given the start (as number or expression) # If start is less than 200 digits, then endpoints will be proven. # # Otherwise, all values will use BPSW + 1 M-R: # a) divisibility by small factors # b) SPSP-2 # c) extra strong Lucas test # d) 1 Miller-Rabin test with a random base 3 .. N-2 # # No composite has been found that passes (b) + (c), so the combination # plus the extra M-R should give quite a bit of certainty that the # endpoints really are prime. # # Runs in parallel for number larger than 200 digits. # Examples: # # verify_primegap.pl "9169*439#/55230 - 6926" # verify_primegap.pl "1931*1933#/7230 - 30244" 2 # verify_primegap.pl "5557*4973#/2310 - 83542" 12 use warnings; use strict; use threads; use threads::shared; use feature 'say'; use Math::Prime::Util ':all'; use Math::Prime::Util::GMP; use Math::BigInt try=>"GMP"; use Math::BigFloat; $|=1; my @mpu_funcs = (qw/next_prime prev_prime prime_count nth_prime random_prime random_ndigit_prime random_nbit_prime random_strong_prime random_maurer_prime primorial pn_primorial moebius mertens euler_phi jordan_totient exp_mangoldt divisor_sum consecutive_integer_lcm/); my %mpu_func_map; my $N = shift || dieusage(); my $nthreads = shift || 8; $N =~ s/\s*$//; $N =~ s/^\s*//; $N = eval_expr($N) unless $N =~ /^\d+$/; $N = Math::BigInt->new("$N") unless ref($N) eq 'Math::BigInt'; $nthreads = 1 if length($N) <= 200; say_primality("start (" . length($N) . " digits)", $N); if ($nthreads <= 1) { my $end = next_prime($N); my $gap = $end-$N; my $merit = merit($N, $gap); say_primality("Endpoint (merit $merit) n+$gap", $end); exit(0); } my $searchto :shared = 1; my $found :shared = 0; my @threads; push @threads, threads->create('search', $_) for 1 .. $nthreads; $_->join() for (@threads); { my $gap = $found; my $end = $N+$found; my $merit = merit($N, $gap); say_primality("Endpoint (merit $merit) n+$gap", $end); exit(0); } sub search { my $tnum = shift; while (!$found) { my ($j, $n); { lock($searchto); $j = $searchto++; } #print " +$j($tnum) "; if ( Math::Prime::Util::GMP::is_prime($N + $j) ) { lock($found); if ($found == 0 || $found > $j) { $found = $j; } last; } } } sub eval_expr { my $expr = shift; die "$expr cannot be evaluated" if $expr =~ /:/; # Use : for escape if (scalar(keys %mpu_func_map) == 0) { my $n = 10; foreach my $func (@mpu_funcs) { $mpu_func_map{$func} = sprintf("%03d", $n++); } } $expr =~ s/\^/**/g; $expr =~ s/\b(\d+)#/primorial($1)/g; $expr =~ s/\blog\(/:001(/g; foreach my $func (@mpu_funcs) { $expr =~ s/\b$func\(/:$mpu_func_map{$func}(/g; } die "$expr cannot be evaluated" if $expr =~ tr|-0123456789+*/() :||c; $expr =~ s/:001/log/g; foreach my $func (@mpu_funcs) { $expr =~ s/:$mpu_func_map{$func}\(/ Math::BigInt->bone*Math::Prime::Util::$func(/g; } $expr =~ s/(\d+)/ Math::BigInt->new("$1") /g; my $res = eval $expr; ## no critic die "Cannot eval: $expr\n" if !defined $res; $res = int($res->bstr) if ref($res) eq 'Math::BigInt' && $res <= ~0; $res; } sub say_primality { my($text, $n) = @_; print "$text is "; my $is_prime = (length($n) <= 200) ? is_provable_prime($n) : is_prime($n); print "", ("composite", "probably prime (BPSW + 1 M-R)", "proven prime")[$is_prime]; print "\n"; } sub merit { my($n, $gap) = @_; my $fgap = Math::BigFloat->new("$gap"); my $fn = Math::BigFloat->new("$n"); return sprintf("%7.4f", $fgap / log($fn)); } sub dieusage { die "Usage: $0 \"expression\" [number-of-threads]\n"; } Math-Prime-Util-GMP-0.52/examples/vcert.c0000644000175000017500000016236213025437621016451 0ustar danadana/* * Verify Cert * version 0.96 * * Copyright (c) 2013-2016 Dana Jacobsen (dana@acm.org). * This is free software; you can redistribute it and/or modify it under * the same terms as the Perl 5 programming language system itself. * * Verifies Primo v3, Primo v4, and MPU certificates. * * Return values: * 0 all numbers are verified prime. * 1 at least one number was verified composite. * 2 the certificate does not provide a complete proof. * 3 there is an error in the certificate. * * TODO: Allow multiple proofs per input file * TODO: Projective EC for ~4x faster operation */ #include #include #include #include #include #include /*****************************************************************************/ /* Preliminary definitions */ /*****************************************************************************/ /* Projective doesn't work yet */ #define USE_AFFINE_EC 1 #define RET_PRIME 0 #define RET_COMPOSITE 1 #define RET_INVALID 2 #define RET_ERROR 3 #define CERT_UNKNOWN 0 #define CERT_PRIMO 1 #define CERT_PRIMO42 2 #define CERT_MPU 3 #define MAX_LINE_LEN 60000 #define MAX_STEPS 20000 #define MAX_QARRAY 100 #define BAD_LINES_ALLOWED 5 /* Similar to WraithX's verifier */ typedef unsigned long UV; typedef signed long IV; #define croak(fmt,...) { gmp_printf(fmt,##__VA_ARGS__); exit(RET_ERROR); } #define MPUassert(c,text) if (!(c)) { croak("Internal error: " text); } #define BGCD_PRIMES 168 #define BGCD_LASTPRIME 997 #define BGCD_NEXTPRIME 1009 void GMP_pn_primorial(mpz_t prim, UV n); UV trial_factor(mpz_t n, UV from_n, UV to_n); int miller_rabin_ui(mpz_t n, UV base); int miller_rabin(mpz_t n, mpz_t a); void lucas_seq(mpz_t U, mpz_t V, mpz_t n, IV P, IV Q, mpz_t k, mpz_t Qk, mpz_t t); #define mpz_mulmod(r, a, b, n, t) \ do { mpz_mul(t, a, b); mpz_mod(r, t, n); } while (0) /*****************************************************************************/ /* Some global variables and functions we'll use */ /*****************************************************************************/ int _verbose = 0; int _quiet = 0; int _testcount = 0; int _base = 10; int _step = 0; int _format = CERT_UNKNOWN; char _line[MAX_LINE_LEN+1]; char _vstr[MAX_LINE_LEN+1]; const char* _filename; FILE* _fh; mpz_t PROOFN, N, A, B, M, Q, X, Y, LQ, LP, S, R, T, J, W, T1, T2; mpz_t QARRAY[MAX_QARRAY]; mpz_t AARRAY[MAX_QARRAY]; mpz_t _bgcd; int _num_chains = 0; mpz_t _chain_n[MAX_STEPS]; mpz_t _chain_q[MAX_STEPS]; static void var_init(void) { int i; mpz_init(PROOFN); mpz_init(N); mpz_init(A); mpz_init(B); /* MPU: */ mpz_init(M); mpz_init(Q); mpz_init(X); mpz_init(Y); mpz_init(LQ); mpz_init(LP); /* Primo: */ mpz_init(S); mpz_init(R); mpz_init(T); mpz_init(J); mpz_init(W); mpz_init(_bgcd); GMP_pn_primorial(_bgcd, BGCD_PRIMES); mpz_init(T1); mpz_init(T2); for (i = 0; i < MAX_QARRAY; i++) { mpz_init(QARRAY[i]); mpz_init(AARRAY[i]); } } static void var_free(void) { int i; mpz_clear(PROOFN); mpz_clear(N); mpz_clear(A); mpz_clear(B); mpz_clear(M); mpz_clear(Q); mpz_clear(X); mpz_clear(Y); mpz_clear(LQ); mpz_clear(LP); mpz_clear(S); mpz_clear(R); mpz_clear(T); mpz_clear(J); mpz_clear(W); mpz_clear(_bgcd); mpz_clear(T1); mpz_clear(T2); for (i = 0; i < MAX_QARRAY; i++) { mpz_clear(QARRAY[i]); mpz_clear(AARRAY[i]); } } static void quit_prime(void) { if (!_quiet) printf(" \r"); if (!_quiet) printf("PRIME\n"); var_free(); exit(RET_PRIME); } static void quit_composite(void) { if (!_quiet) printf(" \r"); if (!_quiet) printf("COMPOSITE\n"); var_free(); exit(RET_COMPOSITE); } static void quit_invalid(const char* type, const char* msg) { if (!_quiet) printf("\n"); if (!_quiet) gmp_printf("%s: step %d, %Zd failed condition %s\n", type, _step, N, msg); var_free(); exit(RET_INVALID); } static void quit_error(const char* msg1, const char* msg2) { if (!_quiet) printf("\n"); if (!_quiet) gmp_printf("ERROR: step %d, %s%s\n", _step, msg1, msg2); var_free(); exit(RET_ERROR); } #if USE_AFFINE_EC /*****************************************************************************/ /* EC: affine with point (x,y,1) */ /*****************************************************************************/ struct ec_affine_point { mpz_t x, y; }; /* P3 = P1 + P2 */ static void _ec_add_AB(mpz_t n, struct ec_affine_point P1, struct ec_affine_point P2, struct ec_affine_point *P3, mpz_t m, mpz_t t1, mpz_t t2) { if (!mpz_cmp(P1.x, P2.x)) { mpz_add(t2, P1.y, P2.y); mpz_mod(t1, t2, n); if (!mpz_cmp_ui(t1, 0) ) { mpz_set_ui(P3->x, 0); mpz_set_ui(P3->y, 1); return; } } mpz_sub(t1, P2.x, P1.x); mpz_mod(t2, t1, n); /* t1 = 1/deltay mod n */ if (!mpz_invert(t1, t2, n)) { /* We've found a factor! In multiply, gcd(mult,n) will be a factor. */ mpz_set_ui(P3->x, 0); mpz_set_ui(P3->y, 1); return; } mpz_sub(m, P2.y, P1.y); mpz_mod(t2, m, n); /* t2 = deltay mod n */ mpz_mul(m, t1, t2); mpz_mod(m, m, n); /* m = deltay / deltax mod n */ /* x3 = m^2 - x1 - x2 mod n */ mpz_mul(t1, m, m); mpz_sub(t2, t1, P1.x); mpz_sub(t1, t2, P2.x); mpz_mod(P3->x, t1, n); /* y3 = m(x1 - x3) - y1 mod n */ mpz_sub(t1, P1.x, P3->x); mpz_mul(t2, m, t1); mpz_sub(t1, t2, P1.y); mpz_mod(P3->y, t1, n); } /* P3 = 2*P1 */ static void _ec_add_2A(mpz_t a, mpz_t n, struct ec_affine_point P1, struct ec_affine_point *P3, mpz_t m, mpz_t t1, mpz_t t2) { /* m = (3x1^2 + a) * (2y1)^-1 mod n */ mpz_mul_ui(t1, P1.y, 2); if (!mpz_invert(m, t1, n)) { mpz_set_ui(P3->x, 0); mpz_set_ui(P3->y, 1); return; } mpz_mul_ui(t1, P1.x, 3); mpz_mul(t2, t1, P1.x); mpz_add(t1, t2, a); mpz_mul(t2, m, t1); mpz_tdiv_r(m, t2, n); /* x3 = m^2 - 2x1 mod n */ mpz_mul(t1, m, m); mpz_mul_ui(t2, P1.x, 2); mpz_sub(t1, t1, t2); mpz_tdiv_r(P3->x, t1, n); /* y3 = m(x1 - x3) - y1 mod n */ mpz_sub(t1, P1.x, P3->x); mpz_mul(t2, t1, m); mpz_sub(t1, t2, P1.y); mpz_tdiv_r(P3->y, t1, n); } static int ec_affine_multiply(mpz_t a, mpz_t k, mpz_t n, struct ec_affine_point P, struct ec_affine_point *R, mpz_t d) { int found = 0; struct ec_affine_point A, B, C; mpz_t t, t2, t3, mult; mpz_init(A.x); mpz_init(A.y); mpz_init(B.x); mpz_init(B.y); mpz_init(C.x); mpz_init(C.y); mpz_init(t); mpz_init(t2); mpz_init(t3); mpz_init_set_ui(mult, 1); /* holds intermediates, gcd at end */ mpz_set(A.x, P.x); mpz_set(A.y, P.y); mpz_set_ui(B.x, 0); mpz_set_ui(B.y, 1); /* Binary ladder multiply. */ while (mpz_cmp_ui(k, 0) > 0) { if (mpz_odd_p(k)) { mpz_sub(t, B.x, A.x); mpz_mul(t2, mult, t); mpz_mod(mult, t2, n); if ( !mpz_cmp_ui(A.x, 0) && !mpz_cmp_ui(A.y, 1) ) { /* nothing */ } else if ( !mpz_cmp_ui(B.x, 0) && !mpz_cmp_ui(B.y, 1) ) { mpz_set(B.x, A.x); mpz_set(B.y, A.y); } else { _ec_add_AB(n, A, B, &C, t, t2, t3); /* If the add failed to invert, then we have a factor. */ mpz_set(B.x, C.x); mpz_set(B.y, C.y); } mpz_sub_ui(k, k, 1); } else { mpz_mul_ui(t, A.y, 2); mpz_mul(t2, mult, t); mpz_mod(mult, t2, n); _ec_add_2A(a, n, A, &C, t, t2, t3); mpz_set(A.x, C.x); mpz_set(A.y, C.y); mpz_tdiv_q_2exp(k, k, 1); } } mpz_gcd(d, mult, n); found = (mpz_cmp_ui(d, 1) && mpz_cmp(d, n)); mpz_tdiv_r(R->x, B.x, n); mpz_tdiv_r(R->y, B.y, n); mpz_clear(mult); mpz_clear(t); mpz_clear(t2); mpz_clear(t3); mpz_clear(A.x); mpz_clear(A.y); mpz_clear(B.x); mpz_clear(B.y); mpz_clear(C.x); mpz_clear(C.y); return found; } #else /*****************************************************************************/ /* EC: projective with point (X,1,Z) (Montgomery) */ /*****************************************************************************/ /* (xout:zout) = (x1:z1) + (x2:z2) */ static void pec_add3(mpz_t xout, mpz_t zout, mpz_t x1, mpz_t z1, mpz_t x2, mpz_t z2, mpz_t xin, mpz_t zin, mpz_t n, mpz_t u, mpz_t v, mpz_t w) { mpz_sub(u, x2, z2); mpz_add(v, x1, z1); mpz_mulmod(u, u, v, n, w); /* u = (x2 - z2) * (x1 + z1) % n */ mpz_add(v, x2, z2); mpz_sub(w, x1, z1); mpz_mulmod(v, v, w, n, v); /* v = (x2 + z2) * (x1 - z1) % n */ mpz_add(w, u, v); /* w = u+v */ mpz_sub(v, u, v); /* v = u-v */ mpz_mulmod(w, w, w, n, u); /* w = (u+v)^2 % n */ mpz_mulmod(v, v, v, n, u); /* v = (u-v)^2 % n */ mpz_set(u, xin); mpz_mulmod(xout, w, zin, n, w); mpz_mulmod(zout, v, u, n, w); /* 6 mulmods, 6 adds */ } /* (x2:z2) = 2(x1:z1) */ static void pec_double(mpz_t x2, mpz_t z2, mpz_t x1, mpz_t z1, mpz_t b, mpz_t n, mpz_t u, mpz_t v, mpz_t w) { mpz_add(u, x1, z1); mpz_mulmod(u, u, u, n, w); /* u = (x1+z1)^2 % n */ mpz_sub(v, x1, z1); mpz_mulmod(v, v, v, n, w); /* v = (x1-z1)^2 % n */ mpz_mulmod(x2, u, v, n, w); /* x2 = uv % n */ mpz_sub(w, u, v); /* w = u-v = 4(x1 * z1) */ mpz_mulmod(u, b, w, n, z2); mpz_add(u, u, v); /* u = (v+b*w) mod n */ mpz_mulmod(z2, w, u, n, v); /* z2 = (w*u) mod n */ /* 5 mulmods, 4 adds */ } #define NORMALIZE(f, u, v, x, z, n) \ mpz_gcdext(f, u, NULL, z, n); \ mpz_mulmod(x, x, u, n, v); \ mpz_set_ui(z, 1); static void pec_mult(mpz_t a, mpz_t b, mpz_t k, mpz_t n, mpz_t x, mpz_t z) { mpz_t u, v, w, x1, x2, z1, z2, r; int l = -1; mpz_init(u); mpz_init(v); mpz_init(w); mpz_init(x1); mpz_init(x2); mpz_init(z1); mpz_init(z2); mpz_sub_ui(k, k, 1); mpz_init_set(r, k); while (mpz_cmp_ui(r, 1) > 0) { mpz_tdiv_q_2exp(r, r, 1); l++; } mpz_clear(r); if (mpz_tstbit(k, l)) { pec_double(x2, z2, x, z, b, n, u, v, w); pec_add3(x1, z1, x2, z2, x, z, x, z, n, u, v, w); pec_double(x2, z2, x2, z2, b, n, u, v, w); } else { pec_double(x1, z1, x, z, b, n, u, v, w); pec_add3(x2, z2, x, z, x1, z1, x, z, n, u, v, w); } l--; while (l >= 1) { if (mpz_tstbit(k, l)) { pec_add3(x1, z1, x1, z1, x2, z2, x, z, n, u, v, w); pec_double(x2, z2, x2, z2, b, n, u, v, w); } else { pec_add3(x2, z2, x2, z2, x1, z1, x, z, n, u, v, w); pec_double(x1, z1, x1, z1, b, n, u, v, w); } l--; } if (mpz_tstbit(k, 0)) { pec_double(x, z, x2, z2, b, n, u, v, w); } else { pec_add3(x, z, x2, z2, x1, z1, x, z, n, u, v, w); } mpz_clear(u); mpz_clear(v); mpz_clear(w); mpz_clear(x1); mpz_clear(x2); mpz_clear(z1); mpz_clear(z2); } #endif /*****************************************************************************/ /* M-R, Lucas, BPSW */ /*****************************************************************************/ int miller_rabin_ui(mpz_t n, UV base) { int rval; mpz_t a; mpz_init_set_ui(a, base); rval = miller_rabin(n, a); mpz_clear(a); return rval; } int miller_rabin(mpz_t n, mpz_t a) { mpz_t nminus1, d, x; UV s, r; int rval; { int cmpr = mpz_cmp_ui(n, 2); if (cmpr == 0) return 1; /* 2 is prime */ if (cmpr < 0) return 0; /* below 2 is composite */ if (mpz_even_p(n)) return 0; /* multiple of 2 is composite */ } if (mpz_cmp_ui(a, 1) <= 0) croak("Base %ld is invalid", mpz_get_si(a)); mpz_init_set(nminus1, n); mpz_sub_ui(nminus1, nminus1, 1); mpz_init_set(x, a); /* Handle large and small bases. Use x so we don't modify their input a. */ if (mpz_cmp(x, n) >= 0) mpz_mod(x, x, n); if ( (mpz_cmp_ui(x, 1) <= 0) || (mpz_cmp(x, nminus1) >= 0) ) { mpz_clear(nminus1); mpz_clear(x); return 1; } mpz_init_set(d, nminus1); s = mpz_scan1(d, 0); mpz_tdiv_q_2exp(d, d, s); mpz_powm(x, x, d, n); mpz_clear(d); /* done with a and d */ rval = 0; if (!mpz_cmp_ui(x, 1) || !mpz_cmp(x, nminus1)) { rval = 1; } else { for (r = 1; r < s; r++) { mpz_powm_ui(x, x, 2, n); if (!mpz_cmp_ui(x, 1)) { break; } if (!mpz_cmp(x, nminus1)) { rval = 1; break; } } } mpz_clear(nminus1); mpz_clear(x); return rval; } /* Returns Lucas sequence U_k mod n and V_k mod n defined by P,Q */ void lucas_seq(mpz_t U, mpz_t V, mpz_t n, IV P, IV Q, mpz_t k, mpz_t Qk, mpz_t t) { UV b = mpz_sizeinbase(k, 2); IV D = P*P - 4*Q; MPUassert( mpz_cmp_ui(n, 2) >= 0, "lucas_seq: n is less than 2" ); MPUassert( mpz_cmp_ui(k, 0) >= 0, "lucas_seq: k is negative" ); MPUassert( P >= 0 && mpz_cmp_si(n, P) >= 0, "lucas_seq: P is out of range" ); MPUassert( mpz_cmp_si(n, Q) >= 0, "lucas_seq: Q is out of range" ); MPUassert( D != 0, "lucas_seq: D is zero" ); if (mpz_cmp_ui(k, 0) <= 0) { mpz_set_ui(U, 0); mpz_set_ui(V, 2); return; } MPUassert( mpz_odd_p(n), "lucas_seq: implementation is for odd n" ); mpz_set_ui(U, 1); mpz_set_si(V, P); mpz_set_si(Qk, Q); if (Q == 1) { /* Use the fast V method if possible. Much faster with small n. */ mpz_set_si(t, P*P-4); if (P > 2 && mpz_invert(t, t, n)) { /* Compute V_k and V_{k+1}, then computer U_k from them. */ mpz_set_si(V, P); mpz_init_set_si(U, P*P-2); while (b > 1) { b--; if (mpz_tstbit(k, b-1)) { mpz_mul(V, V, U); mpz_sub_ui(V, V, P); mpz_mod(V, V, n); mpz_mul(U, U, U); mpz_sub_ui(U, U, 2); mpz_mod(U, U, n); } else { mpz_mul(U, V, U); mpz_sub_ui(U, U, P); mpz_mod(U, U, n); mpz_mul(V, V, V); mpz_sub_ui(V, V, 2); mpz_mod(V, V, n); } } mpz_mul_ui(U, U, 2); mpz_submul_ui(U, V, P); mpz_mul(U, U, t); } else { /* Fast computation of U_k and V_k, specific to Q = 1 */ while (b > 1) { mpz_mulmod(U, U, V, n, t); /* U2k = Uk * Vk */ mpz_mul(V, V, V); mpz_sub_ui(V, V, 2); mpz_mod(V, V, n); /* V2k = Vk^2 - 2 Q^k */ b--; if (mpz_tstbit(k, b-1)) { mpz_mul_si(t, U, D); /* U: U2k+1 = (P*U2k + V2k)/2 */ mpz_mul_si(U, U, P); mpz_add(U, U, V); if (mpz_odd_p(U)) mpz_add(U, U, n); mpz_fdiv_q_2exp(U, U, 1); /* V: V2k+1 = (D*U2k + P*V2k)/2 */ mpz_mul_si(V, V, P); mpz_add(V, V, t); if (mpz_odd_p(V)) mpz_add(V, V, n); mpz_fdiv_q_2exp(V, V, 1); } } } } else { while (b > 1) { mpz_mulmod(U, U, V, n, t); /* U2k = Uk * Vk */ mpz_mul(V, V, V); mpz_submul_ui(V, Qk, 2); mpz_mod(V, V, n); /* V2k = Vk^2 - 2 Q^k */ mpz_mul(Qk, Qk, Qk); /* Q2k = Qk^2 */ b--; if (mpz_tstbit(k, b-1)) { mpz_mul_si(t, U, D); /* U: U2k+1 = (P*U2k + V2k)/2 */ mpz_mul_si(U, U, P); mpz_add(U, U, V); if (mpz_odd_p(U)) mpz_add(U, U, n); mpz_fdiv_q_2exp(U, U, 1); /* V: V2k+1 = (D*U2k + P*V2k)/2 */ mpz_mul_si(V, V, P); mpz_add(V, V, t); if (mpz_odd_p(V)) mpz_add(V, V, n); mpz_fdiv_q_2exp(V, V, 1); mpz_mul_si(Qk, Qk, Q); } mpz_mod(Qk, Qk, n); } } mpz_mod(U, U, n); mpz_mod(V, V, n); } static int lucas_selfridge_params(IV* P, IV* Q, mpz_t n, mpz_t t) { IV D = 5; UV Dui = (UV) D; while (1) { UV gcd = mpz_gcd_ui(NULL, n, Dui); if ((gcd > 1) && mpz_cmp_ui(n, gcd) != 0) return 0; mpz_set_si(t, D); if (mpz_jacobi(t, n) == -1) break; if (Dui == 21 && mpz_perfect_square_p(n)) return 0; Dui += 2; D = (D > 0) ? -Dui : Dui; if (Dui > 1000000) croak("lucas_selfridge_params: D exceeded 1e6"); } if (P) *P = 1; if (Q) *Q = (1 - D) / 4; return 1; } static int lucas_extrastrong_params(IV* P, IV* Q, mpz_t n, mpz_t t, UV inc) { UV tP = 3; if (inc < 1 || inc > 256) croak("Invalid lucas parameter increment: %lu\n", (unsigned long)inc); while (1) { UV D = tP*tP - 4; UV gcd = mpz_gcd_ui(NULL, n, D); if (gcd > 1 && mpz_cmp_ui(n, gcd) != 0) return 0; mpz_set_ui(t, D); if (mpz_jacobi(t, n) == -1) break; if (tP == (3+20*inc) && mpz_perfect_square_p(n)) return 0; tP += inc; if (tP > 65535) croak("lucas_extrastrong_params: P exceeded 65535"); } if (P) *P = (IV)tP; if (Q) *Q = 1; return 1; } int is_lucas_pseudoprime(mpz_t n, int strength) { mpz_t d, U, V, Qk, t; IV P = 0, Q = 0; UV s = 0; int rval; { int cmpr = mpz_cmp_ui(n, 2); if (cmpr == 0) return 1; /* 2 is prime */ if (cmpr < 0) return 0; /* below 2 is composite */ if (mpz_even_p(n)) return 0; /* multiple of 2 is composite */ } mpz_init(t); rval = (strength < 2) ? lucas_selfridge_params(&P, &Q, n, t) : lucas_extrastrong_params(&P, &Q, n, t, 1); if (!rval) { mpz_clear(t); return 0; } mpz_init(U); mpz_init(V); mpz_init(Qk); mpz_init_set(d, n); mpz_add_ui(d, d, 1); if (strength > 0) { s = mpz_scan1(d, 0); mpz_tdiv_q_2exp(d, d, s); } lucas_seq(U, V, n, P, Q, d, Qk, t); mpz_clear(d); rval = 0; if (strength == 0) { /* Standard checks U_{n+1} = 0 mod n. */ rval = (mpz_sgn(U) == 0); } else if (strength == 1) { if (mpz_sgn(U) == 0) { rval = 1; } else { while (s--) { if (mpz_sgn(V) == 0) { rval = 1; break; } if (s) { mpz_mul(V, V, V); mpz_submul_ui(V, Qk, 2); mpz_mod(V, V, n); mpz_mulmod(Qk, Qk, Qk, n, t); } } } } else { mpz_sub_ui(t, n, 2); if ( mpz_sgn(U) == 0 && (mpz_cmp_ui(V, 2) == 0 || mpz_cmp(V, t) == 0) ) { rval = 1; } else { s--; /* The extra strong test tests r < s-1 instead of r < s */ while (s--) { if (mpz_sgn(V) == 0) { rval = 1; break; } if (s) { mpz_mul(V, V, V); mpz_sub_ui(V, V, 2); mpz_mod(V, V, n); } } } } mpz_clear(Qk); mpz_clear(V); mpz_clear(U); mpz_clear(t); return rval; } int is_prob_prime(mpz_t n) { /* Step 1: Look for small divisors. This is done purely for performance. * It is *not* a requirement for the BPSW test. */ /* If less than 1009, make trial factor handle it. */ if (mpz_cmp_ui(n, BGCD_NEXTPRIME) < 0) return trial_factor(n, 2, BGCD_LASTPRIME) ? 0 : 2; /* Check for tiny divisors (GMP can do these really fast) */ if ( mpz_even_p(n) || mpz_divisible_ui_p(n, 3) || mpz_divisible_ui_p(n, 5) ) return 0; /* Do a big GCD with all primes < 1009 */ { mpz_t t; mpz_init(t); mpz_gcd(t, n, _bgcd); if (mpz_cmp_ui(t, 1) != 0) { mpz_clear(t); return 0; } mpz_clear(t); } /* No divisors under 1009 */ if (mpz_cmp_ui(n, BGCD_NEXTPRIME*BGCD_NEXTPRIME) < 0) return 2; /* Step 2: The BPSW test. psp base 2 and slpsp. */ /* Miller Rabin with base 2 */ if (miller_rabin_ui(n, 2) == 0) return 0; /* Extra-Strong Lucas test */ if (is_lucas_pseudoprime(n, 2 /*extra strong*/) == 0) return 0; /* BPSW is deterministic below 2^64 */ if (mpz_sizeinbase(n, 2) <= 64) return 2; return 1; } /* These primorial and trial factor functions are really slow for numerous * reasons, but most of all because mpz_nextprime is dog slow. We don't * really use them, so don't worry about it too much. */ void GMP_pn_primorial(mpz_t prim, UV n) { mpz_t p; mpz_init_set_ui(p, 2); mpz_set_ui(prim, 1); while (n--) { mpz_mul(prim, prim, p); mpz_nextprime(p, p); } mpz_clear(p); } UV trial_factor(mpz_t n, UV from_n, UV to_n) { mpz_t p; UV f = 0; if (mpz_cmp_ui(n, 4) < 0) return (mpz_cmp_ui(n, 1) <= 0) ? 1 : 0; /* 0,1 => 1 2,3 => 0 */ if (from_n <= 2 && to_n >= 2 && mpz_even_p(n) ) return 2; else if (from_n <= 3 && to_n >= 3 && mpz_divisible_ui_p(n, 3)) return 2; if (from_n < 5) from_n = 5; if (from_n > to_n) return 0; mpz_init(p); mpz_sqrt(p, n); if (mpz_cmp_ui(p, to_n) < 0) to_n = mpz_get_ui(p); /* limit to_n to sqrtn */ mpz_set_ui(p, from_n-1); mpz_nextprime(p, p); /* Set p to the first prime >= from_n */ while (mpz_cmp_ui(p, to_n) <= 0) { if (mpz_divisible_p(n, p)) { f = mpz_get_ui(p); break; } mpz_nextprime(p, p); } mpz_clear(p); return f; } /*****************************************************************************/ /* Proof verification */ /*****************************************************************************/ /* What each of these does is verify: * Assume Q is prime. * Then N is prime based on the proof given. * We verify any necessary conditions on Q (e.g. it must be odd, or > 0, etc. * but do not verify Q prime. That is done in another proof step. */ /* ECPP using N, A, B, M, Q, X, Y * * A.O.L. Atkin and F. Morain, "Elliptic Curves and primality proving" * Mathematics of Computation, v61, 1993, pages 29-68. * http://www.ams.org/journals/mcom/1993-61-203/S0025-5718-1993-1199989-X/ * * Page 10, Theorem 5.2: * "Let N be an integer prime to 6, E an elliptic curve over Z/NZ, together * with a point P on E and m and s two integers with s | m. For each prime * divisor q of s, we put (m/q)P = (x_q : y_q : z_q). We assume that * mP = O_E and gcd(z_q,N) = 1 for all q. Then, if p is a prime divisor * of N, one has #E(Z/pZ) = 0 mod s." * Page 10, Corollary 5.1: * "With the same conditions, if s > (N^(1/4) + 1)^2, then N is prime." * * Basically this same result is repeated in Crandall and Pomerance 2005, * Theorem 7.6.1 "Goldwasser-Kilian ECPP theorem". * * Wikipedia, "Elliptic curve primality testing": * "Let N be a positive integer, and E be the set which is defined by the * equation y^2 = x^3 + ax + b (mod N). Consider E over Z/NZ, use the * usual addition law on E, and write O for the neutral element on E. * Let m be an integer. If there is a prime q which divides m, and is * greater than (N^(1/4) + 1)^2 and there exists a point P on E such that * (1) mP = O, (2) (m/q)P is defined and not equal to O, then N is prime." * * We use the restricted form as stated by Wikipedia and used in the * Atkin/Morain ECPP algorithm, where s is a prime (hence the "for each prime * divisor q of s" of the general theorem is just s). */ void verify_ecpp(void) { mpz_mod(A, A, N); mpz_mod(B, B, N); if (mpz_cmp_ui(N, 0) <= 0) quit_invalid("ECPP", "N > 0"); if (mpz_gcd_ui(NULL, N, 6) != 1) quit_invalid("ECPP", "gcd(N, 6) = 1"); mpz_mul(T1, A, A); mpz_mul(T1, T1, A); mpz_mul_ui(T1, T1, 4); mpz_mul(T2, B, B); mpz_mul_ui(T2, T2, 27); mpz_add(T1, T1, T2); mpz_gcd(T1, T1, N); if (mpz_cmp_ui(T1, 1) != 0) quit_invalid("ECPP", "gcd(4*a^3 + 27*b^2, N) = 1"); mpz_mul(T1, X, X); mpz_add(T1, T1, A); mpz_mul(T1, T1, X); mpz_add(T1, T1, B); mpz_mod(T1, T1, N); mpz_mul(T2, Y, Y); mpz_mod(T2, T2, N); if (mpz_cmp(T1, T2) != 0) quit_invalid("ECPP", "Y^2 = X^3 + A*X + B mod N"); mpz_mul_ui(T2, N, 4); mpz_sqrt(T2, T2); mpz_add_ui(T1, N, 1); mpz_sub(T1, T1, T2); if (mpz_cmp(M, T1) < 0) quit_invalid("ECPP", "M >= N + 1 - 2*sqrt(N)"); mpz_add_ui(T1, N, 1); mpz_add(T1, T1, T2); if (mpz_cmp(M, T1) > 0) quit_invalid("ECPP", "M <= N + 1 + 2*sqrt(N)"); mpz_root(T1, N, 4); mpz_add_ui(T1, T1, 1); mpz_mul(T1, T1, T1); if (mpz_cmp(Q, T1) <= 0) quit_invalid("ECPP", "Q > (N^(1/4)+1)^2"); if (mpz_cmp(Q, N) >= 0) quit_invalid("ECPP", "Q < N"); /* While M = Q is odd to compute in a proof, it is allowed. * In Primo terms, this means S=1 is allowed. * if (mpz_cmp(M, Q) == 0) quit_invalid("ECPP", "M != Q"); */ if (!mpz_divisible_p(M, Q)) quit_invalid("ECPP", "Q divides M"); { #if USE_AFFINE_EC struct ec_affine_point P0, P1, P2; mpz_init_set(P0.x, X); mpz_init_set(P0.y, Y); mpz_init(P1.x); mpz_init(P1.y); mpz_init(P2.x); mpz_init(P2.y); mpz_divexact(T1, M, Q); if (ec_affine_multiply(A, T1, N, P0, &P2, T2)) quit_invalid("ECPP", "Factor found for N"); /* Check that P2 is not (0,1) */ if (mpz_cmp_ui(P2.x, 0) == 0 && mpz_cmp_ui(P2.y, 1) == 0) quit_invalid("ECPP", "(M/Q) * EC(A,B,N,X,Y) is not identity"); mpz_set(T1, Q); if (ec_affine_multiply(A, T1, N, P2, &P1, T2)) quit_invalid("ECPP", "Factor found for N"); /* Check that P1 is (0, 1) */ if (! (mpz_cmp_ui(P1.x, 0) == 0 && mpz_cmp_ui(P1.y, 1) == 0) ) quit_invalid("ECPP", "M * EC(A,B,N,X,Y) is identity"); mpz_clear(P0.x); mpz_clear(P0.y); mpz_clear(P1.x); mpz_clear(P1.y); mpz_clear(P2.x); mpz_clear(P2.y); #else mpz_t PX, PY, PA, PB; mpz_init(PX); mpz_init(PY); mpz_init(PA); mpz_init(PB); /* We have A,B,X,Y in affine coordinates, for the curve: * Y^2 = X^3 + AX + B * and want to turn this into points on a Montgomery curve: * by^2 = x^3 + ax^2 + x * so we can use the much faster (~4x) multiplication routines. * The inverse of this operation is: * X = (3x+a)/3b * Y = y/b * A = (3-a^2)/(3b^2) * B = (2a^3-9a)/27b^3 * In our case we need to do the harder job of going the other direction. */ /* Make Montgomery variables from affine (TODO: make this work) */ mpz_add(PB, X, A); mpz_mul(PB, PB, X); mpz_add_ui(PB, PB, 1); mpz_mul(PB, PB, X); mpz_mod(PB, PB, N); mpz_mul_ui(T2, PB, 3); mpz_mul(T2, T2, PB); mpz_mod(T2, T2, N); mpz_gcdext(T2, T1, NULL, T2, N); /* T1 = 1/3g^2 */ if (mpz_cmp_ui(T2,1) != 0) quit_invalid("ECPP", "Factor found during gcd"); mpz_mul_ui(PX, X, 3); mpz_add(PX, PX, A); mpz_mul(PX, PX, PB); mpz_mul(PX, PX, T1); mpz_mod(PX, PX, N); mpz_set(PY, Y); mpz_mul_ui(PY, PY, 3); mpz_mul(PY, PY, PB); mpz_mul(PY, PY, T1); mpz_mod(PY, PY, N); /* y = (3gY)/(3g^2) = Y/g */ mpz_mul(PA, A, A); mpz_sub_ui(PA, PA, 3); mpz_neg(PA, PA); mpz_mul(PA, PA, T1); mpz_mod(PA, PA, N); mpz_divexact(T1, M, Q); pec_mult(PA, PB, T1, N, PX, PY); /* Check that point is not (0,0) */ if (mpz_cmp_ui(PX, 0) == 0 && mpz_cmp_ui(PY, 0) == 0) quit_invalid("ECPP", "(M/Q) * EC(A,B,N,X,Y) is not identity"); mpz_set(T1, Q); pec_mult(PA, PB, T1, N, PX, PY); /* Check that point is (0, 0) */ if (! (mpz_cmp_ui(PX, 0) == 0 && mpz_cmp_ui(PY, 0) == 0) ) quit_invalid("ECPP", "M * EC(A,B,N,X,Y) is identity"); mpz_clear(PX); mpz_clear(PY); mpz_clear(PA); mpz_clear(PB); #endif } } /* Basic N+1 using N, Q, LP, LQ * * John Brillhart, D.H. Lehmer, J.L. Selfridge, * "New Primality Criteria and Factorizations of 2^m +/- 1" * Mathematics of Computation, v29, n130, April 1975, pp 620-647. * http://www.ams.org/journals/mcom/1975-29-130/S0025-5718-1975-0384673-1/S0025-5718-1975-0384673-1.pdf * * Page 631, Theorem 15: * "Let N+1 = mq, where q is an odd prime such that 2q-1 > sqrt(N). * If there exists a Lucas sequence {V_k} of discriminant D with * (D|N) = -1 for which N|V_{(N+1)/2}, but N∤V_{m/2}, then N is prime." */ void verify_bls15(void) { if (mpz_even_p(Q)) quit_invalid("BLS15", "Q odd"); if (mpz_cmp_ui(Q, 2) <= 0) quit_invalid("BLS15", "Q > 2"); mpz_add_ui(T2, N, 1); if (!mpz_divisible_p(T2, Q)) quit_invalid("BLS15", "Q divides N+1"); mpz_divexact(M, T2, Q); mpz_mul(T1, M, Q); mpz_sub_ui(T1, T1, 1); if (mpz_cmp(T1, N) != 0) quit_invalid("BLS15", "MQ-1 = N"); if (mpz_cmp_ui(M, 0) <= 0) quit_invalid("BLS15", "M > 0"); mpz_mul_ui(T1, Q, 2); mpz_sub_ui(T1, T1, 1); mpz_sqrt(T2, N); if (mpz_cmp(T1, T2) <= 0) quit_invalid("BLS15", "2Q-1 > sqrt(N)"); mpz_mul(T1, LP, LP); mpz_mul_ui(T2, LQ, 4); mpz_sub(T1, T1, T2); if (mpz_sgn(T1) == 0) quit_invalid("BLS15", "D != 0"); if (mpz_jacobi(T1, N) != -1) quit_invalid("BLS15", "jacobi(D,N) = -1"); { mpz_t U, V, k; IV iLP, iLQ; mpz_init(U); mpz_init(V); mpz_init(k); iLP = mpz_get_si(LP); iLQ = mpz_get_si(LQ); if (mpz_cmp_si(LP, iLP) != 0) quit_error("BLS15 LP out of range", ""); if (mpz_cmp_si(LQ, iLQ) != 0) quit_error("BLS15 LQ out of range", ""); mpz_tdiv_q_2exp(k, M, 1); lucas_seq(U, V, N, iLP, iLQ, k, T1, T2); if (mpz_sgn(V) == 0) quit_invalid("BLS15", "V_{m/2} mod N != 0"); mpz_add_ui(k, N, 1); mpz_tdiv_q_2exp(k, k, 1); lucas_seq(U, V, N, iLP, iLQ, k, T1, T2); if (mpz_sgn(V) != 0) quit_invalid("BLS15", "V_{(N+1)/2} mod N == 0"); mpz_clear(U); mpz_clear(V); mpz_clear(k); } } /* Simplistic N-1 using N, Q, A * * Hans Riesel, "Prime Numbers and Computer Methods for Factorization" * page 103-104, Theorem 4.6: * "Suppose N-1 = R*F = R prod(j=1,n,q_j^{B_j}), with all q_j's distinct * primes, with GCD(R,F) = 1 and R < F. If an integer a can be found, s.t. * GCD(A^((N-1)/q_j)-1,N) = 1 for all j=1..n * and satisfying * a^(N-1) = 1 mod N * then N is a prime." * * Now make the severe restriction that F must be a single prime q. This then * reduces to the Wikipedia "Pocklington primality test": * "Let N > 1 be an integer, and suppose there exist numbers a and q such that * (1) q is prime, q|N-1 and q > sqrt(N)-1 * (2) a^(N-1) = 1 mod N * (3) gcd(a^((N-1)/q)-1,N) = 1 * Then N is prime." * * Note that BLS75 theorem 3 is similar, but also allows a smaller q. Also, * BLS75 theorem 5 is a much better method than generalized Pocklington. */ void verify_pocklington(void) { mpz_sub_ui(T2, N, 1); if (!mpz_divisible_p(T2, Q)) quit_invalid("Pocklington", "Q divides N-1"); mpz_divexact(M, T2, Q); if (mpz_odd_p(M)) quit_invalid("Pocklington", "M is even"); if (mpz_cmp_ui(M, 0) <= 0) quit_invalid("Pocklington", "M > 0"); if (mpz_cmp(M, Q) >= 0) quit_invalid("Pocklington", "M < Q"); mpz_mul(T1, M, Q); mpz_add_ui(T1, T1, 1); if (mpz_cmp(T1, N) != 0) quit_invalid("Pocklington", "MQ+1 = N"); if (mpz_cmp_ui(A, 1) <= 0) quit_invalid("Pocklington", "A > 1"); if (mpz_cmp(A, N) >= 0) quit_invalid("Pocklington", "A < N"); mpz_powm(T1, A, T2, N); if (mpz_cmp_ui(T1, 1) != 0) quit_invalid("Pocklington", "A^(N-1) mod N = 1"); mpz_powm(T1, A, M, N); if (mpz_sgn(T1)) mpz_sub_ui(T1, T1, 1); else mpz_set(T1, T2); mpz_gcd(T1, T1, N); if (mpz_cmp_ui(T1, 1) != 0) quit_invalid("Pocklington", "gcd(A^M - 1, N) = 1"); } /* Basic N-1 using N, Q, A * * John Brillhart, D.H. Lehmer, J.L. Selfridge, * "New Primality Criteria and Factorizations of 2^m +/- 1" * Mathematics of Computation, v29, n130, April 1975, pp 620-647. * http://www.ams.org/journals/mcom/1975-29-130/S0025-5718-1975-0384673-1/S0025-5718-1975-0384673-1.pdf * * Page 622-623, Theorem 3: * "Let N-1 = mp, where p is an odd prime such that 2p+1 > sqrt(N). * If there exists an a for which a^((N-1)/2) = -1 mod N, * but a^(m/2) != -1 mod N, then N is prime." */ void verify_bls3(void) { if (mpz_even_p(Q)) quit_invalid("BLS3", "Q odd"); if (mpz_cmp_ui(Q, 2) <= 0) quit_invalid("BLS3", "Q > 2"); mpz_sub_ui(T2, N, 1); if (!mpz_divisible_p(T2, Q)) quit_invalid("BLS3", "Q divides N-1"); mpz_divexact(M, T2, Q); mpz_mul(T1, M, Q); mpz_add_ui(T1, T1, 1); if (mpz_cmp(T1, N) != 0) quit_invalid("BLS3", "MQ+1 = N"); if (mpz_cmp_ui(M, 0) <= 0) quit_invalid("BLS3", "M > 0"); mpz_mul_ui(T1, Q, 2); mpz_add_ui(T1, T1, 1); mpz_sqrt(T2, N); if (mpz_cmp(T1, T2) <= 0) quit_invalid("BLS3", "2Q+1 > sqrt(N)"); mpz_sub_ui(T2, N, 1); mpz_divexact_ui(T1, T2, 2); mpz_powm(T1, A, T1, N); if (mpz_cmp(T1, T2) != 0) quit_invalid("BLS3", "A^((N-1)/2) = N-1 mod N"); mpz_divexact_ui(T1, M, 2); mpz_powm(T1, A, T1, N); if (mpz_cmp(T1, T2) == 0) quit_invalid("BLS3", "A^(M/2) != N-1 mod N"); } /* Sophisticated N-1 using N, QARRAY, AARRAY * * John Brillhart, D.H. Lehmer, J.L. Selfridge, * "New Primality Criteria and Factorizations of 2^m +/- 1" * Mathematics of Computation, v29, n130, April 1975, pp 620-647. * http://www.ams.org/journals/mcom/1975-29-130/S0025-5718-1975-0384673-1/S0025-5718-1975-0384673-1.pdf * * Page 621-622: "The expression 'N is a psp base a' will be used for a * number N which satisfies the congruence a^(N-1) = 1 mod N, 1 < a < N-1, * i.e., N is a "pseudoprime" base a." * Page 623: "Throughout the rest of this paper the notation N-1 = F_1 R_1 * will be used, where F_1 is the even factored portion of N-1, R_1 is > 1, * and (F_1,R_1) = 1." * Page 623: "(I) For each prime p_i dividing F_1 there exists an a_i such * that N is a psp base a_i and (a_i^((N-1)/p_i),N) = 1." * Page 624, Theorem 5. * "Assume (I) and let m be >= 1. * When m > 1, assume further that λF_1 + 1 ∤ N for 1 <= λ < m. * If N < (mF_1 + 1) [2(F_1)^2 + (r-m)F_1 + 1], * where r and s are defined by R_1 = (N-1)/F_1 = 2(F_1)s + r, 1 <= r < 2F_1, * then N is prime if and only if s = 0 or r^2 - 8s is not a perfect square. * r != 0 since R_1 is odd." * * Note that we are using m=1, which is simple for the verifier. * */ void verify_bls5(int num_qs) { int i; mpz_t F, R, s, r; if (mpz_cmp_ui(N, 2) <= 0) quit_invalid("BLS5", "N > 2"); if (mpz_even_p(N)) quit_invalid("BLS5", "N odd"); mpz_sub_ui(T2, N, 1); mpz_init_set_ui(F, 1); mpz_init_set(R, T2); mpz_init(s); mpz_init(r); for (i = 0; i < num_qs; i++) { if (mpz_cmp_ui(QARRAY[i], 1 ) <= 0) quit_invalid("BLS5", "Q > 1"); if (mpz_cmp( QARRAY[i], T2) >= 0) quit_invalid("BLS5", "Q < N-1"); if (mpz_cmp_ui(AARRAY[i], 1 ) <= 0) quit_invalid("BLS5", "A > 1"); if (mpz_cmp( AARRAY[i], T2) >= 0) quit_invalid("BLS5", "A < N-1"); if (!mpz_divisible_p(T2, QARRAY[i])) quit_invalid("BLS5", "Q divides N-1"); while (mpz_divisible_p(R, QARRAY[i])) { mpz_mul(F, F, QARRAY[i]); mpz_divexact(R, R, QARRAY[i]); } } mpz_mul(T1, R, F); if (mpz_cmp(T1, T2) != 0) quit_invalid("BLS5", "R == (N-1)/F"); if (mpz_odd_p(F)) quit_invalid("BLS5", "F is even"); mpz_gcd(T1, F, R); if (mpz_cmp_ui(T1, 1) != 0) quit_invalid("BLS5", "gcd(F, R) = 1"); mpz_mul_ui(T1, F, 2); mpz_tdiv_qr(s, r, R, T1); mpz_mul_ui(T1, F, 2); /* T1 = 2*F */ mpz_sub_ui(T2, r, 1); mpz_add(T1, T1, T2); /* T1 = 2*F + (r-1) */ mpz_mul(T1, T1, F); /* T1 = 2*F*F + (r-1)*F */ mpz_add_ui(T1, T1, 1); /* T1 = 2*F*F + (r-1)*F + 1 */ mpz_add_ui(T2, F, 1); mpz_mul(T1, T1, T2); /* T1 = (F+1) * (2*F*F + (r-1)*F + 1) */ if (mpz_cmp(N, T1) >= 0) quit_invalid("BLS5", "N < (F+1)(2F^2+(r-1)F+1)"); if (mpz_sgn(s) != 0) { mpz_mul(T2, r, r); mpz_submul_ui(T2, s, 8); /* T2 = r*r - 8*s */ if (mpz_perfect_square_p(T2)) quit_invalid("BLS5", "S=0 OR R^2-8S not a perfect square"); } mpz_clear(F); mpz_clear(R); mpz_clear(s); mpz_clear(r); mpz_sub_ui(T2, N, 1); for (i = 0; i < num_qs; i++) { mpz_powm(T1, AARRAY[i], T2, N); if (mpz_cmp_ui(T1, 1) != 0) quit_invalid("BLS5", "A[i]^(N-1) mod N = 1"); mpz_divexact(T1, T2, QARRAY[i]); mpz_powm(T1, AARRAY[i], T1, N); if (mpz_sgn(T1)) mpz_sub_ui(T1, T1, 1); else mpz_set(T1, T2); mpz_gcd(T1, T1, N); if (mpz_cmp_ui(T1, 1) != 0) quit_invalid("BLS5", "gcd(A[i]^((N-1)/Q[i]) - 1, N) = 1"); } } /* Most basic N-1 using N, QARRAY, A * * D.H. Lehmer, "Tests for Primality by the Converse of Fermat's Theorem" * Bull. AMS, v33, n3, 1927, pp 327-340. * http://projecteuclid.org/DPubS?service=UI&version=1.0&verb=Display&handle=euclid.bams/1183492108 * * Page 330, Theorem 2: * "If a^x = 1 mod N for x = N-1, but not for x a quotient of N-1 on * division by any of its prime factors, then N is a prime." */ void verify_lucas(int num_qs) { int i; mpz_sub_ui(T2, N, 1); mpz_set(R, T2); if (mpz_cmp_ui(A, 1) <= 0) quit_invalid("Lucas", "A > 1"); if (mpz_cmp( A, N) >= 0) quit_invalid("Lucas", "A < N"); mpz_powm(T1, A, T2, N); if (mpz_cmp_ui(T1, 1) != 0) quit_invalid("Lucas", "A^(N-1) mod N = 1"); for (i = 1; i < num_qs; i++) { if (mpz_cmp_ui(QARRAY[i], 1 ) <= 0) quit_invalid("Lucas", "Q > 1"); if (mpz_cmp( QARRAY[i], T2) >= 0) quit_invalid("Lucas", "Q < N-1"); if (!mpz_divisible_p(T2, QARRAY[i])) quit_invalid("Lucas", "Q divides N-1"); mpz_divexact(T1, T2, QARRAY[i]); mpz_powm(T1, A, T1, N); if (mpz_cmp_ui(T1, 1) == 0) quit_invalid("Lucas", "A^((N-1)/Q[i]) mod N != 1"); while (mpz_divisible_p(R, QARRAY[i])) mpz_divexact(R, R, QARRAY[i]); } if (mpz_cmp_ui(R, 1) != 0) quit_invalid("Lucas", "N-1 has only factors Q[i]"); } void verify_primo_ecpp(void) { /* Calculate a,b,x,y from A, B, T, then verify */ mpz_mul(T1, T, T); mpz_add(T1, T1, A); mpz_mul(T1, T1, T); mpz_add(T1, T1, B); mpz_mod(T1, T1, N); /* L = T1 = T^3 + AT + B mod N */ if (mpz_sgn(T1) <= 0) quit_invalid("Primo ECPP", "L > 0"); mpz_mul(T2, T1, T1); mpz_mul(A, A, T2); mpz_mod(A, A, N); /* a = AL^2 mod N */ mpz_mul(T2, T2, T1); mpz_mul(B, B, T2); mpz_mod(B, B, N); /* b = BL^3 mod N */ mpz_mul(X, T, T1); mpz_mod(X, X, N); /* x = TL mod N */ mpz_mul(Y, T1, T1); mpz_mod(Y, Y, N); /* y = L^2 mod N */ mpz_mul(M, R, S); /* M = R*S */ mpz_set(Q, R); /* Q = R */ verify_ecpp(); /* N, A, B, M, Q, X, Y */ } void verify_ecpp4(void) { mpz_mul_ui(T1, J, 2); if (mpz_cmpabs(T1, N) > 0) quit_invalid("Primo Type 4", "|J| <= N/2"); if (mpz_cmp_ui(T, 0) < 0) quit_invalid("Primo Type 4", "T >= 0"); if (mpz_cmp(T, N) >= 0) quit_invalid("Primo Type 4", "T < N"); mpz_set_ui(T2, 1728); mpz_sub(T2, T2, J); mpz_mul(A, T2, J); mpz_mul_ui(A, A, 3); /* A = 3 J (1728-J) */ mpz_mul(T2, T2, T2); mpz_mul(B, T2, J); mpz_mul_ui(B, B, 2); /* B = 2 J (1728-J)^2 */ verify_primo_ecpp(); /* (A,B,T)->(a,b,x,y) (R,S)->(M,Q) Verify */ } void verify_ecpp3(void) { mpz_mul_ui(T1, A, 2); mpz_mul_ui(T2, B, 2); if (mpz_cmpabs(T1, N) > 0) quit_invalid("Primo Type 3", "|A| <= N/2"); if (mpz_cmpabs(T2, N) > 0) quit_invalid("Primo Type 3", "|B| <= N/2"); if (mpz_cmp_ui(T, 0) < 0) quit_invalid("Primo Type 3", "T >= 0"); if (mpz_cmp(T, N) >= 0) quit_invalid("Primo Type 3", "T < N"); verify_primo_ecpp(); /* (A,B,T)->(a,b,x,y) (R,S)->(M,Q) Verify */ } void verify_primo2(void) { mpz_set(LQ, Q); mpz_set_ui(LP, mpz_odd_p(LQ) ? 2 : 1); mpz_set(Q, R); verify_bls15(); /* N, Q, LP, LQ */ } void verify_primo1(void) { mpz_set(Q, R); mpz_set(A, B); mpz_mul(T1, S, R); mpz_add_ui(T1, T1, 1); if (mpz_cmp(T1, N) != 0) quit_invalid("Primo Type 1", "SR+1 = N"); verify_pocklington(); /* N, Q, A */ } void verify_ecpp4_42(void) { if (mpz_cmp_ui(S, 0) <= 0) quit_invalid("Primo Type 4", "S > 0"); mpz_mul(T1, W, W); mpz_mul_ui(T2, N, 4); if (mpz_cmp(T1, T2) >= 0) quit_invalid("Primo Type 4", "W^2 < 4*N"); mpz_add_ui(R, N, 1); mpz_sub(R, R, W); if (!mpz_divisible_p(R, S)) quit_invalid("Primo Type 4", "(N+1-W) mod S = 0"); mpz_divexact(R, R, S); verify_ecpp4(); } void verify_ecpp3_42(void) { if (mpz_cmp_ui(S, 0) <= 0) quit_invalid("Primo Type 4", "S > 0"); mpz_mul(T1, W, W); mpz_mul_ui(T2, N, 4); if (mpz_cmp(T1, T2) >= 0) quit_invalid("Primo Type 4", "W^2 < 4*N"); mpz_add_ui(R, N, 1); mpz_sub(R, R, W); if (!mpz_divisible_p(R, S)) quit_invalid("Primo Type 4", "(N+1-W) mod S = 0"); mpz_divexact(R, R, S); verify_ecpp3(); } void verify_primo2_42(void) { mpz_add_ui(R, N, 1); if (!mpz_even_p(S)) quit_invalid("Primo N+1", "S is even"); if (mpz_cmp_ui(S,1) <= 0) quit_invalid("Primo N+1", "S > 1"); if (!mpz_divisible_p(R, S)) quit_invalid("Primo N+1", "(N+1) mod S = 0"); if (mpz_cmp_ui(Q,0) <= 0) quit_invalid("Primo N+1", "Q > 0"); if (mpz_cmp(Q,N) >= 0) quit_invalid("Primo N+1", "Q < N"); mpz_divexact(R, R, S); if (mpz_jacobi(Q, N) != -1) quit_invalid("Primo N+1", "jacobi(Q,N) = -1"); mpz_set(LQ, Q); mpz_set_ui(LP, mpz_odd_p(LQ) ? 2 : 1); mpz_set(Q, R); verify_bls15(); /* N, Q, LP, LQ */ } void verify_primo1_42(void) { mpz_sub_ui(R, N, 1); if (!mpz_even_p(S)) quit_invalid("Primo N-1", "S is even"); if (mpz_cmp_ui(S,1) <= 0) quit_invalid("Primo N-1", "S > 1"); if (!mpz_divisible_p(R, S)) quit_invalid("Primo N-1", "(N-1) mod S = 0"); if (mpz_cmp_ui(B,1) <= 0) quit_invalid("Primo N-1", "B > 1"); if (mpz_cmp(B,N) >= 0) quit_invalid("Primo N-1", "B < N"); mpz_divexact(R, R, S); mpz_set(Q, R); mpz_set(A, B); verify_pocklington(); /* N, Q, A */ } void verify_small(void) { if (mpz_sizeinbase(N, 2) > 64) quit_invalid("Small", "N <= 2^64"); if (is_prob_prime(N) != 2) quit_invalid("Small", "N does not pass BPSW"); } void add_chain(mpz_t n, mpz_t q) { mpz_init_set(_chain_n[_num_chains], n); mpz_init_set(_chain_q[_num_chains], q); _num_chains++; } void free_chains(void) { while (_num_chains > 0) { _num_chains--; mpz_clear(_chain_n[_num_chains]); mpz_clear(_chain_q[_num_chains]); } } void verify_chain(mpz_t n) { int i, found; if (mpz_sizeinbase(n, 2) <= 64) { mpz_set(N, n); verify_small(); return; } found = 0; for (i = 0; i < _num_chains; i++) { if (mpz_cmp(n, _chain_n[i]) == 0) { found = 1; verify_chain(_chain_q[i]); } } mpz_set(N, n); if (!found) quit_invalid("Final", "q value has no proof"); } void verify_final(void) { if (_format == CERT_PRIMO) { if (mpz_cmp_ui(N, 18) <= 0) quit_invalid("Primo Type 0", "N > 18"); if (mpz_cmp_ui(N, 340000000000000UL) >= 0) quit_invalid("Primo Type 0", "N < 34 * 10^13"); if (!miller_rabin_ui(N, 2) || !miller_rabin_ui(N, 3) || !miller_rabin_ui(N, 5) || !miller_rabin_ui(N, 7) || !miller_rabin_ui(N, 11) || !miller_rabin_ui(N, 13) || !miller_rabin_ui(N, 17)) quit_invalid("Primo Type 0", "N is SPSP(2,3,5,7,11,13,17)"); } else if (_format == CERT_PRIMO42) { verify_small(); } else { verify_chain(PROOFN); free_chains(); } } /*****************************************************************************/ /* File parsing */ /*****************************************************************************/ static int get_line(int signaleof) { size_t i; /* Read in a line */ if (fgets(_line, MAX_LINE_LEN, _fh) != _line) { if (signaleof) return 1; else quit_error("Error reading from file: ", _filename); } _line[MAX_LINE_LEN] = '\0'; /* Remove trailing newlines and spaces */ i = strlen(_line); while ( i > 0 && isspace(_line[i-1]) ) _line[--i] = '\0'; return 0; } #define PROCESS_VAR(v) \ do { \ mpz_set_str(v, _vstr, _base); \ for (i = 0; i < nargs; i++) { \ if (vlist[i] != 0 && strcmp(vlist[i], #v) == 0) { \ vfound++; \ vlist[i] = 0; \ break; \ } \ } \ if (i >= nargs) \ quit_error("Unknown variable: ", #v); \ } while (0) void read_vars(const char* vars) { char* varstring = strdup(vars); char* vlist[10]; char varname; int i; int nargs = 0; int vfound = 0; int bad_lines = 0; vlist[0] = strtok(varstring, " "); while (vlist[nargs] != 0) vlist[++nargs] = strtok(NULL, " "); while (vfound < nargs) { get_line(0); if (strlen(_line) == 0) /* Skip extrenuous blank lines */ continue; if (_format == CERT_PRIMO) { int varnum = 0; /* Did we read a variable properly this line? */ if (sscanf(_line, "%c$=%s", &varname, _vstr) == 2) { for (i = 0; i < nargs && varnum == 0; i++) { if (vlist[i] != 0 && varname == vlist[i][0]) { switch (varname) { case 'S': mpz_set_str(S, _vstr, 16); break; case 'R': mpz_set_str(R, _vstr, 16); break; case 'A': mpz_set_str(A, _vstr, 16); break; case 'B': mpz_set_str(B, _vstr, 16); break; case 'Q': mpz_set_str(Q, _vstr, 16); break; case 'T': mpz_set_str(T, _vstr, 16); break; case 'J': mpz_set_str(J, _vstr, 16); break; default: quit_error("Internal error: bad Primo variable type",""); break; } varnum = i+1; } } } else if (sscanf(_line, "[%d]", &i) == 1) { quit_error("Variables missing from proof step", ""); } if (varnum != 0) { vfound++; /* We found a variable on the list */ vlist[varnum-1] = 0; /* It should only appear once */ bad_lines = 0; } else { if (_verbose) { printf("%60s\r", ""); printf("skipping bad line: %s\n", _line); } if (bad_lines++ >= BAD_LINES_ALLOWED) quit_error("Too many bad lines reading variables", ""); } } else { if (sscanf(_line, "N %s", _vstr) == 1) PROCESS_VAR(N); else if (sscanf(_line, "A %s", _vstr) == 1) PROCESS_VAR(A); else if (sscanf(_line, "B %s", _vstr) == 1) PROCESS_VAR(B); else if (sscanf(_line, "M %s", _vstr) == 1) PROCESS_VAR(M); else if (sscanf(_line, "Q %s", _vstr) == 1) PROCESS_VAR(Q); else if (sscanf(_line, "X %s", _vstr) == 1) PROCESS_VAR(X); else if (sscanf(_line, "Y %s", _vstr) == 1) PROCESS_VAR(Y); else if (sscanf(_line, "LQ %s", _vstr) == 1) PROCESS_VAR(LQ); else if (sscanf(_line, "LP %s", _vstr) == 1) PROCESS_VAR(LP); /* ECPP3 and ECPP4 */ else if (sscanf(_line, "T %s", _vstr) == 1) PROCESS_VAR(T); else if (sscanf(_line, "J %s", _vstr) == 1) PROCESS_VAR(J); else if (sscanf(_line, "S %s", _vstr) == 1) PROCESS_VAR(S); else if (sscanf(_line, "R %s", _vstr) == 1) PROCESS_VAR(R); else quit_error("Internal error: bad MPU variable type", ""); } } free(varstring); } /* Primo version 4.2 doesn't give us a step type, but infers it from which * variables appear. We have to use a different processing method. */ int read42_vars(void) { char varname; int i; int bad_lines = 0; int varsign, fS = 0, fW = 0, fT = 0, fJ = 0, fA = 0, fB = 0, fQ = 0; MPUassert( _format == CERT_PRIMO42, "wrong parse routine for cert type"); while (1) { varsign = 0; get_line(0); if (strlen(_line) == 0) /* Skip extrenuous blank lines */ continue; if (sscanf(_line, "[%d]", &i) == 1) quit_error("Variables missing from proof step", ""); /* TODO: Hacky even for this file. More robust method would be nice. */ if (sscanf(_line, "%c=-$%s", &varname, _vstr) == 2) varsign =-1; else if (sscanf(_line, "%c=$%s", &varname, _vstr) == 2) varsign = 1; else if (sscanf(_line, "%c=-0x%s", &varname, _vstr) == 2) varsign =-1; else if (sscanf(_line, "%c=0x%s", &varname, _vstr) == 2) varsign = 1; else if (sscanf(_line, "%c=%s", &varname, _vstr) == 2) varsign = 2; if (varsign != 0) { /* Process variable found */ mpz_set_str(T1, _vstr, (varsign == 2) ? 10 : 16); if (varsign < 0) mpz_neg(T1, T1); switch (varname) { case 'S': mpz_set(S,T1); fS=1; break; case 'W': mpz_set(W,T1); fW=1; break; case 'T': mpz_set(T,T1); fT=1; break; case 'J': mpz_set(J,T1); fJ=1; break; case 'A': mpz_set(A,T1); fA=1; break; case 'B': mpz_set(B,T1); fB=1; break; case 'Q': mpz_set(Q,T1); fQ=1; break; default: quit_error("Internal error: bad Primo variable type",""); break; } bad_lines = 0; } else { if (_verbose) { printf("%60s\r", ""); printf("skipping bad line: %s\n", _line); } if (bad_lines++ >= BAD_LINES_ALLOWED) quit_error("Too many bad lines reading variables", ""); } if (fS && fW && fT && fJ) break; if (fS && fW && fT && fA && fB) break; if (fS && !fW && fQ) break; if (fS && !fW && fB) break; } if (!fS) quit_error("Invalid file: no S", ""); if (fW) { if (!fT) quit_error("Invalid file: W no T", ""); if (fJ) return 4; /* type 4: ECPP */ if (!fA) quit_error("Invalid file: W no A", ""); if (!fB) quit_error("Invalid file: W no B", ""); return 3; /* type 3: ECPP */ } else if (fQ) { return 2; /* type 2: n+1 */ } else if (fB) { return 1; /* type 2: n-1 */ } quit_error("Invalid file: no {W,Q,B}", ""); return 0; } /* TODO: * rearrange so we (1) open and read everything up to proof for / candidate. * then (2) func that does the proof * this should let us call #2 if we hit another proof, so we can do multiple * proof in a file. */ void parse_top(void) { do { if (get_line(1)) quit_error("Count not find primality certificate indicator", ""); } while (strstr(_line, "Primality Certificate") == 0); if (strcmp(_line, "[PRIMO - Primality Certificate]") == 0) _format = CERT_PRIMO; else if (strcmp(_line, "[MPU - Primality Certificate]") == 0) _format = CERT_MPU; else quit_error("First line in file is not primality certificate indicator",""); if (_format == CERT_PRIMO) { int items_found = 0; int format_ver; while (items_found < 3) { get_line(0); if (sscanf(_line, "Format=%d", &format_ver) == 1) { switch (format_ver) { case 3: break; case 4: _format = CERT_PRIMO42; break; default: quit_error("Unknown version number", ""); } } if (sscanf(_line, "TestCount=%d", &_testcount) == 1) items_found++; if (strcmp(_line, "[Candidate]") == 0) items_found++; if (_format == CERT_PRIMO42) { if (sscanf(_line, "N=$%s", _vstr) == 1) items_found++; } else { if (sscanf(_line, "N$=%s", _vstr) == 1) items_found++; } } mpz_set_str(PROOFN, _vstr, 16); } else { while (1) { get_line(0); if (_line[0] == '#') continue; if (sscanf(_line, "Base %d", &_base) == 1) continue; if (strcmp(_line, "Proof for:") == 0) { read_vars("N"); mpz_set(PROOFN, N); break; } } } if (!_quiet) { printf("%60s\r", ""); printf("N: "); if (_verbose) gmp_printf("%Zd ", PROOFN); printf("(%d digits)\n", (int)mpz_sizeinbase(PROOFN, 10)); printf("Verifying probable prime status.\r"); fflush(stdout); } if (is_prob_prime(PROOFN) == 0) quit_composite(); mpz_set(N, PROOFN); } void process_file(const char* filename) { _step = 0; if (strcmp(filename, "-") == 0) _fh = stdin; else if ((_fh = fopen(filename, "r")) == NULL) quit_error("Unable to open file: ", filename); _filename = filename; parse_top(); if (_format == CERT_PRIMO) { int type; while (1) { int rstep; get_line(0); if (sscanf(_line, "[%d]", &rstep) == 1) { if (rstep != _step+1) quit_error("Wrong step number found", ""); _step++; } if (sscanf(_line, "Type=%d", &type) == 1) { if (!_quiet) { printf("%60s\r", ""); printf("Step %3d/%-3d %5d digits Type %d\r", _step, _testcount, (int)mpz_sizeinbase(N,10), type); fflush(stdout); } switch (type) { case 4: read_vars("S R J T"); verify_ecpp4(); break; case 3: read_vars("S R A B T"); verify_ecpp3(); break; case 2: read_vars("S R Q"); verify_primo2(); break; case 1: read_vars("S R B"); verify_primo1(); break; case 0: /* verify_small */ break; default: quit_error("Parsing", "Unknown type"); break; } if (type == 0) break; mpz_set(N, R); } } } else if (_format == CERT_PRIMO42) { int type, rstep, rvars = 0; while (_step < _testcount) { get_line(0); if (sscanf(_line, "[%d]", &rstep) == 1) { if (rstep != _step+1) quit_error("Wrong step number found", ""); _step++; rvars = 1; } if (!rvars) continue; /* skip until we find a section */ type = read42_vars(); if (!_quiet) { printf("%60s\r", ""); printf("Step %3d/%-3d %5d digits Type %d\r", _step, _testcount, (int)mpz_sizeinbase(N,10), type); fflush(stdout); } switch (type) { case 4: verify_ecpp4_42(); break; case 3: verify_ecpp3_42(); break; case 2: verify_primo2_42(); break; case 1: verify_primo1_42(); break; case 0: /* verify_small */ break; default: quit_error("Parsing", "Unknown type"); break; } mpz_set(N, R); rvars = 0; if (type == 0) break; } } else { char type[MAX_LINE_LEN+1]; while (1) { if (get_line(1)) break; if (sscanf(_line, "Type %s", type) == 1) { { /* Convert type to upper case */ char* s = type; while (*s != '\0') { if (islower(*s)) *s = toupper(*s); s++; } } _step++; /* TODO: Quick parse of the file to count steps? */ if (!_quiet) { printf("%60s\r", ""); printf("Step %-4d %5d digits Type %s\r", _step, (int)mpz_sizeinbase(N,10), type); fflush(stdout); } if (strcmp(type, "ECPP" ) == 0) { read_vars("N A B M Q X Y"); verify_ecpp(); add_chain(N, Q); } else if (strcmp(type, "ECPP3") == 0) { read_vars("N S R A B T"); verify_ecpp3(); add_chain(N, Q); } else if (strcmp(type, "ECPP4") == 0) { read_vars("N S R J T"); verify_ecpp4(); add_chain(N, Q); } else if (strcmp(type, "BLS15") == 0) { read_vars("N Q LP LQ"); verify_bls15(); add_chain(N, Q); } else if (strcmp(type, "BLS3" ) == 0) { read_vars("N Q A"); verify_bls3(); add_chain(N, Q); } else if (strcmp(type, "POCKLINGTON") == 0) { read_vars("N Q A"); verify_pocklington(); add_chain(N, Q); } else if (strcmp(type, "SMALL") == 0) { read_vars("N"); verify_small(); } else if (strcmp(type, "BLS5") == 0) { int i, index; for (index = 0; index < MAX_QARRAY; index++) { mpz_set_ui(QARRAY[index], 0); mpz_set_ui(AARRAY[index], 2); } mpz_set_ui(QARRAY[0], 2); index = 1; while (1) { get_line(0); if (_line[0] == '-') { break; } else if (sscanf(_line, "N %s", _vstr) == 1) { mpz_set_str(N, _vstr, _base); } else if (sscanf(_line, "Q[%d] %s", &i, _vstr) == 2) { if (i != index) quit_error("BLS5", "Invalid Q index"); mpz_set_str(QARRAY[i], _vstr, _base); index++; } else if (sscanf(_line, "A[%d] %s", &i, _vstr) == 2) { if (i < 0 || i > index) quit_error("BLS5", "Invalid A index"); mpz_set_str(AARRAY[i], _vstr, _base); } } verify_bls5(index); for (i = 0; i < index; i++) add_chain(N, QARRAY[i]); } else if (strcmp(type, "LUCAS") == 0) { int i, index; for (index = 0; index < MAX_QARRAY; index++) mpz_set_ui(QARRAY[index], 0); index = 1; while (1) { get_line(0); if (sscanf(_line, "N %s", _vstr) == 1) { mpz_set_str(N, _vstr, _base); } else if (sscanf(_line, "Q[%d] %s", &i, _vstr) == 2) { if (i != index) quit_error("Lucas", "Invalid Q index"); mpz_set_str(QARRAY[i], _vstr, _base); index++; } else if (sscanf(_line, "A %s", _vstr) == 1) { mpz_set_str(A, _vstr, _base); break; } } verify_lucas(index); for (i = 1; i < index; i++) add_chain(N, QARRAY[i]); } else { quit_error("Parsing", "Unknown type"); } } } } verify_final(); } static void dieusage(const char* prog) { printf("Verify Cert version 0.96. Dana Jacobsen\n\n"); printf("Usage: %s [options] \n\n", prog); printf("Options:\n"); printf(" -v set verbose\n"); printf(" -q set quiet (no output, only exit code)\n"); printf(" -help this message\n"); var_free(); exit(RET_INVALID); } int main(int argc, char *argv[]) { int i; int optdone = 0; if (argc < 2) dieusage(argv[0]); var_init(); mpz_set_ui(N, 0); for (i = 1; i < argc; i++) { if (!optdone && argv[i][0] == '-') { if (strcmp(argv[i], "--") == 0) { optdone = 1; } else if (argv[i][1] == '\0') { process_file("-"); } else if (strcmp(argv[i], "-v") == 0) { _verbose++; } else if (strcmp(argv[i], "-q") == 0) { _quiet++; } else if (strcmp(argv[i], "-help") == 0 || strcmp(argv[i], "--help") == 0) { dieusage(argv[0]); } else { printf("Unknown option: %s\n\n", argv[i]); dieusage(argv[0]); } continue; } /* process_file will exit if not verified prime */ process_file(argv[i]); } if (mpz_sgn(N) == 0) dieusage(argv[0]); quit_prime(); exit(RET_PRIME); } Math-Prime-Util-GMP-0.52/aks.h0000644000175000017500000000017413025437621014263 0ustar danadana#ifndef MPU_GMPAKS_H #define MPU_GMPAKS_H #include #include "ptypes.h" extern int is_aks_prime(mpz_t n); #endif Math-Prime-Util-GMP-0.52/MANIFEST0000644000175000017500000000300413674072603014465 0ustar danadanainc/Devel/CheckLib.pm Changes lib/Math/Prime/Util/GMP.pm LICENSE Makefile.PL MANIFEST README TODO XS.xs ptypes.h gmp_main.h gmp_main.c primality.h primality.c prime_iterator.h prime_iterator.c pbrent63.h pbrent63.c squfof126.h squfof126.c factor.h factor.c ecm.h ecm.c class_poly_data.h bls75.h bls75.c ecpp.h ecpp.c aks.h aks.c simpqs.h simpqs.c tinyqs.h tinyqs.c isaac.h isaac.c random_prime.h random_prime.c real.h real.c utility.h utility.c t/01-load.t t/02-can.t t/10-isprime.t t/11-primes.t t/12-nextprime.t t/13-primecount.t t/15-probprime.t t/16-provableprime.t t/17-pseudoprime.t t/19-moebius.t t/20-primorial.t t/21-conseq-lcm.t t/22-partitions.t t/23-gcd.t t/24-bernfrac.t t/25-const-euler.t t/25-const-pi.t t/26-combinatorial.t t/26-digits.t t/26-int.t t/26-ismisc.t t/26-lambertw.t t/26-logs.t t/26-mersenne.t t/26-mod.t t/26-real.t t/26-riemann.t t/26-roots.t t/27-clusters.t t/28-randomprime.t t/28-rand.t t/28-urandom.t t/50-factoring.t t/90-release-perlcritic.t t/91-release-pod-syntax.t t/92-release-pod-coverage.t t/93-release-spelling.t xt/bench-random-bytes.pl xt/create-standalone.sh xt/calculate-mr-probs.pl xt/proof-text-format.txt xt/expr-impl.h xt/expr.c xt/expr.h xt/llr.pl examples/bench-mp-psrp.pl examples/verify-cert.pl examples/convert-primo-cert.pl examples/convert-gmpecpp-cert.pl examples/vcert.c examples/verify_primegap.pl .travis.yml META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Math-Prime-Util-GMP-0.52/ptypes.h0000644000175000017500000000613613663067455015051 0ustar danadana#ifndef MPU_PTYPES_H #define MPU_PTYPES_H #ifndef _MSC_VER #define __STDC_LIMIT_MACROS #include #else typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; typedef __int64 int64_t; typedef __int32 int32_t; typedef __int16 int16_t; typedef __int8 int8_t; #endif #ifdef STANDALONE #include #include #include typedef unsigned long UV; typedef signed long IV; typedef double NV; #define UV_MAX ULONG_MAX #define UVCONST(x) ((unsigned long)x##UL) #define UVuf "lu" #define IVdf "ld" #define croak(fmt,...) do { printf(fmt,##__VA_ARGS__); exit(3); } while(0) #define New(id, mem, size, type) mem = (type*) malloc((size)*sizeof(type)) #define Newz(id, mem, size, type) mem = (type*) calloc(size, sizeof(type)) #define Renew(mem, size, type) mem =(type*)realloc(mem,(size)*sizeof(type)) #define Safefree(mem) free((void*)mem) /* iterator using mpz_nextprime, which is really slow #define PRIME_ITERATOR(i) mpz_t i; mpz_init_set_ui(i, 2) static UV prime_iterator_next(mpz_t *iter) { mpz_nextprime(*iter, *iter); return mpz_get_ui(*iter); } static void prime_iterator_destroy(mpz_t *iter) { mpz_clear(*iter); } static void prime_iterator_setprime(mpz_t *iter, UV n) {mpz_set_ui(*iter, n);} static int prime_iterator_isprime(mpz_t *iter, UV n) {int isp; mpz_t t; mpz_init_set_ui(t, n); isp = mpz_probab_prime_p(t, 10); mpz_clear(t); return isp;} */ #if ULONG_MAX >> 31 == 1 #define BITS_PER_WORD 32 #elif ULONG_MAX >> 63 == 1 #define BITS_PER_WORD 64 #else #error Unsupported bits per word (must be 32 or 64) #endif #else #include "EXTERN.h" #include "perl.h" /* From perl.h, wrapped in PERL_CORE */ #ifndef U32_CONST # if INTSIZE >= 4 # define U32_CONST(x) ((U32TYPE)x##U) # else # define U32_CONST(x) ((U32TYPE)x##UL) # endif #endif /* From perl.h, wrapped in PERL_CORE */ #ifndef U64_CONST # ifdef HAS_QUAD # if INTSIZE >= 8 # define U64_CONST(x) ((U64TYPE)x##U) # elif LONGSIZE >= 8 # define U64_CONST(x) ((U64TYPE)x##UL) # elif QUADKIND == QUAD_IS_LONG_LONG # define U64_CONST(x) ((U64TYPE)x##ULL) # else /* best guess we can make */ # define U64_CONST(x) ((U64TYPE)x##UL) # endif # endif #endif #ifdef HAS_QUAD #define BITS_PER_WORD 64 #define UVCONST(x) U64_CONST(x) #else #define BITS_PER_WORD 32 #define UVCONST(x) U32_CONST(x) #endif #endif /* Try to determine if we have 64-bit available via uint64_t */ #if defined(UINT64_MAX) || defined(_UINT64_T) || defined(__UINT64_TYPE__) #define HAVE_STD_U64 1 #elif defined(_MSC_VER) /* We set up the types earlier */ #define HAVE_STD_U64 1 #else #define HAVE_STD_U64 0 #endif #define MAXBIT (BITS_PER_WORD-1) #define NWORDS(bits) ( ((bits)+BITS_PER_WORD-1) / BITS_PER_WORD ) #define NBYTES(bits) ( ((bits)+8-1) / 8 ) #define MPUassert(c,text) if (!(c)) { croak("Math::Prime::Util internal error: " text); } #if defined(__GNUC__) #define INLINE __inline__ #elif defined(_MSC_VER) #define INLINE __inline #else #define INLINE #endif #endif Math-Prime-Util-GMP-0.52/prime_iterator.h0000644000175000017500000000117613025437621016535 0ustar danadana#ifndef MPU_PITERATOR_H #define MPU_PITERATOR_H #include "ptypes.h" typedef struct { UV p; UV segment_start; UV segment_bytes; const unsigned char* segment_mem; } prime_iterator; #define PRIME_ITERATOR(i) prime_iterator i = {2, 0, 0, 0} extern void prime_iterator_global_startup(void); extern void prime_iterator_global_shutdown(void); extern void prime_iterator_destroy(prime_iterator *iter); extern UV prime_iterator_next(prime_iterator *iter); extern void prime_iterator_setprime(prime_iterator *iter, UV n); extern int prime_iterator_isprime(prime_iterator *iter, UV n); extern UV* sieve_to_n(UV n, UV* count); #endif Math-Prime-Util-GMP-0.52/ecpp.h0000644000175000017500000000062013025437621014430 0ustar danadana#ifndef MPU_ECPP_H #define MPU_ECPP_H #include #include "ptypes.h" extern void init_ecpp_gcds(UV nsize); extern void destroy_ecpp_gcds(void); extern int _GMP_ecpp(mpz_t N, char** prooftextptr); extern int _GMP_ecpp_fps(mpz_t N, char** prooftextptr); extern int ecpp_check_point(mpz_t x, mpz_t y, mpz_t m, mpz_t q, mpz_t a, mpz_t N, mpz_t t, mpz_t t2); #endif Math-Prime-Util-GMP-0.52/simpqs.h0000644000175000017500000000016613025437621015022 0ustar danadana#ifndef MPU_SIMPQS_H #define MPU_SIMPQS_H #include extern int _GMP_simpqs(mpz_t n, mpz_t* farray); #endif Math-Prime-Util-GMP-0.52/simpqs.c0000644000175000017500000014403213025437621015016 0ustar danadana/*============================================================================ Quadratic Sieve This is derived from SIMPQS, copyright 2006 William Hart. Modifications made in 2013 by Dana Jacobsen: - returns all coprime factors found - put it in one file - merge some of the 2.0 changes - make it work with smaller values - fix some memory errors - free memory all over - fewer globals - Use prime_iterator -- much faster than mpz_nextprime - Alternate multiplier selection routine. - lots of little changes / optimizations Version 2.0 scatters temp files everywhere, but that could be solved. The main benefits left in 2.0 are: (1) combining partial relations (this is huge for large inputs) (2) much less memory use, though partly due to using temp files (3) jasonp's block Lanczos routine. This code goes through curves slightly faster than v2.0, but with big inputs it ends up needing 2x the time because of not combining partials as well as the final linear algebra time. To compile standalone: gcc -O2 -DSTANDALONE_SIMPQS -DSTANDALONE simpqs.c utility.c -lgmp -lm ============================================================================*/ /*============================================================================ SIMPQS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. SIMPQS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with SIMPQS; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ============================================================================*/ #include #include #include #include #include #include #include #ifdef STANDALONE_SIMPQS #include "ptypes.h" #define UV_MAX ULONG_MAX #define UVCONST(x) ((unsigned long)x##UL) /* #define INLINE #define croak(fmt,...) { printf(fmt,##__VA_ARGS__); exit(1); } */ #define New(id, mem, size, type) mem = (type*) malloc((size)*sizeof(type)) #define Newz(id, mem, size, type) mem = (type*) calloc(size, sizeof(type)) #define Safefree(mem) free((void*)mem) #define PRIME_ITERATOR(i) mpz_t i; mpz_init_set_ui(i, 2) static UV prime_iterator_next(mpz_t *iter) { mpz_nextprime(*iter, *iter); return mpz_get_ui(*iter); } static void prime_iterator_destroy(mpz_t *iter) { mpz_clear(*iter); } static void prime_iterator_setprime(mpz_t *iter, UV n) {mpz_set_ui(*iter, n);} /* static int prime_iterator_isprime(mpz_t *iter, UV n) {int isp; mpz_t t; mpz_init_set_ui(t, n); isp = mpz_probab_prime_p(t, 10); mpz_clear(t); return isp;} */ static int _verbose = 0; static int get_verbose_level(void) { return _verbose; } #else #include "ptypes.h" #include "simpqs.h" #include "prime_iterator.h" #endif #include "utility.h" /* DANAJ: Modify matrix code to do 64-bit-padded character arrays */ typedef unsigned char* row_t; /* row of an F2 matrix */ typedef row_t* matrix_t; /* matrix as a list of pointers to rows */ #define insertEntry(m, i, j) m[i][(j)/8] |= (1U << ((j)%8)) #define xorEntry(m, i, j) m[i][(j)/8] ^= (1U << ((j)%8)) #define getEntry(m, i, j) (m[i][(j)/8] & (1U << ((j)%8))) #define swapRows(m, x, y) \ do { row_t temp = m[x]; m[x] = m[y]; m[y] = temp; } while (0) #define matBytes(numcols) (((numcols+63)/64) * 8) #define rightMatrixOffset(numcols) (8 * matBytes(numcols)) /* Clear just the left side */ static INLINE void clearRow(matrix_t m, unsigned int numcols, unsigned int row) { memset( m[row], 0, matBytes(numcols) ); } /* bitwise xor of two rows, both left and right matrices */ static void xorRows(matrix_t m, unsigned int numcols, unsigned int source, unsigned int dest) { unsigned int i, q; UV* x = (UV*) m[dest]; UV* y = (UV*) m[source]; size_t nwords = (2 * matBytes(numcols)) / sizeof(UV); q = 8 * (nwords / 8); for (i = 0; i < q; i += 8) { x[i+0] ^= y[i+0]; x[i+1] ^= y[i+1]; x[i+2] ^= y[i+2]; x[i+3] ^= y[i+3]; x[i+4] ^= y[i+4]; x[i+5] ^= y[i+5]; x[i+6] ^= y[i+6]; x[i+7] ^= y[i+7]; } for ( ; i < nwords; i++) x[i] ^= y[i]; } static matrix_t constructMat(unsigned int cols, unsigned int rows) { unsigned int i; matrix_t m; size_t nbytes = matBytes(cols); unsigned int mat2offset = rightMatrixOffset(cols); /* printf("construct mat %u %u (%lu bytes)\n", cols, rows, rows*sizeof(row) + rows*(2*nbytes)); */ /* If cols > rows, we write off the array */ if (cols < rows) croak("SIMPQS: cols %u > rows %u\n", cols, rows); New(0, m, rows, row_t); if (m == 0) croak("SIMPQS: Unable to allocate memory for matrix!\n"); for (i = 0; i < rows; i++) { /* two matrices, side by side */ Newz(0, m[i], 2*nbytes, unsigned char); if (m[i] == 0) croak("SIMPQS: Unable to allocate memory for matrix!\n"); } /* make second matrix identity, i.e. 1's along diagonal */ for (i = 0; i < rows; i++) insertEntry(m, i, mat2offset + i); return m; } static void destroyMat(matrix_t m, unsigned int rows) { unsigned int i; for (i = 0; i < rows; i++) Safefree(m[i]); Safefree(m); } #if 0 static void displayRow(matrix_t m, unsigned int row, unsigned int numcols) { int j; unsigned int mat2offset = rightMatrixOffset(numcols); printf("["); for (j = 0; j < numcols; j++) printf("%c", getEntry(m,row,j) ? '1' : '0'); printf(" "); for (j = 0; j < numcols; j++) printf("%c", getEntry(m,row,mat2offset+j) ? '1' : '0'); printf("]\n"); } #endif /* gaussReduce: Apply Gaussian elimination to a matrix. */ static unsigned int gaussReduce(matrix_t m, unsigned int cols, unsigned int rows) { unsigned int rowUpto = 0; unsigned int irow, checkRow; int icol; for (icol = cols-1; icol >= 0; icol--) { irow = rowUpto; while ( (irow < rows) && (getEntry(m,irow,icol) == 0) ) irow++; if (irow < rows) { swapRows(m,rowUpto,irow); for (checkRow = rowUpto+1; checkRow < rows; checkRow++) { if (getEntry(m,checkRow,icol) != 0) xorRows(m, cols, rowUpto, checkRow); } rowUpto++; } } return rowUpto; } /*===========================================================================*/ /* Uncomment these for various pieces of debugging information */ /* Shows the number of relations generated and curves used during sieving */ /* #define COUNT */ /* Shows the actual factorizations of the relations */ /* #define RELPRINT */ /* Error if relation should be divisible by a prime but isn't */ /* #define ERRORS */ /* Shows the polynomials being used by the sieve */ /* #define POLS */ /* Prints some details about the factors of the A coefficients of the polys */ /* #define ADETAILS */ /* Prints the size of the largest factorbase prime */ /* #define LARGESTP */ /* Prints the number of curves used and number of partial relations */ /* #define CURPARTS */ /* Report sieve size, multiplier and number of primes used */ /* #define REPORT */ #ifdef ERRORS #define CHECK_EXPONENT(exponent,k) \ if (exponent==0) printf("Error with prime %u!\n", factorBase[k]); #else #define CHECK_EXPONENT(exponent,k) #endif #ifdef RELPRINT #define PRINT_FB(exponent, k) \ do { if (exponent > 0) printf(" %u", factorBase[k]); \ if (exponent > 1) printf("^%d", exponent); } while (0) #else #define PRINT_FB(exponent, k) #endif /*===========================================================================*/ /* Architecture dependent fudge factors */ #if ULONG_MAX == 4294967295UL #define SIEVEMASK 0xC0C0C0C0UL #define SIEVEDIV 1 #elif ULONG_MAX == 18446744073709551615UL #define SIEVEMASK 0xC0C0C0C0C0C0C0C0UL #define SIEVEDIV 1 #else #error Cannot determine ulong size #endif /* Should be a little less than the L1/L2 cache size and a multiple of 64000 */ #define CACHEBLOCKSIZE 64000 /* Make lower for slower machines */ #define SECONDPRIME 6000 /* Used for tweaking the bit size calculation for FB primes */ #define SIZE_FUDGE 0.15 /* Will not factor numbers with less than this number of decimal digits */ #define MINDIG 30 /*===========================================================================*/ /* Large prime cutoffs, in thousands */ static const unsigned int largeprimes[] = { 100, 100, 125, 125, 150, 150, 175, 175, 200, 200, /* 30-39 */ 250, 300, 370, 440, 510, 580, 650, 720, 790, 8600, /* 40-49 */ 930, 1000, 1700, 2400, 3100, 3800, 4500, 5200, 5900, 6600, /* 50-59 */ 7300, 8000, 8900, 10000, 11300, 12800, 14500, 16300, 18100, 20000, /* 60-69 */ 22000, 24000, 27000, 32000, 39000, /* 70-74 */ 53000, 65000, 75000, 87000, 100000, /* 75-79 */ 114000, 130000, 150000, 172000, 195000, /* 80-84 */ 220000, 250000, 300000, 350000, 400000, /* 85-89 */ 450000, 500000 /* 90-91 */ }; /*===========================================================================*/ /* Number of primes to use in factor base */ static const unsigned int primesNo[] = { 1500, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, /* 30-39 */ 1600, 1600, 1600, 1700, 1750, 1800, 1900, 2000, 2050, 2100, /* 40-49 */ 2150, 2200, 2250, 2300, 2400, 2500, 2600, 2700, 2800, 2900, /* 50-59 */ 3000, 3150, 5500, 6000, 6500, 7000, 7500, 8000, 8500, 9000, /* 60-69 */ 9500, 10000, 11500, 13000, 15000, /* 70-74 */ 17000, 24000, 27000, 30000, 37000, /* 75-79 */ 45000, 47000, 53000, 57000, 58000, /* 80-84 */ 59000, 60000, 64000, 68000, 72000, /* 85-89 */ 76000, 80000 /* 90-91 */ }; /*===========================================================================*/ /* First prime actually sieved for */ static const unsigned int firstPrimes[] = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 30-39 */ 3, 3, 3, 4, 6, 6, 7, 8, 9, 10, /* 40-49 */ 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, /* 50-59 */ 14, 14, 14, 14, 14, 14, 14, 14, 15, 17, /* 60-69 */ 19, 21, 22, 22, 23, /* 70-74 */ 24, 25, 25, 26, 26, /* 75-79 */ 27, 27, 27, 27, 28, /* 80-84 */ 28, 28, 28, 29, 29, /* 85-89 */ 29, 29 /* 90-91 */ }; /*===========================================================================*/ /* Logs of primes are rounded and errors accumulate * This specifies how great an error to allow */ static const unsigned int errorAmounts[] = { 10, 10, 10, 11, 13, 14, 14, 15, 15, 16, /* 30-39 */ 16, 17, 17, 18, 18, 19, 19, 19, 20, 20, /* 40-49 */ 21, 21, 21, 22, 22, 22, 23, 23, 23, 24, /* 50-59 */ 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, /* 60-69 */ 27, 27, 28, 28, 29, /* 70-74 */ 29, 30, 30, 30, 31, /* 75-79 */ 31, 31, 31, 32, 32, /* 80-84 */ 32, 32, 32, 33, 33, /* 85-89 */ 33, 33 /* 90-91 */ }; /*===========================================================================*/ /* Threshold the sieve value must exceed to be considered for smoothness */ static const unsigned int thresholds[] = { 63, 63, 63, 64, 64, 64, 65, 65, 65, 66, /* 30-39 */ 66, 67, 67, 68, 68, 68, 69, 69, 69, 69, /* 40-49 */ 70, 70, 70, 71, 71, 71, 72, 72, 73, 73, /* 50-59 */ 74, 74, 75, 75, 76, 76, 77, 77, 78, 79, /* 60-69 */ 80, 81, 82, 83, 84, /* 70-74 */ 85, 86, 87, 88, 89, /* 75-79 */ 91, 92, 93, 93, 94, /* 80-84 */ 95, 96, 97, 98,100, /* 85-89 */ 101, 102 /* 90-91 */ }; /*===========================================================================*/ /* Size of sieve to use divided by 2 * Optimal if chosen to be a multiple of 32000 */ static const unsigned int sieveSize[] = { 64000,64000,64000,64000,64000,64000,64000,64000,64000,64000, /* 30-39 */ 64000,64000,64000,64000,64000,64000,64000,64000,64000,64000, /* 40-49 */ 64000,64000,64000,64000,64000,64000,64000,64000,64000,64000, /* 50-59 */ 64000,64000,64000,64000,64000,64000,64000,64000,64000,64000, /* 60-69 */ 64000, 64000, 64000, 64000, 64000, /* 70-74 */ 96000, 96000, 96000, 128000, 128000, /* 75-79 */ 160000, 160000, 160000, 160000, 160000, /* 80-84 */ 192000, 192000, 192000, 192000, 192000, /* 85-89 */ 192000, 192000 /* 90-91 */ }; /*===========================================================================*/ static unsigned int secondprime; /* cutoff for using flags when sieving */ static unsigned int firstprime; /* first prime actually sieved with */ static unsigned char errorbits; /* first prime actually sieved with */ static unsigned char threshold; /* sieve threshold cutoff for smth relations */ static unsigned int largeprime; static unsigned int *factorBase; /* array of factor base primes */ static unsigned char * primeSizes; /* array of sizes in bits of fb primes */ #define RELATIONS_PER_PRIME 100 static INLINE void set_relation(unsigned long* rel, unsigned int prime, unsigned int nrel, unsigned long val) { if (nrel < RELATIONS_PER_PRIME) rel[ prime*RELATIONS_PER_PRIME + nrel ] = val; } static INLINE unsigned long get_relation(unsigned long* rel, unsigned int prime, unsigned int nrel) { return rel[ prime*RELATIONS_PER_PRIME + nrel ]; } /*========================================================================= Knuth_Schroeppel Multiplier: This is derived from Jason Papadopoulos's mpqs K-S method. I believe it does a slightly better job than the K-S in FLINT 2.3, but that's debatable. An alternative would be to implement the method directly from Silverman 1987. ==========================================================================*/ /* Multiplers should be small square-free numbers, i.e. * do { say $_ if moebius($_) != 0 } for 1..100 * but SIMPQS doesn't deal well with composite multipliers. So, just primes. */ static const unsigned long multipliers[] = { 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}; #define NUMMULTS (sizeof(multipliers)/sizeof(unsigned long)) #ifndef M_LN2 #define M_LN2 0.69314718055994530942 #endif static unsigned long knuthSchroeppel(mpz_t n, unsigned long numPrimes) { unsigned int i, j, best_mult, knmod8; unsigned int maxprimes = (2*numPrimes <= 1000) ? 2*numPrimes : 1000; float best_score, contrib; float scores[NUMMULTS]; mpz_t temp; mpz_init(temp); for (i = 0; i < NUMMULTS; i++) { scores[i] = 0.5 * logf((float)multipliers[i]); mpz_mul_ui(temp, n, multipliers[i]); knmod8 = mpz_mod_ui(temp, temp, 8); switch (knmod8) { case 1: scores[i] -= 2 * M_LN2; break; case 5: scores[i] -= M_LN2; break; case 3: case 7: scores[i] -= 0.5 * M_LN2; break; default: break; } } { unsigned long prime, modp, knmodp; PRIME_ITERATOR(iter); for (i = 1; i < maxprimes; i++) { prime = prime_iterator_next(&iter); modp = mpz_mod_ui(temp, n, prime); contrib = logf((float)prime) / (float)(prime-1); for (j = 0; j < NUMMULTS; j++) { knmodp = (modp * multipliers[j]) % prime; if (knmodp == 0) { scores[j] -= contrib; } else { mpz_set_ui(temp, knmodp); if (mpz_kronecker_ui(temp, prime) == 1) scores[j] -= 2*contrib; } } } prime_iterator_destroy(&iter); } mpz_clear(temp); best_score = 1000.0; best_mult = 1; for (i = 0; i < NUMMULTS; i++) { float score = scores[i]; if (score < best_score) { best_score = score; best_mult = multipliers[i]; } } /* gmp_printf("%Zd mult %lu\n", n, best_mult); */ return best_mult; } /*======================================================================== Initialize Quadratic Sieve: Function: Initialises the global gmp variables. ========================================================================*/ static void initFactorBase(void) { factorBase = 0; primeSizes = 0; } static void clearFactorBase(void) { if (factorBase) { Safefree(factorBase); factorBase = 0; } if (primeSizes) { Safefree(primeSizes); primeSizes = 0; } } /*======================================================================== Compute Factor Base: Function: Computes primes p up to B for which n is a square mod p, allocates memory and stores them in an array pointed to by factorBase. Additionally allocates and computes the primeSizes array. Returns: number of primes actually in the factor base ========================================================================*/ static void computeFactorBase(mpz_t n, unsigned long B,unsigned long multiplier) { UV p; UV primesinbase = 0; PRIME_ITERATOR(iter); if (factorBase) { Safefree(factorBase); factorBase = 0; } New(0, factorBase, B, unsigned int); factorBase[primesinbase++] = multiplier; if (multiplier != 2) factorBase[primesinbase++] = 2; prime_iterator_setprime(&iter, 3); for (p = 3; primesinbase < B; p = prime_iterator_next(&iter)) { if (mpz_kronecker_ui(n, p) == 1) factorBase[primesinbase++] = p; } prime_iterator_destroy(&iter); #ifdef LARGESTP gmp_printf("Largest prime less than %Zd\n",p); #endif /* Allocate and compute the number of bits required to store each prime */ New(0, primeSizes, B, unsigned char); for (p = 0; p < B; p++) primeSizes[p] = (unsigned char) floor( log(factorBase[p]) / log(2.0) - SIZE_FUDGE + 0.5 ); } /*=========================================================================== Tonelli-Shanks: Function: Performs Tonelli-Shanks on n mod every prime in the factor base ===========================================================================*/ static void tonelliShanks(unsigned long numPrimes, mpz_t n, mpz_t * sqrts) { unsigned long i; mpz_t fbprime, t1, t2, t3, t4; mpz_init(fbprime); mpz_init(t1); mpz_init(t2); mpz_init(t3); mpz_init(t4); mpz_set_ui(sqrts[0], 0); for (i = 1; i < numPrimes; i++) { mpz_set_ui(fbprime, factorBase[i]); sqrtmod_t(sqrts[i], n, fbprime, t1, t2, t3, t4); } mpz_clear(t1); mpz_clear(t2); mpz_clear(t3); mpz_clear(t4); mpz_clear(fbprime); } /*========================================================================== evaluateSieve: Function: searches sieve for relations and sticks them into a matrix, then sticks their X and Y values into two arrays XArr and YArr ===========================================================================*/ static void evaluateSieve( unsigned long numPrimes, unsigned long Mdiv2, unsigned long * relations, unsigned long ctimesreps, unsigned long M, unsigned char * sieve, mpz_t A, mpz_t B, mpz_t C, unsigned long * soln1, unsigned long * soln2, unsigned char * flags, matrix_t m, mpz_t * XArr, unsigned long * aind, int min, int s, int * exponents, unsigned long * npartials, unsigned long * nrelsfound, unsigned long * nrelssought, mpz_t temp, mpz_t temp2, mpz_t temp3, mpz_t res) { long i,j,ii; unsigned int k; unsigned int exponent, vv; unsigned char extra; unsigned int modp; unsigned long * sieve2; unsigned char bits; int numfactors; unsigned long relsFound = *nrelsfound; unsigned long relSought = *nrelssought; mpz_set_ui(temp, 0); mpz_set_ui(temp2, 0); mpz_set_ui(temp3, 0); mpz_set_ui(res, 0); i = 0; j = 0; sieve2 = (unsigned long *) sieve; #ifdef POLS gmp_printf("%Zdx^2%+Zdx\n%+Zd\n",A,B,C); #endif while ( (unsigned long)j < M/sizeof(unsigned long)) { do { while (!(sieve2[j] & SIEVEMASK)) j++; i = j * sizeof(unsigned long); j++; while (((unsigned long)i < j*sizeof(unsigned long)) && (sieve[i] < threshold)) i++; } while (sieve[i] < threshold); if (((unsigned long)i= bits) { vv=((unsigned char)1<<(i&7)); for (k = firstprime; (k0) { if (mpz_cmp_ui(res,largeprime)<0) { (*npartials)++; } clearRow(m,numPrimes,relsFound); #ifdef RELPRINT gmp_printf(" %Zd\n",res); #endif } else { mpz_neg(res,res); if (mpz_cmp_ui(res,1000)>0) { if (mpz_cmp_ui(res,largeprime)<0) { (*npartials)++; } clearRow(m,numPrimes,relsFound); #ifdef RELPRINT gmp_printf(" %Zd\n",res); #endif } else { #ifdef RELPRINT printf("....R\n"); #endif for (ii = 0; ii < (long)firstprime; ii++) { int jj; for (jj = 0; jj < exponents[ii]; jj++) set_relation(relations, relsFound, ++numfactors, ii); if (exponents[ii] & 1) insertEntry(m,relsFound,ii); } set_relation(relations, relsFound, 0, numfactors); mpz_init_set(XArr[relsFound], temp3); /* (AX+B) */ relsFound++; #ifdef COUNT if (relsFound%20==0) fprintf(stderr,"%lu relations, %lu partials.\n", relsFound, *npartials); #endif } } } else { clearRow(m,numPrimes,relsFound); #ifdef RELPRINT printf("\r \r"); #endif } i++; } else if (relsFound >= relSought) i++; } /* Update caller */ *nrelsfound = relsFound; *nrelssought = relSought; } static void update_solns(unsigned long first, unsigned long limit, unsigned long * soln1, unsigned long * soln2, int polyadd, const unsigned long * polycorr) { unsigned int prime; unsigned long p, correction; for (prime = first; prime < limit; prime++) { if (soln2[prime] == (unsigned long) -1) continue; p = factorBase[prime]; correction = (polyadd) ? p - polycorr[prime] : polycorr[prime]; soln1[prime] += correction; while (soln1[prime] >= p) soln1[prime] -= p; soln2[prime] += correction; while (soln2[prime] >= p) soln2[prime] -= p; } } static void set_offsets(unsigned char * const sieve, const unsigned long * const soln1, const unsigned long * const soln2, unsigned char * * offsets1, unsigned char * * offsets2) { unsigned int prime; for (prime = firstprime; prime < secondprime; prime++) { if (soln2[prime] == (unsigned long) -1) { offsets1[prime] = 0; offsets2[prime] = 0; } else { offsets1[prime] = sieve+soln1[prime]; offsets2[prime] = sieve+soln2[prime]; } } } /*============================================================================= Sieve: Function: Allocates space for a sieve of M integers and sieves the interval starting at start =============================================================================*/ static void sieveInterval(unsigned long M, unsigned char * sieve, int more, unsigned char * * offsets1, unsigned char * * offsets2) { unsigned int prime, p; unsigned char size; unsigned char * pos1; unsigned char * pos2; unsigned char * end = sieve + M; unsigned char * bound; ptrdiff_t diff; for (prime = firstprime; prime < secondprime; prime++) { if (offsets1[prime] == 0) continue; p = factorBase[prime]; size = primeSizes[prime]; pos1 = offsets1[prime]; pos2 = offsets2[prime]; diff = pos2 - pos1; /* if pos1 < bound, then both *pos1 and *pos2 can be written to. */ bound = (diff >= 0) ? end-diff : end; /* Write both values, unrolled 4 times. */ bound -= (4-1)*p; while (pos1 < bound) { pos1[0 ] += size; pos1[ diff] += size; pos1[1*p] += size; pos1[1*p+diff] += size; pos1[2*p] += size; pos1[2*p+diff] += size; pos1[3*p] += size; pos1[3*p+diff] += size; pos1 += 4*p; } bound += (4-1)*p; /* Write both values */ while (pos1 < bound) { pos1[0] += size; pos1[diff] += size; pos1 += p; } pos2 = pos1 + diff; /* Restore pos2 */ /* Finish writing to pos1 and pos2 */ while (pos1 < end) { *pos1 += size; pos1 += p; } while (pos2 < end) { *pos2 += size; pos2 += p; } if (more) { offsets1[prime] = pos1; offsets2[prime] = pos2; } } } /*=========================================================================== Sieve 2: Function: Second sieve for larger primes =========================================================================== */ static void sieve2(unsigned long M, unsigned long numPrimes, unsigned char * sieve, const unsigned long * soln1, const unsigned long * soln2, unsigned char * flags) { unsigned int prime; unsigned char *end = sieve + M; memset(flags, 0, numPrimes*sizeof(unsigned char)); for (prime = secondprime; prime < numPrimes; prime++) { unsigned int p = factorBase[prime]; unsigned char size = primeSizes[prime]; unsigned char* pos1 = sieve + soln1[prime]; unsigned char* pos2 = sieve + soln2[prime]; if (soln2[prime] == (unsigned long)-1 ) continue; while (end - pos1 > 0) { flags[prime] |= ((unsigned char)1<<((pos1-sieve)&7)); *pos1 += size; pos1 += p; } while (end - pos2 > 0) { flags[prime] |= ((unsigned char)1<<((pos2-sieve)&7)); *pos2 += size; pos2 += p; } } } /*============================================================================ random: Function: Generates a pseudo-random integer between 0 and n-1 inclusive ============================================================================*/ static unsigned long randval = 2994439072U; static unsigned long silly_random(unsigned long upto) { randval = ((unsigned long)randval*1025416097U+286824428U)%(unsigned long)4294967291U; return randval%upto; } /*============================================================================ danaj: added these routines to reduce the set of factors to co-primes. It's not the most efficient solution, but it's trivial in time compared to the loop it's in, much less the rest of the QS. It gives us a nice set of factors back, which is much more useful than the essentially random combinations we discover. ============================================================================*/ /* Verify that the factor reduction hasn't broken anything */ static void verify_factor_array(mpz_t n, mpz_t* farray, int nfacs) { int i, j; mpz_t t; mpz_init_set_ui(t, 1); /* Assert we don't have duplicates */ for (i = 0; i < nfacs; i++) { for (j = i+1; j < nfacs; j++) { if (mpz_cmp(farray[i],farray[j]) == 0) { gmp_printf("duplicate: F[%d] = F[%d] = %Zd\n", i, j, farray[i]); croak("assert"); } } } /* Assert that all factors multiply to n */ for (i = 0; i < nfacs; i++) mpz_mul(t, t, farray[i]); if (mpz_cmp(t, n) != 0) { gmp_printf("farray doesn't multiply: n=%Zd t=%Zd\n", n, t); croak("assert"); } /* Assert that gcd of each non-identical factor is 1 */ for (i = 0; i < nfacs; i++) { for (j = i+1; j < nfacs; j++) { if (mpz_cmp(farray[i],farray[j]) != 0) { mpz_gcd(t, farray[i], farray[j]); if (mpz_cmp_ui(t, 1) != 0) { gmp_printf("gcd: farray[%d] = %Zd farray[%d] = %Zd\n", i, farray[i], j, farray[j]); croak("assert"); } } } } mpz_clear(t); } static int allprime_factor_array(mpz_t* farray, int nfacs) { int i; for (i = 0; i < nfacs; i++) { if (!mpz_probab_prime_p(farray[i], 5)) /* Be lazy */ return 0; } return 1; } static int insert_factor(mpz_t n, mpz_t* farray, int nfacs, mpz_t f) { int i, j; mpz_t t, t2; if (mpz_cmp_ui(f, 1) <= 0) return nfacs; /* skip duplicates */ for (i = 0; i < nfacs; i++) if (mpz_cmp(farray[i], f) == 0) break; if (i != nfacs) { return nfacs; } /* Look for common factors in all the existing set */ /* for (i = 0; i < nfacs; i++) gmp_printf(" F[%d] = %Zd\n", i, farray[i]); */ mpz_init(t); mpz_init(t2); for (i = 0; i < nfacs; i++) { mpz_gcd(t, farray[i], f); if (mpz_cmp_ui(t, 1) == 0) /* t=1: F and f unchanged */ continue; mpz_divexact(t2, farray[i], t); /* t2 = F/t */ mpz_divexact(f, f, t); /* f = f/t */ /* Remove the old farray[i] */ for (j = i+1; j < nfacs; j++) mpz_set(farray[j-1], farray[j]); mpz_set_ui(farray[nfacs--], 0); /* Insert F/t, t, f/t */ nfacs = insert_factor(n, farray, nfacs, t2); nfacs = insert_factor(n, farray, nfacs, t); nfacs = insert_factor(n, farray, nfacs, f); i=0; break; } /* If nothing common, insert it. */ if (i == nfacs) mpz_set(farray[nfacs++], f); mpz_clear(t); mpz_clear(t2); return nfacs; } /*============================================================================ mainRoutine: Function: Generates the polynomials, initialises and calls the sieve, implementing cache blocking (breaking the sieve interval into small blocks for the small primes. ============================================================================*/ static int mainRoutine( unsigned long numPrimes, unsigned long Mdiv2, unsigned long relSought, mpz_t n, mpz_t* farray, unsigned long multiplier) { mpz_t A, B, C, D, Bdivp2, q, r, nsqrtdiv, temp, temp2, temp3, temp4; int i, j, l, s, fact, span, min, nfactors, verbose; unsigned long u1, p, reps, numRelations, M; unsigned long curves = 0; unsigned long npartials = 0; unsigned long relsFound = 0; unsigned long * relations; unsigned short * primecount; unsigned char * sieve; int * exponents; unsigned long * aind; unsigned long * amodp; unsigned long * Ainv; unsigned long * soln1; unsigned long * soln2; unsigned char * flags; unsigned long ** Ainv2B; unsigned char ** offsets; unsigned char ** offsets2; mpz_t * XArr; mpz_t * Bterms; mpz_t * sqrts; matrix_t m; verbose = get_verbose_level(); s = mpz_sizeinbase(n,2)/28+1; New( 0, exponents, firstprime, int ); Newz( 0, aind, s, unsigned long ); Newz( 0, amodp, s, unsigned long ); Newz( 0, Ainv, numPrimes, unsigned long ); Newz( 0, soln1, numPrimes, unsigned long ); Newz( 0, soln2, numPrimes, unsigned long ); Newz( 0, Ainv2B, s, unsigned long*); Newz( 0, XArr, relSought, mpz_t ); New( 0, Bterms, s, mpz_t ); if (exponents == 0 || aind == 0 || amodp == 0 || Ainv == 0 || soln1 == 0 || soln2 == 0 || Ainv2B == 0 || Bterms == 0 || XArr == 0) croak("SIMPQS: Unable to allocate memory!\n"); flags = 0; if (secondprime < numPrimes) { New(0, flags, numPrimes, unsigned char); if (flags == 0) croak("SIMPQS: Unable to allocate memory!\n"); } for (i=0; i=0; fact++); span = numPrimes/s/s/2; min=fact-span/2; while ( min > 0 && (fact*fact)/min - min < span ) min--; #ifdef ADETAILS printf("s = %d, fact = %d, min = %d, span = %d\n",s,fact,min,span); #endif /* Compute first polynomial and adjustments */ while (relsFound < relSought) { int polyindex; mpz_set_ui(A,1); for (i = 0; i < s-1; ) { unsigned long ran = span/2+silly_random(span/2); j=-1L; while (j!=i) { ran++; for (j=0;((j=0; fact++); fact-=min; do { for (j=0;((j0) { mpz_sub_ui(temp,temp,p); mpz_neg(temp,temp); } mpz_mul(temp,temp,A); mpz_tdiv_q_ui(Bterms[i],temp,p); } mpz_set(B,Bterms[0]); for (i = 1; i < s; i++) { mpz_add(B,B,Bterms[i]); } for (i = 0; i < (int)numPrimes; i++) { p = factorBase[i]; Ainv[i] = modinverse(mpz_fdiv_r_ui(temp,A,p),p); for (j=0; j>j)&1)!=0) break; } if ((polyadd = (((polyindex>>j)&2)!=0))) { mpz_add(B,B,Bterms[j]); mpz_add(B,B,Bterms[j]); } else { mpz_sub(B,B,Bterms[j]); mpz_sub(B,B,Bterms[j]); } polycorr = Ainv2B[j]; for (j=0; j0) { unsigned long maxreps = mpz_get_ui(q)-1; for (reps = 1; reps < maxreps; reps++) { sieveInterval(CACHEBLOCKSIZE,sieve+CACHEBLOCKSIZE*reps,1,offsets,offsets2); } if (mpz_cmp_ui(r,0)==0) { sieveInterval(CACHEBLOCKSIZE,sieve+CACHEBLOCKSIZE*reps,0,offsets,offsets2); } else { sieveInterval(CACHEBLOCKSIZE,sieve+CACHEBLOCKSIZE*reps,1,offsets,offsets2); reps++; sieveInterval(mpz_get_ui(r),sieve+CACHEBLOCKSIZE*reps,0,offsets,offsets2); } } evaluateSieve( numPrimes, Mdiv2, relations, 0, M, sieve, A, B, C, soln1, soln2, flags, m, XArr, aind, min, s, exponents, &npartials, &relsFound, &relSought, temp, temp2, temp3, temp4 ); } #ifdef COUNT if (curves%20==0) printf("%ld curves.\n",(long)curves); #endif } #ifdef CURPARTS printf("%lu curves, %lu partials.\n", curves, npartials); #endif #ifdef REPORT printf("Done with sieving!\n"); #endif if (verbose>3) printf("# qs done sieving\n"); /* Free everything we don't need for the linear algebra */ for (p = 0; p < numPrimes; p++) mpz_clear(sqrts[p]); Safefree(sqrts); for (i = 0; i < s; i++) { Safefree(Ainv2B[i]); mpz_clear(Bterms[i]); } Safefree(exponents); Safefree(aind); Safefree(amodp); Safefree(Ainv); Safefree(soln1); Safefree(soln2); Safefree(Ainv2B); Safefree(Bterms); if (flags) Safefree(flags); Safefree(sieve); sieve = 0; Safefree(offsets); offsets = 0; Safefree(offsets2); offsets2 = 0; mpz_clear(A); mpz_clear(B); mpz_clear(C); mpz_clear(D); mpz_clear(q); mpz_clear(r); mpz_clear(Bdivp2); mpz_clear(nsqrtdiv); /* Do the matrix algebra step */ numRelations = gaussReduce(m, numPrimes, relSought); #ifdef REPORT printf("%ld relations in kernel.\n", numRelations); #endif if (verbose>3) printf("# qs found %lu relations in kernel\n", numRelations); /* We want factors of n, not kn, so divide out by the multiplier */ mpz_tdiv_q_ui(n,n,multiplier); /* Now do the "sqrt" and GCD steps hopefully obtaining factors of n */ mpz_set(farray[0], n); nfactors = 1; /* We have one result -- n */ New( 0, primecount, numPrimes, unsigned short); if (primecount == 0) croak("SIMPQS: Unable to allocate memory!\n"); for (l = (int)relSought-64; l < (int)relSought; l++) { unsigned int mat2offset = rightMatrixOffset(numPrimes); mpz_set_ui(temp,1); mpz_set_ui(temp2,1); memset(primecount,0,numPrimes*sizeof(unsigned short)); for (i = 0; i< (int)numPrimes; i++) { if (getEntry(m,l,mat2offset+i)) { int nrelations = get_relation(relations, i, 0); if (nrelations >= RELATIONS_PER_PRIME) nrelations = RELATIONS_PER_PRIME-1; mpz_mul(temp2,temp2,XArr[i]); for (j = 1; j <= nrelations; j++) primecount[ get_relation(relations, i, j) ]++; } if (i%16==0) mpz_mod(temp2,temp2,n); } for (j = 0; j < (int)numPrimes; j++) { mpz_set_ui(temp3,factorBase[j]); mpz_pow_ui(temp3,temp3,primecount[j]/2); mpz_mul(temp,temp,temp3); if (j%16==0) mpz_mod(temp,temp,n); } mpz_sub(temp,temp2,temp); mpz_gcd(temp,temp,n); /* Only non-trivial factors */ if (mpz_cmp_ui(temp,1) && mpz_cmp(temp,n) && mpz_divisible_p(n,temp) ) { if (verbose>4) gmp_printf("# qs factor %Zd\n", temp); nfactors = insert_factor(n, farray, nfactors, temp); verify_factor_array(n, farray, nfactors); if (allprime_factor_array(farray, nfactors)) break; } } /* Free everything remaining */ Safefree(primecount); destroyMat(m, relSought); Safefree(relations); for (i = 0; i < (int)relSought; i++) { mpz_clear(XArr[i]); } Safefree(XArr); mpz_clear(temp); mpz_clear(temp2); mpz_clear(temp3); mpz_clear(temp4); return nfactors; } int _GMP_simpqs(mpz_t n, mpz_t* farray) { unsigned long numPrimes, Mdiv2, multiplier, decdigits, relSought; int result = 0; int verbose = get_verbose_level(); mpz_set(farray[0], n); decdigits = mpz_sizeinbase(n,10); /* often 1 too big */ if (decdigits < MINDIG) return 0; if (verbose>2) gmp_printf("# qs trying %Zd (%lu digits)\n", n, decdigits); #ifdef REPORT gmp_printf("%Zd (%ld decimal digits)\n", n, decdigits); #endif /* It's important to remove small factors. */ { UV p; PRIME_ITERATOR(iter); for (p = 2; p < 1000; p = prime_iterator_next(&iter)) { if (mpz_cmp_ui(n, p*p) < 0) break; while (mpz_divisible_ui_p(n, p)) { mpz_set_ui(farray[result++], p); mpz_divexact_ui(n, n, p); } } decdigits = mpz_sizeinbase(n,10); if (decdigits < MINDIG) return result; mpz_set(farray[result], n); } /* Get a preliminary number of primes, pick a multiplier, apply it */ numPrimes = (decdigits <= 91) ? primesNo[decdigits-MINDIG] : 64000; multiplier = knuthSchroeppel(n, numPrimes); mpz_mul_ui(n, n, multiplier); decdigits = mpz_sizeinbase(n, 10); if (decdigits<=91) { numPrimes=primesNo[decdigits-MINDIG]; Mdiv2 = sieveSize[decdigits-MINDIG]/SIEVEDIV; if (Mdiv2*2 < CACHEBLOCKSIZE) Mdiv2 = CACHEBLOCKSIZE/2; largeprime = 1000 * largeprimes[decdigits-MINDIG]; secondprime = (numPrimes < SECONDPRIME) ? numPrimes : SECONDPRIME; firstprime = firstPrimes[decdigits-MINDIG]; errorbits = errorAmounts[decdigits-MINDIG]; threshold = thresholds[decdigits-MINDIG]; } else { numPrimes = 64000; Mdiv2 = 192000/SIEVEDIV; largeprime = numPrimes*10*decdigits; secondprime = SECONDPRIME; firstprime = 30; errorbits = decdigits/4 + 2; threshold = 43+(7*decdigits)/10; } #ifdef REPORT printf("Using multiplier: %lu\n",multiplier); printf("%lu primes in factor base.\n",numPrimes); printf("Sieving interval M = %lu\n",Mdiv2*2); printf("Large prime cutoff = factorBase[%u]\n",largeprime); #endif if (verbose>2) gmp_printf("# qs mult %lu, digits %lu, sieving %lu, primes %lu\n", multiplier, decdigits, Mdiv2*2, numPrimes); /* We probably need fewer than this */ relSought = numPrimes; initFactorBase(); computeFactorBase(n, numPrimes, multiplier); result += mainRoutine(numPrimes, Mdiv2, relSought, n, farray+result, multiplier); clearFactorBase(); if (verbose>2) { int i; gmp_printf("# qs:"); for (i = 0; i < result; i++) gmp_printf(" %Zd", farray[i]); gmp_printf("%s\n", (result) ? "" : " no factors"); } /* if (!result) gmp_printf("QS Fail: %Zd (%ld digits)\n", n, decdigits); */ return result; } #ifdef STANDALONE_SIMPQS /*=========================================================================== Main Program: Function: Factors a user specified number using a quadratic sieve ===========================================================================*/ int main(int argc, char **argv) { int i, nfactors; mpz_t n; mpz_t* farray; mpz_init(n); New(0, farray, 64, mpz_t); for (i = 0; i < 64; i++) mpz_init_set_ui(farray[i], 0); printf("Input number to factor [ >=%d decimal digits]: ", MINDIG); gmp_scanf("%Zd",n);getchar(); if (mpz_sizeinbase(n,10) < MINDIG) croak("SIMPQS: Error in input or number has too few digits.\n"); nfactors = _GMP_simpqs(n, farray); for (i = 0; i < nfactors; i++) gmp_printf(" %Zd\n", farray[i]); for (i = 0; i < 64; i++) mpz_clear(farray[i]); Safefree(farray); return 0; } #endif Math-Prime-Util-GMP-0.52/xt/0000755000175000017500000000000013674072603013772 5ustar danadanaMath-Prime-Util-GMP-0.52/xt/expr-impl.h0000644000175000017500000001052213025437622016054 0ustar danadana/* Implementation specifics for expression evaluation. Copyright 2000-2002, 2004 Free Software Foundation, Inc. This file is part of the GNU MP Library. The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of either: * the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. or * the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. or both in parallel, as here. The GNU MP Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received copies of the GNU General Public License and the GNU Lesser General Public License along with the GNU MP Library. If not, see https://www.gnu.org/licenses/. */ #include #include "expr.h" #define isasciidigit(c) (isascii (c) && isdigit (c)) #define isasciicsym(c) (isascii (c) && (isalnum(c) || (c) == '_')) #define isasciidigit_in_base(c,base) \ (isascii (c) \ && ((isdigit (c) && (c)-'0' < (base)) \ || (isupper (c) && (c)-'A'+10 < (base)) \ || (islower (c) && (c)-'a'+10 < (base)))) union mpX_t { mpz_t z; mpq_t q; mpf_t f; }; typedef union mpX_t *mpX_ptr; typedef const union mpX_t *mpX_srcptr; typedef void (*mpexpr_fun_one_t) (mpX_ptr); typedef unsigned long (*mpexpr_fun_ui_one_t) (mpX_ptr); typedef void (*mpexpr_fun_0ary_t) (mpX_ptr); typedef int (*mpexpr_fun_i_0ary_t) (void); typedef void (*mpexpr_fun_unary_t) (mpX_ptr, mpX_srcptr); typedef void (*mpexpr_fun_unary_ui_t) (mpX_ptr, unsigned long); typedef int (*mpexpr_fun_i_unary_t) (mpX_srcptr); typedef int (*mpexpr_fun_i_unary_ui_t) (unsigned long); typedef void (*mpexpr_fun_binary_t) (mpX_ptr, mpX_srcptr, mpX_srcptr); typedef void (*mpexpr_fun_binary_ui_t) (mpX_ptr, mpX_srcptr, unsigned long); typedef int (*mpexpr_fun_i_binary_t) (mpX_srcptr, mpX_srcptr); typedef int (*mpexpr_fun_i_binary_ui_t) (mpX_srcptr, unsigned long); typedef void (*mpexpr_fun_ternary_t) (mpX_ptr, mpX_srcptr, mpX_srcptr, mpX_srcptr); typedef void (*mpexpr_fun_ternary_ui_t) (mpX_ptr, mpX_srcptr, mpX_srcptr, unsigned long); typedef int (*mpexpr_fun_i_ternary_t) (mpX_srcptr, mpX_srcptr, mpX_srcptr); typedef int (*mpexpr_fun_i_ternary_ui_t) (mpX_srcptr, mpX_srcptr, unsigned long); typedef size_t (*mpexpr_fun_number_t) (mpX_ptr, const char *str, size_t len, int base); typedef void (*mpexpr_fun_swap_t) (mpX_ptr, mpX_ptr); typedef unsigned long (*mpexpr_fun_get_ui_t) (mpX_srcptr); typedef void (*mpexpr_fun_set_si_t) (mpX_srcptr, long); struct mpexpr_control_t { const struct mpexpr_operator_t *op; int argcount; }; #define MPEXPR_VARIABLES 26 struct mpexpr_parse_t { const struct mpexpr_operator_t *table; mpX_ptr res; int base; unsigned long prec; const char *e; size_t elen; mpX_srcptr *var; int error_code; int token; const struct mpexpr_operator_t *token_op; union mpX_t *data_stack; int data_top; int data_alloc; int data_inited; struct mpexpr_control_t *control_stack; int control_top; int control_alloc; mpexpr_fun_0ary_t mpX_clear; mpexpr_fun_i_unary_t mpX_ulong_p; mpexpr_fun_get_ui_t mpX_get_ui; mpexpr_fun_unary_ui_t mpX_init; mpexpr_fun_number_t mpX_number; mpexpr_fun_unary_t mpX_set; mpexpr_fun_unary_t mpX_set_or_swap; mpexpr_fun_set_si_t mpX_set_si; mpexpr_fun_swap_t mpX_swap; }; int mpexpr_evaluate (struct mpexpr_parse_t *p); int mpexpr_va_to_var (void *var[], va_list ap); size_t mpexpr_mpz_number (mpz_ptr res, const char *e, size_t elen, int base); Math-Prime-Util-GMP-0.52/xt/expr.c0000644000175000017500000010740313025437622015115 0ustar danadana /* This is a concatenation of expr.c, exprv.c, exprza.c, and expr.c from * the GMP-6.0.0a distribution. I have simply added n# for primorial. * DAJ 10 Aug 2014 * Thanks to Mathew from mersenneforum for suggesting expression parsing. */ /* mpz expression evaluation Copyright 2000-2002, 2004 Free Software Foundation, Inc. This file is part of the GNU MP Library. The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of either: * the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. or * the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. or both in parallel, as here. The GNU MP Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received copies of the GNU General Public License and the GNU Lesser General Public License along with the GNU MP Library. If not, see https://www.gnu.org/licenses/. */ #include #include #include #include "gmp.h" #include "expr-impl.h" /* No need to parse '-' since that's handled as an operator. This function also by mpq_expr_a, so it's not static. */ size_t mpexpr_mpz_number (mpz_ptr res, const char *e, size_t elen, int base) { char *edup; size_t i, ret; int base_effective = (base == 0 ? 10 : base); void *(*allocate_func) (size_t); void (*free_func) (void *, size_t); i = 0; if (e[i] == '0') { i++; if (e[i] == 'x' || e[i] == 'b') i++; } for ( ; i < elen; i++) if (! isasciidigit_in_base (e[i], base_effective)) break; mp_get_memory_functions (&allocate_func, NULL, &free_func); edup = (*allocate_func) (i+1); memcpy (edup, e, i); edup[i] = '\0'; if (mpz_set_str (res, edup, base) == 0) ret = i; else ret = 0; (*free_func) (edup, i+1); return ret; } /* ignoring prec */ static void e_mpz_init (mpz_ptr z, unsigned long prec) { mpz_init (z); } int mpz_expr_a (const struct mpexpr_operator_t *table, mpz_ptr res, int base, const char *e, size_t elen, mpz_srcptr var[26]) { struct mpexpr_parse_t p; p.table = table; p.res = (mpX_ptr) res; p.base = base; p.e = e; p.elen = elen; p.var = (mpX_srcptr *) var; p.mpX_clear = (mpexpr_fun_one_t) mpz_clear; p.mpX_ulong_p = (mpexpr_fun_i_unary_t) mpz_fits_ulong_p; p.mpX_get_ui = (mpexpr_fun_get_ui_t) mpz_get_ui; p.mpX_init = (mpexpr_fun_unary_ui_t) e_mpz_init; p.mpX_number = (mpexpr_fun_number_t) mpexpr_mpz_number; p.mpX_set = (mpexpr_fun_unary_t) mpz_set; p.mpX_set_or_swap = (mpexpr_fun_unary_t) mpz_swap; p.mpX_set_si = (mpexpr_fun_set_si_t) mpz_set_si; p.mpX_swap = (mpexpr_fun_swap_t) mpz_swap; return mpexpr_evaluate (&p); } /* Change this to "#define TRACE(x) x" to get some traces. */ #define TRACE(x) /* These are macros, so need function wrappers. */ static int e_mpz_sgn (mpz_srcptr x) { return mpz_sgn (x); } static int e_mpz_odd_p (mpz_srcptr x) { return mpz_odd_p (x); } static int e_mpz_even_p (mpz_srcptr x) { return mpz_even_p (x); } /* These wrapped because MPEXPR_TYPE_I_ functions are expected to return "int" whereas these return "unsigned long". */ static void e_mpz_hamdist (mpz_ptr w, mpz_srcptr x, mpz_srcptr y) { mpz_set_ui (w, mpz_hamdist (x, y)); } static void e_mpz_popcount (mpz_ptr w, mpz_srcptr x) { mpz_set_ui (w, mpz_popcount (x)); } static void e_mpz_scan0 (mpz_ptr w, mpz_srcptr x, unsigned long start) { mpz_set_ui (w, mpz_scan0 (x, start)); } static void e_mpz_scan1 (mpz_ptr w, mpz_srcptr x, unsigned long start) { mpz_set_ui (w, mpz_scan1 (x, start)); } /* These wrapped because they're in-place whereas MPEXPR_TYPE_BINARY_UI expects a separate source and destination. Actually the parser will normally pass w==x anyway. */ static void e_mpz_setbit (mpz_ptr w, mpz_srcptr x, unsigned long n) { if (w != x) mpz_set (w, x); mpz_setbit (w, n); } static void e_mpz_clrbit (mpz_ptr w, mpz_srcptr x, unsigned long n) { if (w != x) mpz_set (w, x); mpz_clrbit (w, n); } static const struct mpexpr_operator_t _mpz_expr_standard_table[] = { { "**", (mpexpr_fun_t) mpz_pow_ui, MPEXPR_TYPE_BINARY_UI | MPEXPR_TYPE_RIGHTASSOC, 220 }, { "~", (mpexpr_fun_t) mpz_com, MPEXPR_TYPE_UNARY | MPEXPR_TYPE_PREFIX, 210 }, { "!", (mpexpr_fun_t) e_mpz_sgn, MPEXPR_TYPE_LOGICAL_NOT | MPEXPR_TYPE_PREFIX, 210 }, { "-", (mpexpr_fun_t) mpz_neg, MPEXPR_TYPE_UNARY | MPEXPR_TYPE_PREFIX, 210 }, { "#", (mpexpr_fun_t) mpz_primorial_ui, MPEXPR_TYPE_UNARY_UI, 205 }, { "*", (mpexpr_fun_t) mpz_mul, MPEXPR_TYPE_BINARY, 200 }, { "/", (mpexpr_fun_t) mpz_tdiv_q, MPEXPR_TYPE_BINARY, 200 }, { "%", (mpexpr_fun_t) mpz_tdiv_r, MPEXPR_TYPE_BINARY, 200 }, { "+", (mpexpr_fun_t) mpz_add, MPEXPR_TYPE_BINARY, 190 }, { "-", (mpexpr_fun_t) mpz_sub, MPEXPR_TYPE_BINARY, 190 }, { "<<", (mpexpr_fun_t) mpz_mul_2exp, MPEXPR_TYPE_BINARY_UI, 180 }, { ">>", (mpexpr_fun_t) mpz_tdiv_q_2exp, MPEXPR_TYPE_BINARY_UI, 180 }, { "<=", (mpexpr_fun_t) mpz_cmp, MPEXPR_TYPE_CMP_LE, 170 }, { "<", (mpexpr_fun_t) mpz_cmp, MPEXPR_TYPE_CMP_LT, 170 }, { ">=", (mpexpr_fun_t) mpz_cmp, MPEXPR_TYPE_CMP_GE, 170 }, { ">", (mpexpr_fun_t) mpz_cmp, MPEXPR_TYPE_CMP_GT, 170 }, { "==", (mpexpr_fun_t) mpz_cmp, MPEXPR_TYPE_CMP_EQ, 160 }, { "!=", (mpexpr_fun_t) mpz_cmp, MPEXPR_TYPE_CMP_NE, 160 }, { "&", (mpexpr_fun_t) mpz_and, MPEXPR_TYPE_BINARY, 150 }, { "^", (mpexpr_fun_t) mpz_xor, MPEXPR_TYPE_BINARY, 140 }, { "|", (mpexpr_fun_t) mpz_ior, MPEXPR_TYPE_BINARY, 130 }, { "&&", (mpexpr_fun_t) e_mpz_sgn, MPEXPR_TYPE_LOGICAL_AND, 120 }, { "||", (mpexpr_fun_t) e_mpz_sgn, MPEXPR_TYPE_LOGICAL_OR, 110 }, { ":", NULL, MPEXPR_TYPE_COLON, 101 }, { "?", (mpexpr_fun_t) e_mpz_sgn, MPEXPR_TYPE_QUESTION, 100 }, { ")", NULL, MPEXPR_TYPE_CLOSEPAREN, 4 }, { "(", NULL, MPEXPR_TYPE_OPENPAREN, 3 }, { ",", NULL, MPEXPR_TYPE_ARGSEP, 2 }, { "$", NULL, MPEXPR_TYPE_VARIABLE, 1 }, { "abs", (mpexpr_fun_t) mpz_abs, MPEXPR_TYPE_UNARY }, { "bin", (mpexpr_fun_t) mpz_bin_ui, MPEXPR_TYPE_BINARY_UI }, { "clrbit", (mpexpr_fun_t) e_mpz_clrbit, MPEXPR_TYPE_BINARY_UI }, { "cmp", (mpexpr_fun_t) mpz_cmp, MPEXPR_TYPE_I_BINARY }, { "cmpabs", (mpexpr_fun_t) mpz_cmpabs, MPEXPR_TYPE_I_BINARY }, { "congruent_p",(mpexpr_fun_t)mpz_congruent_p, MPEXPR_TYPE_I_TERNARY }, { "divisible_p",(mpexpr_fun_t)mpz_divisible_p, MPEXPR_TYPE_I_BINARY }, { "even_p", (mpexpr_fun_t) e_mpz_even_p, MPEXPR_TYPE_I_UNARY }, { "fib", (mpexpr_fun_t) mpz_fib_ui, MPEXPR_TYPE_UNARY_UI }, { "fac", (mpexpr_fun_t) mpz_fac_ui, MPEXPR_TYPE_UNARY_UI }, { "gcd", (mpexpr_fun_t) mpz_gcd, MPEXPR_TYPE_BINARY | MPEXPR_TYPE_PAIRWISE }, { "hamdist", (mpexpr_fun_t) e_mpz_hamdist, MPEXPR_TYPE_BINARY }, { "invert", (mpexpr_fun_t) mpz_invert, MPEXPR_TYPE_BINARY }, { "jacobi", (mpexpr_fun_t) mpz_jacobi, MPEXPR_TYPE_I_BINARY }, { "kronecker", (mpexpr_fun_t) mpz_kronecker, MPEXPR_TYPE_I_BINARY }, { "lcm", (mpexpr_fun_t) mpz_lcm, MPEXPR_TYPE_BINARY | MPEXPR_TYPE_PAIRWISE }, { "lucnum", (mpexpr_fun_t) mpz_lucnum_ui, MPEXPR_TYPE_UNARY_UI }, { "max", (mpexpr_fun_t) mpz_cmp, MPEXPR_TYPE_MAX | MPEXPR_TYPE_PAIRWISE }, { "min", (mpexpr_fun_t) mpz_cmp, MPEXPR_TYPE_MIN | MPEXPR_TYPE_PAIRWISE }, { "nextprime", (mpexpr_fun_t) mpz_nextprime, MPEXPR_TYPE_UNARY }, { "odd_p", (mpexpr_fun_t) e_mpz_odd_p, MPEXPR_TYPE_I_UNARY }, { "perfect_power_p", (mpexpr_fun_t)mpz_perfect_power_p, MPEXPR_TYPE_I_UNARY}, { "perfect_square_p",(mpexpr_fun_t)mpz_perfect_square_p,MPEXPR_TYPE_I_UNARY}, { "popcount", (mpexpr_fun_t) e_mpz_popcount, MPEXPR_TYPE_UNARY }, { "powm", (mpexpr_fun_t) mpz_powm, MPEXPR_TYPE_TERNARY }, { "probab_prime_p", (mpexpr_fun_t)mpz_probab_prime_p, MPEXPR_TYPE_I_UNARY}, { "root", (mpexpr_fun_t) mpz_root, MPEXPR_TYPE_BINARY_UI }, { "scan0", (mpexpr_fun_t) e_mpz_scan0, MPEXPR_TYPE_BINARY_UI }, { "scan1", (mpexpr_fun_t) e_mpz_scan1, MPEXPR_TYPE_BINARY_UI }, { "setbit", (mpexpr_fun_t) e_mpz_setbit, MPEXPR_TYPE_BINARY_UI }, { "tstbit", (mpexpr_fun_t) mpz_tstbit, MPEXPR_TYPE_I_BINARY_UI }, { "sgn", (mpexpr_fun_t) e_mpz_sgn, MPEXPR_TYPE_I_UNARY }, { "sqrt", (mpexpr_fun_t) mpz_sqrt, MPEXPR_TYPE_UNARY }, { NULL } }; /* The table is available globally only through a pointer, so the table size can change without breaking binary compatibility. */ const struct mpexpr_operator_t * const mpz_expr_standard_table = _mpz_expr_standard_table; int mpz_expr (mpz_ptr res, int base, const char *e, ...) { mpz_srcptr var[MPEXPR_VARIABLES]; va_list ap; int ret; va_start (ap, e); TRACE (printf ("mpz_expr(): base %d, %s\n", base, e)); ret = mpexpr_va_to_var ((void **) var, ap); va_end (ap); if (ret != MPEXPR_RESULT_OK) return ret; return mpz_expr_a (mpz_expr_standard_table, res, base, e, strlen(e), var); } /* Change this to "#define TRACE(x) x" to get some traces. The trace printfs junk up the code a bit, but it's very hard to tell what's going on without them. Set MPX_TRACE to a suitable output function for the mpz/mpq/mpf being run (if you have the wrong trace function it'll probably segv). */ #define TRACE(x) #define MPX_TRACE mpz_trace /* A few helper macros copied from gmp-impl.h */ #define ALLOCATE_FUNC_TYPE(n,type) \ ((type *) (*allocate_func) ((n) * sizeof (type))) #define ALLOCATE_FUNC_LIMBS(n) ALLOCATE_FUNC_TYPE (n, mp_limb_t) #define REALLOCATE_FUNC_TYPE(p, old_size, new_size, type) \ ((type *) (*reallocate_func) \ (p, (old_size) * sizeof (type), (new_size) * sizeof (type))) #define REALLOCATE_FUNC_LIMBS(p, old_size, new_size) \ REALLOCATE_FUNC_TYPE(p, old_size, new_size, mp_limb_t) #define FREE_FUNC_TYPE(p,n,type) (*free_func) (p, (n) * sizeof (type)) #define FREE_FUNC_LIMBS(p,n) FREE_FUNC_TYPE (p, n, mp_limb_t) #define ASSERT(x) /* All the error strings are just for diagnostic traces. Only the error code is actually returned. */ #define ERROR(str,code) \ { \ TRACE (printf ("%s\n", str)); \ p->error_code = (code); \ goto done; \ } #define REALLOC(ptr, alloc, incr, type) \ do { \ int new_alloc = (alloc) + (incr); \ ptr = REALLOCATE_FUNC_TYPE (ptr, alloc, new_alloc, type); \ (alloc) = new_alloc; \ } while (0) /* data stack top element */ #define SP (p->data_stack + p->data_top) /* Make sure there's room for another data element above current top. reallocate_func is fetched for when this macro is used in lookahead(). */ #define DATA_SPACE() \ do { \ if (p->data_top + 1 >= p->data_alloc) \ { \ void *(*reallocate_func) (void *, size_t, size_t); \ mp_get_memory_functions (NULL, &reallocate_func, NULL); \ TRACE (printf ("grow stack from %d\n", p->data_alloc)); \ REALLOC (p->data_stack, p->data_alloc, 20, union mpX_t); \ } \ ASSERT (p->data_top + 1 <= p->data_inited); \ if (p->data_top + 1 == p->data_inited) \ { \ TRACE (printf ("initialize %d\n", p->data_top + 1)); \ (*p->mpX_init) (&p->data_stack[p->data_top + 1], p->prec); \ p->data_inited++; \ } \ } while (0) #define DATA_PUSH() \ do { \ p->data_top++; \ ASSERT (p->data_top < p->data_alloc); \ ASSERT (p->data_top < p->data_inited); \ } while (0) /* the last stack entry is never popped, so top>=0 will be true */ #define DATA_POP(n) \ do { \ p->data_top -= (n); \ ASSERT (p->data_top >= 0); \ } while (0) /* lookahead() parses the next token. Return 1 if successful, with some extra data. Return 0 if fail, with reason in p->error_code. "prefix" is MPEXPR_TYPE_PREFIX if an operator with that attribute is preferred, or 0 if an operator without is preferred. */ #define TOKEN_EOF -1 /* no extra data */ #define TOKEN_VALUE -2 /* pushed onto data stack */ #define TOKEN_OPERATOR -3 /* stored in p->token_op */ #define TOKEN_FUNCTION -4 /* stored in p->token_op */ #define TOKEN_NAME(n) \ ((n) == TOKEN_EOF ? "TOKEN_EOF" \ : (n) == TOKEN_VALUE ? "TOKEN_VALUE" \ : (n) == TOKEN_OPERATOR ? "TOKEN_OPERATOR" \ : (n) == TOKEN_VALUE ? "TOKEN_FUNCTION" \ : "UNKNOWN TOKEN") /* Functions default to being parsed as whole words, operators to match just at the start of the string. The type flags override this. */ #define WHOLEWORD(op) \ (op->precedence == 0 \ ? (! (op->type & MPEXPR_TYPE_OPERATOR)) \ : (op->type & MPEXPR_TYPE_WHOLEWORD)) #define isasciispace(c) (isascii (c) && isspace (c)) static int lookahead (struct mpexpr_parse_t *p, int prefix) { const struct mpexpr_operator_t *op, *op_found; size_t oplen, oplen_found, wlen; int i; /* skip white space */ while (p->elen > 0 && isasciispace (*p->e)) p->e++, p->elen--; if (p->elen == 0) { TRACE (printf ("lookahead EOF\n")); p->token = TOKEN_EOF; return 1; } DATA_SPACE (); /* Get extent of whole word. */ for (wlen = 0; wlen < p->elen; wlen++) if (! isasciicsym (p->e[wlen])) break; TRACE (printf ("lookahead at: \"%.*s\" length %u, word %u\n", (int) p->elen, p->e, p->elen, wlen)); op_found = NULL; oplen_found = 0; for (op = p->table; op->name != NULL; op++) { if (op->type == MPEXPR_TYPE_NEW_TABLE) { printf ("new\n"); op = (struct mpexpr_operator_t *) op->name - 1; continue; } oplen = strlen (op->name); if (! ((WHOLEWORD (op) ? wlen == oplen : p->elen >= oplen) && memcmp (p->e, op->name, oplen) == 0)) continue; /* Shorter matches don't replace longer previous ones. */ if (op_found && oplen < oplen_found) continue; /* On a match of equal length to a previous one, the old match isn't replaced if it has the preferred prefix, and if it doesn't then it's not replaced if the new one also doesn't. */ if (op_found && oplen == oplen_found && ((op_found->type & MPEXPR_TYPE_PREFIX) == prefix || (op->type & MPEXPR_TYPE_PREFIX) != prefix)) continue; /* This is now either the first match seen, or a longer than previous match, or an equal to previous one but with a preferred prefix. */ op_found = op; oplen_found = oplen; } if (op_found) { p->e += oplen_found, p->elen -= oplen_found; if (op_found->type == MPEXPR_TYPE_VARIABLE) { if (p->elen == 0) ERROR ("end of string expecting a variable", MPEXPR_RESULT_PARSE_ERROR); i = p->e[0] - 'a'; if (i < 0 || i >= MPEXPR_VARIABLES) ERROR ("bad variable name", MPEXPR_RESULT_BAD_VARIABLE); goto variable; } if (op_found->precedence == 0) { TRACE (printf ("lookahead function: %s\n", op_found->name)); p->token = TOKEN_FUNCTION; p->token_op = op_found; return 1; } else { TRACE (printf ("lookahead operator: %s\n", op_found->name)); p->token = TOKEN_OPERATOR; p->token_op = op_found; return 1; } } oplen = (*p->mpX_number) (SP+1, p->e, p->elen, p->base); if (oplen != 0) { p->e += oplen, p->elen -= oplen; p->token = TOKEN_VALUE; DATA_PUSH (); TRACE (MPX_TRACE ("lookahead number", SP)); return 1; } /* Maybe an unprefixed one character variable */ i = p->e[0] - 'a'; if (wlen == 1 && i >= 0 && i < MPEXPR_VARIABLES) { variable: p->e++, p->elen--; if (p->var[i] == NULL) ERROR ("NULL variable", MPEXPR_RESULT_BAD_VARIABLE); TRACE (printf ("lookahead variable: var[%d] = ", i); MPX_TRACE ("", p->var[i])); p->token = TOKEN_VALUE; DATA_PUSH (); (*p->mpX_set) (SP, p->var[i]); return 1; } ERROR ("no token matched", MPEXPR_RESULT_PARSE_ERROR); done: return 0; } /* control stack current top element */ #define CP (p->control_stack + p->control_top) /* make sure there's room for another control element above current top */ #define CONTROL_SPACE() \ do { \ if (p->control_top + 1 >= p->control_alloc) \ { \ TRACE (printf ("grow control stack from %d\n", p->control_alloc)); \ REALLOC (p->control_stack, p->control_alloc, 20, \ struct mpexpr_control_t); \ } \ } while (0) /* Push an operator on the control stack, claiming currently to have the given number of args ready. Local variable "op" is used in case opptr is a reference through CP. */ #define CONTROL_PUSH(opptr,args) \ do { \ const struct mpexpr_operator_t *op = opptr; \ struct mpexpr_control_t *cp; \ CONTROL_SPACE (); \ p->control_top++; \ ASSERT (p->control_top < p->control_alloc); \ cp = CP; \ cp->op = op; \ cp->argcount = (args); \ TRACE_CONTROL("control stack push:"); \ } while (0) /* The special operator_done is never popped, so top>=0 will hold. */ #define CONTROL_POP() \ do { \ p->control_top--; \ ASSERT (p->control_top >= 0); \ TRACE_CONTROL ("control stack pop:"); \ } while (0) #define TRACE_CONTROL(str) \ TRACE ({ \ int i; \ printf ("%s depth %d:", str, p->control_top); \ for (i = 0; i <= p->control_top; i++) \ printf (" \"%s\"(%d)", \ p->control_stack[i].op->name, \ p->control_stack[i].argcount); \ printf ("\n"); \ }); #define LOOKAHEAD(prefix) \ do { \ if (! lookahead (p, prefix)) \ goto done; \ } while (0) #define CHECK_UI(n) \ do { \ if (! (*p->mpX_ulong_p) (n)) \ ERROR ("operand doesn't fit ulong", MPEXPR_RESULT_NOT_UI); \ } while (0) #define CHECK_ARGCOUNT(str,n) \ do { \ if (CP->argcount != (n)) \ { \ TRACE (printf ("wrong number of arguments for %s, got %d want %d", \ str, CP->argcount, n)); \ ERROR ("", MPEXPR_RESULT_PARSE_ERROR); \ } \ } while (0) /* There's two basic states here. In both p->token is the next token. "another_expr" is when a whole expression should be parsed. This means a literal or variable value possibly followed by an operator, or a function or prefix operator followed by a further whole expression. "another_operator" is when an expression has been parsed and its value is on the top of the data stack (SP) and an optional further postfix or infix operator should be parsed. In "another_operator" precedences determine whether to push the operator onto the control stack, or instead go to "apply_control" to reduce the operator currently on top of the control stack. When an operator has both a prefix and postfix/infix form, a LOOKAHEAD() for "another_expr" will seek the prefix form, a LOOKAHEAD() for "another_operator" will seek the postfix/infix form. The grammar is simple enough that the next state is known before reading the next token. Argument count checking guards against functions consuming the wrong number of operands from the data stack. The same checks are applied to operators, but will always pass since a UNARY or BINARY will only ever parse with the correct operands. */ int mpexpr_evaluate (struct mpexpr_parse_t *p) { void *(*allocate_func) (size_t); void *(*reallocate_func) (void *, size_t, size_t); void (*free_func) (void *, size_t); mp_get_memory_functions (&allocate_func, &reallocate_func, &free_func); TRACE (printf ("mpexpr_evaluate() base %d \"%.*s\"\n", p->base, (int) p->elen, p->e)); /* "done" is a special sentinel at the bottom of the control stack, precedence -1 is lower than any normal operator. */ { static const struct mpexpr_operator_t operator_done = { "DONE", NULL, MPEXPR_TYPE_DONE, -1 }; p->control_alloc = 20; p->control_stack = ALLOCATE_FUNC_TYPE (p->control_alloc, struct mpexpr_control_t); p->control_top = 0; CP->op = &operator_done; CP->argcount = 1; } p->data_inited = 0; p->data_alloc = 20; p->data_stack = ALLOCATE_FUNC_TYPE (p->data_alloc, union mpX_t); p->data_top = -1; p->error_code = MPEXPR_RESULT_OK; another_expr_lookahead: LOOKAHEAD (MPEXPR_TYPE_PREFIX); TRACE (printf ("another expr\n")); /*another_expr:*/ switch (p->token) { case TOKEN_VALUE: goto another_operator_lookahead; case TOKEN_OPERATOR: TRACE (printf ("operator %s\n", p->token_op->name)); if (! (p->token_op->type & MPEXPR_TYPE_PREFIX)) ERROR ("expected a prefix operator", MPEXPR_RESULT_PARSE_ERROR); CONTROL_PUSH (p->token_op, 1); goto another_expr_lookahead; case TOKEN_FUNCTION: CONTROL_PUSH (p->token_op, 1); if (p->token_op->type & MPEXPR_TYPE_CONSTANT) goto apply_control_lookahead; LOOKAHEAD (MPEXPR_TYPE_PREFIX); if (! (p->token == TOKEN_OPERATOR && p->token_op->type == MPEXPR_TYPE_OPENPAREN)) ERROR ("expected open paren for function", MPEXPR_RESULT_PARSE_ERROR); TRACE (printf ("open paren for function \"%s\"\n", CP->op->name)); if ((CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT) == MPEXPR_TYPE_NARY(0)) { LOOKAHEAD (0); if (! (p->token == TOKEN_OPERATOR && p->token_op->type == MPEXPR_TYPE_CLOSEPAREN)) ERROR ("expected close paren for 0ary function", MPEXPR_RESULT_PARSE_ERROR); goto apply_control_lookahead; } goto another_expr_lookahead; } ERROR ("unrecognised start of expression", MPEXPR_RESULT_PARSE_ERROR); another_operator_lookahead: LOOKAHEAD (0); another_operator: TRACE (printf ("another operator maybe: %s\n", TOKEN_NAME(p->token))); switch (p->token) { case TOKEN_EOF: goto apply_control; case TOKEN_OPERATOR: /* The next operator is compared to the one on top of the control stack. If the next is lower precedence, or the same precedence and not right-associative, then reduce using the control stack and look at the next operator again later. */ #define PRECEDENCE_TEST_REDUCE(tprec,cprec,ttype,ctype) \ ((tprec) < (cprec) \ || ((tprec) == (cprec) && ! ((ttype) & MPEXPR_TYPE_RIGHTASSOC))) if (PRECEDENCE_TEST_REDUCE (p->token_op->precedence, CP->op->precedence, p->token_op->type, CP->op->type)) { TRACE (printf ("defer operator: %s (prec %d vs %d, type 0x%X)\n", p->token_op->name, p->token_op->precedence, CP->op->precedence, p->token_op->type)); goto apply_control; } /* An argsep is a binary operator, but is never pushed on the control stack, it just accumulates an extra argument for a function. */ if (p->token_op->type == MPEXPR_TYPE_ARGSEP) { if (CP->op->precedence != 0) ERROR ("ARGSEP not in a function call", MPEXPR_RESULT_PARSE_ERROR); TRACE (printf ("argsep for function \"%s\"(%d)\n", CP->op->name, CP->argcount)); #define IS_PAIRWISE(type) \ (((type) & (MPEXPR_TYPE_MASK_ARGCOUNT | MPEXPR_TYPE_PAIRWISE)) \ == (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_PAIRWISE)) if (IS_PAIRWISE (CP->op->type) && CP->argcount >= 2) { TRACE (printf (" will reduce pairwise now\n")); CP->argcount--; CONTROL_PUSH (CP->op, 2); goto apply_control; } CP->argcount++; goto another_expr_lookahead; } switch (p->token_op->type & MPEXPR_TYPE_MASK_ARGCOUNT) { case MPEXPR_TYPE_NARY(1): /* Postfix unary operators can always be applied immediately. The easiest way to do this is just push it on the control stack and go to the normal control stack reduction code. */ TRACE (printf ("postfix unary operator: %s\n", p->token_op->name)); if (p->token_op->type & MPEXPR_TYPE_PREFIX) ERROR ("prefix unary operator used postfix", MPEXPR_RESULT_PARSE_ERROR); CONTROL_PUSH (p->token_op, 1); goto apply_control_lookahead; case MPEXPR_TYPE_NARY(2): CONTROL_PUSH (p->token_op, 2); goto another_expr_lookahead; case MPEXPR_TYPE_NARY(3): CONTROL_PUSH (p->token_op, 1); goto another_expr_lookahead; } TRACE (printf ("unrecognised operator \"%s\" type: 0x%X", CP->op->name, CP->op->type)); ERROR ("", MPEXPR_RESULT_PARSE_ERROR); break; default: TRACE (printf ("expecting an operator, got token %d", p->token)); ERROR ("", MPEXPR_RESULT_PARSE_ERROR); } apply_control_lookahead: LOOKAHEAD (0); apply_control: /* Apply the top element CP of the control stack. Data values are SP, SP-1, etc. Result is left as stack top SP after popping consumed values. The use of sp as a duplicate of SP will help compilers that can't otherwise recognise the various uses of SP as common subexpressions. */ TRACE (printf ("apply control: nested %d, \"%s\" 0x%X, %d args\n", p->control_top, CP->op->name, CP->op->type, CP->argcount)); TRACE (printf ("apply 0x%X-ary\n", CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT)); switch (CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT) { case MPEXPR_TYPE_NARY(0): { mpX_ptr sp; DATA_SPACE (); DATA_PUSH (); sp = SP; switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) { case 0: (* (mpexpr_fun_0ary_t) CP->op->fun) (sp); break; case MPEXPR_TYPE_RESULT_INT: (*p->mpX_set_si) (sp, (long) (* (mpexpr_fun_i_0ary_t) CP->op->fun) ()); break; default: ERROR ("unrecognised 0ary argument calling style", MPEXPR_RESULT_BAD_TABLE); } } break; case MPEXPR_TYPE_NARY(1): { mpX_ptr sp = SP; CHECK_ARGCOUNT ("unary", 1); TRACE (MPX_TRACE ("before", sp)); switch (CP->op->type & MPEXPR_TYPE_MASK_SPECIAL) { case 0: /* not a special */ break; case MPEXPR_TYPE_DONE & MPEXPR_TYPE_MASK_SPECIAL: TRACE (printf ("special done\n")); goto done; case MPEXPR_TYPE_LOGICAL_NOT & MPEXPR_TYPE_MASK_SPECIAL: TRACE (printf ("special logical not\n")); (*p->mpX_set_si) (sp, (long) ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp) == 0)); goto apply_control_done; case MPEXPR_TYPE_CLOSEPAREN & MPEXPR_TYPE_MASK_SPECIAL: CONTROL_POP (); if (CP->op->type == MPEXPR_TYPE_OPENPAREN) { TRACE (printf ("close paren matching open paren\n")); CONTROL_POP (); goto another_operator; } if (CP->op->precedence == 0) { TRACE (printf ("close paren for function\n")); goto apply_control; } ERROR ("unexpected close paren", MPEXPR_RESULT_PARSE_ERROR); default: TRACE (printf ("unrecognised special unary operator 0x%X", CP->op->type & MPEXPR_TYPE_MASK_SPECIAL)); ERROR ("", MPEXPR_RESULT_BAD_TABLE); } switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) { case 0: (* (mpexpr_fun_unary_t) CP->op->fun) (sp, sp); break; case MPEXPR_TYPE_LAST_UI: CHECK_UI (sp); (* (mpexpr_fun_unary_ui_t) CP->op->fun) (sp, (*p->mpX_get_ui) (sp)); break; case MPEXPR_TYPE_RESULT_INT: (*p->mpX_set_si) (sp, (long) (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)); break; case MPEXPR_TYPE_RESULT_INT | MPEXPR_TYPE_LAST_UI: CHECK_UI (sp); (*p->mpX_set_si) (sp, (long) (* (mpexpr_fun_i_unary_ui_t) CP->op->fun) ((*p->mpX_get_ui) (sp))); break; default: ERROR ("unrecognised unary argument calling style", MPEXPR_RESULT_BAD_TABLE); } } break; case MPEXPR_TYPE_NARY(2): { mpX_ptr sp; /* pairwise functions are allowed to have just one argument */ if ((CP->op->type & MPEXPR_TYPE_PAIRWISE) && CP->op->precedence == 0 && CP->argcount == 1) goto apply_control_done; CHECK_ARGCOUNT ("binary", 2); DATA_POP (1); sp = SP; TRACE (MPX_TRACE ("lhs", sp); MPX_TRACE ("rhs", sp+1)); if (CP->op->type & MPEXPR_TYPE_MASK_CMP) { int type = CP->op->type; int cmp = (* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1); (*p->mpX_set_si) (sp, (long) (( (cmp < 0) & ((type & MPEXPR_TYPE_MASK_CMP_LT) != 0)) | ((cmp == 0) & ((type & MPEXPR_TYPE_MASK_CMP_EQ) != 0)) | ((cmp > 0) & ((type & MPEXPR_TYPE_MASK_CMP_GT) != 0)))); goto apply_control_done; } switch (CP->op->type & MPEXPR_TYPE_MASK_SPECIAL) { case 0: /* not a special */ break; case MPEXPR_TYPE_QUESTION & MPEXPR_TYPE_MASK_SPECIAL: ERROR ("'?' without ':'", MPEXPR_RESULT_PARSE_ERROR); case MPEXPR_TYPE_COLON & MPEXPR_TYPE_MASK_SPECIAL: TRACE (printf ("special colon\n")); CONTROL_POP (); if (CP->op->type != MPEXPR_TYPE_QUESTION) ERROR ("':' without '?'", MPEXPR_RESULT_PARSE_ERROR); CP->argcount--; DATA_POP (1); sp--; TRACE (MPX_TRACE ("query", sp); MPX_TRACE ("true", sp+1); MPX_TRACE ("false", sp+2)); (*p->mpX_set) (sp, (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp) ? sp+1 : sp+2); goto apply_control_done; case MPEXPR_TYPE_LOGICAL_AND & MPEXPR_TYPE_MASK_SPECIAL: TRACE (printf ("special logical and\n")); (*p->mpX_set_si) (sp, (long) ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp) && (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp+1))); goto apply_control_done; case MPEXPR_TYPE_LOGICAL_OR & MPEXPR_TYPE_MASK_SPECIAL: TRACE (printf ("special logical and\n")); (*p->mpX_set_si) (sp, (long) ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp) || (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp+1))); goto apply_control_done; case MPEXPR_TYPE_MAX & MPEXPR_TYPE_MASK_SPECIAL: TRACE (printf ("special max\n")); if ((* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1) < 0) (*p->mpX_swap) (sp, sp+1); goto apply_control_done; case MPEXPR_TYPE_MIN & MPEXPR_TYPE_MASK_SPECIAL: TRACE (printf ("special min\n")); if ((* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1) > 0) (*p->mpX_swap) (sp, sp+1); goto apply_control_done; default: ERROR ("unrecognised special binary operator", MPEXPR_RESULT_BAD_TABLE); } switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) { case 0: (* (mpexpr_fun_binary_t) CP->op->fun) (sp, sp, sp+1); break; case MPEXPR_TYPE_LAST_UI: CHECK_UI (sp+1); (* (mpexpr_fun_binary_ui_t) CP->op->fun) (sp, sp, (*p->mpX_get_ui) (sp+1)); break; case MPEXPR_TYPE_RESULT_INT: (*p->mpX_set_si) (sp, (long) (* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1)); break; case MPEXPR_TYPE_LAST_UI | MPEXPR_TYPE_RESULT_INT: CHECK_UI (sp+1); (*p->mpX_set_si) (sp, (long) (* (mpexpr_fun_i_binary_ui_t) CP->op->fun) (sp, (*p->mpX_get_ui) (sp+1))); break; default: ERROR ("unrecognised binary argument calling style", MPEXPR_RESULT_BAD_TABLE); } } break; case MPEXPR_TYPE_NARY(3): { mpX_ptr sp; CHECK_ARGCOUNT ("ternary", 3); DATA_POP (2); sp = SP; TRACE (MPX_TRACE ("arg1", sp); MPX_TRACE ("arg2", sp+1); MPX_TRACE ("arg3", sp+1)); switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) { case 0: (* (mpexpr_fun_ternary_t) CP->op->fun) (sp, sp, sp+1, sp+2); break; case MPEXPR_TYPE_LAST_UI: CHECK_UI (sp+2); (* (mpexpr_fun_ternary_ui_t) CP->op->fun) (sp, sp, sp+1, (*p->mpX_get_ui) (sp+2)); break; case MPEXPR_TYPE_RESULT_INT: (*p->mpX_set_si) (sp, (long) (* (mpexpr_fun_i_ternary_t) CP->op->fun) (sp, sp+1, sp+2)); break; case MPEXPR_TYPE_LAST_UI | MPEXPR_TYPE_RESULT_INT: CHECK_UI (sp+2); (*p->mpX_set_si) (sp, (long) (* (mpexpr_fun_i_ternary_ui_t) CP->op->fun) (sp, sp+1, (*p->mpX_get_ui) (sp+2))); break; default: ERROR ("unrecognised binary argument calling style", MPEXPR_RESULT_BAD_TABLE); } } break; default: TRACE (printf ("unrecognised operator type: 0x%X\n", CP->op->type)); ERROR ("", MPEXPR_RESULT_PARSE_ERROR); } apply_control_done: TRACE (MPX_TRACE ("result", SP)); CONTROL_POP (); goto another_operator; done: if (p->error_code == MPEXPR_RESULT_OK) { if (p->data_top != 0) { TRACE (printf ("data stack want top at 0, got %d\n", p->data_top)); p->error_code = MPEXPR_RESULT_PARSE_ERROR; } else (*p->mpX_set_or_swap) (p->res, SP); } { int i; for (i = 0; i < p->data_inited; i++) { TRACE (printf ("clear %d\n", i)); (*p->mpX_clear) (p->data_stack+i); } } FREE_FUNC_TYPE (p->data_stack, p->data_alloc, union mpX_t); FREE_FUNC_TYPE (p->control_stack, p->control_alloc, struct mpexpr_control_t); return p->error_code; } int mpexpr_va_to_var (void *var[], va_list ap) { int i = 0; void *v; for (;;) { v = va_arg (ap, void *); if (v == NULL) break; if (i >= MPEXPR_VARIABLES) return MPEXPR_RESULT_BAD_VARIABLE; var[i++] = v; } while (i < MPEXPR_VARIABLES) var[i++] = NULL; return MPEXPR_RESULT_OK; } Math-Prime-Util-GMP-0.52/xt/bench-random-bytes.pl0000644000175000017500000000425713663067455020027 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Math::Prime::Util::GMP; use Bytes::Random::XS; use Bytes::Random; use Bytes::Random::Secure; use Math::Random::MTwist; use Data::Entropy::Algorithms; use Crypt::PRNG; use Crypt::Random; use Benchmark qw/:all/; print "# 8 random bytes\n"; cmpthese(-5,{ "MPU" => sub { Math::Prime::Util::GMP::random_bytes(8); }, "BRXS" => sub { Bytes::Random::XS::random_bytes(8); }, "BR" => sub { Bytes::Random::random_bytes(8); }, "BRS" => sub { Bytes::Random::Secure::random_bytes(8); }, "MRMT" => sub { Math::Random::MTwist::_randstr(8); }, "DEA" => sub { Data::Entropy::Algorithms::rand_bits(8*8); }, "Crypt::PRNG" => sub { Crypt::PRNG::random_bytes(8); }, "rand" => sub { pack('C*', map { int(rand 256) } 1..8); }, "Crypt::Random" => sub { Crypt::Random::makerandom_octet(Length=>8,Strength=>0); }, }); print "# 256 random bytes\n"; cmpthese(-5,{ "MPU" => sub { Math::Prime::Util::GMP::random_bytes(256); }, "BRXS" => sub { Bytes::Random::XS::random_bytes(256); }, "BR" => sub { Bytes::Random::random_bytes(256); }, "BRS" => sub { Bytes::Random::Secure::random_bytes(256); }, "MRMT" => sub { Math::Random::MTwist::_randstr(256); }, "DEA" => sub { Data::Entropy::Algorithms::rand_bits(8*256); }, "CryptX" => sub { Crypt::PRNG::random_bytes(256); }, "rand" => sub { pack('C*', map { int(rand 256) } 1..256); }, "Crypt::Random" => sub { Crypt::Random::makerandom_octet(Length=>256,Strength=>0); }, }); print "# 16384 random bytes\n"; cmpthese(-5,{ "MPU" => sub { Math::Prime::Util::GMP::random_bytes(16384); }, "BRXS" => sub { Bytes::Random::XS::random_bytes(16384); }, "BR" => sub { Bytes::Random::random_bytes(16384); }, "BRS" => sub { Bytes::Random::Secure::random_bytes(16384); }, "MRMT" => sub { Math::Random::MTwist::_randstr(16384); }, "DEA" => sub { Data::Entropy::Algorithms::rand_bits(8*16384); }, "CryptX" => sub { Crypt::PRNG::random_bytes(16384); }, "rand" => sub { pack('C*', map { int(rand 256) } 1..16384); }, "Crypt::Random" => sub { Crypt::Random::makerandom_octet(Length=>16384,Strength=>0); }, }); Math-Prime-Util-GMP-0.52/xt/expr.h0000644000175000017500000001212313025437622015114 0ustar danadana/* Header for expression evaluation. Copyright 2000-2002, 2004 Free Software Foundation, Inc. This file is part of the GNU MP Library. The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of either: * the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. or * the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. or both in parallel, as here. The GNU MP Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received copies of the GNU General Public License and the GNU Lesser General Public License along with the GNU MP Library. If not, see https://www.gnu.org/licenses/. */ #ifndef __EXPR_H__ #define __EXPR_H__ #define MPEXPR_RESULT_OK 0 #define MPEXPR_RESULT_BAD_VARIABLE 1 #define MPEXPR_RESULT_BAD_TABLE 2 #define MPEXPR_RESULT_PARSE_ERROR 3 #define MPEXPR_RESULT_NOT_UI 4 /* basic types */ #define MPEXPR_TYPE_NARY(n) ((n) * 0x0100) #define MPEXPR_TYPE_MASK_ARGCOUNT MPEXPR_TYPE_NARY(0xF) #define MPEXPR_TYPE_0ARY MPEXPR_TYPE_NARY(0) #define MPEXPR_TYPE_UNARY MPEXPR_TYPE_NARY(1) #define MPEXPR_TYPE_BINARY MPEXPR_TYPE_NARY(2) #define MPEXPR_TYPE_TERNARY MPEXPR_TYPE_NARY(3) /* options for all */ #define MPEXPR_TYPE_LAST_UI 0x0010 #define MPEXPR_TYPE_RESULT_INT 0x0020 #define MPEXPR_TYPE_MASK_ARGSTYLE 0x0030 #define MPEXPR_TYPE_UNARY_UI (MPEXPR_TYPE_UNARY | MPEXPR_TYPE_LAST_UI) #define MPEXPR_TYPE_I_UNARY (MPEXPR_TYPE_UNARY | MPEXPR_TYPE_RESULT_INT) #define MPEXPR_TYPE_I_UNARY_UI (MPEXPR_TYPE_I_UNARY | MPEXPR_TYPE_LAST_UI) #define MPEXPR_TYPE_BINARY_UI (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_LAST_UI) #define MPEXPR_TYPE_I_BINARY (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_RESULT_INT) #define MPEXPR_TYPE_I_BINARY_UI (MPEXPR_TYPE_I_BINARY| MPEXPR_TYPE_LAST_UI) #define MPEXPR_TYPE_TERNARY_UI (MPEXPR_TYPE_TERNARY | MPEXPR_TYPE_LAST_UI) #define MPEXPR_TYPE_I_TERNARY (MPEXPR_TYPE_TERNARY | MPEXPR_TYPE_RESULT_INT) #define MPEXPR_TYPE_I_TERNARY_UI (MPEXPR_TYPE_I_TERNARY|MPEXPR_TYPE_LAST_UI) /* 0ary with options */ #define MPEXPR_TYPE_CONSTANT (MPEXPR_TYPE_0ARY | 0x0040) /* unary options */ #define MPEXPR_TYPE_PREFIX 0x0040 /* binary options */ #define MPEXPR_TYPE_RIGHTASSOC 0x0040 #define MPEXPR_TYPE_PAIRWISE 0x0080 #define MPEXPR_TYPE_MASK_SPECIAL 0x000F /* unary specials */ #define MPEXPR_TYPE_NEW_TABLE (MPEXPR_TYPE_UNARY | 0x001) #define MPEXPR_TYPE_DONE (MPEXPR_TYPE_UNARY | 0x002) #define MPEXPR_TYPE_VARIABLE (MPEXPR_TYPE_UNARY | 0x003) #define MPEXPR_TYPE_LOGICAL_NOT (MPEXPR_TYPE_UNARY | 0x004) #define MPEXPR_TYPE_CLOSEPAREN (MPEXPR_TYPE_UNARY | 0x005) #define MPEXPR_TYPE_OPENPAREN (MPEXPR_TYPE_CLOSEPAREN | MPEXPR_TYPE_PREFIX) /* binary specials */ #define MPEXPR_TYPE_LOGICAL_AND (MPEXPR_TYPE_BINARY | 0x001) #define MPEXPR_TYPE_LOGICAL_OR (MPEXPR_TYPE_BINARY | 0x002) #define MPEXPR_TYPE_ARGSEP (MPEXPR_TYPE_BINARY | 0x003) #define MPEXPR_TYPE_QUESTION (MPEXPR_TYPE_BINARY | 0x004) #define MPEXPR_TYPE_COLON (MPEXPR_TYPE_BINARY | 0x005) #define MPEXPR_TYPE_MAX (MPEXPR_TYPE_BINARY | 0x006) #define MPEXPR_TYPE_MIN (MPEXPR_TYPE_BINARY | 0x007) #define MPEXPR_TYPE_MASK_CMP 0x008 #define MPEXPR_TYPE_MASK_CMP_LT 0x001 #define MPEXPR_TYPE_MASK_CMP_EQ 0x002 #define MPEXPR_TYPE_MASK_CMP_GT 0x004 #define MPEXPR_TYPE_CMP_LT (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_MASK_CMP \ | MPEXPR_TYPE_MASK_CMP_LT) #define MPEXPR_TYPE_CMP_EQ (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_MASK_CMP \ | MPEXPR_TYPE_MASK_CMP_EQ) #define MPEXPR_TYPE_CMP_GT (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_MASK_CMP \ | MPEXPR_TYPE_MASK_CMP_GT) #define MPEXPR_TYPE_CMP_LE (MPEXPR_TYPE_CMP_LT | MPEXPR_TYPE_MASK_CMP_EQ) #define MPEXPR_TYPE_CMP_NE (MPEXPR_TYPE_CMP_LT | MPEXPR_TYPE_MASK_CMP_GT) #define MPEXPR_TYPE_CMP_GE (MPEXPR_TYPE_CMP_GT | MPEXPR_TYPE_MASK_CMP_EQ) /* parse options */ #define MPEXPR_TYPE_WHOLEWORD 0x1000 #define MPEXPR_TYPE_OPERATOR 0x2000 #ifdef __cplusplus extern "C" { #endif typedef void (*mpexpr_fun_t) (void); struct mpexpr_operator_t { const char *name; mpexpr_fun_t fun; int type; int precedence; }; int mpf_expr_a (const struct mpexpr_operator_t *, mpf_ptr, int, unsigned long, const char *, size_t, mpf_srcptr [26]); int mpf_expr (mpf_ptr, int, const char *, ...); int mpq_expr_a (const struct mpexpr_operator_t *, mpq_ptr, int, const char *, size_t, mpq_srcptr [26]); int mpq_expr (mpq_ptr, int, const char *, ...); int mpz_expr_a (const struct mpexpr_operator_t *, mpz_ptr, int, const char *, size_t, mpz_srcptr [26]); int mpz_expr (mpz_ptr, int, const char *, ...); #ifdef __cplusplus } /* extern "C" */ #endif #endif Math-Prime-Util-GMP-0.52/xt/create-standalone.sh0000755000175000017500000002453413663067455017741 0ustar danadana#!/bin/bash if [ ! -d standalone ] then mkdir standalone fi cp -p ptypes.h standalone/ cp -p ecpp.[ch] bls75.[ch] aks.[ch] ecm.[ch] prime_iterator.[ch] standalone/ cp -p gmp_main.[ch] real.[ch] standalone/ cp -p factor.[ch] squfof126.[ch] pbrent63.[ch] tinyqs.[ch] standalone/ cp -p utility.[ch] isaac.[ch] random_prime.[ch] standalone/ cp -p primality.[ch] standalone/ cp -p xt/expr.[ch] xt/expr-impl.h standalone/ cp -p xt/proof-text-format.txt standalone/ cp -p examples/verify-cert.pl standalone/ cp -p examples/vcert.c standalone/ if [ -f xt/class_poly_data_big.h ] then echo Using large poly set cp -p xt/class_poly_data_big.h standalone/class_poly_data.h else echo Using small poly set cp -p class_poly_data.h standalone/ fi # Standalone ECPP doesn't need SIMPQS, so let's not include it. # Warning however: large BLS75 proofs won't be practical without it. cat << 'EOSIMPQSH' > standalone/simpqs.h #ifndef MPU_SIMPQS_H #define MPU_SIMPQS_H #include static int _GMP_simpqs(mpz_t n, mpz_t* farray) { return 0; } #endif EOSIMPQSH # gcc -O3 -fomit-frame-pointer -DSTANDALONE -DSTANDALONE_ECPP ecpp.c bls75.c aks.c primality.c ecm.c prime_iterator.c gmp_main.c small_factor.c utility.c expr.c -o ecpp-dj -lgmp -lm cat << 'EOM' > standalone/Makefile TARGET = ecpp-dj CC = gcc DEFINES = -DSTANDALONE -DSTANDALONE_ECPP CFLAGS = -O3 -g -Wall $(DEFINES) LIBS = -lgmp -lm OBJ = ecpp.o bls75.o aks.o primality.o ecm.o prime_iterator.o gmp_main.o \ factor.o squfof126.o pbrent63.o tinyqs.o \ real.o isaac.o random_prime.o utility.o expr.o HEADERS = ptypes.h class_poly_data.h .PHONY: default all clean default: $(TARGET) vcert all: default %.o: %.c $(HEADERS) $(CC) $(CFLAGS) -c $< -o $@ .PRECIOUS: $(TARGET) $(OBJECTS) $(TARGET): $(OBJ) $(CC) $^ $(LIBS) -o $@ vcert: vcert.o $(CC) $^ $(LIBS) -o $@ clean: -rm -f *.o realclean distclean: clean -rm -f $(TARGET) vcert TEST1 = 11739771271677308623 TEST2 = 4101186565771483058393796013015990306873 TEST3 = 35393208195490503043982975376709535956301978008095654379254570182486977128836509 TEST4 = 935006864223353238737221824562525122013245238547726726389470209512876196672409305516259055214126542251267716102384835899 TEST5 = 25433248801892216938808041984973587415848723989586550342338936524369752729114437550630504573611493987544033285909689162724975971196674890122730486522513928304389686931651745712950504486324914805161849 TEST6 = 9805395078382368090505040572030888128042903590778595659611793383233089744266057832338719254777179628060930905633717264804767081354556273122188172463117096876389627469817121375789418174467686118164854924603273433083668455457307317475867158494243611475656192285904836693990000951833 TEST7 = 14783869341310731862535181711924146413209106702463668486125206627959998111552028525869806779180480078890581625378293879184823213870417286554264959032457904699577075117266041686053691857746703656877556879868345571593862758480658145938864170620882703502631810038072518245192559323694333232320523172244347200606659255752705575709361904749964234503630803 TEST8 = 516069211402263086362802849056712149142247708608707602810064116323740967320507238792597022510888972176570219148745538673939283056074749627707686516295450338874349093022059487090007604327705115534233283204877186839852673049019899452650976370088509524263064316558360307931746214148027462933967332118502005274436360122078931230288854613802443446620402918656243749843390157467993315073584216791188709452340255395988925217870997387615378161410168698419453325449311 test: $(TARGET) vcert @for n in $(TEST1) $(TEST2) $(TEST3) $(TEST4) $(TEST5) $(TEST6) $(TEST7) $(TEST8) $(TEST9); do echo -n "$${#n} digits ..."; ./ecpp-dj -c $$n | ./vcert -q -; if [ $$? -eq 0 ]; then echo "Pass"; else echo "FAIL"; fi; done EOM cat << 'EOREADME' > standalone/README ECPP-DJ: Elliptic Curve Primality Proof. Copyright 2012-2016, Dana Jacobsen (dana@acm.org). Let me know if you find this software useful, and suggestions, comments, and patches are welcome. INSTALLATION: # See note 3 at the end of this file if you want to enable APRCL. make make test (optional) ./ecpp-dj -help (shows usage) # If you plan on doing proofs with numbers over 800 digits, consider: # wget http://probableprime.org/ecpp/cpd/huge/class_poly_data.h.gz # gunzip class_poly_data.h.gz This is a standalone version of the ECPP implementation written for the Perl module Math::Prime::Util::GMP in 2013. This uses a "Factor All" strategy, and closely follows the papers by Atkin and Morain. Most of the utility functions closely follow the algorithms presented in Cohen's book "A Course in Computational Algebraic Number Theory". Almost all the factoring is done with my p-1 implementation. The ECM factoring and manipulation was heavily inspired by GMP-ECM by Paul Zimmermann and many others. This includes a BPSW test (strong PRP-2 test followed by extra strong Lucas-Selfridge test). We use this to (1) detect composites, and (2) prove small numbers. BPSW has no counterexamples below 2^64, and this implementation has been verified against Feitsma's database. Using the -c option enables certificate generation. The format is described in the file proof-text-format.txt. Two verification programs are supplied: verify-cert.pl (Perl) vert.c (C+GMP) The Makefile should create the 'vcert' executable for you. Both programs will read both the MPU format and the PRIMO format. Performance is quite good for most sub-1000 digit numbers, but starts getting uneven over 500 digits. Much more work is possible here. For production proving of multi-thousand digit numbers, I recommend: Primo http://www.ellipsa.eu/public/primo/primo.html because of its large speed advantage for 1000+ digit numbers, especially on multi-processor machines. Quick performance comparisons: - Primo is slower under ~500 digits, *much* faster as input grows. - GMP-ECPP 2.49 is very, very slow. Nearly unusable once over 500 digits. - Morain's ancient 6.4.5a ECPP is similar under 300 digits, but gets slower. - David Cleaver's mpz_aprcl is a tiny bit slower under ~500 digits, but gets faster for larger inputs (2-3x faster at 2000 digits). Note that APR-CL does not produce a certificate. - Using the latest GMP (e.g. 6.0.0a or later) will substantially help performance of this code as well as mpz_aprcl. - AKS is not currently a viable method, with all known implementations being millions of times slower than alternative methods (ECPP or APR-CL). This code includes the fastest AKS implementation I know, but this still holds. Some areas to concentrate on: 1. The polynomials. We ought to generate Weber polynomials on the fly. I think it still makes a lot of sense to include a fixed set (e.g. all polys of degree 6 or smaller) for speed. However the lack of polynomials is a big issue with titanic numbers, as we run a good chance of not finding an easily splitable 'm' value and then get bogged down in factoring. The CM package from http://cm.multiprecision.org/ would be an excellent choice, with my only concern being the large dependency chain. 2. The factoring. In most cases this will stay in factoring stage 1 the entire time, meaning we are running my _GMP_pminus1_factor code with small parameters. Optimizing this would help (the stage 2 code certainly could be faster). I have tried GMP-ECM's n-1 and it is quite a bit slower for this purpose (let me be clear: for large B1/B2 values, GMP-ECM rocks, but in this application with small B1/B2, it ran slower for me). If you add the define USE_LIBECM, then GMP-ECM's ECM is used. This will probably be slower. Where using GMP-ECM would really help (I think) is in later factoring stages where we're in trouble and need to work hard to find a factor since there just aren't any easy ones to be found. At this point we want to unleash the full power of GMP-ECM. I have not tested this in this application, but for general factoring, GMP-ECM is much faster than my ECM code so I would expect something similar here. Note that this interacts with #1, as if we can efficiently generate polys or have a giant set, then we must trade off doing more factoring vs. more polys. Morain's fastECPP, for example, uses stupendously more discriminants than we do, so factoring isn't a big issue for them. They have very different polynomials and root finding algorithms however. 3. Parallelism. Currently the entire code is single threaded. There are many opportunities here. - Something I think would be useful and not too much work is parallelizing the dlist loop in ecpp_down, so all the discriminants can be searched at once. A more complicated solution would be a work queue including pruning so we could recurse down many trees at once. - If we have to run ECM, then clearly we can run multiple curves at once. - Finally, once we've hit STEP 2 of ecpp_down, we could do curve finding for the entire chain in parallel. This would be especially useful for titanic numbers where this is a large portion of the total time. 4. ecpp_down. There are a lot of little things here that can have big impacts on performance. For instance the decisions on when to keep searching polys vs. backtracking. The current code, for smallish numbers, will use a cheap factoring stage zero for a while before switching to stage 1. There is a lot of repeated work here that a rewrite could avoid. 5. The poly root finding takes a long time for large degree polys, and perhaps we could speed it up. Note 1: AKS is also included and you can use it via the '-aks' option. The default implentation includes improvements from Bernstein and Voloch, with a tuning heuristic from Bornemann. It is much faster than the version used by Brent (2006) for instance, but it is still very slow. Note 2: You can also force use of the BLS75 theorem 5/7 n-1 proof using the '-nm1' option. This is good for up to 70-80 digits or so. It performs similarly to Pari's n-1 implementation (though is presumably very different internally). Note 3: You can also run APRCL. Get WraithX's code from: http://sourceforge.net/projects/mpzaprcl/ , put the files in this directory, then add -DUSE_APRCL to the DEFINES in the Makefile. The '-aprcl' option will now be available. EOREADME Math-Prime-Util-GMP-0.52/xt/llr.pl0000644000175000017500000000117113025437622015114 0ustar danadana#!/usr/bin/env perl use warnings; use strict; use Math::Prime::Util::GMP ":all"; use Math::GMPz; $|=1; llr_test(10,10+8*80-1,1,100); llr_test(10,10+4*80-1,101,1000); llr_test(14,14+2*80-1,1001,10000); llr_test(17,17+1*80-1,10001,100000); sub llr_test { my($b1, $b2, $k1, $k2) = @_; print "Testing LLR with {$k1..$k2} * 2^{$b1..$b2} - 1\n"; for my $b ($b1..$b2) { print "."; my $b2 = Math::GMPz->new(2)**$b; for my $k ($k1..$k2) { my $n = $k * $b2 - 1; my $t1 = is_bpsw_prime($n) ? 2 : 0; my $t2 = is_llr_prime($n); die "$t1 $t2 ${k} * 2^$b -1" unless $t1==$t2; } } print "\n"; } Math-Prime-Util-GMP-0.52/xt/calculate-mr-probs.pl0000755000175000017500000000216313025437621020023 0ustar danadana#!/usr/bin/env perl use warnings; use strict; use List::Util qw/min max/; # From Damgård, Landrock, and Pomerance, 1993. Page 178. # k = bits in n my $k = shift; if (!defined $k || $k < 2) { die "Usage: $0 []\n k = the number of bits in n\n"; } my $maxtests = shift || 30; foreach my $t (1 .. $maxtests) { printf("k: %d t:%4d p < %lg\n", $k, $t, min(mr_prob($k, $t))); #my @p = mr_prob($k, $t); print "k: $k t: $t p: @p\n"; } sub mr_prob { my($k, $t) = @_; die "k must be >= 2" unless $k >= 2; die "t must be >= 1" unless $t >= 1; my @probs; push @probs, 4**-$t; if ($t == 1) { push @probs, $k*$k * 4**(2.0-sqrt($k)); } if (($t == 2 && $k >= 88) || ($t >= 3 && $k >= 21 && $t <= $k/9)) { push @probs, $k**1.5 * 2**$t * $t**-.5 * 4**(2.0-sqrt($t*$k)); } if ($t >= $k/9 && $k >= 21) { push @probs, ( (7.0/20.0) * $k * 2**(-5*$t) + (1.0/7.0) * $k**(15.0/4.0) * 2**(-$k/2 - 2*$t) + 12 * $k * 2**(-$k/4 - 3*$t) ); } if ($t >= $k/4 && $k >= 21) { push @probs, (1.0/7.0) * $k**(15.0/4.0) * 2**(-$k/2 - 2*$t); } return @probs; } Math-Prime-Util-GMP-0.52/xt/proof-text-format.txt0000644000175000017500000002055013663067455020141 0ustar danadana[MPU - Primality Certificate] Version 1.0 # We should allow base 10, base 16, and base 62. Base 10 is the default. Base 10 # This is the N value we're proving. Proof for: N 8087094497428743437627091507362881 # The following types allow a simple chain: # Pocklington # BLS3 # BLS15 # ECPP # Small # These could result in a tree: # Lucas # BLS5 # BLS7 # # Types ECPP3 and ECPP4 are from Primo, and can be easily translated into # a type ECPP. We include them here rather than convert because they save # quite a bit of space and we may want to generate them ourselves someday. # I remain dubious about including them, so it is possible they will go away # in the format and we'll just have the converter/verifier do the conversion. # # MPU will generate types: BLS3, BLS15, ECPP, BLS5, Small. # Primo (converted) will generate types: Pocklington, BLS15, ECPP3, ECPP4. # Lucas is included for completeness. # I no longer use BLS7 so will not include it. # BLS## stands for theorem ## in the paper: # "New Primality Criteria and Factorizations of 2^m +/- 1" by # Brillhart, Lehmer, and Selfridge, Mathematics of Computation, 1975. # which includes 21 theorems related to N-1, N+1, and hybrid primality proofs. # The paper is often referred to as BLS75, and is highly recommended reading. # I allow N or any Q smaller than 2^64 to implicitly construct a "Small" # certificate. So once we have a Q of <= 2^64, we can run a deterministic # test to prove its primality. One of the many BPSW variants works for this, # or 7 M-R tests with bases 2, 325, 9375, 28178, 450775, 9780504, 1795265022. # Hence if we have Q values <= 2^64, the verifier needs to do its test, and # the certificate can leave out an explicit proof for the Q. This is done # to prevent a few Lucas, BLS5, etc. type tests from creating a swarm of # "Small" certificates for each little factor. Type BLS15 N 8087094497428743437627091507362881 Q 175806402118016161687545467551367 LP 1 LQ 22 # Note: Primo type 2 can map to this, though this allows Q to be # smaller. ( prevR->N, R->Q, S->M, Q->(LP,LQ) ) # Primo condition a is implied by Q odd # Primo condition c is stricter than required by BLS15. # Primo conditions e and f relate to the Lucas code # Primo condition g is not required # Verify: Q is odd # Verify: Q > 2 # Verify: Q divides N+1 # Let: M = (N+1)/Q # Verify: MQ-1 = N # Primo d # Verify: M > 0 # Primo b # Verify: 2Q-1 > sqrt(N) # Primo c (less strict) # Let: D = LP*LP - 4*LQ # Verify: D != 0 # Verify Jacobi(D,N) = -1 # Primo h # Verify V_{m/2} mod N != 0 # Primo j # Verify V_{(N+1)/2} mod N == 0 # Primo i # Then N is prime if Q is prime. Type ECPP N 175806402118016161687545467551367 A 96642115784172626892568853507766 B 111378324928567743759166231879523 M 175806402118016177622955224562171 Q 2297612322987260054928384863 X 3273750212 Y 82061726986387565872737368000504 # Generic ECPP / AKGM block # A and/or B can be -1, so mod them. # Let A = A % N # Let B = B % N # Verify: N > 0 # Primo b # Verify: gcd(N, 6) = 1 # Primo a # Verify: gcd(4*a^3 + 27*b^2, N) = 1 # Primo i # Verify: Y^2 mod N = X^3 + A*X + B mod N # Primo j # Verify: M >= N + 1 - 2*sqrt(N) # Primo g # Verify: M <= N + 1 + 2*sqrt(N) # Primo h # Verify: Q > (N^(1/4)+1)^2 # Primo f # Verify: Q < N # Primo e # Verify: M != Q # Verify: Q divides M # Note: EC(A,B,N,X,Y) defines the elliptic curve Y^2 = X^3 + A*X + B, mod N # with operations defined in affine coordinates. # Let POINT = (M/Q) * EC(A,B,N,X,Y) # Verify: POINT is not the identity # Primo k # Let POINT = Q * POINT (or M * EC(A,B,N,X,Y)) # Verify: POINT is the identity # Primo l # Then N is prime if Q is prime. Type BLS3 N 2297612322987260054928384863 Q 16501461106821092981 A 5 # Note: This is similar to Pocklington, but Q can be smaller. # Verify: Q odd # Verify: Q > 2 # Verify: Q divides N-1 # Let: M = (N-1)/Q # Verify: MQ+1 = N # Verify: M > 0 # Verify: 2Q+1 > sqrt(N) # Verify A^((N-1)/2) mod N = N-1 # Verify A^(M/2) mod N != N-1 # Then N is prime if Q is prime. Type BLS5 N 8087094497428743437627091507362881 Q[1] 98277749 Q[2] 3631 A[0] 11 ---- # Note: This also covers generalized Pocklington # Note: We have to have N-1 factored to (N/2)^1/3 # Note: A line starting with - is required at the end. # Verify: N > 2, N odd # For each i (0-max): # Q[0] = 2 # 2 is always a factor of n-1 # A[i] = 2 unless specified # Verify: Q[i] > 1, Q[i] < N-1 # Verify: A[i] > 1, A[i] < N-1 # Verify: Q[i] divides N-1 # Let: F = N-1 divided by each Q[i] with multiplicity # (i.e. if Q[i] evenly divides N-1 3 times, then divide it out 3 times) # Let: R = (N-1)/F # Verify: F is even # Verify: gcd(F, R) = 1 # Let: s = integer part of R / 2*F # Let: r = fractional part of R / 2*F # Let: P = (F+1) * (2*F*F + (r-1)*F + 1) # Verify: n < P # Note: The next condition is trivially met if F >= R, # as is the case with Pocklington. # Let: rt = r^2 - 8s # Verify: s = 0 OR rt not a perfect square [e.g. floor(sqrt(rt))^2 != rt] # For each i: # Verify: A[i]^(N-1) mod N = 1 # Verify: gcd(A[i]^((N-1)/Q[i])-1, N) = 1 # Then N is prime if each Q is prime. Type Lucas N 10384593717069655257060992658440473 Q[1] 2 Q[2] 3 Q[3] 13 Q[4] 379 Q[5] 87820459687010818424506060639 A 41 # Note: All factors of N-1 are listed # Verify: A > 1 and A < N # Verify: N-1 has only factors Q (to some multiplicity). # Verify: A^(N-1) mod N = 1 # Verify for each Q: # Q > 0 # Q < N-1 # Q divides N-1 # A^((N-1)/Q) mod N != 1 # Then N is prime if each Q is prime. Type Pocklington N 2297612322987260054928384863 Q 16501461106821092981 A 5 # Note: This is Primo type 1 ( prevR->N, R->Q, S->M, B->A ) # verify: Q divides N-1 # let: M = (N-1)/Q # Verify: M is even # Primo a # Verify: M > 0 # Primo b # Verify: M < Q # Primo c # Verify: MQ+1 = N # Primo d # Verify: A > 1 # Primo e # Verify: A^(N-1) mod N = 1 # Primo f # Verify: gcd(A^M - 1, N) = 1 # Primo g # Then N is prime if Q is prime. Type ECPP3 N 33863876771064627047864880693347 S 8929168182 R 3792500721324706215857 A -30 B 56 T 0 # From Primo. Experimental, may go away. # Verify: |A| <= N/2 # Verify: |B| <= N/2 # Verify: T >= 0 # Verify: T < N # Let: L = (T^3 + A*T + B) mod N # Let: A = (A * L^2) mod N # Let: B = (B * L^3) mod N # Let: X = (T*L) mod N # Let: Y = (L^2) mod N # Let: Q = R # Let: M = R*S # Continue as type ECPP. Type ECPP4 N 346908375519289784739191985209489924762236002832827279935279239073873837063 S 26591618 R 13045779144363828659812726897983038292936490633310834005307717308699 J -4092776160830678382137043215242735918658074999545950247507675196218505248 T 4 # From Primo. Experimental, may go away. # Verify: |J| <= N/2 # Verify: T >= 0 # Verify: T < N # Let: A = 3 * J * (1728 - J) # Let: B = 2 * J * (1728 - J)^2 # Let: L = (T^3 + A*T + B) mod N # Let: A = (A * L^2) mod N # Let: B = (B * L^3) mod N # Let: X = (T*L) mod N # Let: Y = (L^2) mod N # Let: Q = R # Let: M = R*S # Continue as type ECPP. Type Small N 5791 # Verify: N < 2^64 # Verify: N is prime using BPSW or deterministic M-R tests # Experimental, not used: #Type BLS7 #N 10384593717069655257060992658440473 #Q[1] 87820459687010818424506060639 #Q[2] 379 #Q[3] 13 #Q[4] 3 #Q[5] 2 #A[1] 2 #A[2] 2 #A[3] 2 #A[4] 19 #A[5] 5 #B 10000 #AR 2 # Verify for each i: # Q[i] > 1, Q[i] < N # A[i] > 1, A[i] < N # Q[i] divides n-1 # Let: F = product of all Qs # Let: R = N/F # Verify: F is even # Verify: gcd(F, R) = 1 # Verify: F has no factors smaller than B (this may be time consuming) # Let: s = integer part of R / 2*F # Let: r = fractional part of R / 2*F # Let: P = (F*B+1) * (2*F*F + (r-B)*F + 1) # Verify: n < P # Let: rt = r^2 - 8s # Verify: s = 0 OR rt not a perfect square [e.g. floor(sqrt(rt))^2 != rt] # For each i: # Verify: A[i]^(N-1) mod N = 1 # Verify: gcd(A[i]^((N-1)/Q[i])-1, N) = 1 # Verify: AR^(N-1) mod N = 1 # Verify: gcd(AR^((N-1)/R)-1, N) = 1 # Then N is prime if each Q is prime. Math-Prime-Util-GMP-0.52/utility.c0000644000175000017500000013773113674066653015232 0ustar danadana/* * Utility functions, such as sqrt mod p, polynomial manipulation, etc. */ #include #include #include #include #include #include "ptypes.h" /* includes mpz_mulmod(r, a, b, n, temp) */ #include "utility.h" #include "factor.h" #include "primality.h" #include "isaac.h" static int _verbose = 0; int get_verbose_level(void) { return _verbose; } void set_verbose_level(int level) { _verbose = level; } static gmp_randstate_t _randstate; gmp_randstate_t* get_randstate(void) { return &_randstate; } #if __LITTLE_ENDIAN__ || (defined(BYTEORDER) && (BYTEORDER == 0x1234 || BYTEORDER == 0x12345678)) #define LESWAP(mem, val) #else #if !defined(__x86_64__) #undef U8TO32_LE #undef U32TO8_LE #endif #ifndef U32TO8_LE #define U32TO8_LE(p, v) \ do { \ uint32_t _v = v; \ (p)[0] = (((_v) ) & 0xFFU); \ (p)[1] = (((_v) >> 8) & 0xFFU); \ (p)[2] = (((_v) >> 16) & 0xFFU); \ (p)[3] = (((_v) >> 24) & 0xFFU); \ } while (0) #endif #define LESWAP(mem, val) U32TO8_LE(mem,val) #endif void init_randstate(unsigned long seed) { unsigned char seedstr[8] = {0}; #if (__GNU_MP_VERSION > 4) || (__GNU_MP_VERSION == 4 && __GNU_MP_VERSION_MINOR >= 2) /* MT was added in GMP 4.2 released in 2006. */ gmp_randinit_mt(_randstate); #else gmp_randinit_default(_randstate); #endif gmp_randseed_ui(_randstate, seed); #if BITS_PER_WORD == 64 if (seed > UVCONST(4294967295)) { LESWAP(seedstr, seed); LESWAP(seedstr + 4, (seed >> 16) >> 16); isaac_init(8, seedstr); } else #endif { LESWAP(seedstr, seed); isaac_init(4, seedstr); } } void clear_randstate(void) { gmp_randclear(_randstate); } UV irand64(int nbits) { if (nbits == 0) return 0; if (nbits <= 32) return( isaac_rand32() >> (32-nbits) ); #if BITS_PER_WORD == 64 if (nbits <= 64) return( ((UV)isaac_rand32() | ((UV)isaac_rand32() << 32)) >> (64-nbits) ); #endif croak("irand64 too many bits for UV"); } static NV _tonv_32 = -1.0; static NV _tonv_64; NV drand64(void) { if (_tonv_32 < 0) { int i; NV t64, t32 = 1.0; for (i = 0; i < 32; i++) t32 /= 2.0; t64 = t32; for (i = 0; i < 32; i++) t64 /= 2.0; _tonv_64 = t64; _tonv_32 = t32; } return isaac_rand32() * _tonv_32 + isaac_rand32() * _tonv_64; } void mpz_isaac_urandomb(mpz_t rop, int nbits) { if (nbits <= 32) { mpz_set_ui(rop, irand64(nbits)); } else { unsigned char* d; int nbytes = (nbits+7)/8; New(0, d, nbytes, unsigned char); isaac_rand_bytes(nbytes, d); mpz_import(rop, nbytes, 1, sizeof(unsigned char), 0, 0, d); Safefree(d); if (nbits != nbytes*8) mpz_tdiv_r_2exp(rop, rop, nbits); } } void mpz_isaac_urandomm(mpz_t rop, mpz_t n) { int count = 80; unsigned long nbits = mpz_sizeinbase(n,2); if (mpz_sgn(n) <= 0) { mpz_set_ui(rop,0); return; } else if (nbits <= 32) { mpz_set_ui(rop, isaac_rand(mpz_get_ui(n))); } else if (nbits < 3000) { /* Just like GMP, try until we're in range or we're tired. */ while (count-- > 0) { mpz_isaac_urandomb(rop, nbits); if (mpz_cmp(rop,n) < 0) return; } mpz_mod(rop, rop, n); } else { /* Reduce tries needed by selecting from a range that is a multiple of n * (so no bias) and uses the max space inside the power-of-2 range. * Downside is that we do an alloc and two mods. For large values * it can be much faster however. */ mpz_t rmax; mpz_init(rmax); mpz_setbit(rmax, nbits+8); mpz_sub_ui(rmax,rmax,1); mpz_tdiv_q(rmax, rmax, n); mpz_mul(rmax, rmax, n); do { mpz_isaac_urandomb(rop, nbits+8); } while (mpz_cmp(rop, rmax) >= 0 && count-- > 0); mpz_clear(rmax); mpz_mod(rop, rop, n); } } /* a=0, return power. a>1, return bool if an a-th power */ UV is_power(mpz_t n, UV a) { if (mpz_cmp_ui(n,3) <= 0 && a == 0) return 0; else if (a == 1) return 1; else if (a == 2) return mpz_perfect_square_p(n); else { UV result; mpz_t t; mpz_init(t); result = (a == 0) ? power_factor(n, t) : (UV)mpz_root(t, n, a); mpz_clear(t); return result; } } UV prime_power(mpz_t prime, mpz_t n) { UV k; if (mpz_even_p(n)) { k = mpz_scan1(n, 0); if (k+1 == mpz_sizeinbase(n, 2)) { mpz_set_ui(prime, 2); return k; } return 0; } if (_GMP_is_prob_prime(n)) { mpz_set(prime, n); return 1; } k = power_factor(n, prime); if (k && !_GMP_is_prob_prime(prime)) k = 0; return k; } int is_primitive_root(mpz_t ina, mpz_t n, int nprime) { mpz_t a, s, r, sreduced, t, *factors; int ret, i, nfactors, *exponents; if (mpz_sgn(n) == 0) return 0; if (mpz_sgn(n) < 0) mpz_neg(n,n); if (mpz_cmp_ui(n,1) == 0) return 1; if (mpz_cmp_ui(n,4) <= 0) return mpz_get_ui(ina) == mpz_get_ui(n)-1; if (mpz_divisible_2exp_p(n,2)) return 0; mpz_init(a); mpz_mod(a,ina,n); mpz_init(s); mpz_gcd(s, a, n); if (mpz_cmp_ui(s,1) != 0) { mpz_clear(s); mpz_clear(a); return 0; } mpz_init(t); if (nprime) { mpz_sub_ui(s, n, 1); } else { /* totient(s, n); */ /* Fine, but slow. */ UV k; mpz_init(r); if (mpz_odd_p(n)) mpz_set(t, n); else mpz_fdiv_q_2exp(t, n, 1); k = prime_power(r, t); if (!k) { /* Not of form p^a or 2p^a */ mpz_clear(r); mpz_clear(t); mpz_clear(s); mpz_clear(a); return 0; } mpz_divexact(t, t, r); mpz_mul(s, t, r); mpz_sub(s, s, t); mpz_clear(r); } mpz_init_set(sreduced, s); ret = 0; mpz_sub_ui(t, n, 1); if (mpz_cmp(s,t) == 0 && mpz_kronecker(a,n) != -1) goto DONE_IPR; /* Unclear if this is worth doing. i = is_power(a, 0); if (i > 1 && mpz_gcd_ui(NULL, s, i) != 1) goto DONE_IPR; */ #define IPR_TEST_UI(s, p, a, n, t, ret) \ mpz_divexact_ui(t, s, p); \ mpz_powm(t, a, t, n); \ if (mpz_cmp_ui(t, 1) == 0) { ret = 0; } #define IPR_TEST(s, p, a, n, t, ret) \ mpz_divexact(t, s, p); \ mpz_powm(t, a, t, n); \ if (mpz_cmp_ui(t, 1) == 0) { ret = 0; } ret = 1; { /* Pull out small factors and test */ UV p, fromp = 0; while (ret == 1 && (p = _GMP_trial_factor(sreduced, fromp, 60))) { if (mpz_cmp_ui(sreduced,p) == 0) break; IPR_TEST_UI(s, p, a, n, t, ret); mpz_set_ui(t, p); (void) mpz_remove(sreduced, sreduced, t); fromp = p+1; } } if (ret == 0 || mpz_cmp_ui(sreduced,1) == 0) goto DONE_IPR; if (_GMP_BPSW(sreduced)) { IPR_TEST(s, sreduced, a, n, t, ret); goto DONE_IPR; } /* Pull out more factors, noting they can be composites. */ while (_GMP_pminus1_factor(sreduced, t, 100000, 100000)) { mpz_divexact(sreduced, sreduced, t); if (_GMP_BPSW(t)) { IPR_TEST(s, t, a, n, t, ret); } else { nfactors = factor(t, &factors, &exponents); for (i = 0; ret == 1 && i < nfactors; i++) { IPR_TEST(s, factors[i], a, n, t, ret); } clear_factors(nfactors, &factors, &exponents); } if (ret == 0 || mpz_cmp_ui(sreduced,1) == 0) goto DONE_IPR; if (_GMP_BPSW(sreduced)) { IPR_TEST(s, sreduced, a, n, t, ret); goto DONE_IPR; } } /* We have a composite and so far it could be a primitive root. Factor. */ nfactors = factor(sreduced, &factors, &exponents); for (i = 0; ret == 1 && i < nfactors; i++) { IPR_TEST(s, factors[i], a, n, t, ret); } clear_factors(nfactors, &factors, &exponents); DONE_IPR: mpz_clear(sreduced); mpz_clear(t); mpz_clear(s); mpz_clear(a); return ret; } int mpz_divmod(mpz_t r, mpz_t a, mpz_t b, mpz_t n, mpz_t t) { int invertible; invertible = mpz_invert(t, b, n); if (!invertible) return 0; mpz_mulmod(r, t, a, n, t); /* mpz_mul(t,t,a); mpz_mod(r,t,n); */ return 1; } /* set x to sqrt(a) mod p. Returns 0 if a is not a square root mod p * See Cohen section 1.5 and http://www.math.vt.edu/people/brown/doc/sqrts.pdf */ int sqrtmod(mpz_t s, mpz_t a, mpz_t p) { int res; mpz_t x, t1, t2, t3, t4; mpz_init(x); mpz_init(t1); mpz_init(t2); mpz_init(t3); mpz_init(t4); res = sqrtmod_t(x, a, p, t1, t2, t3, t4); mpz_set(s, x); mpz_clear(x); mpz_clear(t1); mpz_clear(t2); mpz_clear(t3); mpz_clear(t4); return res; } /* Returns 1 if x^2 = a mod p, otherwise set x to 0 and return 0. */ static int verify_sqrt(mpz_t x, mpz_t a, mpz_t p, mpz_t t, mpz_t t2) { /* reflect to get the smaller of +/- x */ mpz_sub(t, p, x); if (mpz_cmp(t,x) < 0) mpz_set(x,t); mpz_mulmod(t, x, x, p, t2); mpz_mod(t2, a, p); if (mpz_cmp(t, t2) == 0) return 1; mpz_set_ui(x, 0); return 0; } /* Internal version that takes temp variables and x cannot overlap args */ int sqrtmod_t(mpz_t x, mpz_t a, mpz_t p, mpz_t t, mpz_t q, mpz_t b, mpz_t z) /* 4 temp variables */ { int r, e, m; if (mpz_cmp_ui(p,2) <= 0) { if (mpz_cmp_ui(p,0) <= 0) { mpz_set_ui(x,0); return 0; } mpz_mod(x, a, p); return verify_sqrt(x, a, p, t, q); } if (!mpz_cmp_ui(a,0) || !mpz_cmp_ui(a,1)) { mpz_set(x,a); return verify_sqrt(x, a, p, t, q); } /* Easy cases from page 31 (or Menezes 3.36, 3.37) */ if (mpz_congruent_ui_p(p, 3, 4)) { mpz_add_ui(t, p, 1); mpz_tdiv_q_2exp(t, t, 2); mpz_powm(x, a, t, p); return verify_sqrt(x, a, p, t, q); } if (mpz_congruent_ui_p(p, 5, 8)) { mpz_sub_ui(t, p, 1); mpz_tdiv_q_2exp(t, t, 2); mpz_powm(q, a, t, p); if (mpz_cmp_si(q, 1) == 0) { /* s = a^((p+3)/8) mod p */ mpz_add_ui(t, p, 3); mpz_tdiv_q_2exp(t, t, 3); mpz_powm(x, a, t, p); } else { /* s = 2a * (4a)^((p-5)/8) mod p */ mpz_sub_ui(t, p, 5); mpz_tdiv_q_2exp(t, t, 3); mpz_mul_ui(q, a, 4); mpz_powm(x, q, t, p); mpz_mul_ui(x, x, 2); mpz_mulmod(x, x, a, p, x); } return verify_sqrt(x, a, p, t, q); } if (mpz_kronecker(a, p) != 1) { /* Possible no solution exists. Check Euler criterion. */ mpz_sub_ui(t, p, 1); mpz_tdiv_q_2exp(t, t, 1); mpz_powm(x, a, t, p); if (mpz_cmp_si(x, 1) != 0) { mpz_set_ui(x, 0); return 0; } } mpz_sub_ui(q, p, 1); e = mpz_scan1(q, 0); /* Remove 2^e from q */ mpz_tdiv_q_2exp(q, q, e); mpz_set_ui(t, 2); while (mpz_kronecker(t, p) != -1) { /* choose t "at random" */ mpz_add_ui(t, t, 1); if (!mpz_cmp_ui(t,133)) { /* If a root of p exists, then our chances are nearly 1/2 that * (t|p) = -1. After 133 tries it seems dubious that a root * exists. It's likely that p is not prime. */ if (mpz_even_p(p)) { mpz_set_ui(x,0); return 0; } /* Euler probable prime test with base t. (t|p) = 1 or t divides p */ if (mpz_divisible_p(p, t)) { mpz_set_ui(x,0); return 0; } mpz_sub_ui(z, p, 1); mpz_fdiv_q_2exp(b,z,1); mpz_powm(z, t, b, p); if (mpz_cmp_ui(z,1)) { mpz_set_ui(x,0); return 0; } /* Fermat base 2 */ mpz_set_ui(b,2); mpz_sub_ui(z, p, 1); mpz_powm(z, b, z, p); if (mpz_cmp_ui(z,1)) { mpz_set_ui(x,0); return 0; } } if (!mpz_cmp_ui(t,286)) { /* Another Euler probable prime test, p not even so t can't divide. */ mpz_sub_ui(z, p, 1); mpz_fdiv_q_2exp(b,z,1); mpz_powm(z, t, b, p); if (mpz_cmp_ui(z,1)) { mpz_set_ui(x,0); return 0; } } if (!mpz_cmp_ui(t,20000)) { mpz_set_ui(x,0); return 0; } } mpz_powm(z, t, q, p); /* Step 1 complete */ r = e; mpz_powm(b, a, q, p); mpz_add_ui(q, q, 1); mpz_divexact_ui(q, q, 2); mpz_powm(x, a, q, p); /* Done with q, will use it for y now */ while (mpz_cmp_ui(b, 1)) { /* calculate how many times b^2 mod p == 1 */ mpz_set(t, b); m = 0; do { mpz_powm_ui(t, t, 2, p); m++; } while (m < r && mpz_cmp_ui(t, 1)); if (m >= r) break; mpz_ui_pow_ui(t, 2, r-m-1); mpz_powm(t, z, t, p); mpz_mulmod(x, x, t, p, x); mpz_powm_ui(z, t, 2, p); mpz_mulmod(b, b, z, p, b); r = m; } return verify_sqrt(x, a, p, t, q); } /* Smith-Cornacchia: Solve x,y for x^2 + |D|y^2 = p given prime p */ /* See Cohen 1.5.2 */ int cornacchia(mpz_t x, mpz_t y, mpz_t D, mpz_t p) { int result = 0; mpz_t a, b, c, d; if (mpz_jacobi(D, p) < 0) /* No solution */ return 0; mpz_init(a); mpz_init(b); mpz_init(c); mpz_init(d); sqrtmod_t(x, D, p, a, b, c, d); mpz_set(a, p); mpz_set(b, x); mpz_sqrt(c, p); while (mpz_cmp(b,c) > 0) { mpz_set(d, a); mpz_set(a, b); mpz_mod(b, d, b); } mpz_mul(a, b, b); mpz_sub(a, p, a); /* a = p - b^2 */ mpz_abs(d, D); /* d = |D| */ if (mpz_divisible_p(a, d)) { mpz_divexact(c, a, d); if (mpz_perfect_square_p(c)) { mpz_set(x, b); mpz_sqrt(y, c); result = 1; } } mpz_clear(a); mpz_clear(b); mpz_clear(c); mpz_clear(d); return result; } /* Modified Cornacchia, Solve x,y for x^2 + |D|y^2 = 4p given prime p */ /* See Cohen 1.5.3 */ int modified_cornacchia(mpz_t x, mpz_t y, mpz_t D, mpz_t p) { int result = 0; mpz_t a, b, c, d; if (mpz_cmp_ui(p, 2) == 0) { mpz_add_ui(x, D, 8); if (mpz_perfect_square_p(x)) { mpz_sqrt(x, x); mpz_set_ui(y, 1); result = 1; } return result; } if (mpz_jacobi(D, p) == -1) /* No solution */ return 0; mpz_init(a); mpz_init(b); mpz_init(c); mpz_init(d); sqrtmod_t(x, D, p, a, b, c, d); if ( (mpz_even_p(D) && mpz_odd_p(x)) || (mpz_odd_p(D) && mpz_even_p(x)) ) mpz_sub(x, p, x); mpz_mul_ui(a, p, 2); mpz_set(b, x); mpz_sqrt(c, p); mpz_mul_ui(c, c, 2); /* Euclidean algorithm */ while (mpz_cmp(b, c) > 0) { mpz_set(d, a); mpz_set(a, b); mpz_mod(b, d, b); } mpz_mul_ui(c, p, 4); mpz_mul(a, b, b); mpz_sub(a, c, a); /* a = 4p - b^2 */ mpz_abs(d, D); /* d = |D| */ if (mpz_divisible_p(a, d)) { mpz_divexact(c, a, d); if (mpz_perfect_square_p(c)) { mpz_set(x, b); mpz_sqrt(y, c); result = 1; } } mpz_clear(a); mpz_clear(b); mpz_clear(c); mpz_clear(d); return result; } /* Modular inversion: invert a mod p. * This implementation from William Hart, using extended gcd. */ unsigned long modinverse(unsigned long a, unsigned long p) { long u1 = 1; long u3 = a; long v1 = 0; long v3 = p; long t1 = 0; long t3 = 0; long quot; while (v3) { quot = u3 - v3; if (u3 < (v3<<2)) { if (quot < v3) { if (quot < 0) { t1 = u1; u1 = v1; v1 = t1; t3 = u3; u3 = v3; v3 = t3; } else { t1 = u1 - v1; u1 = v1; v1 = t1; t3 = u3 - v3; u3 = v3; v3 = t3; } } else if (quot < (v3<<1)) { t1 = u1 - (v1<<1); u1 = v1; v1 = t1; t3 = u3 - (v3<<1); u3 = v3; v3 = t3; } else { t1 = u1 - v1*3; u1 = v1; v1 = t1; t3 = u3 - v3*3; u3 = v3; v3 = t3; } } else { quot = u3 / v3; t1 = u1 - v1*quot; u1 = v1; v1 = t1; t3 = u3 - v3*quot; u3 = v3; v3 = t3; } } if (u1 < 0) u1 += p; return u1; } #if __GNU_MP_VERSION < 5 extern void gcdext(mpz_t g, mpz_t s, mpz_t t, const mpz_t ia, const mpz_t ib) { mpz_t a, b; mpz_init_set(a, ia); mpz_init_set(b, ib); if (mpz_sgn(a) == 0 || mpz_cmp(a,b) == 0) { mpz_set_si(s, 0); mpz_set_si(t, mpz_sgn(b)); mpz_abs(g, b); } else if (mpz_sgn(b) == 0) { mpz_set_si(s, mpz_sgn(a)); mpz_set_si(t, 0); mpz_abs(g, a); } else { mpz_t os, ot, or, r, q, tmp; mpz_init(os); mpz_init(ot); mpz_init(or); mpz_init(r); mpz_init(q); mpz_init(tmp); mpz_set_ui(s,0); mpz_set_ui(os,1); mpz_set_ui(t,1); mpz_set_ui(ot,0); mpz_set(r,b); mpz_set(or,a); while (mpz_sgn(r)) { mpz_tdiv_q(q, or, r); mpz_set(tmp, r); mpz_mul(r, r, q); mpz_sub(r, or, r); mpz_set(or, tmp); mpz_set(tmp, s); mpz_mul(s, s, q); mpz_sub(s, os, s); mpz_set(os, tmp); mpz_set(tmp, t); mpz_mul(t, t, q); mpz_sub(t, ot, t); mpz_set(ot, tmp); } mpz_set(s, os); mpz_set(t, ot); mpz_set(g, or); mpz_clear(r); mpz_clear(q); mpz_clear(tmp); mpz_clear(os); mpz_clear(ot); mpz_clear(or); if (mpz_sgn(g) < 0) { mpz_neg(s, s); mpz_neg(t, t); mpz_neg(g, g); } } mpz_clear(a); mpz_clear(b); } #endif int chinese(mpz_t ret, mpz_t lcm, mpz_t *a, mpz_t *m, int items) { mpz_t sum, gcd, u, v, s, t, temp1, temp2; int i, rval = 1; #if 0 if (items >= 128) { int first = items/2; mpz_t ca[2], cm[2]; for (i = 0; i < 2; i++) { mpz_init(ca[i]); mpz_init(cm[i]); } rval = chinese(ca[0], cm[0], a, m, first); if (rval == 1) rval = chinese(ca[1], cm[1], a+first, m+first, items-first); if (rval == 1) rval = chinese(ret, lcm, ca, cm, 2); for (i = 0; i < 2; i++) { mpz_clear(ca[i]); mpz_clear(cm[i]); } return rval; } #else #define CRTN 8 if (items >= 64) { int step = items/CRTN; mpz_t ca[CRTN], cm[CRTN]; for (i = 0; i < CRTN; i++) { mpz_init(ca[i]); mpz_init(cm[i]); } for (i = 0; rval && i < CRTN; i++) { int citems = (i==CRTN-1) ? items-(CRTN-1)*step : step; rval = chinese(ca[i], cm[i], a+i*step, m+i*step, citems); } if (rval) rval = chinese(ret, lcm, ca, cm, CRTN); for (i = 0; i < CRTN; i++) { mpz_clear(ca[i]); mpz_clear(cm[i]); } return rval; } #endif /* Avoid dividing by zero, which GMP doesn't enjoy. */ for (i = 0; i < items; i++) if (mpz_sgn(m[i]) == 0) return 0; mpz_init(temp1); mpz_init(temp2); mpz_init(sum); mpz_init(gcd); mpz_init(s); mpz_init(t); mpz_init(u); mpz_init(v); mpz_set(lcm, m[0]); mpz_mod(sum, a[0], m[0]); for (i = 1; i < items; i++) { mpz_gcdext(gcd, u, v, lcm, m[i]); mpz_divexact(s, m[i], gcd); mpz_divexact(t, lcm, gcd); if (mpz_cmp_ui(gcd,1) != 0) { mpz_mod(temp1, sum, gcd); mpz_mod(temp2, a[i], gcd); if (mpz_cmp(temp1, temp2) != 0) { rval = 0; break; } } if (mpz_sgn(s) < 0) mpz_neg(s,s); if (mpz_sgn(t) < 0) mpz_neg(t,t); mpz_mul(lcm, lcm, s); if (mpz_sgn(u) < 0) mpz_add(u, u, lcm); if (mpz_sgn(v) < 0) mpz_add(v, v, lcm); mpz_mul(temp1, v, s); mpz_mul(v, temp1, sum); mpz_mul(temp1, u, t); mpz_mul(u, temp1, a[i]); mpz_add(temp1, v, u); mpz_mod(sum, temp1, lcm); } mpz_set(ret, sum); mpz_clear(sum); mpz_clear(gcd); mpz_clear(s); mpz_clear(t); mpz_clear(u); mpz_clear(v); mpz_clear(temp1); mpz_clear(temp2); return rval; } UV mpz_order_ui(UV r, mpz_t n, UV limit) { UV j; mpz_t t; /* If n < limit, set limit to n */ if (mpz_cmp_ui(n, limit) < 0) limit = mpz_get_ui(n); mpz_init_set_ui(t, 1); for (j = 1; j <= limit; j++) { mpz_mul(t, t, n); mpz_mod_ui(t, t, r); if (!mpz_cmp_ui(t, 1)) break; } mpz_clear(t); return j; } void mpz_arctan(mpz_t r, unsigned long base, mpz_t pow, mpz_t t1, mpz_t t2) { unsigned long i = 1; mpz_tdiv_q_ui(r, pow, base); mpz_set(t1, r); do { if (base > 65535) { mpz_ui_pow_ui(t2, base, 2); mpz_tdiv_q(t1, t1, t2); } else mpz_tdiv_q_ui(t1, t1, base*base); mpz_tdiv_q_ui(t2, t1, 2*i+1); if (i++ & 1) mpz_sub(r, r, t2); else mpz_add(r, r, t2); } while (mpz_sgn(t2)); } void mpz_arctanh(mpz_t r, unsigned long base, mpz_t pow, mpz_t t1, mpz_t t2) { unsigned long i = 1; mpz_tdiv_q_ui(r, pow, base); mpz_set(t1, r); do { if (base > 65535) { mpz_ui_pow_ui(t2, base, 2); mpz_tdiv_q(t1, t1, t2); } else mpz_tdiv_q_ui(t1, t1, base*base); mpz_tdiv_q_ui(t2, t1, 1 + (i++ << 1)); mpz_add(r, r, t2); } while (mpz_sgn(t2)); } void mpz_product(mpz_t* A, UV a, UV b) { if (b <= a) { /* nothing */ } else if (b == a+1) { mpz_mul(A[a], A[a], A[b]); } else if (b == a+2) { mpz_mul(A[a+1], A[a+1], A[a+2]); mpz_mul(A[a], A[a], A[a+1]); } else { UV c = a + (b-a+1)/2; mpz_product(A, a, c-1); mpz_product(A, c, b); mpz_mul(A[a], A[a], A[c]); } } void mpz_veclcm(mpz_t* A, UV a, UV b) { if (b <= a) { /* nothing */ } else if (b == a+1) { mpz_lcm(A[a], A[a], A[b]); } else if (b == a+2) { mpz_lcm(A[a+1], A[a+1], A[a+2]); mpz_lcm(A[a], A[a], A[a+1]); } else { UV c = a + (b-a+1)/2; mpz_veclcm(A, a, c-1); mpz_veclcm(A, c, b); mpz_lcm(A[a], A[a], A[c]); } } UV logint(mpz_t n, UV base) { mpz_t nt; double logn, logbn, coreps; UV res, nbits; if (mpz_cmp_ui(n,0) <= 0 || base <= 1) croak("mpz_logint: bad input\n"); /* If base is a small power of 2, then this is exact */ if (base <= 62 && (base & (base-1)) == 0) return mpz_sizeinbase(n, base)-1; if (mpz_cmp_ui(n,base) < 0) return 0; #if 0 /* example using mpf_log for high precision. Slow. */ { mpf_t fr, fn; mpf_init(fr); mpf_init(fn); mpf_set_z(fn, n); mpf_log(fr, fn); logn = mpf_get_d(fr); mpf_clear(fn); mpf_clear(fr); coreps = 1e-8; } #endif /* A typical way to do this is to start with base, then compare * base^2, base^4, base^8, ... until larger than n. Then either work * back down or do a binary search * It uses O(log2(log2(n)) integer squares+multiplies plus some space. * * However, libc gives us the very fast log() function for doubles. While * reducing the argument as needed to make sure we fit inside a double, * we can use this to give us a result extremely close to the right * answer, then adjust if we're not sure of the result. * * My benchmarks show it as about 2-10x faster than the all-integer method. */ nbits = mpz_sizeinbase(n,2); mpz_init(nt); /* Step 1, get an approximation of log(n) */ if (nbits < 512) { logn = log(mpz_get_d(n)); coreps = 1e-8; } else { /* Reduce bits using log(x * 2^k) = log(x) + k * log(2) */ uint32_t redbits = nbits - 256; mpz_tdiv_q_2exp(nt, n, redbits); logn = log(mpz_get_d(nt)) + redbits * 0.69314718055994530941723212145818L; coreps = 1e-7; } /* Step 2, approximate log_base(n) */ logbn = logn / log(base); res = (UV) logbn; /* Step 3, correct if logbn might be rounded wrong */ if (res != (UV)(logbn+coreps) || res != (UV)(logbn-coreps)) { mpz_ui_pow_ui(nt, base, res); if (mpz_cmp(nt, n) > 0) { res--; } else if (mpz_cmp(nt, n) < 0) { mpz_mul_ui(nt, nt, base); if (mpz_cmp(nt, n) <= 0) res++; } } mpz_clear(nt); /* res is largest res such that base^res <= n */ return res; } /******************************************************************************/ /* * Floating point routines. * These are not rigorously accurate. Use MPFR if possible. * * See also: http://fredrikj.net/math/elefun.pdf * for how to really look at this correctly. * * Many ideas from Brent's presentation: * https://pdfs.semanticscholar.org/8aec/ea97b8f2f23d4f09ec8f69025598f742ae9e.pdf */ extern void const_pi(mpf_t pi, unsigned long prec); extern void const_log2(mpf_t logn, unsigned long prec); /* Log using Brent's second AGM algorithm (Sasaki and Kanada theta) */ void mpf_log(mpf_t logn, mpf_t n) { mpf_t N, t, q, theta2, theta3, logdn; unsigned long k, bits = mpf_get_prec(logn); int neg = (mpf_sgn(n) < 0); if (mpf_sgn(n) == 0) croak("mpf_log(0)"); if (mpf_cmp_ui(n,2) == 0) { const_log2(logn,BITS2DIGS(bits)); return; } if ((neg && !mpf_cmp_si(n,-1)) || (!neg && !mpf_cmp_si(n,1))) { mpf_set_ui(logn,0); return; } mpf_init2(N, bits); mpf_set(N, n); if (neg) mpf_neg(N, N); mpf_init2(t, 64 + bits); mpf_init2(q, 64 + bits); mpf_init2(theta2, 64 + bits); mpf_init2(theta3, 64 + bits); mpf_init2(logdn, 64 + bits); mpf_set_ui(logn, 0); /* ensure N >> 1 */ mpf_set_ui(t, 1); mpf_mul_2exp(t, t, 1+(35+bits)/36); if (mpf_cmp(N, t) <= 0) { /* log(n) = log(n*2^k) - k*log(2) */ for (k = 0; mpf_cmp(N, t) <= 0; k += 16) mpf_mul_2exp(N, N, 16); if (k > 0) { const_log2(t, BITS2DIGS(bits)); mpf_mul_ui(logn, t, k); mpf_neg(logn, logn); } } mpf_ui_div(q, 1, N); mpf_pow_ui(t,q,9); mpf_add(theta2, q, t); mpf_pow_ui(t,q,25); mpf_add(theta2, theta2, t); mpf_mul_2exp(theta2, theta2, 1); mpf_pow_ui(theta3,q,4); mpf_pow_ui(t,q,16); mpf_add(theta3, theta3, t); mpf_mul_2exp(theta3, theta3, 1); mpf_add_ui(theta3, theta3, 1); /* Normally we would do: * mpf_mul(theta2, theta2, theta2); mpf_mul(theta3, theta3, theta3); * mpf_agm(t, theta2, theta3); mpf_mul_2exp(t, t, 2); * but Brent points out the one term acceleration: * AGM(t2^2,t3^2) => AGM(2*t2*t3,t2^2+t3^2)/2 */ mpf_mul(t, theta2, theta3); mpf_mul_2exp(q, t, 1); /* q = 2*t2*t3 */ mpf_add(t, theta2, theta3); mpf_mul(t, t, t); /* t = (t2+t3)^2 = t2^2 + t3^2 + 2*t2*t3 */ mpf_sub(theta3, t, q); mpf_set(theta2, q); mpf_agm(t, theta2, theta3); mpf_mul_2exp(t, t, 1); const_pi(logdn, BITS2DIGS(bits)); mpf_div(logdn, logdn, t); mpf_add(logn, logn, logdn); mpf_clear(logdn); mpf_clear(theta3); mpf_clear(theta2); mpf_clear(q); mpf_clear(t); mpf_clear(N); if (neg) mpf_neg(logn, logn); } /* x should be 0 < x < 1 */ static void _exp_sinh(mpf_t expx, mpf_t x, unsigned long bits) { unsigned long k; mpf_t t, s, N, D, X; mpf_init2(t, 10 + bits); mpf_init2(s, 10 + bits); mpf_init2(N, 10 + bits); mpf_init2(D, 10 + bits); mpf_init2(X, 10 + bits); /* 1. Compute s =~ sinh(x). */ mpf_set(s,x); mpf_set(N,x); mpf_mul(X,x,x); mpf_set_ui(D,1); for (k = 1; k < bits; k++) { mpf_mul(N, N, X); mpf_mul_ui(D, D, 2*k); mpf_mul_ui(D, D, 2*k+1); mpf_div(t, N, D); mpf_add(s, s, t); mpf_abs(t, t); mpf_mul_2exp(t, t, bits); if (mpf_cmp_d(t, .5) < 0) break; } mpf_clear(X); mpf_clear(D); mpf_clear(N); /* 2. Compute s =~ e(x) from sinh(x). */ mpf_mul(t, s, s); mpf_add_ui(t, t, 1); mpf_sqrt(t, t); mpf_add(s, s, t); mpf_set(expx, s); mpf_clear(s); mpf_clear(t); } static void _exp_lift(mpf_t expx, mpf_t x, unsigned long bits) { mpf_t s, t1, t2; unsigned long k; mpf_init2(s, 10 + bits); mpf_init2(t1, 10 + bits); mpf_init2(t2, 10 + bits); mpf_set(s, expx); mpf_log(t1, s); mpf_sub(t2, x, t1); /* t2 = s-ln(x) */ mpf_mul(t1, s, t2); /* t1 = s(s-ln(x) */ mpf_add(s, s, t1); /* third and higher orders */ for (k = 3; k <= 8; k++) { mpf_mul(t1, t1, t2); mpf_div_ui(t1, t1, k-1); mpf_add(s, s, t1); } mpf_set(expx, s); mpf_clear(t2); mpf_clear(t1); mpf_clear(s); } void mpf_exp(mpf_t expn, mpf_t x) { mpf_t t; unsigned long k, r, rbits, bits = mpf_get_prec(expn); if (mpf_sgn(x) == 0) { mpf_set_ui(expn, 1); return; } mpf_init2(t, 10 + bits); if (mpf_sgn(x) < 0) { /* As per Brent, exp(x) = 1/exp(-x) */ mpf_neg(t, x); mpf_exp(t, t); if (mpf_sgn(t) != 0) mpf_ui_div(expn, 1, t); else mpf_set_ui(expn, 0); mpf_clear(t); return; } /* Doubling rule, to make -.25 < x < .25. Speeds convergence. */ mpf_set(t, x); for (k = 0; mpf_cmp_d(t, 1.0L/8192.0L) > 0; k++) mpf_div_2exp(t, t, 1); /* exp with sinh method, then Newton lift to final bits */ for (rbits = bits, r = 0; rbits > 4000; rbits = (rbits+7)/8) r++; _exp_sinh(expn, t, rbits); while (r-- > 0) { rbits *= 8; _exp_lift(expn, t, rbits); } if (rbits < bits) _exp_lift(expn, t, bits); if (k > 0) { const unsigned long maxred = 8*sizeof(unsigned long)-1; for ( ; k > maxred; k -= maxred) mpf_pow_ui(expn, expn, 1UL << maxred); mpf_pow_ui(expn, expn, 1UL << k); } mpf_clear(t); } /* Negative b with non-int x usually gives a complex result. * We try to at least give a consistent result. */ void mpf_pow(mpf_t powx, mpf_t b, mpf_t x) { mpf_t t; int neg = 0; if (mpf_sgn(b) == 0) { mpf_set_ui(powx, 0); return; } if (mpf_sgn(b) < 0) { neg = 1; } if (mpf_cmp_ui(b,1) == 0) { mpf_set_ui(powx, 1-2*neg); return; } if (mpf_integer_p(x) && mpf_fits_ulong_p(x)) { mpf_pow_ui(powx, b, mpf_get_ui(x)); return; } if (neg) mpf_neg(b,b); mpf_init2(t, mpf_get_prec(powx)); mpf_log(t, b); mpf_mul(t, t, x); mpf_exp(powx, t); if (neg) mpf_neg(powx,powx); mpf_clear(t); } void mpf_root(mpf_t rootx, mpf_t x, mpf_t n) { if (mpf_sgn(n) == 0) { mpf_set_ui(rootx, 0); } else if (mpf_cmp_ui(n, 2) == 0) { mpf_sqrt(rootx, x); } else { mpf_t t; mpf_init2(t, mpf_get_prec(rootx)); mpf_ui_div(t, 1, n); mpf_pow(rootx, x, t); mpf_clear(t); } } void mpf_agm(mpf_t r, mpf_t a, mpf_t b) { mpf_t t; unsigned long bits = mpf_get_prec(r); if (mpf_cmp(a,b) > 0) mpf_swap(a,b); mpf_init2(t, 6+bits); while (1) { mpf_sub(t, b, a); mpf_abs(t, t); mpf_mul_2exp(t, t, bits); mpf_sub_ui(t,t,1); if (mpf_sgn(t) < 0) break; mpf_sub_ui(t,t,1); mpf_set(t, a); mpf_add(a, a, b); mpf_div_2exp(a, a, 1); mpf_mul(b, b, t); mpf_sqrt(b, b); } mpf_set(r, b); mpf_clear(t); } /******************************************************************************/ #if 0 /* Simple polynomial multiplication */ void poly_mod_mul(mpz_t* px, mpz_t* py, mpz_t* ptmp, UV r, mpz_t mod) { UV i, j, prindex; for (i = 0; i < r; i++) mpz_set_ui(ptmp[i], 0); for (i = 0; i < r; i++) { if (!mpz_sgn(px[i])) continue; for (j = 0; j < r; j++) { if (!mpz_sgn(py[j])) continue; prindex = (i+j) % r; mpz_addmul( ptmp[prindex], px[i], py[j] ); } } /* Put ptmp into px and mod n */ for (i = 0; i < r; i++) mpz_mod(px[i], ptmp[i], mod); } void poly_mod_sqr(mpz_t* px, mpz_t* ptmp, UV r, mpz_t mod) { UV i, d, s; UV degree = r-1; for (i = 0; i < r; i++) mpz_set_ui(ptmp[i], 0); for (d = 0; d <= 2*degree; d++) { UV prindex = d % r; for (s = (d <= degree) ? 0 : d-degree; s <= (d/2); s++) { if (s*2 == d) { mpz_addmul( ptmp[prindex], px[s], px[s] ); } else { mpz_addmul( ptmp[prindex], px[s], px[d-s] ); mpz_addmul( ptmp[prindex], px[s], px[d-s] ); } } } /* Put ptmp into px and mod n */ for (i = 0; i < r; i++) mpz_mod(px[i], ptmp[i], mod); } #endif #if (__GNU_MP_VERSION < 4) || (__GNU_MP_VERSION == 4 && __GNU_MP_VERSION_MINOR < 1) /* Binary segmentation, using simple shift+add method for processing p. * Faster than twiddling bits, but not nearly as fast as import/export. * mpz_import and mpz_export were added in GMP 4.1 released in 2002. */ void poly_mod_mul(mpz_t* px, mpz_t* py, UV r, mpz_t mod, mpz_t p, mpz_t p2, mpz_t t) { UV i, d, bits; UV degree = r-1; mpz_mul(t, mod, mod); mpz_mul_ui(t, t, r); bits = mpz_sizeinbase(t, 2); mpz_set_ui(p, 0); for (i = 0; i < r; i++) { mpz_mul_2exp(p, p, bits); mpz_add(p, p, px[r-i-1]); } if (px == py) { mpz_mul(p, p, p); } else { mpz_set_ui(p2, 0); for (i = 0; i < r; i++) { mpz_mul_2exp(p2, p2, bits); mpz_add(p2, p2, py[r-i-1]); } mpz_mul(p, p, p2); } for (d = 0; d <= 2*degree; d++) { mpz_tdiv_r_2exp(t, p, bits); mpz_tdiv_q_2exp(p, p, bits); if (d < r) mpz_set(px[d], t); else mpz_add(px[d-r], px[d-r], t); } for (i = 0; i < r; i++) mpz_mod(px[i], px[i], mod); } #else /* Binary segmentation, using import/export method for processing p. * Thanks to Dan Bernstein's 2007 Quartic paper. */ void poly_mod_mul(mpz_t* px, mpz_t* py, UV r, mpz_t mod, mpz_t p, mpz_t p2, mpz_t t) { UV i, bytes; char* s; mpz_mul(t, mod, mod); mpz_mul_ui(t, t, r); bytes = mpz_sizeinbase(t, 256); mpz_set_ui(p, 0); mpz_set_ui(p2, 0); /* 1. Create big integers from px and py with padding. */ { Newz(0, s, r*bytes, char); for (i = 0; i < r; i++) mpz_export(s + i*bytes, NULL, -1, 1, 0, 0, px[i]); mpz_import(p, r*bytes, -1, 1, 0, 0, s); Safefree(s); } if (px != py) { Newz(0, s, r*bytes, char); for (i = 0; i < r; i++) mpz_export(s + i*bytes, NULL, -1, 1, 0, 0, py[i]); mpz_import(p2, r*bytes, -1, 1, 0, 0, s); Safefree(s); } /* 2. Multiply using the awesomeness that is GMP. */ mpz_mul( p, p, (px == py) ? p : p2 ); /* 3. Pull out the parts of the result, add+mod, and put in px. */ { Newz(0, s, 2*r*bytes, char); /* fill s with data from p */ mpz_export(s, NULL, -1, 1, 0, 0, p); for (i = 0; i < r; i++) { /* Set px[i] to the top part, t to the bottom. */ mpz_import(px[i], bytes, -1, 1, 0, 0, s + (i+r)*bytes); mpz_import(t, bytes, -1, 1, 0, 0, s + i*bytes); /* Add and mod */ mpz_add(px[i], px[i], t); mpz_mod(px[i], px[i], mod); } Safefree(s); } } #endif void poly_mod_pow(mpz_t *pres, mpz_t *pn, mpz_t power, UV r, mpz_t mod) { UV i; mpz_t mpow, t1, t2, t3; for (i = 0; i < r; i++) mpz_set_ui(pres[i], 0); mpz_set_ui(pres[0], 1); mpz_init_set(mpow, power); mpz_init(t1); mpz_init(t2); mpz_init(t3); while (mpz_cmp_ui(mpow, 0) > 0) { if (mpz_odd_p(mpow)) poly_mod_mul(pres, pn, r, mod, t1, t2, t3); mpz_tdiv_q_2exp(mpow, mpow, 1); if (mpz_cmp_ui(mpow, 0) > 0) poly_mod_mul(pn, pn, r, mod, t1, t2, t3); } mpz_clear(t1); mpz_clear(t2); mpz_clear(t3); mpz_clear(mpow); } void poly_mod(mpz_t *pres, mpz_t *pn, UV *dn, mpz_t mod) { UV i; for (i = 0; i < *dn; i++) { mpz_mod(pres[i], pn[i], mod); } while (*dn > 0 && mpz_sgn(pres[*dn-1]) == 0) *dn -= 1; } void polyz_mod(mpz_t *pres, mpz_t *pn, long *dn, mpz_t mod) { long i; for (i = 0; i <= *dn; i++) { mpz_mod(pres[i], pn[i], mod); } while (*dn > 0 && mpz_sgn(pres[*dn]) == 0) *dn -= 1; } void polyz_set(mpz_t* pr, long* dr, mpz_t* ps, long ds) { *dr = ds; do { mpz_set(pr[ds], ps[ds]); } while (ds-- > 0); } void polyz_print(const char* header, mpz_t* pn, long dn) { gmp_printf("%s", header); do { gmp_printf("%Zd ", pn[dn]); } while (dn-- > 0); gmp_printf("\n"); } /* Multiply polys px and py to create new poly pr, all modulo 'mod' */ #if 0 void polyz_mulmod(mpz_t* pr, mpz_t* px, mpz_t *py, long *dr, long dx, long dy, mpz_t mod) { long i, j; *dr = dx + dy; for (i = 0; i <= *dr; i++) mpz_set_ui(pr[i], 0); for (i = 0; i <= dx; i++) { if (!mpz_sgn(px[i])) continue; for (j = 0; j <= dy; j++) { if (!mpz_sgn(py[j])) continue; mpz_addmul( pr[i+j], px[i], py[j] ); } } for (i = 0; i <= *dr; i++) mpz_mod(pr[i], pr[i], mod); while (*dr > 0 && mpz_sgn(pr[*dr]) == 0) dr[0]--; } #endif #if 1 void polyz_mulmod(mpz_t* pr, mpz_t* px, mpz_t *py, long *dr, long dx, long dy, mpz_t mod) { UV i, bits, r; mpz_t p, p2, t; mpz_init(p); mpz_init(t); *dr = dx+dy; r = *dr+1; mpz_mul(t, mod, mod); mpz_mul_ui(t, t, r); bits = mpz_sizeinbase(t, 2); mpz_set_ui(p, 0); /* Create big integers p and p2 from px and py, with padding */ { for (i = 0; i <= (UV)dx; i++) { mpz_mul_2exp(p, p, bits); mpz_add(p, p, px[dx-i]); } } if (px == py) { mpz_pow_ui(p, p, 2); } else { mpz_init_set_ui(p2, 0); for (i = 0; i <= (UV)dy; i++) { mpz_mul_2exp(p2, p2, bits); mpz_add(p2, p2, py[dy-i]); } mpz_mul(p, p, p2); mpz_clear(p2); } /* Pull out parts of result p to pr */ for (i = 0; i < r; i++) { mpz_tdiv_r_2exp(t, p, bits); mpz_tdiv_q_2exp(p, p, bits); mpz_mod(pr[i], t, mod); } mpz_clear(p); mpz_clear(t); } #endif #if 0 void polyz_mulmod(mpz_t* pr, mpz_t* px, mpz_t *py, long *dr, long dx, long dy, mpz_t mod) { UV i, bytes, r; char* s; mpz_t p, p2, t; mpz_init(p); mpz_init(p2); mpz_init(t); *dr = dx+dy; r = *dr+1; mpz_mul(t, mod, mod); mpz_mul_ui(t, t, r); bytes = mpz_sizeinbase(t, 256); mpz_set_ui(p, 0); mpz_set_ui(p2, 0); /* Create big integers p and p2 from px and py, with padding */ { Newz(0, s, (dx+1)*bytes, char); for (i = 0; i <= dx; i++) mpz_export(s + i*bytes, NULL, -1, 1, 0, 0, px[i]); mpz_import(p, (dx+1)*bytes, -1, 1, 0, 0, s); Safefree(s); } if (px != py) { Newz(0, s, (dy+1)*bytes, char); for (i = 0; i <= dy; i++) mpz_export(s + i*bytes, NULL, -1, 1, 0, 0, py[i]); mpz_import(p2, (dy+1)*bytes, -1, 1, 0, 0, s); Safefree(s); } /* Multiply! */ mpz_mul( p ,p, (px == py) ? p : p2 ); /* Pull out parts of result p to pr */ { Newz(0, s, r*bytes, char); /* fill s with data from p */ mpz_export(s, NULL, -1, 1, 0, 0, p); for (i = 0; i < r; i++) { mpz_import(t, bytes, -1, 1, 0, 0, s + i*bytes); mpz_mod(pr[i], t, mod); } Safefree(s); } mpz_clear(p); mpz_clear(p2); mpz_clear(t); } #endif /* Polynomial division modulo N. * This is Cohen algorithm 3.1.2 "pseudo-division". */ void polyz_div(mpz_t *pq, mpz_t *pr, mpz_t *pn, mpz_t *pd, long *dq, long *dr, long dn, long dd, mpz_t NMOD) { long i, j; mpz_t t; /* Ensure n and d are reduced */ while (dn > 0 && mpz_sgn(pn[dn]) == 0) dn--; while (dd > 0 && mpz_sgn(pd[dd]) == 0) dd--; if (dd == 0 && mpz_sgn(pd[0]) == 0) croak("polyz_divmod: divide by zero\n"); /* Q = 0 */ *dq = 0; mpz_set_ui(pq[0], 0); /* R = N */ *dr = dn; for (i = 0; i <= dn; i++) mpz_set(pr[i], pn[i]); /* pn should already be mod */ if (*dr < dd) return; if (dd == 0) { *dq = 0; *dr = 0; mpz_tdiv_qr( pq[0], pr[0], pn[0], pd[0] ); return; } *dq = dn - dd; *dr = dd-1; if (mpz_cmp_ui(pd[dd], 1) == 0) { for (i = *dq; i >= 0; i--) { long di = dd + i; mpz_set(pq[i], pr[di]); for (j = di-1; j >= i; j--) { mpz_submul(pr[j], pr[di], pd[j-i]); mpz_mod(pr[j], pr[j], NMOD); } } } else { mpz_init(t); for (i = *dq; i >= 0; i--) { long di = dd + i; mpz_powm_ui(t, pd[dd], i, NMOD); mpz_mul(t, t, pr[di]); mpz_mod(pq[i], t, NMOD); for (j = di-1; j >= 0; j--) { mpz_mul(pr[j], pr[j], pd[dd]); /* j != di so this is safe */ if (j >= i) mpz_submul(pr[j], pr[di], pd[j-i]); mpz_mod(pr[j], pr[j], NMOD); } } mpz_clear(t); } /* Reduce R and Q. */ while (*dr > 0 && mpz_sgn(pr[*dr]) == 0) dr[0]--; while (*dq > 0 && mpz_sgn(pq[*dq]) == 0) dq[0]--; } /* Raise poly pn to the power, modulo poly pmod and coefficient NMOD. */ void polyz_pow_polymod(mpz_t* pres, mpz_t* pn, mpz_t* pmod, long *dres, long dn, long dmod, mpz_t power, mpz_t NMOD) { mpz_t mpow; long dProd, dQ, dX, maxd, i; mpz_t *pProd, *pQ, *pX; /* Product = res*x. With a prediv this would be dmod+dmod, but without it * is max(dmod,dn)+dmod. */ maxd = (dn > dmod) ? dn+dmod : dmod+dmod; New(0, pProd, maxd+1, mpz_t); New(0, pQ, maxd+1, mpz_t); New(0, pX, maxd+1, mpz_t); for (i = 0; i <= maxd; i++) { mpz_init(pProd[i]); mpz_init(pQ[i]); mpz_init(pX[i]); } *dres = 0; mpz_set_ui(pres[0], 1); dX = dn; for (i = 0; i <= dX; i++) mpz_set(pX[i], pn[i]); mpz_init_set(mpow, power); while (mpz_cmp_ui(mpow, 0) > 0) { if (mpz_odd_p(mpow)) { polyz_mulmod(pProd, pres, pX, &dProd, *dres, dX, NMOD); polyz_div(pQ, pres, pProd, pmod, &dQ, dres, dProd, dmod, NMOD); } mpz_tdiv_q_2exp(mpow, mpow, 1); if (mpz_cmp_ui(mpow, 0) > 0) { polyz_mulmod(pProd, pX, pX, &dProd, dX, dX, NMOD); polyz_div(pQ, pX, pProd, pmod, &dQ, &dX, dProd, dmod, NMOD); } } mpz_clear(mpow); for (i = 0; i <= maxd; i++) { mpz_clear(pProd[i]); mpz_clear(pQ[i]); mpz_clear(pX[i]); } Safefree(pProd); Safefree(pQ); Safefree(pX); } void polyz_gcd(mpz_t* pres, mpz_t* pa, mpz_t* pb, long* dres, long da, long db, mpz_t MODN) { long i; long dr1, dq, dr, maxd; mpz_t *pr1, *pq, *pr; /* Early reduction so we're not wasteful with messy input. */ while (da > 0 && mpz_sgn(pa[da]) == 0) da--; while (db > 0 && mpz_sgn(pb[db]) == 0) db--; /* Swap a/b so degree a >= degree b */ if (db > da) { mpz_t* mtmp; long ltmp; mtmp = pa; pa = pb; pb = mtmp; ltmp = da; da = db; db = ltmp; } /* TODO: Should set c=pa[da], then after Euclid loop, res = c^-1 * res */ /* Allocate temporary polys */ maxd = da; New(0, pr1, maxd+1, mpz_t); New(0, pq, maxd+1, mpz_t); New(0, pr, maxd+1, mpz_t); for (i = 0; i <= maxd; i++) { mpz_init(pr1[i]); mpz_init(pq[i]); mpz_init(pr[i]); } /* R0 = a (we use pres) */ *dres = da; for (i = 0; i <= da; i++) mpz_mod(pres[i], pa[i], MODN); while (*dres > 0 && mpz_sgn(pres[*dres]) == 0) dres[0]--; /* R1 = b */ dr1 = db; for (i = 0; i <= db; i++) mpz_mod(pr1[i], pb[i], MODN); while (dr1 > 0 && mpz_sgn(pr1[dr1]) == 0) dr1--; while (dr1 > 0 || mpz_sgn(pr1[dr1]) != 0) { polyz_div(pq, pr, pres, pr1, &dq, &dr, *dres, dr1, MODN); if (dr < 0 || dq < 0 || dr > maxd || dq > maxd) croak("division error: dq %ld dr %ld maxd %ld\n", dq, dr, maxd); /* pr0 = pr1. pr1 = pr */ *dres = dr1; for (i = 0; i <= dr1; i++) mpz_set(pres[i], pr1[i]); /* pr1 is mod MODN already */ dr1 = dr; for (i = 0; i <= dr; i++) mpz_set(pr1[i], pr[i]); } /* return pr0 */ while (*dres > 0 && mpz_sgn(pres[*dres]) == 0) dres[0]--; for (i = 0; i <= maxd; i++) { mpz_clear(pr1[i]); mpz_clear(pq[i]); mpz_clear(pr[i]); } Safefree(pr1); Safefree(pq); Safefree(pr); } void polyz_root_deg1(mpz_t root, mpz_t* pn, mpz_t NMOD) { mpz_invert(root, pn[1], NMOD); mpz_mul(root, root, pn[0]); mpz_neg(root, root); mpz_mod(root, root, NMOD); } void polyz_root_deg2(mpz_t root1, mpz_t root2, mpz_t* pn, mpz_t NMOD) { mpz_t e, d, t, t2, t3, t4; mpz_init(e); mpz_init(d); mpz_init(t); mpz_init(t2); mpz_init(t3); mpz_init(t4); mpz_mul(t, pn[0], pn[2]); mpz_mul_ui(t, t, 4); mpz_mul(d, pn[1], pn[1]); mpz_sub(d, d, t); sqrtmod_t(e, d, NMOD, t, t2, t3, t4); mpz_neg(t4, pn[1]); /* t4 = -a_1 */ mpz_mul_ui(t3, pn[2], 2); /* t3 = 2a_2 */ mpz_add(t, t4, e); /* t = -a_1 + e */ mpz_divmod( root1, t, t3, NMOD, t2); /* (-a_1+e)/2a_2 */ mpz_sub(t, t4, e); /* t = -a_1 - e */ mpz_divmod( root2, t, t3, NMOD, t2); /* (-a_1-e)/2a_2 */ mpz_clear(e); mpz_clear(d); mpz_clear(t); mpz_clear(t2); mpz_clear(t3); mpz_clear(t4); } /* Algorithm 2.3.10 procedure "roots" from Crandall & Pomerance. * Step 3/4 of Cohen Algorithm 1.6.1. * Uses some hints from Pate Williams (1997-1998) for the poly math */ static void polyz_roots(mpz_t* roots, long *nroots, long maxroots, mpz_t* pg, long dg, mpz_t NMOD) { long i, ntries, maxtries, maxd, dxa, dt, dh, dq, dup; mpz_t t, power; mpz_t pxa[2]; mpz_t *pt, *ph, *pq; if (*nroots >= maxroots || dg <= 0) return; mpz_init(t); mpz_init(pxa[0]); mpz_init(pxa[1]); if (dg <= 2) { if (dg == 1) polyz_root_deg1( pxa[0], pg, NMOD ); else polyz_root_deg2( pxa[0], pxa[1], pg, NMOD ); for (dt = 0; dt < dg; dt++) { mpz_set(t, pxa[dt]); dup = 0; /* don't add duplicate roots */ for (i = 0; i < *nroots; i++) if (mpz_cmp(t, roots[i]) == 0) { dup = 1; break; } if (!dup) mpz_set(roots[ (*nroots)++ ], t); } mpz_clear(t); mpz_clear(pxa[0]); mpz_clear(pxa[1]); return; } /* If not a monic polynomial, divide by leading coefficient */ if (mpz_cmp_ui(pg[dg], 1) != 0) { if (!mpz_invert(t, pg[dg], NMOD)) { mpz_clear(t); return; } for (i = 0; i <= dg; i++) mpz_mulmod(pg[i], pg[i], t, NMOD, pg[i]); } /* Try hard to find a single root, work less after we got one or two. * In a generic routine we would want to try hard all the time. */ ntries = 0; maxtries = (*nroots == 0) ? 200 : (*nroots == 1) ? 50 : 10; mpz_init(power); mpz_set_ui(pxa[1], 1); dxa = 1; maxd = 2 * dg; New(0, pt, maxd+1, mpz_t); New(0, ph, maxd+1, mpz_t); New(0, pq, maxd+1, mpz_t); for (i = 0; i <= maxd; i++) { mpz_init(pt[i]); mpz_init(ph[i]); mpz_init(pq[i]); } mpz_sub_ui(t, NMOD, 1); mpz_tdiv_q_2exp(power, t, 1); /* We'll pick random "a" values from 1 to 1000M */ mpz_set_ui(t, 1000000000UL); if (mpz_cmp(t, NMOD) > 0) mpz_set(t, NMOD); while (ntries++ < maxtries) { /* pxa = X+a for randomly selected a */ if (ntries <= 2) mpz_set_ui(pxa[0], ntries); /* Simple small values */ else mpz_isaac_urandomm(pxa[0], t); /* Raise pxa to (NMOD-1)/2, all modulo NMOD and g(x) */ polyz_pow_polymod(pt, pxa, pg, &dt, dxa, dg, power, NMOD); /* Subtract 1 and gcd */ mpz_sub_ui(pt[0], pt[0], 1); polyz_gcd(ph, pt, pg, &dh, dt, dg, NMOD); if (dh >= 1 && dh < dg) break; } if (dh >= 1 && dh < dg) { /* Pick the smaller of the two splits to process first */ if (dh <= 2 || dh <= (dg-dh)) { polyz_roots(roots, nroots, maxroots, ph, dh, NMOD); if (*nroots < maxroots) { /* q = g/h, and recurse */ polyz_div(pq, pt, pg, ph, &dq, &dt, dg, dh, NMOD); polyz_roots(roots, nroots, maxroots, pq, dq, NMOD); } } else { polyz_div(pq, pt, pg, ph, &dq, &dt, dg, dh, NMOD); polyz_roots(roots, nroots, maxroots, pq, dq, NMOD); if (*nroots < maxroots) { polyz_roots(roots, nroots, maxroots, ph, dh, NMOD); } } } mpz_clear(t); mpz_clear(power); mpz_clear(pxa[0]); mpz_clear(pxa[1]); for (i = 0; i <= maxd; i++) { mpz_clear(pt[i]); mpz_clear(ph[i]); mpz_clear(pq[i]); } Safefree(pt); Safefree(ph); Safefree(pq); } /* Algorithm 1.6.1 from Cohen, minus step 1. */ void polyz_roots_modp(mpz_t** roots, long *nroots, long maxroots, mpz_t *pP, long dP, mpz_t NMOD) { long i; *nroots = 0; *roots = 0; if (dP == 0) return; /* Do degree 1 or 2 explicitly */ if (dP == 1) { New(0, *roots, 1, mpz_t); mpz_init((*roots)[0]); polyz_root_deg1( (*roots)[0], pP, NMOD ); *nroots = 1; return; } if (dP == 2) { New(0, *roots, 2, mpz_t); mpz_init((*roots)[0]); mpz_init((*roots)[1]); polyz_root_deg2( (*roots)[0], (*roots)[1], pP, NMOD ); *nroots = 2; return; } /* Allocate space for the maximum number of roots (plus 1 for safety) */ New(0, *roots, dP+1, mpz_t); for (i = 0; i <= dP; i++) mpz_init((*roots)[i]); if (maxroots > dP || maxroots == 0) maxroots = dP; polyz_roots(*roots, nroots, maxroots, pP, dP, NMOD); /* This could be just really bad luck. Let the caller handle it. */ /* if (*nroots == 0) croak("failed to find roots\n"); */ /* Clear out space for roots we didn't find */ for (i = *nroots; i <= dP; i++) mpz_clear((*roots)[i]); } #include "class_poly_data.h" const char* poly_class_type_name(int type) { switch (type) { case 1: return "Hilbert"; case 2: return "Weber"; case 3: return "Ramanujan"; default: return "Unknown"; } } int* poly_class_nums(void) { int* dlist; UV i; int degree_offset[256] = {0}; for (i = 1; i < NUM_CLASS_POLYS; i++) if (_class_poly_data[i].D < _class_poly_data[i-1].D) croak("Problem with data file, out of order at D=%d\n", (int)_class_poly_data[i].D); Newz(0, dlist, NUM_CLASS_POLYS + 1, int); /* init degree_offset to total number of this degree */ for (i = 0; i < NUM_CLASS_POLYS; i++) degree_offset[_class_poly_data[i].degree]++; /* set degree_offset to sum of this and all previous degrees. */ for (i = 1; i < 256; i++) degree_offset[i] += degree_offset[i-1]; /* Fill in dlist, sorted */ for (i = 0; i < NUM_CLASS_POLYS; i++) { int position = degree_offset[_class_poly_data[i].degree-1]++; dlist[position] = i+1; } /* Null terminate */ dlist[NUM_CLASS_POLYS] = 0; return dlist; } UV poly_class_poly_num(int i, int *D, mpz_t**T, int* type) { UV degree, j; int ctype; mpz_t t; const char* s; if (i < 1 || i > (int)NUM_CLASS_POLYS) { /* Invalid number */ if (D != 0) *D = 0; if (T != 0) *T = 0; return 0; } i--; /* i now is the index into our table */ degree = _class_poly_data[i].degree; ctype = _class_poly_data[i].type; s = _class_poly_data[i].coefs; if (D != 0) *D = -_class_poly_data[i].D; if (type != 0) *type = ctype; if (T == 0) return degree; New(0, *T, degree+1, mpz_t); mpz_init(t); for (j = 0; j < degree; j++) { unsigned char signcount = (*s++) & 0xFF; unsigned char sign = signcount >> 7; unsigned long count = signcount & 0x7F; if (count == 127) { do { signcount = (*s++) & 0xFF; count += signcount; } while (signcount == 127); } mpz_set_ui(t, 0); while (count-- > 0) { mpz_mul_2exp(t, t, 8); mpz_add_ui(t, t, (unsigned long) (*s++) & 0xFF); } /* Cube the last coefficient of Hilbert polys */ if (j == 0 && ctype == 1) mpz_pow_ui(t, t, 3); if (sign) mpz_neg(t, t); mpz_init_set( (*T)[j], t ); } mpz_clear(t); mpz_init_set_ui( (*T)[degree], 1 ); return degree; } Math-Prime-Util-GMP-0.52/random_prime.c0000644000175000017500000004465613665653651016206 0ustar danadana#include #include #include #include #include #include #include "ptypes.h" #include "random_prime.h" #include "utility.h" #include "primality.h" #include "gmp_main.h" #include "isaac.h" #include "prime_iterator.h" static char pr[31] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127}; void mpz_random_nbit_prime(mpz_t p, UV n) { switch (n) { case 0: case 1: mpz_set_ui(p, 0); return; case 2: mpz_set_ui(p, pr[ 0+isaac_rand(2)]); return; case 3: mpz_set_ui(p, pr[ 2+isaac_rand(2)]); return; case 4: mpz_set_ui(p, pr[ 4+isaac_rand(2)]); return; case 5: mpz_set_ui(p, pr[ 6+isaac_rand(5)]); return; case 6: mpz_set_ui(p, pr[11+isaac_rand(7)]); return; case 7: mpz_set_ui(p, pr[18+isaac_rand(13)]); return; default: break; } /* For 32-bit inputs, use fast trivial method */ if (n <= 32) { uint32_t mask = (0xFFFFFFFFU >> (34-n)) << 1, base = mask+3; do { mpz_set_ui(p, base | (isaac_rand32() & mask)); } while (!_GMP_is_prob_prime(p)); } else { #if 0 do { /* Trivial method. */ mpz_isaac_urandomb(p, n); mpz_setbit(p, n-1); mpz_setbit(p, 0); } while (!_GMP_is_prob_prime(p)); #else mpz_t base; /* Fouque+Tibouchi Alg 1, without modulo checks */ mpz_init(base); if (n > 33) { mpz_isaac_urandomb(base, n-33); mpz_mul_2exp(base,base,1); } mpz_setbit(base, n-1); mpz_setbit(base, 0); do { mpz_set_ui(p, isaac_rand32()); mpz_mul_2exp(p, p, n-32); mpz_ior(p, p, base); } while (!_GMP_is_prob_prime(p)); mpz_clear(base); #endif } } /* PRIMEINC: pick random value, select next prime. */ /* Fast but bad distribution. */ static int _random_prime_primeinc(mpz_t p, mpz_t lo, mpz_t hi) { mpz_t r, t; mpz_init(t); mpz_init(r); mpz_sub(r, hi, lo); mpz_isaac_urandomm(t, r); mpz_clear(r); mpz_add(t, t, lo); mpz_sub_ui(t, t, 1); _GMP_next_prime(t); if (mpz_cmp(t,hi) > 0) { mpz_sub_ui(t, lo, 1); _GMP_next_prime(t); if (mpz_cmp(t,hi) > 0) { mpz_clear(t); return 0; } } mpz_set(p, t); mpz_clear(t); return 1; } /* TRIVIAL: pick random values until one is prime */ /* Perfect distribution. */ static int _random_prime_trivial(mpz_t p, mpz_t lo_in, mpz_t hi_in) { mpz_t r, t, lo, hi; int res = 0, tries = 10000; if (mpz_cmp_ui(hi_in,2) < 0 || mpz_cmp(lo_in,hi_in) > 0) return 0; mpz_init_set(lo, lo_in); mpz_init_set(hi, hi_in); if (mpz_cmp_ui(lo,2) <= 0) { mpz_set_ui(lo,1); } else if (mpz_even_p(lo)) { mpz_add_ui(lo,lo,1); } if (mpz_cmp_ui(hi,2) <= 0) { mpz_set_ui(hi,1); } else if (mpz_even_p(hi)) { mpz_sub_ui(hi,hi,1); } /* lo and hi are now odd */ if (mpz_cmp(lo,hi) >= 0) { if (mpz_cmp(lo,hi) > 0) { /* null range */ } else if (mpz_cmp_ui(lo,1) == 0) { mpz_set_ui(p,2); res = 1; } else if (_GMP_is_prob_prime(lo)) { mpz_set(p,lo); res = 1; } mpz_clear(hi); mpz_clear(lo); return res; } /* lo and hi are now odd and at least one odd between them */ mpz_init(t); mpz_init(r); mpz_sub(r, hi, lo); mpz_tdiv_q_2exp(r, r, 1); mpz_add_ui(r,r,1); do { mpz_isaac_urandomm(t, r); mpz_mul_2exp(t, t, 1); mpz_add(t, t, lo); if (mpz_cmp_ui(t,1) == 0) mpz_set_ui(t,2); /* map 1 back to 2 */ } while (!_GMP_is_prob_prime(t) && --tries > 0); if (tries > 0) { mpz_set(p, t); res = 1; } else { /* We couldn't find anything. Perhaps no primes in range. */ res = _random_prime_primeinc(p, lo, hi); } mpz_clear(r); mpz_clear(t); mpz_clear(hi); mpz_clear(lo); return res; } /* Set p to a random prime between lo and hi inclusive */ int mpz_random_prime(mpz_t p, mpz_t lo, mpz_t hi) { return _random_prime_trivial(p,lo,hi); } void mpz_random_ndigit_prime(mpz_t p, UV n) { mpz_t lo, hi; switch (n) { case 0: mpz_set_ui(p,0); return; case 1: mpz_set_ui(p, pr[isaac_rand(4)]); return; case 2: mpz_set_ui(p, pr[4+isaac_rand(21)]); return; default: break; } mpz_init_set_ui(lo,10); mpz_pow_ui(lo, lo, n-1); mpz_init(hi); mpz_mul_ui(hi, lo, 10); if (!mpz_random_prime(p, lo, hi)) croak("Failed to find %"UVuf" digit prime\n", n); mpz_clear(lo); mpz_clear(hi); } /* Random number rop such that 2*mult*rop+1 has nbits bits. */ static void _rand_in_bit_interval(mpz_t rop, UV nbits, mpz_t mult) { mpz_t t, lo, hi; mpz_init(t); mpz_init(lo); mpz_init(hi); mpz_mul_ui(t, mult, 2); mpz_setbit(lo, nbits-1); mpz_sub_ui(lo, lo, 1); mpz_cdiv_q(lo, lo, t); /* lo = ceil(2^(nbits-1)-1 / (2*mult)) */ mpz_setbit(hi, nbits); mpz_sub_ui(hi, hi, 2); mpz_fdiv_q(hi, hi, t); /* hi = floor(2^nbits-2 / (2*mult)) */ mpz_sub(t, hi, lo); mpz_isaac_urandomm(rop, t); mpz_add(rop, rop, lo); mpz_clear(t); mpz_clear(lo); mpz_clear(hi); } #define _SAFE_REJECT(q, p1, p2, p3, p4, p5) \ { uint32_t qm = mpz_fdiv_ui(q, p1*p2*p3*p4*p5); \ if ((qm % p1) == 0 || (qm % p1) == (p1>>1)) continue; \ if ((qm % p2) == 0 || (qm % p2) == (p2>>1)) continue; \ if ((qm % p3) == 0 || (qm % p3) == (p3>>1)) continue; \ if ((qm % p4) == 0 || (qm % p4) == (p4>>1)) continue; \ if ((qm % p5) == 0 || (qm % p5) == (p5>>1)) continue; \ } void mpz_random_safe_prime(mpz_t p, UV nbits) { static const unsigned char small_safe[] = {5,7,11,23,47,59,83,107}; mpz_t q, base; uint32_t qmod, PR, tlimit; int verbose; PRIME_ITERATOR(iter); switch (nbits) { case 0: case 1: case 2: mpz_set_ui(p, 0); return; case 3: mpz_set_ui(p, small_safe[ 0+isaac_rand(2)]); return; case 4: mpz_set_ui(p, 11); return; case 5: mpz_set_ui(p, 23); return; case 6: mpz_set_ui(p, small_safe[ 4+isaac_rand(2)]); return; case 7: mpz_set_ui(p, small_safe[ 6+isaac_rand(2)]); return; default: break; } mpz_init(q); mpz_init(base); if (nbits > 35) { mpz_isaac_urandomb(base, nbits-35); mpz_mul_2exp(base,base,2); } mpz_setbit(base, nbits-1); mpz_setbit(base, 1); mpz_setbit(base, 0); verbose = get_verbose_level(); tlimit = (nbits <= 512000) ? (nbits*(nbits/64.0) + 0.5) : 4000000000U; while (1) { /* 1. Generate random nbit p */ if (nbits > 35) { mpz_set_ui(p, isaac_rand32()); mpz_mul_2exp(p, p, nbits-33); } else { mpz_isaac_urandomb(p, nbits-3); mpz_mul_2exp(p, p, 2); } mpz_ior(p, p, base); /* 2. p = 2q+1 => q = p >> 1 */ mpz_div_2exp(q, p, 1); /* 3. Fast compositeness pretests for both q and p at the same time. */ qmod = mpz_fdiv_ui(q, 1155UL); if ( (qmod % 3) != 2 || (qmod % 5) == 0 || (qmod % 7) == 0 || (qmod % 11) == 0 || (qmod % 5) == 2 || (qmod % 7) == 3 || (qmod % 11) == 5) continue; if (nbits < 16) { /* 4. Pretest that p isn't easily composite */ if (!primality_pretest(p)) continue; /* 5. Pretest that q isn't easily composite */ if (!primality_pretest(q)) continue; } else { _SAFE_REJECT(q, 13U, 17U, 19U, 23U, 29U); _SAFE_REJECT(q, 31U, 37U, 41U, 43U, 47U); _SAFE_REJECT(q, 53U, 59U, 61U, 67U, 71U); _SAFE_REJECT(q, 73U, 79U, 83U, 89U, 97U); if (tlimit >= 101) { prime_iterator_setprime(&iter, PR = 101); while (PR <= tlimit) { uint32_t qm = mpz_fdiv_ui(q, PR); if (qm == 0 || qm == (PR>>1)) break; PR = prime_iterator_next(&iter); } if (PR <= tlimit) continue; } } if (verbose > 2) { printf("."); fflush(stdout); } /* 6. BPSW on q and M-R base 2 on p. */ if (!is_euler_plumb_pseudoprime(q)) continue; /* Start faster */ if (verbose > 2) { printf("+"); fflush(stdout); } if (!miller_rabin_ui(p, 2)) continue; if (verbose > 2) { printf("*"); fflush(stdout); } if (!_GMP_is_lucas_pseudoprime(q, 2)) continue; if (nbits > 64 && !miller_rabin_ui(q, 2)) continue; /* Verify fast test */ break; } mpz_clear(base); mpz_clear(q); prime_iterator_destroy(&iter); } /* Gordon's algorithm */ void mpz_random_strong_prime(mpz_t p, UV nbits) { mpz_t S, T, R, P0, t, i, j; UV rbits, sbits, tbits; if (nbits < 128) croak("random_strong_prime, bits must be >= 128"); if (nbits < 256) { rbits = ((nbits+1) >> 1) - 2; sbits = (nbits >> 1) - 20; tbits = rbits - 20; } else { UV N1, N2; { /* Calculate FIPS 186-4 C.10 recommended parameter */ UV t_, l2_; for (l2_ = 1, t_ = nbits; t_ >>= 1; ) l2_++; N1 = (nbits/2)-l2_-7; N2 = N1/2; } if (N1 > 200) N1 = 201; if (N2 > 100) N2 = 101; if (N2 < 100) N2 += N1/4; rbits = sbits = N1; tbits = N2; } mpz_init(S); mpz_init(T); mpz_init(R); mpz_init(P0); mpz_init(t); mpz_init(i); mpz_init(j); while (1) { mpz_random_nbit_prime(S, sbits); mpz_random_nbit_prime(T, tbits); _rand_in_bit_interval(i, rbits, T); while (1) { mpz_mul(t, i, T); mpz_mul_ui(t, t, 2); mpz_add_ui(R, t, 1); /* R = 2*i*T+1 */ if (_GMP_is_prob_prime(R)) break; mpz_add_ui(i,i,1); } mpz_sub_ui(t, R, 2); mpz_powm(P0, S, t, R); mpz_mul_ui(P0, P0, 2); mpz_mul(P0, P0, S); mpz_sub_ui(P0, P0, 1); mpz_mul(i, R, S); mpz_mul_ui(t, i, 2); _rand_in_bit_interval(j, nbits, i); while (1) { mpz_mul(p, j, t); mpz_add(p, p, P0); /* p = 2*j*R*S+p0 */ if (mpz_sizeinbase(p,2) > nbits) break; if (_GMP_is_prob_prime(p)) { mpz_clear(t); mpz_clear(i); mpz_clear(j); mpz_clear(S); mpz_clear(T); mpz_clear(R); mpz_clear(P0); /* p-1 has factor R. p+1 has factor S. r-1 has factor T. */ return; } mpz_add_ui(j,j,1); } } } /*===========================================================================*/ /* Proven primes (Maurer and Shawe-Taylor */ /*===========================================================================*/ #define MAKE_PROOF_START(proofptr, n, nums) \ if (proofptr) { \ char* thisproof, *thisptr; \ int prevlen = (*proofptr == 0) ? 0 : strlen(*proofptr); \ int thislen = (5 + mpz_sizeinbase(n,10)) * nums + 200; \ New(0, thisproof, thislen + prevlen + 1, char); \ thisptr = thisproof; \ thisptr += gmp_sprintf(thisptr, #define MAKE_PROOF_END(proofptr) \ ); \ if (*proofptr) { \ thisptr += gmp_sprintf(thisptr,"\n"); \ strcat(thisptr, *proofptr); \ Safefree(*proofptr); \ } \ *proofptr = thisproof; \ } #define USE_THEOREM5 0 void mpz_random_maurer_prime(mpz_t n, UV k, char** proofptr) { mpz_t t, a, q, I, R; double m, r, minr = USE_THEOREM5 ? 0.334 : 0.5; int i, verbose = get_verbose_level(); /* We could use safely use k <= 64. */ if (k <= 32) return mpz_random_nbit_prime(n, k); r = minr; /* size of q relative to size of n */ m = 20; /* always use at least this many bits of randomness */ if (k > 2*m) { do { double s = ((double)isaac_rand32()) / ((double)4294967295.0); /* [0,1] */ r = pow(2,s-1); /* exp2 is C99 */ #if USE_THEOREM5 r = 0.334 + 1.332 * (r-0.5); /* Stretch r to cover 0.334 - 1 */ #endif } while ((k-r*k) <= m); } #if 0 /* Improve efficiency for less than ideal distribution */ r -= 0.25; if (r < minr) r = minr; #endif mpz_init(t); mpz_init(a); mpz_init(q); mpz_init(I); mpz_init(R); mpz_random_maurer_prime(q, (UV)(r*k)+1, proofptr); mpz_setbit(I, k-1); mpz_mul_ui(t, q, 2); mpz_fdiv_q(I, I, t); /* I = floor(2^(k-1) / 2q) */ if (verbose && verbose != 3) { gmp_printf("r = %lf k = %lu q = %Zd I = %Zd\n",r,k,q,I); fflush(stdout); } while (1) { if (verbose > 2) { printf("."); fflush(stdout); } mpz_isaac_urandomm(R, I); /* [0, I-1] */ mpz_add(R, R, I); /* [I, 2I-I] */ mpz_add_ui(R, R, 1); /* [I+1,2I] */ #if USE_THEOREM5 mpz_setbit(R, 0); /* We need R to be odd */ #endif mpz_mul(n, R, q); mpz_mul_ui(n,n,2); mpz_add_ui(n,n,1); /* n = 2Rq+1 */ if (!primality_pretest(n)) continue; if (verbose > 2) { printf("+"); fflush(stdout); } /* if (!is_euler_plumb_pseudoprime(n)) continue; */ if (!miller_rabin_ui(n,2)) continue; /* n is a base-2 psp and probably prime */ if (verbose > 2) { printf("*"); fflush(stdout); } /* See if we can use BLS75 theorem 3 */ mpz_mul_ui(t, q, 2); mpz_add_ui(t, t, 1); mpz_mul(t, t, t); if (mpz_cmp(t, n) > 0) { for (i = 0; i < 20; i++) { mpz_set_ui(a, pr[i]); /* Check A^R mod N != N-1 */ mpz_powm(a, a, R, n); mpz_add_ui(t,a,1); if (mpz_cmp(t, n) == 0) continue; /* Check A^{Rq} mod N == N-1 */ mpz_powm(a, a, q, n); mpz_add_ui(t,a,1); if (mpz_cmp(t, n) != 0) continue; if (verbose > 2) { printf("(%"UVuf")",k); fflush(stdout); } /* Ensure all results passed BPSW. ~20% speed penalty. */ if (!_GMP_is_lucas_pseudoprime(n,2)) croak("Maurer internal failure"); MAKE_PROOF_START(proofptr, n, 3) "Type BLS3\nN %Zd\nQ %Zd\nA %u\n", n, q, pr[i] MAKE_PROOF_END(proofptr) mpz_clear(t); mpz_clear(a); mpz_clear(q); mpz_clear(I); mpz_clear(R); return; } /* Blast, we couldn't find the right 'a' value fast enough. Try a new n. */ continue; } /* Our q is smaller than sqrt(n)/2-1, so use BLS75 theorem 5. */ #if !USE_THEOREM5 croak("random_maurer_prime: internal bit size error"); #else /* Check for obvious generation problems. */ if (mpz_even_p(R)) continue; if (mpz_cmp_ui(R, 1) <= 0) continue; mpz_gcd(t, q, R); if (mpz_cmp_ui(t, 1) != 0) continue; /* Theorem 5 with m = 2, assuming (I) which we'll check after this. */ { mpz_t ts, tr, F; mpz_init(ts); mpz_init(tr); mpz_init(F); mpz_mul_ui(F, q, 2); /* Calculate r,s from page 624 of BLS75 */ mpz_mul_ui(t, F, 2); mpz_tdiv_qr(ts, tr, R, t); /* Verify the r,s condition */ mpz_mul(t, tr, tr); mpz_submul_ui(t, ts, 8); /* t = r^2-8s */ if (mpz_sgn(ts) != 0 && mpz_perfect_square_p(t)) { /* printf("fail r/s check\n"); */ mpz_clear(ts); mpz_clear(tr); mpz_clear(F); continue; } /* Verify size of N with m=2. a,t are temps. Should not fail. */ mpz_mul(t, F, tr); mpz_add_ui(a, t, 1); /* a = rF + 1 */ mpz_sub_ui(tr, tr, 1); mpz_mul(t, F, F); mpz_mul_ui(t, t, 2); mpz_mul(t, t, tr); mpz_add(a, a, t); /* a = (r-1)2FF + rF + 1 */ mpz_mul(t, F, F); mpz_mul(t, t, F); mpz_mul_ui(t, t, 4); mpz_add(a, a, t); /* a = 4FFF + (r-1)2FF + rF + 1 */ mpz_add_ui(t, F, 1); mpz_clear(tr); mpz_clear(ts); mpz_clear(F); if (mpz_cmp(n,a) >= 0) { /* printf("fail N size check\n"); */ continue; } /* Check divisibility required to use m=2 */ if (mpz_divisible_p(n,t)) { /* printf("fail N divisiblity check\n"); */ continue; } } #define SET_A_CHECK_PSP(i) \ mpz_set_ui(a, pr[i]); \ if (apsp[i] == -1) \ { mpz_sub_ui(t,n,1); mpz_powm(t,a,t,n); apsp[i] = (mpz_cmp_ui(t,1) == 0); } \ if (apsp[i] == 0) continue; #define CHECK_GCD(t) \ mpz_powm(t, a, t, n); mpz_sub_ui(t, t, 1); mpz_gcd(t, t, n); \ if (mpz_cmp_ui(t,1) != 0) continue; { int j, apsp[20]; /* apsp caches psp check. Init all to -1. */ for (i = 0; i < 20; i++) apsp[i] = -1; apsp[0] = 1; /* We passed a base 2 psp test to get here */ /* Find an a that works for p=2 */ for (i = 0; i < 20; i++) { SET_A_CHECK_PSP(i); mpz_mul(t, q, R); CHECK_GCD(t); /* We are good for p=2. Find an a for p=q. */ for (j = 0; j < 20; j++) { SET_A_CHECK_PSP(j); mpz_mul_ui(t, R, 2); CHECK_GCD(t); /* Success */ if (verbose > 2) { printf("(%lu)",k); fflush(stdout); } if (i == 0 && j == 0) { MAKE_PROOF_START(proofptr, n, 2) "Type BLS5\nN %Zd\nQ[1] %Zd\n----\n", n, q MAKE_PROOF_END(proofptr) } else { MAKE_PROOF_START(proofptr, n, 2) "Type BLS5\nN %Zd\nQ[1] %Zd\nA[0] %lu\nA[1] %lu\n----\n", n, q, pr[i], pr[j] MAKE_PROOF_END(proofptr) } /* Ensure all results passed BPSW. ~20% speed penalty. */ if (!_GMP_is_lucas_pseudoprime(n,2)) croak("Maurer internal failure"); mpz_clear(t); mpz_clear(a); mpz_clear(q); mpz_clear(I); mpz_clear(R); return; } break; /* Failed for p=q */ } } /* Blast, we couldn't find the right 'a' value fast enough. Try a new n. */ #endif } } /* FIPS 186-4 algorithm but using our CSPRNG (ISAAC) instead of SHA-256 */ void mpz_random_shawe_taylor_prime(mpz_t c, UV k, char** proofptr) { mpz_t c0, t, u, a, z; if (k <= 32) return mpz_random_nbit_prime(c, k); mpz_init(c0); mpz_init(t); mpz_init(u); mpz_init(a); mpz_init(z); mpz_random_shawe_taylor_prime(c0, 1 + (k+1)/2, proofptr); mpz_isaac_urandomb(t, k-1); mpz_setbit(t,k-1); /* Steps 18-21: t a random k-bit integer */ mpz_mul_ui(u, c0, 2); mpz_cdiv_q(t, t, u); /* Step 22: set t based on random integer */ while (1) { /* Steps 23-24 */ mpz_mul_ui(u, c0, 2); /* u = 2c0 */ mpz_mul(c, u, t); mpz_add_ui(c, c, 1); /* c = 2tc0+1 */ if (mpz_sizeinbase(c,2) > k) { mpz_set_ui(t,0); mpz_setbit(t,k-1); mpz_cdiv_q(t, t, u); mpz_mul(c, u, t); mpz_add_ui(c, c, 1); } /* Don't bother with Steps 26-31 for obvious composites */ if (primality_pretest(c) && miller_rabin_ui(c,2)) { /* Steps 26-29 */ mpz_sub_ui(u, c, 3); mpz_isaac_urandomm(a, u); mpz_add_ui(a, a, 2); /* Step 30 */ mpz_mul_ui(u, t, 2); mpz_powm(z, a, u, c); /* Step 31 */ mpz_sub_ui(u, z, 1); mpz_gcd(u, u, c); if (mpz_cmp_ui(u, 1) == 0) { mpz_powm(u, z, c0, c); if (mpz_cmp_ui(u, 1) == 0) { /* Ensure all results passed BPSW. ~20% speed penalty. */ if (!_GMP_is_lucas_pseudoprime(c,2)) croak("ST internal failure"); MAKE_PROOF_START(proofptr, c, 3) "Type Pocklington\nN %Zd\nQ %Zd\nA %Zd\n", c, c0, a MAKE_PROOF_END(proofptr) mpz_clear(c0); mpz_clear(t); mpz_clear(u); mpz_clear(a); mpz_clear(z); return; } } } mpz_add_ui(t,t,1); } } /*===========================================================================*/ Math-Prime-Util-GMP-0.52/META.yml0000644000175000017500000000174713674072603014621 0ustar danadana--- abstract: 'Utilities related to prime numbers, using GMP' author: - 'Dana A Jacobsen ' build_requires: ExtUtils::MakeMaker: '0' Math::BigInt: '1.88' Test::More: '0.45' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Math-Prime-Util-GMP no_index: directory: - t - inc provides: Math::Prime::Util::GMP: file: lib/Math/Prime/Util/GMP.pm version: '0.52' recommends: Math::Prime::Util: '0.68' requires: Carp: '0' Exporter: '5.57' Fcntl: '0' XSLoader: '0.01' base: '0' perl: '5.006002' resources: homepage: https://github.com/danaj/Math-Prime-Util-GMP license: http://dev.perl.org/licenses/ repository: https://github.com/danaj/Math-Prime-Util-GMP version: '0.52' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Math-Prime-Util-GMP-0.52/real.c0000644000175000017500000010115413670326321014423 0ustar danadana#include #include #include #include #include "ptypes.h" #include "real.h" #include "prime_iterator.h" #include "primality.h" #include "factor.h" #define FUNC_mpz_logn 1 #include "utility.h" static unsigned long precbits(mpf_t x, unsigned long prec, unsigned long add) { unsigned long bits1 = mpf_get_prec(x), bits2 = DIGS2BITS(prec); return add + ((bits1 > bits2) ? bits1 : bits2); } /*****************************************************************************/ /* Put result into char with correct number of digits */ static char* _str_real(mpf_t f, unsigned long prec) { char* out; unsigned long k; int neg = (mpf_sgn(f) < 0); if (neg) mpf_neg(f, f); for (k = 0; mpf_cmp_ui(f, 1000000000U) >= 0; k += 9) mpf_div_ui(f, f, 1000000000U); for (; mpf_cmp_ui(f, 1) >= 0; k++) mpf_div_ui(f, f, 10); New(0, out, 10+((k>prec) ? k : prec), char); gmp_sprintf(out, "%.*Ff", prec, f); if (out[0] == '0') { memmove(out, out+2, prec); } else { /* We rounded up. Treat like 0.1 with one larger k */ memmove(out+1, out+2, prec); k++; } if (k >= prec) { /* No decimal */ if (k-prec < 10) { memset(out+prec, '0', k-prec); prec=k-1; } else { out[prec++] = 'E'; prec += sprintf(out+prec, "%lu", k-prec+1); } } else { /* insert decimal in correct place */ memmove(out+k+1, out+k, prec-k); out[k] = '.'; } out[prec+1]='\0'; if (neg) { memmove(out+1, out, prec+2); out[0] = '-'; } return out; } static char* _frac_real(mpz_t num, mpz_t den, unsigned long prec) { #if 0 char* out; mpf_t fnum, fden, res; unsigned long numbits = mpz_sizeinbase(num, 2); unsigned long denbits = mpz_sizeinbase(den, 2); unsigned long numdigs = mpz_sizeinbase(num, 10); unsigned long dendigs = mpz_sizeinbase(den, 10); mpf_init2(fnum, 1 + numbits); mpf_set_z(fnum, num); mpf_init2(fden, 1 + denbits); mpf_set_z(fden, den); mpf_init2(res, (unsigned long) (8 + (numbits-denbits+1) + prec*3.4) ); mpf_div(res, fnum, fden); mpf_clear(fnum); mpf_clear(fden); New(0, out, (10+numdigs-dendigs)+prec, char); gmp_sprintf(out, "%.*Ff", (int)(prec), res); mpf_clear(res); return out; #else char* out; mpf_t fnum, fden; unsigned long bits = 32+(unsigned long)(prec*3.32193); mpf_init2(fnum, bits); mpf_set_z(fnum, num); mpf_init2(fden, bits); mpf_set_z(fden, den); mpf_div(fnum, fnum, fden); out = _str_real(fnum, prec); mpf_clear(fden); mpf_clear(fnum); return out; #endif } /********************* Riemann Zeta and Riemann R *********************/ static void _bern_real_zeta(mpf_t bn, mpz_t zn, unsigned long prec); static unsigned long zeta_n = 0; static mpz_t* zeta_d = 0; void free_borwein_zeta(void) { unsigned long i; if (zeta_n > 0) { for (i = 0; i <= zeta_n; i++) mpz_clear(zeta_d[i]); Safefree(zeta_d); zeta_n = 0; } } static void _borwein_d(unsigned long D) { mpz_t t1, t2, t3, sum; unsigned long i, n = 3 + (1.31 * D); if (zeta_n >= n) return; free_borwein_zeta(); n += 10; /* Add some in case we want a few more digits later */ zeta_n = n; New(0, zeta_d, n+1, mpz_t); mpz_init(t1); mpz_init(t2); mpz_init(t3); mpz_init_set_ui(sum, 1); mpz_init_set(zeta_d[0], sum); mpz_fac_ui(t1, n); mpz_fac_ui(t2, n); for (i = 1; i <= n; i++) { mpz_mul_ui(t1, t1, 2*(n+i-1)); /* We've pulled out a 2 from t1 and t2 */ mpz_divexact_ui(t2, t2, n-i+1); mpz_mul_ui(t2, t2, (2*i-1) * i); mpz_divexact(t3, t1, t2); mpz_add(sum, sum, t3); mpz_init_set(zeta_d[i], sum); } mpz_clear(sum); mpz_clear(t3); mpz_clear(t2); mpz_clear(t1); } /* MPFR does some shortcuts, then does an in-place version of Borwein 1991. * It's quite clever, and has the advantage of not using the statics. Our * code can be a little faster in some cases, slower in others. They * certainly have done more rigorous error bounding, allowing fewer guard * bits and earlier loop exits. * * For real values, we use our home-grown mpf_pow function, which is slower * at high precisions compared to MPFR or Pari. */ static void _zeta(mpf_t z, mpf_t f, unsigned long prec) { unsigned long k, S, p; mpf_t s, tf, term; mpz_t t1; if (mpf_cmp_ui(f,1) == 0) { mpf_set_ui(z, 0); return; } /* Shortcut if we know all prec terms are zeros. */ if (mpf_cmp_ui(f, 1+3.3219281*prec) >= 0 || mpf_cmp_ui(f, mpf_get_prec(z)) > 0) { mpf_set_ui(z,1); return; } S = (mpf_integer_p(f) && mpf_fits_ulong_p(f)) ? mpf_get_ui(f) : 0; /* Negative integers using Bernoulli */ if (S == 0 && mpf_integer_p(f) && mpf_fits_slong_p(f) && mpf_sgn(f) != 0) { S = -mpf_get_si(f); if (!(S & 1)) { /* negative even integers are zero */ mpf_set_ui(z,0); } else { /* negative odd integers are -B_(n+1)/(n+1) */ mpz_t n; mpz_init_set_ui(n, S+1); _bern_real_zeta(z, n, prec); mpf_div_ui(z, z, S+1); mpf_neg(z,z); mpz_clear(n); } return; } mpf_init2(s, 96+mpf_get_prec(z)); mpf_set(s, f); mpf_init2(tf, 96+mpf_get_prec(z)); mpf_init2(term, 96+mpf_get_prec(z)); mpz_init(t1); if (S && S <= 14 && !(S & 1)) { /* Small even S can be done with Pi */ unsigned long div[]={0,6,90,945,9450,93555,638512875,18243225}; const_pi(z, prec); mpf_pow_ui(z, z, S); if (S == 12) mpf_mul_ui(z, z, 691); if (S == 14) mpf_mul_ui(z, z, 2); mpf_div_ui(z, z, div[S/2]); } else if (mpf_cmp_ui(f, 3+prec*2.15) > 0) { /* Only one term (3^s < prec) */ if (S) { mpf_set_ui(term, 1); mpf_mul_2exp(term, term, S); } else { mpf_set_ui(term, 2); mpf_pow(term, term, s); } mpf_sub_ui(tf, term, 1); mpf_div(z, term, tf); } else if ( (mpf_cmp_ui(f,20) > 0 && mpf_cmp_ui(f, prec/3.5) > 0) || (prec > 500 && (mpz_ui_pow_ui(t1, 8*prec, S), mpz_sizeinbase(t1,2) > (20+3.3219281*prec))) ) { /* Basic formula, for speed (also note only valid for > 1) */ PRIME_ITERATOR(iter); mpf_set_ui(z, 1); for (p = 2; p <= 1000000000; p = prime_iterator_next(&iter)) { if (S) { mpz_ui_pow_ui(t1, p, S); mpf_set_z(term, t1); } else { mpf_set_ui(tf, p); mpf_pow(term, tf, s); mpz_set_f(t1, term); } if (mpz_sizeinbase(t1,2) > (20+3.3219281*prec)) break; mpf_sub_ui(tf, term, 1); mpf_div(term, term, tf); mpf_mul(z, z, term); } prime_iterator_destroy(&iter); } else { /* TODO: negative non-integer inputs past -20 or so are very wrong. */ _borwein_d( (mpf_cmp_d(f,-3.0) >= 0) ? prec : 80+2*prec ); mpf_set_ui(z, 0); for (k = 0; k <= zeta_n-1; k++) { if (S) { mpz_ui_pow_ui(t1, k+1, S); mpf_set_z(term, t1); } else { mpf_set_ui(tf, k+1); mpf_pow(term, tf, s); } mpz_sub(t1, zeta_d[k], zeta_d[zeta_n]); mpf_set_z(tf, t1); mpf_div(term, tf, term); if (k&1) mpf_sub(z, z, term); else mpf_add(z, z, term); } mpf_set_z(tf, zeta_d[zeta_n]); mpf_div(z, z, tf); if (S) { mpf_set_ui(tf, 1); mpf_div_2exp(tf, tf, S-1); } else { mpf_set_ui(term, 2); mpf_ui_sub(tf, 1, s); mpf_pow(tf, term, tf); } mpf_ui_sub(tf, 1, tf); mpf_div(z, z, tf); mpf_neg(z, z); } mpz_clear(t1); mpf_clear(term); mpf_clear(tf); mpf_clear(s); } static void _zetaint(mpf_t z, unsigned long s, unsigned long prec) { mpf_t f; if (s <= 1) { mpf_set_ui(z, 0); } else if (s >= (1+3.3219281*prec) || s > mpf_get_prec(z)) { /* Shortcut if we know all prec terms are zeros. */ mpf_set_ui(z,1); } else { mpf_init2(f, mpf_get_prec(z)); mpf_set_ui(f, s); _zeta(z, f, prec); mpf_clear(f); } } static void _riemann_r(mpf_t r, mpf_t n, unsigned long prec) { mpf_t logn, sum, term, part_term, tol, tf; unsigned long k, bits = precbits(r, prec, 7); mpf_init2(logn, bits); mpf_init2(sum, bits); mpf_init2(term, bits); mpf_init2(part_term, bits); mpf_init2(tol, bits); mpf_init2(tf, bits); mpf_log(logn, n); mpf_set_ui(tol, 10); mpf_pow_ui(tol, tol, prec); mpf_ui_div(tol,1,tol); #if 1 /* Standard Gram Series */ mpf_set_ui(part_term, 1); mpf_set_ui(sum, 1); for (k = 1; k < 10000; k++) { mpf_mul(part_term, part_term, logn); mpf_div_ui(part_term, part_term, k); _zetaint(tf, k+1, prec+1); mpf_mul_ui(tf, tf, k); mpf_div(term, part_term, tf); mpf_add(sum, sum, term); mpf_abs(term, term); mpf_mul(tf, sum, tol); if (mpf_cmp(term, tf) <= 0) break; } #else /* Accelerated (about half the number of terms needed) */ /* See: http://mathworld.wolfram.com/GramSeries.html (5) * Ramanujan's G (3) and its restatements (5) and (6) are equal, * but G is only asymptotically equal to R (restated in (4) as per Gram). * To avoid confusion we won't use this. Too bad, as it can be 2x faster. */ mpf_set(part_term, logn); mpf_set_ui(sum, 0); _zetaint(tf, 2, prec); mpf_div(term, part_term, tf); mpf_add(sum, sum, term); for (k = 2; k < 1000000; k++) { if (mpf_cmp(part_term, tol) <= 0) break; mpf_mul(tf, logn, logn); if (k < 32768) { mpf_div_ui(tf, tf, (2*k-2) * (2*k-1)); } else { mpf_div_ui(tf, tf, 2*k-2); mpf_div_ui(tf, tf, 2*k-1); } mpf_mul(part_term, part_term, tf); _zetaint(tf, 2*k, prec); mpf_mul_ui(tf, tf, 2*k-1); mpf_div(term, part_term, tf); mpf_add(sum, sum, term); } mpf_mul_ui(sum, sum, 2); mpf_add_ui(sum, sum, 1); #endif mpf_set(r, sum); mpf_clear(tf); mpf_clear(tol); mpf_clear(part_term); mpf_clear(term); mpf_clear(sum); mpf_clear(logn); } /*********************** Constants: Euler, Pi ***********************/ /* See: * http://numbers.computation.free.fr/Constants/Gamma/gamma.pdf * https://www.ginac.de/CLN/binsplit.pdf (3.1) * https://www-fourier.ujf-grenoble.fr/~demailly/manuscripts/gamma_gazmath_eng.pdf * Pari/GP trans1.c * * Mortici and Chen (2013) have a O(n^-12) method, but it still too slow. * https://link.springer.com/content/pdf/10.1186/1029-242X-2013-222.pdf * * The Stieltjes zeta method isn't terrible but too slow for large n. * * We use the same series method as Pari, running about 3x faster. * We should use binary splitting as it still isn't really fast. * Each doubling of digits increases time by 4x. */ static void _const_euler(mpf_t gamma, unsigned long prec) { const double log10 = 2.3025850929940456840179914546843642076L; const unsigned long maxsqr = (1UL << (4*sizeof(unsigned long))) - 1; unsigned long bits = 40 + DIGS2BITS(prec); unsigned long x = floor(2 + prec * log10/4); unsigned long N = ceil(1 + 3.591121477*x - 0.195547*log(x)); unsigned long xx = x*x; unsigned long k; mpf_t u, v, a, b, fxx; if (prec <= 100) { mpf_set_str(gamma, "0.5772156649015328606065120900824024310421593359399235988057672348848677267776646709369470632917467495", 10); return; } mpf_init2(u, bits); mpf_init2(v, bits); mpf_init2(a, bits); mpf_init2(b, bits); /* * Brent and McMillan (1980) algorithm B1. * http://www.ams.org/journals/mcom/1980-34-149/S0025-5718-1980-0551307-4/ */ mpf_set_ui(u, x); mpf_log(u, u); mpf_neg(u, u); mpf_set(a, u); mpf_set_ui(b, 1); mpf_set_ui(v, 1); if (x <= maxsqr && N <= maxsqr) { for (k = 1; k <= N; k++) { mpf_mul_ui(b, b, xx); mpf_div_ui(b, b, k*k); /* B_k = B_{k-1} * x^2 / k^2 */ mpf_mul_ui(a, a, xx); mpf_div_ui(a, a, k); mpf_add(a, a, b); mpf_div_ui(a, a, k); /* A_k = (A_{k-1} * x^2 / k + B_k) / k */ mpf_add(u, u, a); mpf_add(v, v, b); } } else { mpf_init2(fxx,bits); mpf_set_ui(fxx, x); mpf_mul(fxx, fxx, fxx); for (k = 1; k <= N; k++) { mpf_mul(b,b,fxx); if (k <= maxsqr) { mpf_div_ui(b,b,k*k); } else { mpf_div_ui(b,b,k); mpf_div_ui(b,b,k); } mpf_mul(a,a,fxx); mpf_div_ui(a, a, k); mpf_add(a, a, b); mpf_div_ui(a, a, k); mpf_add(u, u, a); mpf_add(v, v, b); } mpf_clear(fxx); } mpf_div(gamma, u, v); mpf_clear(u); mpf_clear(v); mpf_clear(a); mpf_clear(b); } /* There are a plethora of interesting ways to calculate Pi. * * - Spigot. Far too slow, though nice in plain C for a few hundred digits. * * - Machin-like, using Machin, Störmer, Chien-lih, Arndt, etc. * See http://www.jjj.de/arctan/arctanpage.html for best arctan series. * * - AGM. Quite good, and this seems to be best for relatively small sizes. * See: https://arxiv.org/abs/1802.07558 * * - Ramanujan / Chudnovsky with binary splitting. * About 2-4x faster than AGM for large enough sizes. This version is based * on Alexander Yee's example. I have tested vs a port of Pari/GP's abpq_sum * and it came out about the same speed but uses a lot more memory. * There are many more optimizations that can be done for this. Xue's code * on the GMP page uses quite a bit of code to do running reduction of P,Q * which makes it about 1.5x faster. */ static void _set_pqr(mpz_t P, mpz_t Q, mpz_t R, unsigned long b) { if (sizeof(unsigned long) < 8 || b > 630000) { mpz_set_ui(P, b); mpz_mul(Q, P, P); mpz_mul_ui(R, P, 26726400UL); mpz_mul_ui(R, R, 409297880UL); mpz_mul(Q, Q, R); mpz_set_ui(R, 2*b-1); mpz_mul_ui(R, R, 6*b-5); mpz_mul_ui(R, R, 6*b-1); mpz_mul_ui(P, P, 545140134UL); mpz_add_ui(P, P, 13591409UL); } else { mpz_set_ui(Q, b*b*b); mpz_mul_ui(Q, Q, 26726400UL*409297880UL); /* 10939058860032000UL */ mpz_set_ui(R, (2*b-1) * (6*b-5) * (6*b-1)); mpz_set_ui(P, b*545140134UL); mpz_add_ui(P, P, 13591409UL); } mpz_mul(P, P, R); if (b % 2 == 1) mpz_neg(P, P); } static void _sum_pqr(mpz_t P, mpz_t Q, mpz_t R, mpz_t u, unsigned long a, unsigned long b) { if (b-a == 1) { _set_pqr(P, Q, R, b); } else { mpz_t P1, Q1, R1; unsigned long m; mpz_init(P1); mpz_init(Q1); mpz_init(R1); if (b-a == 2) { _set_pqr(P, Q, R, b-1); _set_pqr(P1, Q1, R1, b); } else if (b-a == 3) { m = a+2; _sum_pqr(P, Q, R, u, a, m); _set_pqr(P1, Q1, R1, b); } else { m = a + (b-a)*0.54; /* Biased splitting */ _sum_pqr(P, Q, R, u, a, m); _sum_pqr(P1, Q1, R1, u, m, b); } /* P = P0*Q1+P1*R0 Q = Q0*Q1 R = R0*R1 */ mpz_mul(u, P1, R); mpz_mul(P, P, Q1); mpz_add(P, P, u); mpz_mul(Q, Q, Q1); mpz_mul(R, R, R1); mpz_clear(P1); mpz_clear(Q1); mpz_clear(R1); } } static void _ramanujan_pi(mpf_t pi, unsigned long prec) { unsigned long terms = (1 + DIGS2BITS(prec)/47.11041314); mpz_t P, Q, R, u; mpf_t t; mpz_init(P); mpz_init(Q); mpz_init(R); mpz_init(u); _sum_pqr(P, Q, R, u, 0, terms); mpz_clear(u); mpz_mul_ui(R, Q, 13591409UL); mpz_add(P, P, R); mpz_mul_ui(Q, Q, 4270934400UL); /* pi = Q / (P * sqrt(10005)) */ mpf_init2(t, mpf_get_prec(pi)); mpf_set_ui(t, 10005); mpf_sqrt(t, t); mpf_set_z(pi, P); mpf_mul(t, t, pi); mpf_set_z(pi, Q); mpf_div(pi, pi, t); mpf_clear(t); mpz_clear(R); mpz_clear(Q); mpz_clear(P); } static void _agm_pi(mpf_t pi, unsigned long prec) { mpf_t t, an, bn, tn, prev_an; unsigned long k, bits = ceil(prec * 3.322); mpf_init2(t, 10+bits); mpf_init2(an, 10+bits); mpf_init2(bn, 10+bits); mpf_init2(tn, 10+bits); mpf_init2(prev_an, 10+bits); mpf_set_ui(an, 1); mpf_div_2exp(bn, an, 1); mpf_div_2exp(tn, an, 2); mpf_sqrt(bn, bn); /* Comments from Brent 1976 */ for (k = 0; (prec >> (k+1)) > 0; k++) { mpf_set(prev_an, an); /* Y <- A */ mpf_add(t, an, bn); mpf_div_2exp(an, t, 1); /* A <- (A+B)/2 */ mpf_mul(t, bn, prev_an); mpf_sqrt(bn, t); /* B <- (BY)^(1/2) */ mpf_sub(prev_an, prev_an, an); mpf_mul(t, prev_an, prev_an); mpf_mul_2exp(t, t, k); mpf_sub(tn, tn, t); /* T <- T - 2^k (A-Y)^2 */ #if 0 /* Instead of doing the comparison, we assume doubling per iteration */ mpf_sub(t, an, bn); mpf_mul_2exp(t, t, bits); if (mpf_cmp_ui(t,1) <= 0) break; #endif } mpf_add(t, an, bn); mpf_mul(an, t, t); mpf_mul_2exp(t, tn, 2); mpf_div(pi, an, t); /* return (A+B)^2 / 4T */ mpf_clear(tn); mpf_clear(bn); mpf_clear(an); mpf_clear(prev_an); mpf_clear(t); } static void _const_pi(mpf_t pi, unsigned long prec) { if (prec <= 100) { mpf_set_str(pi, "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798215", 10); } else if (prec <= 3000) { _agm_pi(pi, prec); } else { _ramanujan_pi(pi, prec); } } /* http://numbers.computation.free.fr/Constants/Log2/log2.ps * Machin-like formula 25. */ static void _const_log2(mpf_t logn, unsigned long prec) { mpf_t t; mpz_t t1, t2, term1, term2, pows; unsigned long bits = precbits(logn, prec, 64); mpz_init(t1); mpz_init(t2); mpz_init(term1); mpz_init(term2); mpz_init(pows); mpf_init2(t, bits); mpz_ui_pow_ui(pows, 10, 20+prec); mpz_arctanh(term1, 26, pows, t1, t2); mpz_mul_ui(term1, term1, 18); mpz_arctanh(term2, 4801, pows, t1, t2); mpz_mul_ui(term2, term2, 2); mpz_sub(term1, term1, term2); mpz_arctanh(term2, 8749, pows, t1, t2); mpz_mul_ui(term2, term2, 8); mpz_add(term1, term1, term2); /* term1 = 69313147... */ mpf_set_z(logn, term1); mpf_set_z(t, pows); mpf_div(logn, logn, t); /* logn = .69313147... */ mpf_clear(t); mpz_clear(t1); mpz_clear(t2); mpz_clear(term1); mpz_clear(term2); mpz_clear(pows); } /* Cache constants. We should thread lock these. */ static mpf_t _fconst_euler, _fconst_pi, _fconst_log2; static unsigned long _prec_euler = 0, _prec_pi = 0, _prec_log2 = 0; #define CONST_FUNC(name) \ void const_##name(mpf_t c, unsigned long prec) { \ if (prec > _prec_##name) { \ prec += 10; \ if (_prec_##name == 0) mpf_init2(_fconst_##name, 7+DIGS2BITS(prec)); \ else mpf_set_prec(_fconst_##name, 7+DIGS2BITS(prec)); \ _const_##name(_fconst_##name, prec); \ _prec_##name = prec; \ } \ mpf_set(c, _fconst_##name); \ } CONST_FUNC(euler); CONST_FUNC(pi); CONST_FUNC(log2); void free_float_constants(void) { _prec_euler = 0; mpf_clear(_fconst_euler); _prec_pi = 0; mpf_clear(_fconst_pi); _prec_log2 = 0; mpf_clear(_fconst_log2); } /***************** Exponential / Logarithmic Integral *****************/ void li(mpf_t r, mpf_t n, unsigned long prec) { mpz_t factorial; mpf_t logn, sum, inner_sum, term, p, q, tol; unsigned long j, k, bits = precbits(r, prec, 10); mpf_init2(logn, bits); mpf_log(logn, n); mpf_init2(sum, bits); mpf_init2(inner_sum, bits); mpf_init2(term, bits); mpf_init2(p, bits); mpf_init2(q, bits); mpf_init2(tol, bits); mpf_set_ui(tol, 10); mpf_pow_ui(tol, tol, prec); mpf_ui_div(tol,1,tol); mpz_init_set_ui(factorial, 1); mpf_set_si(p, -1); for (j = 1, k = 0; j < 1000000; j++) { mpz_mul_ui(factorial, factorial, j); mpf_mul(p, p, logn); mpf_neg(p, p); for (; k <= (j - 1) / 2; k++) { mpf_set_ui(q, 1); mpf_div_ui(q, q, 2*k+1); mpf_add(inner_sum, inner_sum, q); } mpf_set_z(q, factorial); mpf_mul_2exp(q, q, j-1); mpf_mul(term, p, inner_sum); mpf_div(term, term, q); mpf_add(sum, sum, term); mpf_abs(term, term); mpf_mul(q, sum, tol); mpf_abs(q, q); if (mpf_cmp(term, q) <= 0) break; } mpf_sqrt(q, n); mpf_mul(r, sum, q); mpf_abs(logn,logn); mpf_log(q, logn); mpf_add(r, r, q); /* Find out roughly how many digits of C we need, then get it and add */ mpf_set(q, r); for (k = prec; mpf_cmp_ui(q, 1024*1024) >= 0; k -= 6) mpf_div_2exp(q, q, 20); const_euler(q, k); mpf_add(r, r, q); mpz_clear(factorial); mpf_clear(tol); mpf_clear(q); mpf_clear(p); mpf_clear(term); mpf_clear(inner_sum); mpf_clear(sum); mpf_clear(logn); } void ei(mpf_t r, mpf_t x, unsigned long prec) { #if 0 #include mpfr_t C, Cin; mpfr_init2(C, 10+DIGS2BITS(prec)); mpfr_init2(Cin, mpf_get_prec(x)); mpfr_set_f(Cin, x, MPFR_RNDN); mpfr_eint(C, Cin, MPFR_RNDN); mpfr_get_f(r, C, MPFR_RNDN); mpfr_clear(Cin); mpfr_clear(C); return; #endif if (mpf_sgn(x) > 0 && mpf_cmp_ui(x, 100) < 0) { /* x > 0 only */ mpf_t factn, invn, term, sum, t, tol; unsigned long n, bits = precbits(r, prec, 14); mpf_init2(factn, bits); mpf_init2(invn, bits); mpf_init2(term, bits); mpf_init2(sum, bits); mpf_init2(t, bits); mpf_init2(tol, bits); mpf_set_ui(tol, 10); mpf_pow_ui(tol, tol, prec+4); mpf_ui_div(tol,1,tol); mpf_set(factn, x); for (n = 2; n <= 1000000; n++) { mpf_set_ui(t, n); mpf_ui_div(invn, 1, t); mpf_mul(t, x, invn); mpf_mul(factn, factn, t); mpf_mul(term, factn, invn); mpf_add(sum, sum, term); mpf_abs(term, term); mpf_mul(t, sum, tol); mpf_abs(t, t); if (mpf_cmp(term, t) <= 0) break; } const_euler(t, prec+4); mpf_add(sum, sum, t); mpf_log(t, x); mpf_add(sum, sum, t); mpf_add(sum, sum, x); mpf_set(r, sum); mpf_clear(tol); mpf_clear(t); mpf_clear(sum); mpf_clear(term); mpf_clear(invn); mpf_clear(factn); } else { mpf_exp(r, x); li(r, r, prec+3); } } /*************************** Harmonic ***************************/ static void _harmonic(mpz_t a, mpz_t b, mpz_t t) { mpz_sub(t, b, a); if (mpz_cmp_ui(t, 1) == 0) { mpz_set(b, a); mpz_set_ui(a, 1); } else { mpz_t q, r; mpz_add(t, a, b); mpz_tdiv_q_2exp(t, t, 1); mpz_init_set(q, t); mpz_init_set(r, t); _harmonic(a, q, t); _harmonic(r, b, t); mpz_mul(a, a, b); mpz_mul(t, q, r); mpz_add(a, a, t); mpz_mul(b, b, q); mpz_clear(q); mpz_clear(r); } } void harmfrac(mpz_t num, mpz_t den, mpz_t zn) { mpz_t t; mpz_init(t); mpz_add_ui(den, zn, 1); mpz_set_ui(num, 1); _harmonic(num, den, t); mpz_gcd(t, num, den); mpz_divexact(num, num, t); mpz_divexact(den, den, t); mpz_clear(t); } /************************** Bernoulli **************************/ static void _bern_real_zeta(mpf_t bn, mpz_t zn, unsigned long prec) { unsigned long s = mpz_get_ui(zn); mpf_t tf; if (s & 1) { mpf_set_d(bn, (s == 1) ? 0.5 : 0.0); return; } mpf_init2(tf, mpf_get_prec(bn)); /* For large values with low precision, we should look at approximations. * http://www.ebyte.it/library/downloads/2008_MTH_Nemes_GammaApproximationUpdate.pdf * http://www.luschny.de/math/primes/bernincl.html * http://arxiv.org/pdf/math/0702300.pdf */ _zetaint(bn, s, prec); /* We should be using an approximation here, e.g. Pari's mpfactr. For * large values this is the majority of time taken for this function. */ { mpz_t t; mpz_init(t); mpz_fac_ui(t, s); mpf_set_z(tf, t); mpz_clear(t);} mpf_mul(bn, bn, tf); /* bn = s! * zeta(s) */ const_pi(tf, prec); mpf_mul_ui(tf, tf, 2); mpf_pow_ui(tf, tf, s); mpf_div(bn, bn, tf); /* bn = s! * zeta(s) / (2Pi)^s */ mpf_mul_2exp(bn, bn, 1); if ((s & 3) == 0) mpf_neg(bn, bn); /* bn = (-1)^(n-1) * 2 * s! * zeta(s) / (2Pi)^s */ mpf_clear(tf); } static void _bernfrac_comb(mpz_t num, mpz_t den, mpz_t zn, mpz_t t) { unsigned long k, j, n = mpz_get_ui(zn); mpz_t* T; if (n <= 1 || (n & 1)) { mpz_set_ui(num, (n<=1) ? 1 : 0); mpz_set_ui(den, (n==1) ? 2 : 1); return; } /* Denominator */ mpz_set_ui(t, 1); mpz_mul_2exp(den, t, n); /* den = U = 1 << n */ mpz_sub_ui(t, den, 1); /* t = U-1 */ mpz_mul(den, den, t); /* den = U*(U-1) */ n >>= 1; /* Luschny's version of the "Brent-Harvey" method */ /* Algorithm TangentNumbers from https://arxiv.org/pdf/1108.0286.pdf */ New(0, T, n+1, mpz_t); for (k = 1; k <= n; k++) mpz_init(T[k]); mpz_set_ui(T[1], 1); for (k = 2; k <= n; k++) mpz_mul_ui(T[k], T[k-1], k-1); for (k = 2; k <= n; k++) { for (j = k; j <= n; j++) { mpz_mul_ui(t, T[j], j-k+2); mpz_mul_ui(T[j], T[j-1], j-k); mpz_add(T[j], T[j], t); } } /* (14), also last line of Algorithm FastTangentNumbers from paper */ mpz_mul_ui(num, T[n], n); mpz_mul_si(num, num, (n & 1) ? 2 : -2); for (k = 1; k <= n; k++) mpz_clear(T[k]); Safefree(T); } static void _bernfrac_zeta(mpz_t num, mpz_t den, mpz_t zn, mpz_t t) { unsigned long prec, n = mpz_get_ui(zn); double nbits; mpf_t bn, tf; /* Compute integer numerator by getting the real bn first. */ if (n <= 1 || (n & 1)) { mpz_set_ui(num, (n<=1) ? 1 : 0); mpz_set_ui(den, (n==1) ? 2 : 1); return; } if (n == 2) { mpz_set_ui(num, 1); mpz_set_ui(den, 6); return; } /* Calculate denominator */ { int i, ndivisors; mpz_t *D; mpz_set_ui(t, n >> 1); D = divisor_list(&ndivisors, t); mpz_set_ui(den, 6); for (i = 1; i < ndivisors; i++) { mpz_mul_2exp(t,D[i],1); mpz_add_ui(t,t,1); if (_GMP_is_prime(t)) mpz_mul(den, den, t); } for (i = 0; i < ndivisors; i++) mpz_clear(D[i]); Safefree(D); } /* Estimate number of bits, from Pari, also see Stein 2006 */ nbits = mpz_logn(den) + (n+0.5) * log((double)n) - n*2.8378770664093454835606594728L + 1.712086L; nbits /= log(2); nbits += 32; prec = (unsigned long)(nbits/3.32193 + 1); mpf_init2(bn, nbits); mpf_init2(tf, nbits); _bern_real_zeta(bn, zn, prec); mpf_set_z(tf, den); mpf_mul(bn, bn, tf); mpf_set_d(tf, (mpf_sgn(bn) < 0) ? -0.5 : 0.5); mpf_add(bn, bn, tf); mpz_set_f(num, bn); mpf_clear(tf); mpf_clear(bn); } void bernfrac(mpz_t num, mpz_t den, mpz_t zn) { mpz_t t; mpz_init(t); if (mpz_cmp_ui(zn,46) < 0) { _bernfrac_comb(num, den, zn, t); } else { _bernfrac_zeta(num, den, zn, t); } mpz_gcd(t, num, den); mpz_divexact(num, num, t); mpz_divexact(den, den, t); mpz_clear(t); } /*************************** Lambert W ***************************/ static double _lambertw_approx(double x) { double w, k1, k2, k3; if (x < -0.312) { /* Near the branch point. See Fukushima (2013) section 2.5. */ k2 = 2.0 * (1.0 + 2.71828182845904523536 * x); if (k2 <= 0) return -1.0 + 1*DBL_EPSILON; k1 = sqrt(k2); /* Use Puiseux series, e.g. Verberic 2009, Boost, Johannson (2020). */ w = -1.0 + (1.0 + (-1.0/3.0 + (11.0/72.0 + (-43.0/540.0 + (769.0/17280.0 + (-221.0/8505.0 + (680863.0/43545600.0 + (-1963.0/204120.0 + 226287557.0/37623398400.0 * k1) * k1) * k1) * k1) * k1) * k1) * k1) * k1) * k1; } else if (x > -0.14 && x < 0.085) { /* Around zero. See Fukushima (2013) section 2.6. */ w = (1.0 + (-1.0 + (3.0/2.0 + (-8.0/3.0 + (125.0/24.0 + (-54.0/5.0 + (16807.0/720.0 + (-16384.0/315.0 + 531441.0/4480.0 * x) * x) * x) * x) * x) * x) * x) * x) * x; } else if (x < 1) { /* This and the rest from Vazquez-Leal et al. (2019). */ k1 = sqrt(1.0 + 2.71828182845904523536 * x); k2 = 0.33333333333333333333 + 0.7071067811865475244 / k1 - 0.058925565098880 * k1 + (x + 0.36787944117144) * (0.050248489761611 + (0.11138904851051 + 0.040744556245195 * x) * x) / (1.0 + (2.7090878606183 + (1.5510922597820 + 0.095477712183841 * x) * x) * x); w = -(k2-1)/k2; } else if (x < 40) { k1 = 1.0 + (5.950065500550155 + (13.96586471370701 + (10.52192021050505 + (3.065294254265870 + 0.1204576876518760 * x) * x) * x) * x) * x; w = 0.1600049638651493 * log(k1); } else if (x < 20000) { k1 = 1.0 + (-3.16866642511229e11 + (3.420439800038598e10 + (-1.501433652432257e9 + (3.44887729947585e7 + (-4.453783741137856e5 + (3257.926478908996 + (-10.82545259305382 + (0.6898058947898353e-1 + 0.4703653406071575e-4 * x) * x) * x) * x) * x) * x) * x) * x) * x; w = 0.9898045358731312e-1 * log(k1); } else { k1 = 1.0 / (1.0 + log(1.0 + x)); k2 = 1.0 / k1; k3 = log(k2); w = k2-1-k3+(1+k3+(-1/2+(1/2)*k3*k3 +(-1/6+(-1+(-1/2+ (1/3) * k3) * k3) * k3) * k1) * k1) * k1; } /* Improve the FP estimate using two simple Halley iterations. */ if (x >= -0.36728) { if (w != 0) w = (w/(1.0+w)) * (1.0+log(x/w)); if (w != 0) w = (w/(1.0+w)) * (1.0+log(x/w)); if (isnan(w)) w = DBL_EPSILON; } /* Result is over 15 digits, 16 when x > 0 */ return w; } static void _lambertw(mpf_t r, mpf_t x, unsigned long prec) { int i; unsigned long bits = 96+mpf_get_prec(r); /* More bits for intermediate */ mpf_t w, t, tol, w1, zn, qn, en; if (mpf_cmp_d(x, -0.36787944117145) < 0) croak("Invalid input to LambertW: x must be >= -1/e"); if (mpf_sgn(x) == 0) { mpf_set(r, x); return; } /* Use Fritsch rather than Halley. */ mpf_init2(w, bits); mpf_init2(t, bits); mpf_init2(tol, bits); mpf_init2(w1, bits); mpf_init2(zn, bits); mpf_init2(qn, bits); mpf_init2(en, bits); /* Initial estimate done in FP instead of mpf. */ mpf_set_d(w, _lambertw_approx(mpf_get_d(x))); /* Divide prec by 2 since t should be have 4x number of zeros each round */ mpf_set_ui(tol, 10); mpf_pow_ui(tol, tol, (mpf_cmp_d(x, -.36) < 0) ? prec : prec/2); mpf_ui_div(tol,1,tol); for (i = 0; i < 500 && mpz_sgn(w) != 0; i++) { mpf_add_ui(w1, w, 1); mpf_div(t, x, w); mpf_log(zn, t); mpf_sub(zn, zn, w); mpf_mul_ui(t, zn, 2); mpf_div_ui(t, t, 3); mpf_add(t, t, w1); mpf_mul(t, t, w1); mpf_mul_ui(qn, t, 2); mpf_sub(en, qn, zn); mpf_mul_ui(t, zn, 2); mpf_sub(t, qn, t); mpf_div(en, en, t); mpf_div(t, zn, w1); mpf_mul(en, en, t); mpf_mul(t, w, en); mpf_add(w, w, t); mpf_abs(t, t); if (mpf_cmp(t, tol) <= 0) break; if (mpf_cmp_d(w,-1) <= 0) break; } mpf_clear(en); mpf_clear(qn); mpf_clear(zn); mpf_clear(w1); mpf_clear(tol); mpf_clear(t); if (mpf_cmp_d(w, -1) <= 0) mpf_set_si(r, -1); else mpf_set(r, w); mpf_clear(w); } /*****************************************************************************/ /*****************************************************************************/ char* zetareal(mpf_t z, unsigned long prec) { size_t est_digits = 10+prec; char* out; if (mpf_cmp_ui(z,1) == 0) return 0; if (mpz_sgn(z) < 0) est_digits += -mpf_get_si(z); _zeta(z, z, prec); New(0, out, est_digits, char); gmp_sprintf(out, "%.*Ff", (int)(prec), z); return out; } char* riemannrreal(mpf_t r, unsigned long prec) { if (mpf_cmp_ui(r,0) <= 0) return 0; _riemann_r(r, r, prec); return _str_real(r, prec); } char* lambertwreal(mpf_t x, unsigned long prec) { _lambertw(x, x, prec); return _str_real(x, prec); } char* lireal(mpf_t r, unsigned long prec) { if (mpf_cmp_ui(r,0) < 0) return 0; if (mpf_cmp_ui(r,1) == 0) return 0; li(r, r, prec); return _str_real(r, prec); } char* eireal(mpf_t r, unsigned long prec) { if (mpf_cmp_ui(r,0) == 0) return 0; ei(r, r, prec); return _str_real(r, prec); } #define DEFINE_REAL_1ARG(func, mfunc) \ char* func(mpf_t r, unsigned long prec) { \ mfunc(r, r); \ return _str_real(r, prec); \ } #define DEFINE_REAL_2ARG(func, mfunc) \ char* func(mpf_t r, mpf_t x, unsigned long prec) { \ mfunc(r, r, x); \ return _str_real(r, prec); \ } DEFINE_REAL_1ARG(logreal, mpf_log) DEFINE_REAL_1ARG(expreal, mpf_exp) DEFINE_REAL_2ARG(powreal, mpf_pow) DEFINE_REAL_2ARG(rootreal, mpf_root) DEFINE_REAL_2ARG(addreal, mpf_add) DEFINE_REAL_2ARG(subreal, mpf_sub) DEFINE_REAL_2ARG(mulreal, mpf_mul) DEFINE_REAL_2ARG(divreal, mpf_div) char* agmreal(mpf_t a, mpf_t b, unsigned long prec) { if (mpz_sgn(a) == 0 || mpz_sgn(b) == 0) { mpf_set_ui(a,0); } else if (mpz_sgn(a) < 0 || mpz_sgn(b) < 0) { return 0; /* NaN */ } mpf_agm(a, a, b); return _str_real(a, prec); } char* eulerconst(unsigned long prec) { char* out; mpf_t gamma; unsigned long bits = 7 + DIGS2BITS(prec); mpf_init2(gamma, bits); const_euler(gamma, prec); New(0, out, prec+4, char); gmp_sprintf(out, "%.*Ff", (int)(prec), gamma); mpf_clear(gamma); return out; } char* piconst(unsigned long prec) { char* out; mpf_t pi; unsigned long bits = 7 + DIGS2BITS(prec); mpf_init2(pi, bits); const_pi(pi, prec); New(0, out, prec+4, char); gmp_sprintf(out, "%.*Ff", (int)(prec-1), pi); mpf_clear(pi); return out; } char* harmreal(mpz_t zn, unsigned long prec) { char* out; mpz_t num, den; mpz_init(num); mpz_init(den); harmfrac(num, den, zn); out = _frac_real(num, den, prec); mpz_clear(den); mpz_clear(num); return out; } char* bernreal(mpz_t zn, unsigned long prec) { char* out; if (mpz_cmp_ui(zn,40) < 0) { mpz_t num, den, t; mpz_init(num); mpz_init(den); mpz_init(t); _bernfrac_comb(num, den, zn, t); out = _frac_real(num, den, prec); mpz_clear(t); mpz_clear(den); mpz_clear(num); } else { mpf_t z; unsigned long bits = 32 + DIGS2BITS(prec); mpf_init2(z, bits); _bern_real_zeta(z, zn, prec); out = _str_real(z, prec); mpf_clear(z); } return out; } Math-Prime-Util-GMP-0.52/bls75.c0000644000175000017500000012547613663067455014465 0ustar danadana#include #include #include "ptypes.h" #include "bls75.h" #include "primality.h" #include "prime_iterator.h" #include "pbrent63.h" #include "squfof126.h" #include "factor.h" #include "simpqs.h" #include "ecm.h" #define _GMP_ECM_FACTOR(n, f, b1, ncurves) \ _GMP_ecm_factor_projective(n, f, b1, 0, ncurves) #include "utility.h" /* * Lucas (1876): Given a completely factored n-1, if there exists an a s.t. * a^(n-1) % n = 1 * a^((n-1/f) % n != 1 for ALL factors f of n-1 * then n is prime. * * PPBLS:, given n-1 = A*B, A > sqrt(n), if we can find an a s.t. * a^A % n = 1 * gcd(a^(A/f)-1,n) = 1 for ALL factors f of A * then n is prime. * * Generalized Pocklington: given n-1 = A*B, gcd(A,B)=1, A > sqrt(n), then if * for each each factor f of A, there exists an a (1 < a < n-1) s.t. * a^(n-1) % n = 1 * gcd(a^((n-1)/f)-1,n) = 1 * then n is prime. * * BLS T5: given n-1 = A*B, factored A, s=B/2A r=B mod (2A), and an a, then if: * - A is even, B is odd, and AB=n-1 (all implied by n = odd and the above), * - n < (A+1) * (2*A*A + (r-1) * A + 1) * - for each each factor f of A, there exists an a (1 < a < n-1) s.t. * - a^(n-1) % n = 1 * - gcd(a^((n-1)/f)-1,n) = 1 for ALL factors f of A * then: * if s = 0 or r*r - 8*s is not a perfect square * n is prime * else * n is composite * * The generalized Pocklington test is also sometimes known as the * Pocklington-Lehmer test. It's definitely an improvement over Lucas * since we only have to find factors up to sqrt(n), _and_ we can choose * a different 'a' value for each factor. This is corollary 1 from BLS75. * * BLS is the Brillhart-Lehmer-Selfridge 1975 theorem 5 (see link below). * We can factor even less of n, and the test lets us kick out some * composites early, without having to test n-3 different 'a' values. * * Once we've found the factors of n-1 (or enough of them), verification * usually happens really fast. a=2 works for most, and few seem to require * more than ~ log2(n). However all but BLS75 require testing all integers * 1 < a < n-1 before answering in the negative, which is impractical. * * BLS75 theorem 7 is the final n-1 theorem and takes into account any * knowledge that the remaining factor is not below a threshold B. Since * we do initial trial division this helps. It is usually of only small * benefit. * * * AKS is not too hard to implement, but it's impractically slow. * * ECPP is very fast and definitely the best method for most numbers. * * BLS75: http://www.ams.org/journals/mcom/1975-29-130/S0025-5718-1975-0384673-1/S0025-5718-1975-0384673-1.pdf * */ /* Like all the primality functions: * 2 = definitely prime, 1 = maybe prime, 0 = definitely composite * * You really should run is_prob_prime on n first, so we only have to run * these tests on numbers that are very probably prime. */ static int tfe(mpz_t f, mpz_t n, int effort) { int success = 0; UV log2n = mpz_sizeinbase(n, 2); if (mpz_cmp_ui(n,3) <= 0) { mpz_set(f,n); return 1; } if (effort == 0) { if (!success && log2n <= 63) success = pbrent63(n, f, 1000000); if (!success) success = (int)power_factor(n, f); if (success) return success; } /* TODO: Use tinyqs effectively here, e.g. stage 3 for 50-90 bit */ switch (effort) { case 0: success = _GMP_pminus1_factor(n, f, 400, 400); break; case 1: success = _GMP_pminus1_factor(n, f, 1000, 11000); break; case 2: { UV brent_rounds = (log2n <= 64) ? 100000 : 100000 / (log2n-63); int final_B2 = 1000 * (150-(int)log2n); if (log2n < 70) brent_rounds *= 3; if (log2n < 80) success = _GMP_ECM_FACTOR(n, f, 150, 5); if (!success) success = _GMP_pbrent_factor(n, f, 3, brent_rounds); if (!success && final_B2 > 11000) success = _GMP_pminus1_factor(n, f, 10000, final_B2); } break; case 3: success = _GMP_pminus1_factor(n, f, 20000, 200000); if (!success && log2n <= 80) success = squfof126(n, f, 2000000); break; case 4: success = _GMP_ECM_FACTOR(n, f, 500, 30); break; case 5: success = _GMP_ECM_FACTOR(n, f, 2000, 20); break; case 6: if (log2n > 170) { UV B1 = (log2n > 2500) ? 10000000 : 4000 * log2n; success = _GMP_pminus1_factor(n, f, B1, 20*B1); } break; case 7: if (log2n > 210) { success = _GMP_ECM_FACTOR(n, f, 20000, 10); } break; case 8: if (log2n > 240) { success = _GMP_ECM_FACTOR(n, f, 40000, 10); } break; case 9: if (log2n > 240) { success = _GMP_ECM_FACTOR(n, f, 80000, 5); } break; case 10:if (log2n > 270) { success = _GMP_ECM_FACTOR(n, f,160000, 20); } break; /* QS for sizes 30-90 digits */ case 20: case 21:{ UV log10n = mpz_sizeinbase(n, 10); if (log10n >= 30 && log10n <= ((effort == 20) ? 54 : 90)) { mpz_t farray[66]; int i, nfactors; for (i = 0; i < 66; i++) mpz_init(farray[i]); nfactors = _GMP_simpqs(n, farray); /* TODO: Return all factors */ if (nfactors > 1) { success = 1; mpz_set(f, farray[nfactors-1]); /* Return largest */ } for (i = 0; i < 66; i++) mpz_clear(farray[i]); } } break; case 30:success = _GMP_pminus1_factor(n, f, 200000, 4000000); break; case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57:{ UV B1 = UVCONST(1) << (13 + (effort-40)); success = _GMP_ECM_FACTOR(n, f, B1, 10); } break; default: break; } /* if (success) printf(" bls75 factored %lu-bit at effort %d\n", log2n, effort); */ return success; } /* F*R = n, F is factored part, R is remainder */ static void small_factor(mpz_t F, mpz_t R, UV B1) { PRIME_ITERATOR(iter); UV tf; for (tf = 2; tf < B1; tf = prime_iterator_next(&iter)) { if (mpz_cmp_ui(R, tf*tf) < 0) break; if (mpz_divisible_ui_p(R, tf)) { do { mpz_mul_ui(F, F, tf); mpz_divexact_ui(R, R, tf); } while (mpz_divisible_ui_p(R, tf)); } } prime_iterator_destroy(&iter); } typedef struct { int cur; int max; mpz_t* stack; } fstack_t; #define FACTOR_STACK(name) fstack_t name = {0, 0, 0} static int nstack(fstack_t* s) { return s->cur; } static void push_fstack(fstack_t* s, mpz_t v) { if (s->stack == 0) New(0,s->stack, s->max = 10, mpz_t); if (s->cur == s->max) Renew(s->stack, s->max += 10, mpz_t); mpz_init_set(s->stack[(s->cur)++], v); } static void push_fstack_ui(fstack_t* s, unsigned long v) { if (s->stack == 0) New(0,s->stack, s->max = 10, mpz_t); if (s->cur == s->max) Renew(s->stack, s->max += 10, mpz_t); mpz_init_set_ui(s->stack[(s->cur)++], v); } static void pop_fstack(mpz_t rv, fstack_t* s) { mpz_set(rv, s->stack[--(s->cur)]); mpz_clear(s->stack[s->cur]); } static void clear_fstack(fstack_t* s) { while (s->cur > 0) mpz_clear(s->stack[--(s->cur)]); } static void destroy_fstack(fstack_t* s) { clear_fstack(s); Safefree(s->stack); s->stack = 0; } static void factor_out(mpz_t R, mpz_t F, mpz_t v) { int ndiv = mpz_remove(R, R, v); while (ndiv-- > 0) mpz_mul(F, F, v); } static void factor_out_ui(mpz_t R, mpz_t F, unsigned long v) { while (mpz_divisible_ui_p(R, v)) { mpz_mul_ui(F, F, v); mpz_divexact_ui(R, R, v); } } static void factor_test_ui(unsigned long f, mpz_t R, mpz_t F, fstack_t* s) { if (mpz_divisible_ui_p(R, f)) { push_fstack_ui(s, f); factor_out_ui(R, F, f); } } typedef int (*bls_func_t)(mpz_t, int, char**); typedef int (*limit_func_t)(mpz_t, mpz_t, mpz_t, UV, mpz_t,mpz_t,mpz_t,mpz_t); static void handle_factor(mpz_t f, mpz_t R, mpz_t F, fstack_t* sf, fstack_t* sm, int effort, char** prtext, int push_if_probable, bls_func_t func) { int pr = _GMP_BPSW(f); if (pr == 1) { /* Try to prove */ if (effort > 1 || mpz_sizeinbase(f,2) < 200) { pr = (*func)(f, effort, prtext); } } if (pr == 2) { push_fstack(sf, f); factor_out(R, F, f); } else if (pr == 0 || push_if_probable) { push_fstack(sm, f); } } static void handle_factor2(mpz_t f, mpz_t R, mpz_t F, fstack_t* sf, fstack_t* sp, fstack_t* sm, int effort, char** prtext, bls_func_t func) { int pr = _GMP_BPSW(f); if (pr == 1) { /* Try to prove */ pr = (*func)(f, effort, prtext); } if (pr == 0) { push_fstack(sm, f); } else if (pr == 2) { push_fstack(sf, f); factor_out(R, F, f); } else { /* Save actual proof for later, but for now assume we can do it */ push_fstack(sp, f); factor_out(R, F, f); } } static void trim_factors(mpz_t F, mpz_t R, mpz_t n, mpz_t none, UV flim, fstack_t* fs, limit_func_t func, mpz_t t, mpz_t m, mpz_t r, mpz_t s) { if (fs->cur > 1) { int i; mpz_set_ui(F, 1); mpz_set(R, none); for (i = 0; i < fs->cur; i++) { if (i > 0 && func(n, F, R, flim, t, m, r, s)) break; factor_out(R, F, fs->stack[i]); } /* Remove excess factors */ while (i < fs->cur) pop_fstack(t, fs); } /* Verify Q[0] = 2 */ if (mpz_cmp_ui(fs->stack[0], 2) != 0) croak("BLS75 internal error: 2 not at start of fstack"); /* r and s have been set by func */ } /* Sort factors found from largest to smallest, but 2 must be at start. */ static void sort_and_trim_factors(int* fsp, mpz_t* fstack) { int i, j; for (i = 2; i < *fsp; i++) for (j = i; j > 1 && mpz_cmp(fstack[j-1], fstack[j]) < 0; j--) mpz_swap( fstack[j-1], fstack[j] ); for (i = 2; i < *fsp; i++) { /* Remove any duplicate factors */ if (mpz_cmp(fstack[i], fstack[i-1]) == 0) { for (j = i+1; j < *fsp; j++) mpz_set(fstack[j-1], fstack[j]); *fsp -= 1; } } } static void fstack_sort_trim(fstack_t* s) { sort_and_trim_factors(&(s->cur), s->stack); } /******************************************************************************/ static int bls_theorem5_limit(mpz_t n, mpz_t A, mpz_t B, UV dummy, mpz_t t, mpz_t y, mpz_t r, mpz_t s) { mpz_mul(t, A, B); mpz_add_ui(t, t, 1); if (mpz_cmp(t, n) != 0) croak("BLS75 internal error: A*B != n-1\n"); mpz_mul_ui(t, A, 2); mpz_tdiv_qr(s, r, B, t); mpz_mul(y, t, A); /* y = 2*A*A */ mpz_sub_ui(t, r, 1); /* t = r-1 */ mpz_mul(t, t, A); /* t = A*(r-1) */ mpz_add(y, y, t); /* y = 2A^2 + A(r-1) */ mpz_add_ui(y, y, 1); /* y = 2A^2 + A(r-1) + 1 */ mpz_add_ui(t, A, 1); /* t = A+1 */ mpz_mul(y, y, t); /* y = (A+1)*(2A^2+(r-1)A+1) */ return (mpz_cmp(n, y) < 0) ? 1 : 0; } static int bls_theorem7_limit(mpz_t n, mpz_t F1, mpz_t R1, UV B1, mpz_t t, mpz_t y, mpz_t r, mpz_t s) { mpz_mul(t, F1, R1); mpz_add_ui(t, t, 1); if (mpz_cmp(t, n) != 0) croak("BLS75 internal error: F1*R1 != n-1\n"); mpz_mul_ui(t, F1, 2); mpz_tdiv_qr(s, r, R1, t); mpz_add(y, t, r); mpz_sub_ui(y, y, B1); mpz_mul(y, y, F1); mpz_add_ui(y, y, 1); /* y = 2F1^2 + (r - B1)F1 + 1 */ mpz_mul_ui(t, F1, B1); mpz_add_ui(t, t, 1); mpz_mul(y, y, t); /* times (B1F1+1) */ return (mpz_cmp(n, y) < 0) ? 1 : 0; } static int bls_theorem17_limit(mpz_t n, mpz_t F2, mpz_t R2, UV dummy, mpz_t t, mpz_t y, mpz_t r, mpz_t s) { mpz_mul(t, F2, R2); mpz_sub_ui(t, t, 1); if (mpz_cmp(t, n) != 0) croak("BLS75 internal error: F2*R2 != n+1\n"); mpz_mul_ui(t, F2, 2); mpz_tdiv_qr(s, r, R2, t); if (mpz_cmp(r, F2) >= 0) { mpz_add_ui(s, s, 1); mpz_sub(r, r, t); } /* Let m = 1 */ mpz_add_ui(y, t, 1); mpz_abs(t, r); mpz_sub(y, y, t); mpz_mul(y, y, F2); mpz_add_ui(y, y, 1); /* y = 2F2^2 + (m-r)F2 + 1 */ mpz_sub_ui(t, F2, 1); mpz_mul(y, y, t); /* times (mF2-1) */ return (mpz_cmp(n, y) < 0) ? 1 : 0; } static int bls_theorem19_limit(mpz_t n, mpz_t F2, mpz_t R2, UV B2, mpz_t t, mpz_t y, mpz_t r, mpz_t s) { mpz_mul(t, F2, R2); mpz_sub_ui(t, t, 1); if (mpz_cmp(t, n) != 0) croak("BLS75 internal error: F2*R2 != n+1\n"); mpz_mul_ui(t, F2, 2); mpz_tdiv_qr(s, r, R2, t); if (mpz_cmp(r, F2) >= 0) { mpz_add_ui(s, s, 1); mpz_sub(r, r, t); } mpz_add_ui(y, t, B2); mpz_abs(t, r); mpz_sub(y, y, t); mpz_mul(y, y, F2); mpz_add_ui(y, y, 1); /* y = 2F2^2 + (B2 - r)F2 + 1 */ mpz_mul_ui(t, F2, B2); mpz_sub_ui(t, t, 1); mpz_mul(y, y, t); /* times (B2F2-1) */ return (mpz_cmp(n, y) < 0) ? 1 : 0; } /* 17: N < (m F2 - 1) ( 2 F2 F2 + m F2 - |r| F2 + 1 ) (III) test (l*F2+1) doesn't divide N for 1 .. m 19: N < (B2 F2 - 1) ( 2 F2 F2 + B2 F2 - |r| F2 + 1 ) (III) (IV) R2 factors > B2 */ static int bls_theorem20_limit(mpz_t n, mpz_t R1, mpz_t F1, mpz_t F2, UV B, UV m, mpz_t t, mpz_t g, mpz_t r, mpz_t s) { mpz_tdiv_q_2exp(t, F2, 1); mpz_tdiv_qr(s, r, R1, t); mpz_mul_ui(t, F1, B); mpz_add_ui(g, t, 1); mpz_mul_ui(t, F2, B); mpz_sub_ui(t, t, 1); if (mpz_cmp(t, g) > 0) mpz_set(g, t); mpz_mul(t, F1, F2); mpz_tdiv_q_2exp(t, t, 1); mpz_mul_ui(t, t, B); mpz_mul_ui(t, t, B); mpz_add_ui(s, t, 1); /* s = B1*B2*F1*F2/2+1 */ mpz_mul(g, g, s); if (mpz_cmp(n, g) < 0) { mpz_set_ui(s, 0); /* Use s to signal whether we must test for m. */ return 1; } mpz_mul(t, F1, F2); mpz_mul_ui(t, t, m); mpz_tdiv_q_2exp(t, t, 1); mpz_mul(r, r, F1); /* r *= F1; t += r, r /= F1; */ mpz_add(t, t, r); mpz_divexact(r, r, F1); mpz_add_ui(t, t, 1); /* t = m * F1 * F2/2 + r * F1 + 1 */ mpz_mul(g, s, t); mpz_set_ui(s, 1); return (mpz_cmp(n, g) < 0) ? 1 : 0; } /******************************************************************************/ /* (I) For each prime p_i dividing F1 [N-1 = F1R1] there exists an a_i * such that N is a psp base a_i and gcd(A_i^{(N-1)/p_i}-1,N) = 1. */ static int _verify_cond_I_p(mpz_t n, mpz_t pi, mpz_t ap, mpz_t t, int alimit, char* pspcache) { int a, success = 0; PRIME_ITERATOR(iter); for (a = 2; !success && a <= alimit; a = prime_iterator_next(&iter)) { int psp = -1; mpz_set_ui(ap, a); if (pspcache) psp = pspcache[a]; if (psp == -1) { mpz_sub_ui(t, n, 1); mpz_powm(t, ap, t, n); psp = (mpz_cmp_ui(t, 1) == 0); } if (pspcache) pspcache[a] = psp; if (!psp) continue; mpz_sub_ui(t, n, 1); mpz_divexact(t, t, pi); mpz_powm(t, ap, t, n); mpz_sub_ui(t, t, 1); mpz_gcd(t, t, n); if (mpz_cmp_ui(t, 1) != 0) continue; success = 1; /* We found an a for this p */ } prime_iterator_destroy(&iter); return success; } /* (III) For each prime q_i dividing F2 [N+1 = F2R2] there exists a Lucas * sequence U_k with discriminant D for which D/N = -1, N divides * U_{N+1} and gcd(U_{(N+1)/q_i},N} = 1. */ static int _verify_cond_III_q2(mpz_t n, mpz_t qi, IV p, IV q, mpz_t U, mpz_t V, mpz_t k, mpz_t t1, mpz_t t2) { mpz_add_ui(k, n, 1); mpz_divexact(k, k, qi); lucas_seq(U, V, n, p, q, k, t1, t2); mpz_gcd(k, U, n); return (mpz_cmp_ui(k, 1) == 0) ? 1 : 0; } #define MAXQV 50 static int _verify_cond_III_q(mpz_t n, mpz_t qi, IV* qv, int* pnumqv, IV* lp, IV* lq) { int i, numqv = *pnumqv, rval = 0; IV d, p, q, startq; mpz_t U, V, k, t1, t2; mpz_init(U); mpz_init(V); mpz_init(k); mpz_init(t1); mpz_init(t2); /* Try previous q values with (D|n)=-1 and U_(n+1) = 0 mod n */ for (i = 0; i < numqv; i++) { q = qv[i]; p = (q % 2) ? 2 : 1; if (_verify_cond_III_q2(n, qi, p, q, U, V, k, t1, t2)) { rval = 2; break; } } if (rval == 0) { /* Search for a q value */ startq = (numqv > 0) ? qv[numqv-1]+1 : 2; for (q = startq; q < startq+1000; q++) { if (mpz_cmp_ui(n, (unsigned long)q) <= 0) break; p = (q % 2) ? 2 : 1; d = p*p - 4*q; mpz_set_si(t1, d); if (mpz_jacobi(t1, n) != -1) continue; /* we have a d/p/q where d = -1. Check the first Lucas sequence. */ mpz_add_ui(k, n, 1); lucas_seq(U, V, n, p, q, k, t1, t2); if (mpz_sgn(U) != 0) continue; /* Passed first test, add to qv list */ if (numqv < MAXQV) { qv[numqv] = q; *pnumqv = ++numqv; } /* Verify second Lucas sequence */ if (_verify_cond_III_q2(n, qi, p, q, U, V, k, t1, t2)) { rval = 2; break; } } } mpz_clear(U); mpz_clear(V); mpz_clear(k); mpz_clear(t1); mpz_clear(t2); if (lp) *lp = p; if (lq) *lq = q; return rval; } #if 0 /* N divides V_{(N+1)/2} and for q > 2 does not divide V{(N+1)/(2q)} */ static int _verify_theorem14_q(mpz_t n, mpz_t qi, IV* lastq, IV* lp, IV* lq) { int rval = 0; IV d, p, q; mpz_t U, V, k, t1, t2; mpz_init(U); mpz_init(V); mpz_init(k); mpz_init(t1); mpz_init(t2); if (lastq && *lastq > 0 && mpz_cmp_ui(qi,2) > 0) { q = *lastq; p = (q % 2) ? 2 : 1; d = p*p - 4*q; mpz_set_si(t1, d); if (mpz_jacobi(t1, n) == -1) { /* q passed the first tst. Do the second that depends on the factor. */ mpz_add_ui(k, n, 1); mpz_tdiv_q_2exp(k, k, 1); mpz_divexact(k, k, qi); lucas_seq(U, V, n, p, q, k, t1, t2); if (mpz_sgn(V) != 0) { rval = 2; } } } if (!rval) { for (q = (lastq && *lastq > 0) ? *lastq + 1 : 2; q < 1000; q++) { p = (q % 2) ? 2 : 1; d = p*p - 4*q; mpz_set_si(t1, d); if (mpz_jacobi(t1, n) != -1) continue; /* we have a d/p/q where d = -1. Check the Lucas sequence. */ mpz_add_ui(k, n, 1); mpz_tdiv_q_2exp(k, k, 1); lucas_seq(U, V, n, p, q, k, t1, t2); if (mpz_sgn(V) == 0) { if (mpz_cmp_ui(qi, 2) <= 0) { rval = 2; break; } else { mpz_divexact(k, k, qi); lucas_seq(U, V, n, p, q, k, t1, t2); if (mpz_sgn(V) != 0) { rval = 2; break; } } } } } mpz_clear(U); mpz_clear(V); mpz_clear(k); mpz_clear(t1); mpz_clear(t2); if (lp) *lp = p; if (lq) *lq = q; if (lastq) *lastq = q; return rval; } #endif /******************************************************************************/ int _GMP_primality_bls_nm1(mpz_t n, int effort, char** prooftextptr) { mpz_t nm1, A, B, t, m, f, r, s; FACTOR_STACK(fstack); FACTOR_STACK(mstack); int e, success = 1; UV B1 = (mpz_sizeinbase(n,10) > 1000) ? 100000 : 10000; /* We need to do this for BLS */ if (mpz_even_p(n)) return 0; mpz_init(nm1); mpz_sub_ui(nm1, n, 1); mpz_init_set_ui(A, 1); mpz_init_set(B, nm1); mpz_init(m); mpz_init(f); mpz_init(t); mpz_init(r); mpz_init(s); { /* Pull small factors out */ PRIME_ITERATOR(iter); UV tf; for (tf = 2; tf < B1; tf = prime_iterator_next(&iter)) { if (mpz_cmp_ui(B, tf*tf) < 0) break; factor_test_ui(tf, B, A, &fstack); } prime_iterator_destroy(&iter); } if (success && mpz_cmp_ui(B,1) > 0) { mpz_set(f, B); handle_factor(f, B, A, &fstack, &mstack, effort, prooftextptr, 1, &_GMP_primality_bls_nm1); } while (success) { if ( (prooftextptr && bls_theorem5_limit(n, A, B, B1, t, m, r, s)) || (!prooftextptr && bls_theorem7_limit(n, A, B, B1, t, m, r, s)) ) break; success = 0; if (nstack(&mstack) == 0) /* If the stack is empty, we have failed. */ break; pop_fstack(m, &mstack); /* pop a component off the stack */ for (e = 0; !success && e <= effort; e++) success = tfe(f, m, e); /* If we couldn't factor m and the stack is empty, we've failed. */ if ( (!success) && (nstack(&mstack) == 0) ) break; /* Put the two factors f and m/f into the stacks, smallest first */ mpz_divexact(m, m, f); if (mpz_cmp(m, f) < 0) mpz_swap(m, f); handle_factor(f, B, A, &fstack, &mstack, effort, prooftextptr, 0, &_GMP_primality_bls_nm1); handle_factor(m, B, A, &fstack, &mstack, effort, prooftextptr, 0, &_GMP_primality_bls_nm1); } /* clear mstack since we don't care about it. Use to hold a values. */ clear_fstack(&mstack); fstack_sort_trim(&fstack); /* Shrink to smallest set and verify conditions. */ if (success > 0) { if (prooftextptr) trim_factors(A, B, n, nm1, B1, &fstack, &bls_theorem5_limit, t, m, r, s); else trim_factors(A, B, n, nm1, B1, &fstack, &bls_theorem7_limit, t, m, r, s); /* Verify conditions */ success = 0; if ( (prooftextptr && bls_theorem5_limit(n, A, B, B1, t, m, r, s)) || (!prooftextptr && bls_theorem7_limit(n, A, B, B1, t, m, r, s)) ) { mpz_mul(t, r, r); mpz_submul_ui(t, s, 8); /* t = r^2 - 8s */ /* N is prime if and only if s=0 OR t not a perfect square */ success = (mpz_sgn(s) == 0 || !mpz_perfect_square_p(t)) ? 1 : -1; } } if (success > 0) { int pcount, a; int const alimit = (effort <= 2) ? 200 : 10000; char afermat[10000+1]; mpz_t p, ap; mpz_init(p); mpz_init(ap); /* Cache result that doesn't depend on factor */ for (a = 0; a <= alimit; a++) afermat[a] = -1; for (pcount = 0; success && pcount < fstack.cur; pcount++) { success = _verify_cond_I_p(n, fstack.stack[pcount], ap, t, alimit, afermat); if (success) push_fstack(&mstack, ap); } /* If we could not find 'a' values, then we should return 1 (maybe prime) * since we did not perform an exhaustive search. It would be quite * unusual to find a prime that didn't have an 'a' in the first 10,000 * primes, but it could happen. It's a "dubiously prime" :) */ if (!success && get_verbose_level() > 0) printf("N-1 factored but failed to prove. Perhaps composite.\n"); mpz_clear(p); mpz_clear(ap); } if (success > 0 && prooftextptr != 0) { int i; char *proofstr, *proofptr; int curprooflen = (*prooftextptr == 0) ? 0 : strlen(*prooftextptr); int fsp = nstack(&fstack); int msp = nstack(&mstack); int myprooflen = (5 + mpz_sizeinbase(n, 10)) * (2 + fsp + msp) + 200; if (fsp != msp) croak("Different f and a counts\n"); New(0, proofstr, myprooflen + curprooflen + 1, char); proofptr = proofstr; proofptr += gmp_sprintf(proofptr, "Type BLS5\nN %Zd\n", n); /* Q[0] is always 2 */ for (i = 1; i < fsp; i++) proofptr += gmp_sprintf(proofptr, "Q[%d] %Zd\n", i, fstack.stack[i]); /* A[i] only printed if not 2 */ for (i = 0; i < msp; i++) if (mpz_cmp_ui(mstack.stack[i], 2) != 0) proofptr += gmp_sprintf(proofptr, "A[%d] %Zd\n", i, mstack.stack[i]); proofptr += gmp_sprintf(proofptr, "----\n"); /* Set or prepend */ if (*prooftextptr) { proofptr += gmp_sprintf(proofptr, "\n"); strcat(proofptr, *prooftextptr); Safefree(*prooftextptr); } *prooftextptr = proofstr; } destroy_fstack(&fstack); destroy_fstack(&mstack); mpz_clear(nm1); mpz_clear(A); mpz_clear(B); mpz_clear(m); mpz_clear(f); mpz_clear(t); mpz_clear(r); mpz_clear(s); if (success < 0) return 0; if (success > 0) return 2; return 1; } int _GMP_primality_bls_np1(mpz_t n, int effort, char** prooftextptr) { mpz_t np1, F2, R2, t, m, f, r, s; FACTOR_STACK(fstack); FACTOR_STACK(mstack); int e, success = 1; UV B2 = (mpz_sizeinbase(n,10) > 1000) ? 100000 : 10000; /* TODO: T19 doesn't seem right, and we're still * passing some composites like 14299. */ /* We need to do this for BLS */ if (mpz_even_p(n)) return 0; mpz_init(np1); mpz_add_ui(np1, n, 1); mpz_init_set_ui(F2, 1); mpz_init_set(R2, np1); mpz_init(m); mpz_init(f); mpz_init(t); mpz_init(r); mpz_init(s); { /* Pull small factors out */ PRIME_ITERATOR(iter); UV tf; for (tf = 2; tf < B2; tf = prime_iterator_next(&iter)) { if (mpz_cmp_ui(R2, tf*tf) < 0) break; factor_test_ui(tf, R2, F2, &fstack); } prime_iterator_destroy(&iter); } /* printf("trial np1: %lu bits, %lu bits factored\n", mpz_sizeinbase(np1,2), mpz_sizeinbase(F2,2)); */ if (success && mpz_cmp_ui(R2,1) > 0) { mpz_set(f, R2); handle_factor(f, R2, F2, &fstack, &mstack, effort, prooftextptr, 1, &_GMP_primality_bls_np1); } while (success) { if (bls_theorem17_limit(n, F2, R2, B2, t, m, r, s)) break; success = 0; if (nstack(&mstack) == 0) /* If the stack is empty, we have failed. */ break; pop_fstack(m, &mstack); /* pop a component off the stack */ for (e = 0; !success && e <= effort; e++) success = tfe(f, m, e); /* If we couldn't factor m and the stack is empty, we've failed. */ if ( (!success) && (nstack(&mstack) == 0) ) break; /* Put the two factors f and m/f into the stacks, smallest first */ mpz_divexact(m, m, f); if (mpz_cmp(m, f) < 0) mpz_swap(m, f); handle_factor(f, R2, F2, &fstack, &mstack, effort, prooftextptr, 0, &_GMP_primality_bls_np1); handle_factor(m, R2, F2, &fstack, &mstack, effort, prooftextptr, 0, &_GMP_primality_bls_np1); } /* clear mstack since we don't care about it. Use to hold a values. */ clear_fstack(&mstack); /* printf("factor np1: %lu bits, %lu bits factored\n", mpz_sizeinbase(np1,2), mpz_sizeinbase(F2,2)); */ fstack_sort_trim(&fstack); /* Shrink to smallest set and verify conditions. */ if (success > 0) { trim_factors(F2, R2, n, np1, B2, &fstack, &bls_theorem17_limit, t, m, r, s); /* Verify conditions */ success = 0; if (bls_theorem17_limit(n, F2, R2, B2, t, m, r, s)) { mpz_mul(t, r, r); mpz_addmul_ui(t, s, 8); /* t = r^2 + 8s */ /* N is prime if and only if s=0 OR t not a perfect square */ success = (mpz_sgn(s) == 0 || !mpz_perfect_square_p(t)) ? 1 : -1; } } if (success > 0) { IV qv[MAXQV]; int pcount, numqv = 0; for (pcount = 0; success && pcount < fstack.cur; pcount++) { success = _verify_cond_III_q(n, fstack.stack[pcount], qv, &numqv, 0, 0); } /* If we meet theorem 17 limits, then no need to test R2 */ if (success && !bls_theorem17_limit(n, F2, R2, B2, t, m, r, s)) { success = _verify_cond_III_q(n, R2, qv, &numqv, 0, 0); } if (!success && get_verbose_level() > 0) printf("N+1 factored but failed to prove. Perhaps composite.\n"); } /* TODO: Proof text */ destroy_fstack(&fstack); destroy_fstack(&mstack); mpz_clear(np1); mpz_clear(F2); mpz_clear(R2); mpz_clear(m); mpz_clear(f); mpz_clear(t); mpz_clear(r); mpz_clear(s); if (success < 0) return 0; if (success > 0) return 2; return 1; } /******************************************************************************/ #define PRINT_PCT 0 /* Will use one of: * N-1 Corollary 1 * N-1 Theorem 5 * N-1 Theorem 7 * N+1 Corollary 8 * N+1 Theorem 17 * N+1 Theorem 19 * Comb Theorem 20 */ int bls75_hybrid(mpz_t n, int effort, char** prooftextptr) { mpz_t nm1, np1, F1, F2, R1, R2; mpz_t r, s, t, u, f, c1, c2; /* fstack: definite prime factors * pstack: probable prime factors product of fstack and pstack = F * mstack: composite remainders product of mstack = R */ FACTOR_STACK(f1stack); FACTOR_STACK(f2stack); FACTOR_STACK(p1stack); FACTOR_STACK(p2stack); FACTOR_STACK(m1stack); FACTOR_STACK(m2stack); int pcount, e, success = 1; int low_effort = (effort < 1) ? 0 : 1; UV B1 = (effort < 2 && mpz_sizeinbase(n,2) < 160) ? 6000 : (mpz_sizeinbase(n,2) < 1024) ? 20000 : 200000; UV m = B1-1; /* m should be less than B1 */ #if PRINT_PCT double trial_pct, prime_pct, fac_pct, fin_pct; #endif /* We need to do this for BLS */ if (mpz_even_p(n)) return 0; mpz_init(nm1); mpz_sub_ui(nm1, n, 1); mpz_init(np1); mpz_add_ui(np1, n, 1); mpz_init_set_ui(F1, 1); mpz_init_set(R1, nm1); mpz_init_set_ui(F2, 1); mpz_init_set(R2, np1); mpz_init(r); mpz_init(s); mpz_init(u); mpz_init(t); mpz_init(f); mpz_init(c1); mpz_init(c2); { /* Pull small factors out */ PRIME_ITERATOR(iter); UV tf; for (tf = 2; tf < B1; tf = prime_iterator_next(&iter)) { /* Page 635 of BLS75 describes an optimization for divisibility * testing. It seems slower than just doing two UI div tests. */ if (mpz_cmp_ui(R1, tf*tf) >= 0) factor_test_ui(tf, R1, F1, &f1stack); if (mpz_cmp_ui(R2, tf*tf) >= 0) factor_test_ui(tf, R2, F2, &f2stack); } prime_iterator_destroy(&iter); } #if PRINT_PCT trial_pct = (100.0 * (mpz_sizeinbase(F1,2) + mpz_sizeinbase(F2,2))) / (mpz_sizeinbase(nm1,2) + mpz_sizeinbase(np1,2)); printf("\n%6.2f .. ", trial_pct); fflush(stdout); #endif if ( bls_theorem7_limit(n, F1, R1, B1, t, u, r, s) || bls_theorem19_limit(n, F2, R2, B1, t, u, r, s) || bls_theorem20_limit(n, R1, F1, F2, B1, m, t, u, r, s) ) goto start_hybrid_proof; if (mpz_cmp_ui(R1,1) > 0) { mpz_set(f, R1); handle_factor2(f, R1, F1, &f1stack, &p1stack, &m1stack, low_effort, prooftextptr, &bls75_hybrid); } if (mpz_cmp_ui(R2,1) > 0) { mpz_set(f, R2); handle_factor2(f, R2, F2, &f2stack, &p2stack, &m2stack, low_effort, prooftextptr, &bls75_hybrid); } #if PRINT_PCT prime_pct = (100.0 * (mpz_sizeinbase(F1,2) + mpz_sizeinbase(F2,2))) / (mpz_sizeinbase(nm1,2) + mpz_sizeinbase(np1,2)); printf("\n%6.2f .. ", prime_pct); fflush(stdout); #endif while (1) { int d1, d2; success = 1; if ( bls_theorem7_limit(n, F1, R1, B1, t, u, r, s) || bls_theorem19_limit(n, F2, R2, B1, t, u, r, s) || bls_theorem20_limit(n, R1, F1, F2, B1, m, t, u, r, s) ) break; success = 0; mpz_set_ui(c1, 0); mpz_set_ui(c2, 0); d1 = nstack(&m1stack) > 0; d2 = nstack(&m2stack) > 0; if (!d1 && !d2) break; if (d1) pop_fstack(c1, &m1stack); if (d2) pop_fstack(c2, &m2stack); for (e = 0; !success && e <= effort; e++) { if (d1 && tfe(f, c1, e)) { if (d2) push_fstack(&m2stack, c2); mpz_set(u, c1); success = 1; } else if (d2 && tfe(f, c2, e)) { if (d1) push_fstack(&m1stack, c1); mpz_set(u, c2); success = 2; } } /* No success for this set of composites. Move on. */ if (!success) continue; if (success == 1) { mpz_divexact(u, u, f); if (mpz_cmp(u, f) < 0) mpz_swap(u, f); handle_factor2(f, R1, F1, &f1stack, &p1stack, &m1stack, low_effort, prooftextptr, &bls75_hybrid); handle_factor2(u, R1, F1, &f1stack, &p1stack, &m1stack, low_effort, prooftextptr, &bls75_hybrid); } else if (success == 2) { mpz_divexact(u, u, f); if (mpz_cmp(u, f) < 0) mpz_swap(u, f); handle_factor2(f, R2, F2, &f2stack, &p2stack, &m2stack, low_effort, prooftextptr, &bls75_hybrid); handle_factor2(u, R2, F2, &f2stack, &p2stack, &m2stack, low_effort, prooftextptr, &bls75_hybrid); } #if PRINT_PCT fac_pct = (100.0 * (mpz_sizeinbase(F1,2) + mpz_sizeinbase(F2,2))) / (mpz_sizeinbase(nm1,2) + mpz_sizeinbase(np1,2)); printf("%6.2f .. ", fac_pct); fflush(stdout); #endif } start_hybrid_proof: mpz_mul(t, F1, R1); if (mpz_cmp(nm1, t) != 0) croak("Bad n-1 factor"); mpz_mul(t, F2, R2); if (mpz_cmp(np1, t) != 0) croak("Bad n+1 factor"); /* We've done all the factoring we need or can. */ /* Finish proofs for p{1,2}stack as needed. */ /* TODO: optimize for cases of both n-1 and n+1 working */ if (nstack(&p1stack) > 0) { while (nstack(&p1stack) > 0) { int pr = 1; pop_fstack(f, &p1stack); if (effort > low_effort) pr = bls75_hybrid(f, effort, prooftextptr); if (pr == 0) croak("probable prime factor proved composite"); else if (pr == 2) push_fstack(&f1stack, f); /* Proved, put on F stack */ else factor_out(F1, R1, f); /* No proof. Move to R */ } } if (nstack(&p2stack) > 0) { while (nstack(&p2stack) > 0) { int pr = 1; pop_fstack(f, &p2stack); if (effort > low_effort) pr = bls75_hybrid(f, effort, prooftextptr); if (pr == 0) croak("probable prime factor proved composite"); else if (pr == 2) push_fstack(&f2stack, f); /* Proved, put on F stack */ else factor_out(F2, R2, f); /* No proof. Move to R */ } } fstack_sort_trim(&f1stack); fstack_sort_trim(&f2stack); #if PRINT_PCT fin_pct = (100.0 * (mpz_sizeinbase(F1,2) + mpz_sizeinbase(F2,2))) / (mpz_sizeinbase(nm1,2) + mpz_sizeinbase(np1,2)); printf("%6.2f .. ", fin_pct); fflush(stdout); printf("\n"); fflush(stdout); #endif /* Check the theorems we have available */ if (bls_theorem7_limit(n, F1, R1, B1, t, u, r, s)) { if (get_verbose_level() > 0) printf("BLS75 proof using N-1\n"); trim_factors(F1, R1, n, nm1, B1, &f1stack, &bls_theorem7_limit, t, u, r, s); for (pcount = 0; success > 0 && pcount < f1stack.cur; pcount++) success = _verify_cond_I_p(n, f1stack.stack[pcount], u, t, 1000, 0); if (success > 0 && (mpz_mul(t, F1, F1), mpz_cmp(t,n) > 0)) goto end_hybrid; /* Corollary 1, n-1 factored more than sqrt(n) */ if (success > 0 && !bls_theorem5_limit(n, F1, R1, B1, t, u, r, s)) success = _verify_cond_I_p(n, R1, u, t, 1000, 0); if (success > 0) { mpz_mul(t, r, r); mpz_submul_ui(t, s, 8); /* t = r^2 - 8s */ /* N is prime if and only if s=0 OR t not a perfect square */ success = (mpz_sgn(s) == 0 || !mpz_perfect_square_p(t)) ? 1 : -1; } goto end_hybrid; /* Theorem 5 or 7 */ } if (bls_theorem19_limit(n, F2, R2, B1, t, u, r, s)) { IV qv[MAXQV]; int numqv = 0; if (get_verbose_level() > 0) printf("BLS75 proof using N+1\n"); trim_factors(F2, R2, n, np1, B1, &f2stack, &bls_theorem19_limit, t, u, r, s); for (pcount = 0; success > 0 && pcount < f2stack.cur; pcount++) success = _verify_cond_III_q(n, f2stack.stack[pcount], qv, &numqv, 0, 0); if (success > 0 && (mpz_mul(t,F2,F2), mpz_add_ui(t,t,1), mpz_cmp(t,n) > 0)) goto end_hybrid; /* Corollary 8, n+1 factored more than sqrt(n)+1 */ if (success > 0 && !bls_theorem17_limit(n, F2, R2, B1, t, u, r, s)) success = _verify_cond_III_q(n, R2, qv, &numqv, 0, 0); if (success > 0) { mpz_mul(t, r, r); mpz_submul_ui(t, s, 8); /* t = r^2 - 8s */ /* N is prime if and only if s=0 OR t not a perfect square */ success = (mpz_sgn(s) == 0 || !mpz_perfect_square_p(t)) ? 1 : -1; } goto end_hybrid; /* Theorem 17 or 19 */ } if (get_verbose_level() > 0) printf("BLS75 proof using N-1 / N+1 (T20)\n"); /* Check N < B^3 F1*F2*F2/2 or N < B^3 F1*F1*F2/2 */ success = bls_theorem20_limit(n, R1, F1, F2, B1, m, t, u, r, s); /* Trim some factors from f2stack if possible */ if (nstack(&f2stack) > 1) { int i; mpz_set_ui(F2, 1); mpz_set(R2, np1); for (i = 0; i < f2stack.cur; i++) { if (i > 0 && bls_theorem20_limit(n, R1, F1, F2, B1, m, t, u, r, s)) break; factor_out(R2, F2, f2stack.stack[i]); } /* Remove excess factors */ while (i < f2stack.cur) pop_fstack(t, &f2stack); /* Verify Q[0] = 2 */ if (mpz_cmp_ui(f2stack.stack[0], 2) != 0) croak("BLS75 internal error: 2 not at start of fstack"); } /* Check lambda divisibility if needed */ if (success > 0 && mpz_sgn(s)) { UV lambda; mpz_mul(t, F1, F2); mpz_tdiv_q_2exp(t, t, 1); mpz_mul(u, r, F1); mpz_add_ui(u, u, 1); for (lambda = 0; success > 0 && lambda < m; lambda++, mpz_add(u,u,t)) { if (lambda > 0 || mpz_sgn(r)) if (mpz_divisible_p(n, u)) { /* Check that we found a non-trivial divisor */ mpz_gcd(t, u, n); success = (mpz_cmp_ui(t,1) > 0 || mpz_cmp(t,n) < 0) ? -1 : 0; break; } } } /* Verify (I) page 623 and (II) page 625 */ if (success > 0) { for (pcount = 0; success > 0 && pcount < f1stack.cur; pcount++) success = _verify_cond_I_p(n, f1stack.stack[pcount], u, t, 1000, 0); if (success > 0) success = _verify_cond_I_p(n, R1, u, t, 1000, 0); } /* Verify (III) page 631 and (IV) page 633 */ if (success > 0) { IV qv[MAXQV]; int numqv = 0; for (pcount = 0; success > 0 && pcount < f2stack.cur; pcount++) success = _verify_cond_III_q(n, f2stack.stack[pcount], qv, &numqv, 0, 0); if (success > 0) success = _verify_cond_III_q(n, R2, qv, &numqv, 0, 0); } #if 0 { double p1 = (100.0 * mpz_sizeinbase(F1,2) / mpz_sizeinbase(nm1,2)); double p2 = (100.0 * mpz_sizeinbase(F2,2) / mpz_sizeinbase(np1,2)); printf("%6.2f %6.2f\n", p1, p2); fflush(stdout); } //{ double pct = (100.0 * (mpz_sizeinbase(R1,2) + mpz_sizeinbase(R2,2))) / (mpz_sizeinbase(nm1,2) + mpz_sizeinbase(np1,2)); printf("%6.2f\n", 100.0-pct); fflush(stdout); } #endif end_hybrid: destroy_fstack(&f1stack); destroy_fstack(&f2stack); destroy_fstack(&p1stack); destroy_fstack(&p2stack); destroy_fstack(&m1stack); destroy_fstack(&m2stack); mpz_clear(nm1); mpz_clear(np1); mpz_clear(F1); mpz_clear(F2); mpz_clear(R1); mpz_clear(R2); mpz_clear(r); mpz_clear(s); mpz_clear(u); mpz_clear(t); mpz_clear(f); mpz_clear(c1); mpz_clear(c2); if (success < 0) return 0; if (success > 0) return 2; return 1; } /* Given an n where we're factored n-1 down to p, check BLS theorem 3 */ int _GMP_primality_bls_3(mpz_t n, mpz_t p, UV* reta) { mpz_t nm1, m, t, t2; int rval = 0; if (reta) *reta = 0; if (mpz_cmp_ui(n, 2) <= 0 || mpz_even_p(n) || mpz_even_p(p)) return 0; /* n is <= 2, n is even, or p is even */ if (!_GMP_is_prob_prime(p)) return 0; /* p is not a probable prime */ mpz_init(nm1); mpz_init(m); mpz_init(t); mpz_init(t2); mpz_sub_ui(nm1, n, 1); mpz_divexact(m, nm1, p); mpz_mul(t, m, p); if (mpz_cmp(nm1, t) != 0) goto end_bls3; /* m*p != n+1 */ mpz_mul_ui(t, p, 2); mpz_add_ui(t, t, 1); mpz_sqrt(t2, n); if (mpz_cmp(t, t2) <= 0) goto end_bls3; /* 2p+1 <= sqrt(n) */ { /* N-1 = mp, p is an odd probable prime, and 2p+1 > sqrt(n). * Now find an 'a' where a^(n-1)/2 = -1 mod n, a^(m/2) != -1 mod n. */ PRIME_ITERATOR(iter); UV const alimit = 1000; UV a; for (a = 2; a <= alimit; a = prime_iterator_next(&iter)) { /* should check kronecker(a,n) == -1 here */ mpz_set_ui(t2, a); mpz_divexact_ui(t, m, 2); mpz_powm(t, t2, t, n); /* a^(m/2) mod n */ if (mpz_cmp(t, nm1) == 0) continue; mpz_divexact_ui(t, nm1, 2); mpz_powm(t, t2, t, n); /* a^((n-1)/2) mod n */ if (mpz_cmp(t, nm1) != 0) continue; rval = 2; if (reta) *reta = a; break; } prime_iterator_destroy(&iter); } end_bls3: mpz_clear(nm1); mpz_clear(m); mpz_clear(t); mpz_clear(t2); return rval; } /* Given an n where we're factored n+1 down to f, check BLS theorem 15 */ int _GMP_primality_bls_15(mpz_t n, mpz_t f, IV* lp, IV* lq) { mpz_t np1, m, t, t2; int rval = 0; if (lp) *lp = 0; if (lq) *lq = 0; if (mpz_cmp_ui(n, 2) <= 0 || mpz_even_p(n) || mpz_even_p(f)) return 0; /* n is <= 2, n is even, or f is even */ if (!_GMP_is_prob_prime(f)) return 0; /* f is not a probable prime */ mpz_init(np1); mpz_init(m); mpz_init(t); mpz_init(t2); mpz_add_ui(np1, n, 1); mpz_divexact(m, np1, f); mpz_mul(t, m, f); if (mpz_cmp(np1, t) != 0) goto end_bls15; /* m*f != n+1 */ mpz_mul_ui(t, f, 2); mpz_sub_ui(t, t, 1); mpz_sqrt(t2, n); if (mpz_cmp(t, t2) <= 0) goto end_bls15; /* 2f-1 <= sqrt(n) */ { /* N+1 = mf, f is an odd probable prime, and 2f-1 > sqrt(n). * Now find a Lucas sequence V_k with discriminant D s.t. D/N = -1 * where N divides V_(N+1)/2 and N does not divide V_m/2. */ IV d, p, q; mpz_t U, V, k; mpz_init(U); mpz_init(V); mpz_init(k); /* Primo gave me the idea of this p/q selection method */ for (q = 2; q < 1000; q++) { p = (q % 2) ? 2 : 1; d = p*p - 4*q; mpz_set_si(t, d); if (mpz_jacobi(t, n) != -1) continue; /* we have a d/p/q where d = -1. Check the Lucas sequences. */ mpz_divexact_ui(k, m, 2); lucas_seq(U, V, n, p, q, k, t, t2); if (mpz_sgn(V) != 0) { mpz_divexact_ui(k, np1, 2); lucas_seq(U, V, n, p, q, k, t, t2); if (mpz_sgn(V) == 0) { rval = 2; if (lp) *lp = p; if (lq) *lq = q; break; } } } mpz_clear(U); mpz_clear(V); mpz_clear(k); } end_bls15: /* Somehow there is a tester getting 0 for LQ */ if (rval && lq && *lq < 2) croak("Internal error in BLS15\n"); mpz_clear(np1); mpz_clear(m); mpz_clear(t); mpz_clear(t2); return rval; } /* Given an n, try using BLS75 theorem 15, N+1 = mq. * Note: this does _not_ prove n is prime! If it returns 1, then we have * found a q/D that satisfy theorem 15, but we leave proving q for the caller. */ int _GMP_primality_bls_np1_split(mpz_t n, int effort, mpz_t q, IV* lp, IV* lq) { mpz_t np1, m, f, sqrtn, t; int e, success = 1; UV B1 = 2000; /* We need to do this for BLS */ if (mpz_even_p(n)) return 0; mpz_init(np1); mpz_init(m); mpz_init(f); mpz_init(sqrtn); mpz_init(t); mpz_add_ui(np1, n, 1); mpz_set_ui(m, 1); mpz_set(q, np1); mpz_sqrt(sqrtn, n); small_factor(m, q, B1); while (success) { success = 0; mpz_mul_ui(t, q, 2); mpz_sub_ui(t, t, 1); if (mpz_cmp(t, sqrtn) <= 0) break; if (_GMP_is_prob_prime(q)) { success = 1; break; } for (e = 0; !success && e <= effort; e++) success = tfe(f, q, e); if (success) { mpz_divexact(q, q, f); if (mpz_cmp(q, f) < 0) mpz_swap(q, f); mpz_mul(m, m, f); } } if (success) success = _GMP_primality_bls_15(n, q, lp, lq); mpz_clear(np1); mpz_clear(m); mpz_clear(f); mpz_clear(sqrtn); mpz_clear(t); return success; } /* Given an n, try using BLS75 theorem 3, N-1 = mp. */ int _GMP_primality_bls_nm1_split(mpz_t n, int effort, mpz_t p, UV *reta) { mpz_t nm1, m, f, sqrtn, t; int e, success = 1; UV B1 = 2000; /* We need to do this for BLS */ if (mpz_even_p(n)) return 0; mpz_init(nm1); mpz_init(m); mpz_init(f); mpz_init(sqrtn); mpz_init(t); mpz_sub_ui(nm1, n, 1); mpz_set_ui(m, 1); mpz_set(p, nm1); mpz_sqrt(sqrtn, n); small_factor(m, p, B1); while (success) { success = 0; mpz_mul_ui(t, p, 2); mpz_add_ui(t, t, 1); if (mpz_cmp(t, sqrtn) <= 0) break; if (_GMP_is_prob_prime(p)) { success = 1; break; } for (e = 0; !success && e <= effort; e++) success = tfe(f, p, e); if (success) { mpz_divexact(p, p, f); if (mpz_cmp(p, f) < 0) mpz_swap(p, f); mpz_mul(m, m, f); } } if (success) success = _GMP_primality_bls_3(n, p, reta); mpz_clear(nm1); mpz_clear(m); mpz_clear(f); mpz_clear(sqrtn); mpz_clear(t); return success; } Math-Prime-Util-GMP-0.52/class_poly_data.h0000644000175000017500000037630313663067455016674 0ustar danadana/* This file is meant to be loaded by utility.c */ struct _class_poly { unsigned int D; unsigned short type; unsigned short degree; const char *coefs; }; /* Type: 1 = Hilbert, 2 = Weber, 3 = Ramanujan */ static const struct _class_poly _class_poly_data[] = { { 3, 1, 1, "\x00" }, { 4, 1, 1, "\x81\x0c" }, { 7, 1, 1, "\x01\x0f" }, { 8, 1, 1, "\x81\x14" }, { 11, 3, 1, "\x81\x01" }, { 15, 2, 2, "\x81\x01\x81\x01" }, { 19, 1, 1, "\x01\x60" }, { 20, 2, 2, "\x81\x01\x81\x01" }, { 23, 2, 3, "\x81\x01\x81\x01\x00" }, { 24, 2, 2, "\x81\x01\x81\x02" }, { 31, 2, 3, "\x81\x01\x00\x81\x01" }, { 35, 3, 2, "\x81\x01\x01\x01" }, { 39, 2, 4, "\x81\x01\x81\x02\x81\x04\x81\x03" }, { 40, 2, 2, "\x81\x01\x81\x01" }, { 43, 1, 1, "\x02\x03\xc0" }, { 47, 2, 5, "\x81\x01\x81\x02\x81\x02\x81\x01\x00" }, { 51, 1, 2, "\x02\x48\x00\x05\x01\x4a\x46\x80\x00" }, { 52, 2, 2, "\x81\x01\x81\x03" }, { 55, 2, 4, "\x81\x01\x01\x01\x00\x81\x02" }, { 56, 2, 4, "\x01\x01\x81\x02\x01\x01\x81\x02" }, { 59, 3, 3, "\x81\x01\x01\x02\x00" }, { 67, 1, 1, "\x02\x14\xa0" }, { 68, 2, 4, "\x01\x01\x81\x01\x81\x02\x81\x01" }, { 71, 2, 7, "\x81\x01\x81\x01\x01\x01\x01\x01\x01\x01\x81\x01\x81\x02" }, { 79, 2, 5, "\x81\x01\x01\x01\x81\x01\x01\x02\x81\x03" }, { 83, 3, 3, "\x81\x01\x01\x02\x01\x02" }, { 84, 2, 4, "\x01\x01\x01\xa8\x01\x8e\x81\xa8" }, { 87, 2, 6, "\x81\x01\x81\x01\x81\x04\x01\x04\x81\x0b\x81\x0d" }, { 88, 2, 2, "\x81\x01\x81\x02" }, { 91, 1, 2, "\x83\x02\x64\x00\x06\x09\x6b\xe8\xde\x00\x00" }, { 95, 2, 8, "\x81\x01\x01\x01\x00\x81\x01\x01\x02\x01\x01\x81\x02\x81\x02" }, { 103, 2, 5, "\x81\x01\x81\x02\x81\x03\x81\x03\x81\x01" }, { 104, 2, 6, "\x81\x01\x81\x02\x01\x02\x00\x81\x02\x81\x02" }, { 107, 3, 3, "\x81\x01\x01\x04\x81\x02" }, { 111, 2, 8, "\x81\x01\x81\x01\x81\x06\x81\x0b\x01\x04\x01\x0e\x81\x1a\x81\x15" }, { 115, 1, 2, "\x03\x07\xbc\x00\x07\x01\x85\x23\xfe\x2a\x00\x00" }, { 116, 2, 6, "\x81\x01\x81\x09\x81\x05\x01\x02\x01\x05\x81\x09" }, { 119, 2, 10, "\x01\x01\x81\x01\x01\x02\x81\x04\x01\x05\x81\x07\x01\x09\x81\x08\x01\x05\x81\x04" }, { 120, 2, 4, "\x01\x01\x81\x18\x81\x36\x81\x18" }, { 123, 1, 2, "\x03\x50\xdc\x00\x07\x04\xcf\x96\xe1\x68\x00\x00" }, { 127, 2, 5, "\x81\x01\x01\x01\x01\x02\x81\x01\x81\x03" }, { 131, 3, 5, "\x81\x01\x01\x05\x81\x03\x81\x01\x01\x01" }, { 132, 2, 4, "\x01\x01\x81\x1e\x81\x46\x81\x1e" }, { 136, 2, 4, "\x01\x01\x81\x03\x00\x81\x03" }, { 139, 1, 3, "\x04\x02\x6d\x00\x00\x89\x02\xe0\x1a\x48\x06\xc0\x00\x00\x00\x07\x2b\x48\x85\x2d\xc1\x00\x00" }, { 143, 2, 10, "\x81\x01\x01\x03\x81\x06\x01\x06\x81\x03\x81\x03\x01\x09\x81\x0d\x01\x0c\x81\x06" }, { 148, 2, 2, "\x81\x01\x81\x0c" }, { 151, 2, 7, "\x81\x01\x81\x01\x81\x01\x00\x81\x03\x81\x01\x81\x03" }, { 152, 2, 6, "\x81\x01\x81\x04\x00\x01\x06\x00\x81\x04" }, { 155, 3, 4, "\x81\x01\x01\x04\x01\x05\x01\x02" }, { 159, 2, 10, "\x81\x01\x01\x01\x81\x01\x81\x07\x81\x3f\x81\x79\x81\xdb\x81\xc4\x81\x92\x81\x2f" }, { 163, 1, 1, "\x03\x09\xc5\x40" }, { 164, 2, 8, "\x01\x01\x81\x05\x01\x07\x81\x0c\x01\x0e\x81\x0c\x01\x07\x81\x05" }, { 167, 2, 11, "\x81\x01\x81\x01\x81\x05\x81\x04\x81\x0a\x81\x06\x81\x0b\x81\x07\x81\x09\x81\x04\x81\x02" }, { 168, 2, 4, "\x01\x01\x01\x38\x81\x52\x81\x38" }, { 179, 3, 5, "\x81\x01\x01\x06\x81\x01\x01\x05\x81\x02" }, { 183, 2, 8, "\x81\x01\x81\x01\x01\x0b\x01\x0a\x81\x62\x01\x9d\x81\x35\x81\x47" }, { 184, 2, 4, "\x01\x01\x81\x06\x01\x09\x81\x06" }, { 187, 1, 2, "\x83\xef\x10\x00\x08\x3f\x14\x47\x5b\x65\x24\x80\x00" }, { 191, 2, 13, "\x81\x01\x01\x02\x00\x81\x04\x01\x05\x81\x01\x81\x05\x01\x0b\x81\x13\x01\x16\x81\x10\x01\x0a\x81\x06" }, { 195, 1, 4, "\x85\x0e\x56\x50\x00\x00\x0d\x01\x52\x8a\x46\xfd\x3a\x45\x40\x00\x00\x00\x00\x00\x0b\x14\xf7\xe3\xad\x05\xbb\xdd\x00\x00\x00\x00\x08\x9c\x9a\x48\x7a\x35\xdf\x00\x00" }, { 199, 2, 9, "\x81\x01\x81\x01\x00\x81\x03\x00\x00\x81\x03\x01\x03\x81\x05" }, { 203, 3, 4, "\x81\x01\x01\x07\x00\x81\x03" }, { 211, 1, 3, "\x04\x67\xfe\x00\x00\x0a\x3a\xbd\x5f\x8f\x2b\x18\xc0\x00\x00\x00\x09\x03\x92\x2d\xfe\xa0\x33\x7c\x00\x00" }, { 212, 2, 6, "\x81\x01\x81\x17\x81\x0c\x81\x4b\x01\x0c\x81\x17" }, { 215, 2, 14, "\x81\x01\x01\x02\x00\x81\x06\x01\x03\x01\x08\x81\x0d\x81\x04\x01\x10\x81\x07\x81\x0d\x01\x0b\x01\x04\x81\x06" }, { 219, 1, 4, "\x05\x6f\xe3\xa0\x00\x00\x8d\xc9\xb1\x36\x8a\x9f\xf0\x2c\xa0\x00\x00\x00\x00\x00\x0c\x02\xaf\x6b\x60\xe1\xe4\x44\x86\xc0\x00\x00\x00\x09\x08\x6a\x00\xf2\x0f\x9b\x84\x80\x00" }, { 223, 2, 7, "\x81\x01\x00\x81\x01\x81\x04\x01\x01\x00\x81\x05" }, { 227, 3, 5, "\x81\x01\x01\x09\x81\x09\x01\x09\x81\x05" }, { 228, 2, 4, "\x01\x01\x81\x82\x82\x01\x86\x81\x82" }, { 231, 2, 12, "\x01\x01\x81\x04\x01\x1d\x81\x2d\x01\x72\x81\x20\x81\x76\x02\x01\x5d\x82\x02\xd4\x02\x02\x05\x81\x21\x81\x8a" }, { 232, 2, 2, "\x81\x01\x81\x05" }, { 235, 1, 2, "\x04\x0d\xa0\x34\x00\x09\x2c\x9f\xe1\xad\x9b\xbd\xc3\x00\x00" }, { 239, 2, 15, "\x81\x01\x01\x04\x81\x04\x81\x04\x01\x05\x01\x0d\x81\x14\x81\x04\x01\x0f\x01\x0d\x81\x1b\x01\x04\x01\x08\x01\x02\x81\x06" }, { 244, 2, 6, "\x81\x01\x81\x1e\x81\x06\x81\x30\x01\x06\x81\x1e" }, { 247, 2, 6, "\x81\x01\x81\x03\x81\x06\x81\x07\x81\x07\x81\x04" }, { 248, 2, 8, "\x01\x01\x81\x02\x81\x0d\x81\x1e\x81\x24\x81\x1e\x81\x0d\x81\x02" }, { 251, 3, 7, "\x81\x01\x01\x09\x01\x02\x81\x04\x81\x02\x01\x06\x01\x05" }, { 255, 2, 12, "\x01\x01\x81\x0b\x01\x42\x81\xdd\x02\x02\x01\x82\x03\x90\x02\x03\xf4\x82\x01\x1f\x82\x02\xbe\x02\x03\x47\x81\xc2\x81\xba" }, { 259, 1, 4, "\x05\x26\x1b\x70\x00\x00\x0d\x45\x55\xdf\xf9\x45\x98\x82\x40\x00\x00\x00\x00\x00\x8c\x01\x30\x8f\x27\x46\xe1\xea\x98\x00\x00\x00\x00\x0a\x01\xeb\xa1\xa7\x44\x5b\x52\x9b\x00\x00" }, { 260, 2, 8, "\x01\x01\x81\x08\x01\x0c\x01\x08\x81\x1b\x01\x08\x01\x0c\x81\x08" }, { 263, 2, 13, "\x81\x01\x01\x06\x81\x0f\x01\x15\x81\x13\x01\x0d\x81\x0c\x01\x16\x81\x24\x01\x26\x81\x1b\x01\x10\x81\x08" }, { 264, 2, 8, "\x01\x01\x81\xcc\x82\x03\xcc\x82\x06\xb4\x82\x09\x6a\x82\x06\xb4\x82\x03\xcc\x81\xcc" }, { 267, 1, 2, "\x05\x01\xe2\xcb\x50\x00\x0a\x04\x2b\x05\xc5\xab\xcb\x90\xb9\x80\x00" }, { 271, 2, 11, "\x81\x01\x00\x81\x01\x81\x01\x81\x03\x01\x03\x01\x06\x01\x03\x81\x05\x81\x06\x81\x05" }, { 275, 3, 4, "\x01\x01\x81\x0b\x01\x06\x81\x01" }, { 276, 2, 8, "\x01\x01\x02\xe2\xb0\x03\x09\x19\xdc\x03\x07\x26\xf0\x03\x14\x15\x46\x83\x07\x26\xf0\x03\x09\x19\xdc\x82\xe2\xb0" }, { 280, 2, 4, "\x01\x01\x01\x06\x81\x03\x81\x06" }, { 283, 1, 3, "\x05\x01\x5d\x5d\x80\x00\x0b\x4b\x23\xf4\xe1\x43\x46\xca\xc0\x00\x00\x00\x0a\x12\xf9\xd6\xee\x5f\x2f\x57\x7c\x80\x00" }, { 287, 2, 14, "\x01\x01\x01\x01\x01\x03\x81\x01\x81\x01\x00\x01\x02\x01\x06\x81\x08\x81\x07\x81\x05\x01\x06\x01\x09\x81\x08" }, { 291, 1, 4, "\x06\x19\x66\x62\xc0\x00\x00\x0f\x36\xf6\xc6\x86\x91\xb9\x98\xb9\x88\x20\x00\x00\x00\x00\x00\x0d\x88\x25\x58\x96\x0b\x2a\x30\x0a\xde\xc0\x00\x00\x00\x0a\x27\xd7\xef\x08\xe7\xbd\xfb\xb9\x80\x00" }, { 292, 2, 4, "\x01\x01\x81\x05\x81\x0a\x81\x05" }, { 295, 2, 8, "\x81\x01\x01\x03\x81\x07\x01\x0a\x81\x07\x81\x01\x01\x09\x81\x08" }, { 296, 2, 10, "\x81\x01\x81\x08\x81\x09\x81\x04\x81\x09\x81\x04\x01\x09\x81\x04\x01\x09\x81\x08" }, { 299, 3, 8, "\x01\x01\x81\x0d\x01\x0f\x81\x0c\x01\x10\x81\x0c\x81\x01\x01\x01" }, { 303, 2, 10, "\x81\x01\x81\x02\x81\x24\x81\x2e\x81\xad\x82\x01\xbf\x82\x02\xd0\x82\x02\xf4\x82\x05\x16\x82\x01\x45" }, { 307, 1, 3, "\x05\x04\xd7\x42\x00\x00\x8c\x10\x6d\x18\x00\xf2\x4a\xf9\xd8\x00\x00\x00\x00\x0a\xaa\x78\x0c\x7f\xb1\x36\x22\x3f\x80\x00" }, { 308, 2, 8, "\x01\x01\x01\x2e\x81\xab\x01\x2e\x02\x01\x64\x81\x2e\x81\xab\x81\x2e" }, { 311, 2, 19, "\x81\x01\x81\x01\x81\x02\x81\x05\x81\x08\x81\x0e\x81\x0d\x81\x0a\x01\x01\x01\x09\x01\x12\x01\x19\x01\x0a\x81\x04\x81\x26\x81\x2a\x81\x25\x81\x10\x81\x04" }, { 312, 2, 4, "\x01\x01\x82\x01\x68\x82\x05\x76\x82\x01\x68" }, { 319, 2, 10, "\x81\x01\x81\x05\x81\x0b\x81\x0e\x81\x0a\x81\x02\x81\x01\x81\x05\x81\x09\x81\x06" }, { 323, 3, 4, "\x81\x01\x01\x0d\x01\x04\x81\x01" }, { 327, 2, 12, "\x81\x01\x81\x0e\x81\x3f\x81\x3a\x01\xae\x01\x5c\x82\x05\x9c\x82\x0f\xa6\x82\x15\x94\x82\x12\xec\x82\x0a\x0d\x82\x01\xa7" }, { 328, 2, 4, "\x01\x01\x81\x09\x01\x0c\x81\x09" }, { 331, 1, 3, "\x05\x59\x2b\xd0\x80\x00\x0d\x04\xa7\x6e\x3f\xa2\x56\x09\x40\x52\xc0\x00\x00\x00\x0b\x05\x7f\xa4\x88\x51\x69\x5d\xe1\x49\x80\x00" }, { 335, 2, 18, "\x81\x01\x81\x05\x81\x0e\x81\x19\x81\x21\x81\x2a\x81\x40\x81\x66\x81\x90\x81\xab\x81\xb3\x81\xae\x81\xa3\x81\x90\x81\x6a\x81\x37\x81\x14\x81\x04" }, { 339, 1, 6, "\x08\x01\x09\xe3\x87\x00\x00\x00\x00\x14\x13\xfa\x51\xd3\x61\x5f\xa6\x30\x46\x67\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x01\x80\x7f\xa9\xc4\xed\xb7\x3e\x27\xf7\x90\x90\x00\x00\x00\x00\x00\x00\x00\x91\x01\x8d\x2b\x09\x62\xfb\x78\xc1\xa8\x65\xaf\x80\x00\x00\x00\x00\x00\x0e\x99\xd1\xd7\xde\x0f\x8c\x10\x61\xc1\x3d\x80\x00\x00\x00\x0b\x0a\xec\xe0\x1b\x45\x9b\xa0\xe4\x8e\x00\x00" }, { 340, 2, 4, "\x01\x01\x01\x3f\x01\x22\x81\x3f" }, { 344, 2, 10, "\x81\x01\x81\x08\x81\x02\x81\x12\x81\x09\x81\x04\x01\x09\x81\x12\x01\x02\x81\x08" }, { 347, 3, 5, "\x81\x01\x01\x0d\x01\x1b\x01\x15\x01\x07" }, { 355, 1, 4, "\x06\x05\x03\x6c\x40\x00\x00\x8f\x04\x9f\xf8\x4b\x50\x38\x5a\xdf\xdc\x00\x00\x00\x00\x00\x00\x0d\x56\x31\x78\x30\x73\xd0\xba\x84\x4f\xc0\x00\x00\x00\x0b\x2a\x1d\x09\x83\xf6\x1d\xce\x12\x46\x00\x00" }, { 356, 2, 12, "\x01\x01\x81\x05\x81\x15\x81\x32\x81\x41\x81\x51\x81\x46\x81\x51\x81\x41\x81\x32\x81\x15\x81\x05" }, { 359, 2, 19, "\x81\x01\x01\x02\x81\x02\x01\x02\x01\x03\x81\x0e\x01\x07\x01\x16\x81\x1e\x01\x09\x81\x05\x01\x02\x01\x33\x81\x5a\x01\x13\x01\x5b\x81\x71\x01\x3b\x81\x0e" }, { 367, 2, 9, "\x81\x01\x01\x02\x01\x01\x81\x06\x01\x02\x00\x81\x02\x01\x03\x81\x09" }, { 371, 3, 8, "\x81\x01\x01\x12\x81\x17\x01\x08\x01\x0e\x81\x0a\x01\x09" }, { 372, 2, 4, "\x01\x01\x03\x07\x3b\x48\x03\x8c\xa5\x0e\x83\x07\x3b\x48" }, { 376, 2, 8, "\x01\x01\x81\x06\x81\x15\x81\x2a\x81\x34\x81\x2a\x81\x15\x81\x06" }, { 379, 1, 3, "\x06\x02\x43\xd0\xb6\x00\x00\x8e\x05\xfe\x66\xb7\xd5\x92\xd4\xc1\x8e\x25\x40\x00\x00\x00\x0c\x01\x2d\x6b\xba\x70\x4e\x88\xe4\x80\x44\x00\x00" }, { 383, 2, 17, "\x81\x01\x01\x01\x01\x01\x01\x01\x00\x81\x01\x81\x0d\x81\x07\x81\x0b\x81\x04\x81\x01\x81\x07\x81\x17\x81\x1f\x81\x2a\x81\x18\x81\x06" }, { 388, 2, 4, "\x01\x01\x81\x09\x81\x02\x81\x09" }, { 391, 2, 14, "\x01\x01\x00\x81\x05\x81\x05\x01\x07\x01\x0f\x01\x06\x81\x08\x81\x03\x01\x04\x00\x81\x0c\x81\x0c\x81\x08" }, { 395, 3, 8, "\x81\x01\x01\x11\x01\x1b\x01\x18\x01\x1c\x01\x10\x01\x05\x81\x01" }, { 399, 2, 16, "\x01\x01\x01\x13\x01\x7d\x02\x01\x4a\x02\x01\x69\x02\x02\x81\x02\x09\xba\x02\x0b\xce\x82\x01\x68\x02\x05\xce\x02\x2b\xbf\x02\x1c\xd0\x82\x1d\x63\x82\x18\x15\x82\x14\x8c\x82\x03\x80" }, { 403, 1, 2, "\x85\x01\x1c\x96\x4c\x00\x0c\x07\xec\xeb\x03\xd8\x50\xb4\x8f\x4e\x9d\x00\x00" }, { 404, 2, 14, "\x81\x01\x81\x65\x82\x01\xc3\x82\x04\x64\x82\x04\x50\x82\x07\x2c\x81\xc2\x82\x09\x26\x01\xc2\x82\x07\x2c\x02\x04\x50\x82\x04\x64\x02\x01\xc3\x81\x65" }, { 407, 2, 16, "\x81\x01\x81\x01\x81\x02\x81\x01\x81\x09\x01\x02\x81\x0f\x00\x81\x0c\x00\x81\x04\x81\x13\x01\x11\x81\x21\x01\x04\x81\x0a" }, { 408, 2, 4, "\x01\x01\x02\x03\xd4\x82\x12\x5e\x82\x03\xd4" }, { 411, 1, 6, "\x08\x3a\x02\x01\x29\x00\x00\x00\x00\x96\x0c\x81\xf6\x70\x54\x6e\x64\x07\x33\x8e\x74\x7c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x98\x77\x80\x1c\x23\x6b\x25\x43\x95\x3d\xb1\x8c\xf0\x00\x00\x00\x00\x00\x00\x00\x12\x11\xbb\x44\xfa\xcb\x8c\x35\x13\xa2\x5f\x67\xbf\xc0\x00\x00\x00\x00\x00\x10\x05\xb5\xfa\xdc\xcc\x96\xed\x0b\x01\xf3\x8b\x8a\x00\x00\x00\x00\x0c\x0e\xc6\x90\x58\x43\xfd\xce\x9d\x95\xc5\x00\x00" }, { 415, 2, 10, "\x81\x01\x00\x81\x06\x01\x02\x81\x0e\x01\x02\x81\x0b\x81\x07\x81\x01\x81\x0a" }, { 419, 3, 9, "\x81\x01\x01\x14\x01\x0a\x01\x1f\x81\x08\x01\x0c\x81\x07\x01\x0c\x81\x06" }, { 420, 2, 8, "\x01\x01\x82\x04\x4c\x82\x18\x88\x01\x3c\x02\x3d\x2e\x01\x3c\x82\x18\x88\x82\x04\x4c" }, { 424, 2, 6, "\x81\x01\x81\x0b\x81\x05\x01\x06\x01\x05\x81\x0b" }, { 427, 1, 2, "\x05\x0c\x82\x0f\xbc\x00\x0c\x32\x71\x7e\x4b\x1d\xf0\xbb\x69\x80\xde\x00\x00" }, { 431, 2, 21, "\x81\x01\x81\x03\x81\x06\x81\x09\x81\x09\x01\x04\x01\x0a\x01\x24\x01\x1e\x01\x0e\x01\x02\x81\x42\x81\x29\x81\x53\x81\x2c\x81\x0a\x81\x15\x01\x28\x81\x10\x01\x0f\x81\x0c" }, { 435, 1, 4, "\x87\x08\x3f\x6d\x33\x90\x00\x00\x13\x01\xec\x14\x81\xad\xa4\x78\x26\x63\x8a\xe5\xc4\xee\x40\x00\x00\x00\x00\x00\x10\x41\xcd\x38\x26\xc3\x9f\x4f\x0a\x66\xcb\x4c\x0c\x00\x00\x00\x00\x0c\x5c\x67\x21\x8e\x69\xaf\xe3\x9e\x56\x8b\x00\x00" }, { 436, 2, 6, "\x81\x01\x81\x75\x01\x9c\x81\x09\x81\x9c\x81\x75" }, { 439, 2, 15, "\x81\x01\x01\x05\x81\x0b\x01\x09\x01\x07\x81\x11\x01\x01\x01\x1d\x81\x26\x01\x0d\x01\x14\x81\x18\x81\x07\x01\x17\x81\x0d" }, { 440, 2, 12, "\x01\x01\x81\x10\x01\x40\x81\x68\x01\x20\x01\x90\x81\xf6\x01\x90\x01\x20\x81\x68\x01\x40\x81\x10" }, { 443, 3, 5, "\x81\x01\x01\x16\x01\x11\x81\x03\x81\x04" }, { 447, 2, 14, "\x81\x01\x81\x16\x81\xf3\x82\x05\xec\x82\x16\x20\x82\x33\xbe\x82\x4f\x15\x82\x5a\x4d\x82\x71\x0c\x82\xae\x16\x82\xd2\x42\x82\x94\xd5\x82\x33\xf6\x82\x05\x89" }, { 451, 1, 6, "\x07\xdf\x6e\x06\x00\x00\x00\x00\x15\x04\x79\x45\xf6\x36\xac\xc6\x89\x18\xd7\xc4\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x1a\x35\x65\x0b\x13\x2d\xd7\xd1\xbd\x36\x23\x30\x00\x00\x00\x00\x00\x00\x00\x11\x6d\x8f\x36\x3f\x37\xf6\xae\x45\x52\x21\xa6\xc0\x00\x00\x00\x00\x00\x0f\x07\x44\x59\x71\x99\xab\x6e\x19\x24\x0c\xa1\x00\x00\x00\x00\x0d\x01\x30\xff\x03\x69\xc8\xd6\x4a\x8d\x9b\x9d\x00\x00" }, { 452, 2, 8, "\x01\x01\x81\x09\x81\x16\x81\x3b\x81\x4e\x81\x3b\x81\x16\x81\x09" }, { 455, 2, 20, "\x01\x01\x01\x06\x01\x0f\x01\x17\x01\x1a\x01\x10\x81\x0f\x81\x39\x81\x49\x81\x1e\x01\x4c\x01\xc2\x01\xf6\x01\xbf\x01\x26\x81\x81\x81\xc8\x81\x8e\x81\x32\x81\x06" }, { 456, 2, 8, "\x01\x01\x82\x06\x0c\x82\x0c\x6c\x02\x60\x0c\x82\xbb\x2a\x02\x60\x0c\x82\x0c\x6c\x82\x06\x0c" }, { 463, 2, 7, "\x81\x01\x81\x03\x81\x07\x81\x07\x81\x08\x81\x09\x81\x0b" }, { 467, 3, 7, "\x81\x01\x01\x1a\x81\x17\x01\x03\x81\x03\x01\x07\x01\x06" }, { 471, 2, 16, "\x81\x01\x81\x06\x81\x3e\x01\x6a\x82\x01\x7e\x02\x03\xae\x82\x12\x94\x02\x25\x9d\x82\x4a\x2b\x02\x57\x09\x82\x8e\xf9\x02\xac\xbe\x82\xec\x36\x02\x72\x21\x82\x0f\xf5\x82\x06\xef" }, { 472, 2, 6, "\x81\x01\x81\x0c\x00\x81\x16\x00\x81\x0c" }, { 483, 1, 4, "\x87\x17\xae\xec\x9c\xb0\x00\x00\x13\x07\x33\x75\x84\x6f\xa6\x2e\x90\x37\x16\xce\x84\xe4\x80\x00\x00\x00\x00\x00\x11\x1c\x16\x35\x65\xbd\x9b\x09\xc6\xec\xe5\xa6\x75\xf4\x80\x00\x00\x00\x0d\x0c\x33\x50\x41\xef\x2c\x48\x7e\x0a\xc0\x36\x00\x00" }, { 487, 2, 7, "\x81\x01\x01\x01\x81\x04\x01\x07\x81\x04\x01\x04\x81\x0d" }, { 488, 2, 10, "\x81\x01\x81\x0c\x01\x07\x81\x20\x81\x01\x01\x24\x01\x01\x81\x20\x81\x07\x81\x0c" }, { 491, 3, 9, "\x81\x01\x01\x1d\x81\x28\x01\x2c\x81\x1f\x01\x25\x01\x02\x01\x10\x01\x01" }, { 499, 1, 3, "\x06\x98\x08\xb8\xd9\x00\x00\x90\x04\x8f\xd4\x5e\xec\xd9\x0f\x6c\x7a\x44\x66\x0d\x40\x00\x00\x00\x0d\x25\xee\x01\x60\x17\x75\xcd\x35\x64\x8e\x80\x00\x00" }, { 503, 2, 21, "\x81\x01\x00\x01\x01\x01\x06\x81\x07\x00\x01\x03\x81\x0c\x01\x0a\x01\x17\x81\x1e\x81\x1b\x01\x13\x01\x5c\x81\x4a\x81\x6a\x01\xab\x81\x22\x81\x57\x01\x45\x81\x12" }, { 511, 2, 14, "\x01\x01\x81\x07\x01\x15\x81\x23\x01\x23\x81\x15\x01\x10\x81\x25\x01\x46\x81\x54\x01\x4d\x81\x38\x01\x24\x81\x10" }, { 515, 3, 6, "\x81\x01\x01\x1c\x01\x44\x01\x3c\x01\x20\x01\x08" }, { 516, 2, 12, "\x01\x01\x82\x0a\x52\x82\x26\x36\x02\xaa\x4e\x83\x01\x5b\x81\x03\x01\x68\x04\x83\x03\x0c\x94\x03\x01\x68\x04\x83\x01\x5b\x81\x02\xaa\x4e\x82\x26\x36\x82\x0a\x52" }, { 519, 2, 18, "\x81\x01\x01\x19\x81\xf2\x02\x04\x9a\x82\x0e\x63\x02\x1e\x7e\x82\x31\xdb\x02\x51\xbe\x82\x78\x6a\x02\xa3\xa4\x83\x01\x18\xe4\x03\x01\xbc\x38\x83\x02\x4d\x32\x03\x02\x17\x0c\x82\xc3\x19\x02\x18\x7b\x82\x40\xa1\x82\x0a\x95" }, { 520, 2, 4, "\x01\x01\x81\x0c\x81\x1b\x81\x0c" }, { 523, 1, 5, "\x07\x05\x57\x48\x6a\x00\x00\x00\x92\x5f\xb0\xb8\x03\x26\x1d\x06\x81\x63\x21\x30\x00\x00\x00\x00\x00\x00\x00\x11\x27\x5d\x52\xf5\x36\x9f\x7f\x6a\xa5\x64\x92\x40\x00\x00\x00\x00\x00\x8f\x2d\xa2\xe9\x99\x86\x6b\xc2\x49\x7e\xb0\x3b\x80\x00\x00\x00\x0d\xc9\x0d\x23\x10\x9c\x12\x5e\x46\xfc\x65\xb0\x80\x00" }, { 527, 2, 18, "\x01\x01\x00\x01\x02\x01\x05\x01\x08\x81\x04\x81\x07\x81\x01\x81\x0a\x81\x20\x81\x05\x01\x14\x01\x0c\x01\x0f\x01\x2d\x81\x18\x81\x1f\x81\x0c" }, { 532, 2, 4, "\x01\x01\x01\xd2\x01\x4f\x81\xd2" }, { 535, 2, 14, "\x81\x01\x00\x01\x03\x01\x06\x81\x10\x81\x01\x01\x03\x01\x22\x81\x25\x01\x0a\x81\x0e\x01\x07\x01\x14\x81\x10" }, { 536, 2, 14, "\x81\x01\x81\x0c\x01\x22\x81\x42\x01\x25\x81\x4c\x01\x03\x81\x7e\x81\x03\x81\x4c\x81\x25\x81\x42\x81\x22\x81\x0c" }, { 539, 3, 8, "\x01\x01\x81\x22\x01\x1c\x81\x38\x01\x4d\x81\x38\x01\x1c\x81\x06" }, { 543, 2, 12, "\x81\x01\x01\x15\x81\xce\x02\x03\xa1\x82\x0b\x4f\x02\x19\xfe\x82\x39\x7a\x02\x5d\xce\x82\x68\x9a\x02\x69\x21\x82\x51\x02\x82\x0c\xfd" }, { 547, 1, 3, "\x06\x03\xf8\xdc\xa6\x80\x00\x8f\x1a\xe8\x59\x80\x85\x6a\x81\x97\x88\xc2\x70\x40\x00\x00\x00\x0e\x04\x02\x1e\x0d\x71\x02\x19\x93\x7e\xb8\x6a\x05\x80\x00" }, { 548, 2, 8, "\x01\x01\x81\x15\x01\x67\x81\xec\x02\x01\x2e\x81\xec\x01\x67\x81\x15" }, { 552, 2, 8, "\x01\x01\x02\x0e\x00\x82\x78\x04\x02\x53\x00\x02\x73\x06\x82\x53\x00\x82\x78\x04\x82\x0e\x00" }, { 555, 1, 4, "\x88\x01\x20\x01\xc5\x50\x40\x00\x00\x15\x0d\x31\x86\x32\xeb\x23\x69\xf8\x3a\xd8\x94\x36\x49\xb9\xf2\x00\x00\x00\x00\x00\x00\x12\x52\x8c\x7d\x34\xfb\x2b\x21\x93\x81\xa1\x9e\x17\xd5\xd8\xc0\x00\x00\x00\x0e\x06\xd8\xa7\x5c\x91\x90\xc9\xda\xe3\xb1\x2d\x84\x00\x00" }, { 559, 2, 16, "\x81\x01\x01\x01\x00\x81\x02\x81\x01\x01\x0e\x81\x33\x01\x62\x81\x7b\x01\x53\x01\x12\x81\x8b\x01\xc4\x81\xa1\x01\x4e\x81\x14" }, { 563, 3, 9, "\x81\x01\x01\x26\x81\x40\x01\x5b\x81\x4c\x01\x2c\x81\x0b\x01\x06\x01\x04" }, { 564, 2, 8, "\x01\x01\x03\xf0\x6b\x10\x04\x33\x2a\x24\x5c\x85\x01\xcb\x27\x30\x30\x05\x05\xbb\x80\x78\x46\x05\x01\xcb\x27\x30\x30\x04\x33\x2a\x24\x5c\x83\xf0\x6b\x10" }, { 568, 2, 4, "\x01\x01\x81\x12\x01\x21\x81\x12" }, { 571, 1, 5, "\x08\x03\x71\xa6\xc5\xb8\x00\x00\x00\x95\x0b\x2a\x9a\x0b\xe8\xa5\xd7\xac\x2a\x03\xf4\xfa\x6d\x00\x00\x00\x00\x00\x00\x00\x00\x13\xc5\x39\x71\x48\x4d\x57\x1f\xe8\x63\xdb\xc5\xd4\x69\x60\x00\x00\x00\x00\x00\x11\x02\x67\xc9\x5f\xa7\x3b\x28\xb2\xc2\xf8\x27\x7a\x13\xc0\x00\x00\x00\x0e\x13\xbe\xfe\x54\xe1\x9f\x93\xff\x30\xec\x2e\xea\x80\x00" }, { 580, 2, 8, "\x01\x01\x81\x11\x01\x07\x01\x0c\x81\x2a\x01\x0c\x01\x07\x81\x11" }, { 583, 2, 8, "\x81\x01\x81\x04\x81\x03\x01\x05\x01\x0c\x01\x0b\x81\x0c\x81\x10" }, { 584, 2, 16, "\x01\x01\x81\x16\x01\x63\x81\xbe\x01\xb1\x81\x58\x81\x22\x01\xe4\x82\x01\x76\x01\xe4\x81\x22\x81\x58\x01\xb1\x81\xbe\x01\x63\x81\x16" }, { 587, 3, 7, "\x81\x01\x01\x27\x01\x18\x01\x14\x81\x0c\x01\x10\x01\x01" }, { 595, 1, 4, "\x87\x10\x00\xd5\xd1\xc0\x00\x00\x13\x15\xa9\x31\xfd\xb2\xb2\x07\x03\xac\xbc\x57\xe7\x36\x00\x00\x00\x00\x00\x00\x11\x19\xb8\x5b\x5a\x51\xa5\x46\x50\x9f\xb0\xc8\x92\xb3\x40\x00\x00\x00\x0e\x5e\x1a\x00\xcd\x92\xc9\x14\x20\xef\x79\x77\x39\x00\x00" }, { 596, 2, 14, "\x81\x01\x82\x01\x21\x02\x0a\xc1\x82\x22\x48\x02\x21\x78\x82\x06\xb8\x02\x09\xb2\x82\x41\xce\x82\x09\xb2\x82\x06\xb8\x82\x21\x78\x82\x22\x48\x82\x0a\xc1\x82\x01\x21" }, { 599, 2, 25, "\x81\x01\x01\x02\x01\x01\x81\x08\x81\x06\x01\x11\x01\x05\x81\x20\x01\x0d\x01\x24\x81\x16\x81\x3a\x01\x06\x01\x47\x00\x81\x23\x01\x18\x01\x42\x81\x1c\x81\x3f\x81\x5c\x01\x52\x01\x03\x81\x19\x81\x10" }, { 607, 2, 13, "\x81\x01\x01\x02\x81\x03\x01\x01\x01\x07\x01\x09\x81\x15\x81\x15\x01\x03\x01\x22\x01\x10\x81\x0f\x81\x11" }, { 611, 3, 10, "\x01\x01\x81\x2e\x01\x7d\x81\x64\x81\x41\x01\x74\x81\x01\x81\x3e\x01\x23\x81\x08" }, { 616, 2, 8, "\x01\x01\x01\x12\x81\x03\x01\x12\x01\x14\x81\x12\x81\x03\x81\x12" }, { 619, 1, 5, "\x08\xa3\xdb\xc6\xfe\x78\x00\x00\x00\x16\x4c\x28\x45\x16\x97\x31\x98\xaa\xab\xa1\xf4\x4d\xe8\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x14\x39\x25\x0e\xb8\x17\xd6\x69\xcd\xfa\x81\xa4\x6f\xa4\x5d\x20\x00\x00\x00\x00\x00\x91\xff\xb8\x1a\x13\x8d\x4e\xcf\x50\x48\xca\xca\x37\x68\x40\x00\x00\x00\x0f\x01\xb2\xad\xfc\xc0\x42\x61\x36\x88\xb5\xa6\xb9\x7b\x80\x00" }, { 623, 2, 22, "\x01\x01\x81\x06\x01\x0e\x81\x0c\x81\x07\x01\x22\x81\x39\x01\x3d\x81\x26\x01\x03\x01\x27\x81\x4a\x01\x81\x82\x01\x2f\x02\x02\x22\x82\x02\xc8\x02\x03\x13\x82\x02\xc4\x02\x01\xba\x81\xbe\x01\x49\x81\x16" }, { 627, 1, 4, "\x88\x01\x7f\xe4\xbd\x37\x00\x00\x00\x14\x5c\x31\x4d\x55\x7f\x41\x6c\xd7\x92\xcb\x6e\xb8\x1d\x28\x00\x00\x00\x00\x00\x00\x13\x9f\xcf\x15\xdc\xd9\x41\xe1\x34\x56\x7e\x97\xec\xac\x9d\x60\x00\x00\x00\x00\x0f\x02\xcf\x26\xf0\xe0\x6e\x68\x0b\x83\x95\x2b\xf1\x25\x80\x00" }, { 628, 2, 6, "\x81\x01\x82\x01\x62\x81\xde\x82\x01\x08\x01\xde\x82\x01\x62" }, { 631, 2, 13, "\x81\x01\x81\x04\x81\x0c\x81\x15\x81\x25\x81\x2e\x81\x36\x81\x48\x81\x47\x81\x4d\x81\x45\x81\x21\x81\x11" }, { 632, 2, 8, "\x01\x01\x81\x12\x81\x0d\x81\x6e\x81\x24\x81\x6e\x81\x0d\x81\x12" }, { 635, 3, 10, "\x81\x01\x01\x31\x81\x62\x01\x33\x01\x57\x81\xc0\x01\xc9\x81\x79\x01\x32\x81\x0b" }, { 643, 1, 3, "\x07\x02\x66\x3e\xc6\x12\x80\x00\x91\x12\x83\xe0\xc3\x2b\xa0\x0f\x43\x4a\x73\x25\xd9\xaa\x40\x00\x00\x00\x0f\x07\x9d\xbf\x54\xde\xdd\x98\x01\x84\xfe\x73\x54\x25\x80\x00" }, { 644, 2, 16, "\x01\x01\x81\x12\x81\x21\x01\x1a\x01\xa5\x81\x6c\x82\x01\x26\x01\x28\x02\x01\xca\x01\x28\x82\x01\x26\x81\x6c\x01\xa5\x01\x1a\x81\x21\x81\x12" }, { 647, 2, 23, "\x81\x01\x81\x02\x01\x03\x01\x0d\x01\x13\x01\x15\x00\x81\x4b\x81\xca\x82\x01\x7a\x82\x02\x54\x82\x03\x1e\x82\x03\xbb\x82\x03\xe3\x82\x03\x51\x82\x02\x62\x82\x01\x80\x81\x97\x81\x02\x01\x2e\x01\x25\x01\x03\x81\x14" }, { 655, 2, 12, "\x81\x01\x01\x01\x81\x06\x81\x04\x81\x0f\x81\x13\x81\x20\x81\x2b\x81\x37\x81\x2f\x81\x29\x81\x12" }, { 659, 3, 11, "\x81\x01\x01\x31\x01\x61\x01\x9d\x01\x5b\x81\x05\x81\x2b\x01\x13\x01\x1b\x01\x07\x81\x07" }, { 660, 2, 8, "\x01\x01\x04\x04\x50\xd5\x30\x05\x01\xe0\x2e\xf3\xdc\x05\x0c\x62\x4c\xa7\x70\x85\x02\x59\x4b\x3e\xba\x85\x0c\x62\x4c\xa7\x70\x05\x01\xe0\x2e\xf3\xdc\x84\x04\x50\xd5\x30" }, { 663, 2, 16, "\x01\x01\x81\x08\x01\x6f\x02\x02\x3e\x02\x01\x1b\x82\x15\x8a\x02\x03\x5d\x02\x57\x3c\x02\x21\xd8\x83\x01\x80\x5a\x02\xf8\x01\x03\x01\xce\x5a\x83\x01\x9a\x39\x82\x36\x59\x83\x01\x5e\xd3\x82\x21\xf8" }, { 664, 2, 10, "\x81\x01\x81\x16\x81\x1d\x81\x0c\x01\x13\x81\x1a\x81\x13\x81\x0c\x01\x1d\x81\x16" }, { 667, 1, 4, "\x87\x02\x52\x15\x1d\x10\x00\x00\x92\x01\xb0\x40\x53\x39\x2c\x50\xb2\x19\x5e\xdd\xe9\x40\x00\x00\x00\x00\x00\x90\x02\xcf\xe2\x1a\x41\xc2\xf5\xf1\xd0\x20\x97\x62\x00\x00\x00\x00\x0f\x21\x3a\x22\xe4\xf5\x7c\xbc\xd8\x62\x4f\x9b\x83\x01\x00\x00" }, { 679, 2, 18, "\x01\x01\x00\x01\x07\x00\x01\x0c\x81\x09\x01\x0c\x01\x06\x01\x0d\x81\x03\x81\x08\x81\x09\x01\x21\x81\x1b\x01\x18\x81\x3c\x01\x3a\x81\x18" }, { 680, 2, 12, "\x01\x01\x01\x12\x81\x45\x01\x76\x81\x35\x01\x44\x81\x0e\x81\x44\x81\x35\x81\x76\x81\x45\x81\x12" }, { 683, 3, 5, "\x81\x01\x01\x38\x81\x29\x81\x05\x01\x06" }, { 687, 2, 12, "\x81\x01\x81\x06\x81\xbf\x82\x02\x5d\x82\x06\xa0\x02\x08\x2e\x02\x26\x1e\x02\x22\x9a\x82\x27\x7d\x02\x2b\x89\x83\x01\xb9\x32\x82\x28\xbb" }, { 691, 1, 5, "\x09\x07\xb6\xb4\x25\xdd\xf0\x00\x00\x00\x97\x65\xbc\xcc\x30\x3c\x4e\x6a\x77\x14\x8d\x11\x03\xe7\xd1\x9a\xd0\x00\x00\x00\x00\x00\x00\x00\x15\x6f\x05\x30\x81\xc8\x5a\x55\x94\xe0\xec\x9b\xdd\xb7\x5f\x89\xc0\x00\x00\x00\x00\x00\x12\x4c\xf4\x07\x0b\xf7\x56\x3e\x7a\x39\x74\x3c\xc1\xb3\x6d\x00\x00\x00\x00\x0f\x8d\x33\x57\xc6\xca\xb4\x25\x4b\x68\x96\xe0\xae\xbd\x00\x00" }, { 692, 2, 14, "\x81\x01\x82\x01\xf1\x82\x0e\x1f\x82\x2b\xa8\x02\x07\x38\x82\x16\xd8\x82\x12\xae\x02\x67\xd2\x02\x12\xae\x82\x16\xd8\x82\x07\x38\x82\x2b\xa8\x02\x0e\x1f\x82\x01\xf1" }, { 696, 2, 12, "\x01\x01\x82\x2b\x98\x82\x92\xe2\x03\x09\xfe\x88\x83\x2c\xb0\xd1\x03\x61\x8f\x90\x83\x81\x29\xdc\x03\x61\x8f\x90\x83\x2c\xb0\xd1\x03\x09\xfe\x88\x82\x92\xe2\x82\x2b\x98" }, { 703, 2, 14, "\x81\x01\x81\x03\x81\x01\x81\x01\x81\x09\x01\x04\x01\x02\x01\x0f\x01\x07\x81\x06\x81\x0b\x81\x29\x81\x0f\x81\x16" }, { 707, 3, 6, "\x81\x01\x01\x3a\x01\x6c\x01\x48\x01\x1e\x01\x04" }, { 708, 2, 4, "\x01\x01\x82\x2f\x9e\x83\x02\x28\xc6\x82\x2f\x9e" }, { 712, 2, 8, "\x01\x01\x81\x15\x81\x33\x81\x1e\x01\x02\x81\x1e\x81\x33\x81\x15" }, { 715, 1, 4, "\x07\x53\xf0\xe1\x43\xf0\x00\x00\x14\x10\x94\x97\x5a\x28\x66\x90\xb5\x7d\x54\xcb\xeb\xad\x24\xc0\x00\x00\x00\x00\x00\x13\x02\xb2\x8f\xb5\x0f\xf7\xe9\xa8\xe9\x7b\xc3\x97\x34\x3b\x5a\x00\x00\x00\x00\x10\x02\x49\x46\x6d\x55\xc5\x51\xa6\xf7\xfb\x23\xd2\xd5\x79\x00\x00" }, { 723, 1, 4, "\x08\x30\xeb\x30\x80\xdf\x80\x00\x00\x96\x2e\x9b\x70\x4d\x52\x2d\xa7\x04\x26\xe0\xb5\x64\x3c\xc7\x5a\x04\x60\x00\x00\x00\x00\x00\x15\x05\xa0\x43\x71\xc5\xcb\x39\x55\xd0\x3b\x32\xf7\x0f\x2f\x63\xe4\xbc\xc0\x00\x00\x00\x10\x03\xa7\x2c\x01\x7e\x69\x52\x83\xe5\xc8\x84\x4f\x4a\x77\x80\x00" }, { 724, 2, 10, "\x81\x01\x82\x02\x3d\x01\x56\x82\x04\xa7\x02\x0b\xab\x82\x01\x68\x82\x0b\xab\x82\x04\xa7\x81\x56\x82\x02\x3d" }, { 727, 2, 13, "\x81\x01\x01\x04\x81\x08\x01\x05\x81\x06\x00\x81\x04\x81\x08\x81\x1e\x01\x0f\x81\x29\x01\x17\x81\x19" }, { 728, 2, 12, "\x01\x01\x01\x1c\x01\x60\x01\x54\x81\x18\x01\x1c\x81\x2e\x81\x1c\x81\x18\x81\x54\x01\x60\x81\x1c" }, { 731, 3, 12, "\x81\x01\x01\x43\x81\x99\x01\xd8\x81\x85\x01\x49\x01\x5c\x01\x09\x01\x29\x01\x0c\x01\x19\x01\x07" }, { 739, 1, 5, "\x09\x02\x3e\x53\xf5\x57\x70\x00\x00\x00\x98\x01\x9c\x08\xec\x08\x01\x4c\xd7\x96\xc5\x6d\x1a\x82\x1e\xcf\xee\x30\x00\x00\x00\x00\x00\x00\x00\x16\x16\x8b\x94\xce\x39\x31\x92\x22\x10\x79\xa8\xeb\x78\xaf\x8c\x64\x80\x00\x00\x00\x00\x00\x93\x17\x5f\x1d\x83\xfe\x0b\xae\x68\xa2\xc8\x77\xd9\x61\x37\x37\x80\x00\x00\x00\x10\x09\x41\x36\x07\xd0\x11\xdb\x4f\xb1\x31\x10\x90\xf2\xa6\x00\x00" }, { 740, 2, 16, "\x01\x01\x81\x12\x81\x8f\x82\x02\x6e\x82\x07\x67\x82\x10\x70\x82\x1c\x06\x82\x26\x40\x82\x2a\x6e\x82\x26\x40\x82\x1c\x06\x82\x10\x70\x82\x07\x67\x82\x02\x6e\x81\x8f\x81\x12" }, { 743, 2, 21, "\x81\x01\x01\x06\x81\x17\x01\x44\x81\x9c\x02\x01\x12\x82\x01\x83\x02\x01\xeb\x82\x02\x82\x02\x03\x40\x82\x03\x81\x02\x02\xbd\x82\x01\xc3\x02\x01\xfd\x82\x03\x39\x02\x03\x7f\x82\x02\x03\x01\x56\x01\x21\x01\x16\x81\x1a" }, { 744, 2, 12, "\x01\x01\x02\x3d\xe8\x83\x03\x63\xd6\x03\x06\x79\x78\x83\x19\x65\xb1\x83\x08\x99\xf0\x83\x0c\xdc\xf4\x03\x08\x99\xf0\x83\x19\x65\xb1\x83\x06\x79\x78\x83\x03\x63\xd6\x82\x3d\xe8" }, { 751, 2, 15, "\x81\x01\x01\x05\x81\x09\x01\x06\x81\x07\x01\x0c\x81\x11\x01\x1d\x81\x02\x01\x04\x81\x15\x01\x09\x81\x35\x81\x0c\x81\x19" }, { 755, 3, 12, "\x81\x01\x01\x42\x02\x01\x06\x02\x01\xe6\x02\x02\x56\x02\x02\x0a\x02\x01\x68\x01\xb6\x01\x52\x01\x32\x01\x12\x81\x02" }, { 760, 2, 4, "\x01\x01\x81\x18\x81\x36\x81\x18" }, { 763, 1, 4, "\x07\x25\xe1\x79\x19\xc0\x00\x00\x13\xa7\x43\xf1\x15\xa8\x8b\x9c\x2a\x98\x06\xa3\xeb\x12\x00\x00\x00\x00\x00\x00\x12\x87\x0c\xfd\xef\x4f\xed\x04\xb5\x80\xff\x16\x8a\xed\x8a\xc0\x00\x00\x00\x10\x24\xa1\x02\xcd\x9c\x9c\xe7\xdb\xf1\xa5\xbd\xa7\xb3\x44\x00\x00" }, { 767, 2, 22, "\x81\x01\x01\x01\x01\x09\x81\x05\x81\x27\x81\x03\x01\x51\x01\x22\x81\x83\x81\x9c\x01\x22\x01\x6f\x81\x4a\x81\xae\x81\x98\x81\x88\x81\x14\x81\x4a\x82\x01\x04\x81\xbb\x81\x3c\x81\x18" }, { 771, 1, 6, "\x0a\xde\x6d\x16\x2b\x52\x46\x40\x00\x00\x00\x9d\x35\x06\x6e\x09\xe2\xb3\xe5\x64\x61\x4a\x14\x46\xdf\x04\x88\xbb\x0f\x04\x83\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x04\x67\xa4\xf0\x5b\x2a\x63\xf9\xda\xe9\x19\xda\x45\x4d\x3a\xfc\x1d\xb0\xad\x53\x70\x00\x00\x00\x00\x00\x00\x00\x19\x01\x35\xb5\xe7\x3f\x97\x01\x49\x57\xee\x83\xa1\x36\x50\x0b\x48\x40\x15\xec\x80\x00\x00\x00\x00\x00\x15\xde\xc3\xfa\xcb\x54\xd7\xe7\x4b\x23\xcb\xec\x2c\xd7\xf9\x04\xbc\x6f\xc0\x00\x00\x00\x10\x39\xa9\x49\x31\xec\x7b\xaa\x20\x0a\x77\xc9\x37\x11\x09\x00\x00" }, { 772, 2, 4, "\x01\x01\x81\x1a\x81\x16\x81\x1a" }, { 776, 2, 20, "\x01\x01\x81\x1a\x81\x17\x81\xbe\x81\x24\x81\xbe\x01\x67\x81\xe6\x81\x51\x81\x84\x02\x02\x48\x81\x84\x81\x51\x81\xe6\x01\x67\x81\xbe\x81\x24\x81\xbe\x81\x17\x81\x1a" }, { 779, 3, 10, "\x81\x01\x01\x4a\x01\x62\x01\xdc\x01\x51\x01\x1a\x81\x0b\x81\x08\x01\x18\x01\x08" }, { 787, 1, 5, "\x08\x44\xca\xa5\x93\xa8\x00\x00\x00\x16\x30\x07\x41\x33\xba\x6e\x03\x53\xce\xa8\x96\xe3\x65\xb2\x70\x00\x00\x00\x00\x00\x00\x00\x15\x0b\x26\x6c\x34\x92\x14\xee\x3d\x91\xfd\x3b\x2d\x16\xe2\xc0\x40\x00\x00\x00\x00\x00\x13\x03\x18\x1d\xc2\xdf\x75\x9a\xcc\xf7\x64\x82\x24\xc3\x82\x2c\x00\x00\x00\x00\x10\x8d\xe4\x8b\xc8\x00\x7d\x29\xca\xa7\xfa\x7b\x1c\xce\xeb\x00\x00" }, { 788, 2, 10, "\x81\x01\x82\x03\x0b\x82\x05\x16\x82\x61\x7d\x02\x29\x9f\x02\x3f\x00\x82\x29\x9f\x82\x61\x7d\x02\x05\x16\x82\x03\x0b" }, { 795, 1, 4, "\x09\x06\x50\xa8\xe6\xe3\x7e\x30\x00\x00\x19\x0f\x73\x88\x52\x39\x99\x58\x1d\x40\xd6\x31\x03\x18\x7d\xe4\x74\x16\x40\xbd\xc0\x00\x00\x00\x00\x00\x16\x05\x3e\xce\x32\x31\x66\x6b\x91\xc4\xcd\x43\x57\x85\x70\xee\x36\xb6\x73\x00\x00\x00\x00\x10\xdd\xd2\xcb\xe2\x66\xd6\x5d\x16\x86\xe5\xed\x6a\x12\xcd\x00\x00" }, { 799, 2, 16, "\x01\x01\x01\x03\x01\x09\x01\x09\x81\x06\x81\x15\x81\x27\x81\x06\x01\x34\x01\x18\x01\x12\x81\x12\x81\x4b\x01\x1e\x01\x27\x81\x1e" }, { 803, 3, 10, "\x01\x01\x81\x53\x01\x96\x81\x53\x01\x07\x01\x10\x81\x41\x01\x0b\x01\x1a\x01\x03" }, { 804, 2, 12, "\x01\x01\x82\x5e\x8e\x83\x07\xbb\xf6\x83\x2c\xb5\x2e\x83\xac\xeb\x81\x84\x01\x99\xec\x44\x84\x02\x2e\xd1\x14\x84\x01\x99\xec\x44\x83\xac\xeb\x81\x83\x2c\xb5\x2e\x83\x07\xbb\xf6\x82\x5e\x8e" }, { 807, 2, 14, "\x81\x01\x81\x0a\x82\x01\x05\x81\x63\x02\x07\xe5\x82\x21\x8c\x02\x1d\x5f\x02\xcf\xde\x83\x04\x99\x19\x03\x0b\x05\x2e\x83\x0f\x99\xd6\x03\x0c\xf6\xd8\x83\x04\x88\x2d\x82\x60\x93" }, { 808, 2, 6, "\x81\x01\x81\x1d\x01\x04\x81\x39\x81\x04\x81\x1d" }, { 811, 1, 7, "\x0b\x01\x4e\xcd\x24\x68\xdb\xe0\x00\x00\x00\x00\x9d\x1d\xb2\xa4\xaa\xab\xc7\xfc\xc7\xce\x25\x28\xdd\x48\x79\x5f\xee\x38\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x03\x09\xde\x5e\xe7\x1d\x7e\x62\x0c\x75\x20\xd8\x06\xab\xc6\x4e\x75\xf4\xe8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x99\xff\x5a\xc8\xee\x27\x12\x79\x74\x23\x4a\x0d\x5f\x73\x0f\xed\x77\x22\x70\x00\x00\x00\x00\x00\x00\x00\x17\x19\xda\x46\x4c\xf5\x94\x3f\xe1\x78\xfb\x81\x96\x80\xf4\x98\x7e\x57\xc0\x00\x00\x00\x00\x00\x14\x04\x7d\xf8\xb7\xfc\x53\x00\xb1\xbf\xb6\x1e\x91\x51\xf1\x4e\x8d\x80\x00\x00\x00\x11\x02\x1a\x82\xce\x94\xa5\x87\x21\x3d\x40\x57\x1b\x42\x62\xfa\x80\x00" }, { 820, 2, 8, "\x01\x01\x02\x03\x87\x02\x06\x98\x02\x01\x3b\x02\x07\x0e\x82\x01\x3b\x02\x06\x98\x82\x03\x87" }, { 823, 2, 9, "\x81\x01\x81\x01\x00\x81\x0c\x81\x1e\x81\x21\x81\x1e\x81\x24\x81\x1d" }, { 824, 2, 20, "\x01\x01\x81\x1e\x81\x0d\x01\x76\x01\xcc\x82\x03\x1a\x01\x8d\x02\x04\xd6\x82\x02\xf1\x82\x03\xb4\x02\x06\x78\x82\x03\xb4\x82\x02\xf1\x02\x04\xd6\x01\x8d\x82\x03\x1a\x01\xcc\x01\x76\x81\x0d\x81\x1e" }, { 827, 3, 7, "\x81\x01\x01\x59\x81\x92\x01\x70\x81\x36\x01\x26\x81\x07" }, { 835, 1, 6, "\x09\x09\x33\xd7\x7e\xc7\x00\x00\x00\x00\x99\x01\x1f\x3a\x82\x18\xac\xa9\xe0\xc1\x4b\xbc\xaa\xeb\x41\xde\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\x45\x95\xf8\x19\x7a\xe9\x67\x01\x5a\xab\x50\xc3\x45\x18\x44\x30\x00\x00\x00\x00\x00\x00\x00\x96\x05\x85\x62\x21\xf9\xc4\xdd\x4b\xf2\xa4\x7f\x5e\x13\x5d\xec\x76\xc0\x00\x00\x00\x00\x00\x14\x23\xcf\x51\x95\xc8\x76\x06\xd0\xf4\xb3\x49\xe0\x40\xda\x8e\xb1\x00\x00\x00\x00\x11\x07\xd4\x1a\x09\x7c\x5c\x23\xe3\x44\xf8\xed\x9f\x4d\x8d\x3f\x00\x00" }, { 836, 2, 20, "\x01\x01\x81\x22\x01\x5d\x81\x7c\x02\x01\x24\x82\x01\xa4\x81\x45\x82\x02\xc6\x82\x05\x09\x82\x02\xf0\x82\x08\x78\x82\x02\xf0\x82\x05\x09\x82\x02\xc6\x81\x45\x82\x01\xa4\x02\x01\x24\x81\x7c\x01\x5d\x81\x22" }, { 840, 2, 8, "\x01\x01\x82\x79\x08\x83\x08\x1e\x04\x83\x07\xa6\xb8\x03\x30\xfc\x86\x83\x07\xa6\xb8\x83\x08\x1e\x04\x82\x79\x08" }, { 843, 1, 6, "\x0a\x72\xa5\x66\xe9\xa2\x74\x80\x00\x00\x00\x1d\x02\xb5\xe4\x3d\x89\x28\xb6\xae\x17\x3e\x69\x4e\xb4\xed\x71\x6f\x36\x4b\x04\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\x21\xba\xa0\x42\x6c\xa2\xed\xf3\x4b\x59\x48\xd2\x27\x98\xb1\x0e\x71\xf7\x57\x50\x00\x00\x00\x00\x00\x00\x00\x19\x06\x02\x04\xec\xb2\x43\xce\x2e\xed\x15\x15\x46\x15\xba\x83\x10\x60\x69\xc7\xc0\x00\x00\x00\x00\x00\x16\xb0\x02\xbe\xa0\xae\x8e\x47\x9b\xd8\x14\x75\xf9\xb2\x82\x78\x18\xd8\x70\x80\x00\x00\x00\x11\x0c\x14\xac\xd6\x69\x20\x23\x50\xd7\xbc\x13\x40\xf8\xa4\xd1\x80\x00" }, { 851, 3, 10, "\x01\x01\x81\x5f\x01\x67\x01\x5e\x81\xdb\x81\xc9\x01\x45\x01\x56\x81\x01\x81\x07" }, { 852, 2, 8, "\x01\x01\x04\x43\x5c\x08\x70\x05\x43\x10\xdf\x6a\xdc\x86\x01\x78\x17\xff\xd6\x50\x06\x02\x24\x86\x2d\xa3\x46\x06\x01\x78\x17\xff\xd6\x50\x05\x43\x10\xdf\x6a\xdc\x84\x43\x5c\x08\x70" }, { 856, 2, 6, "\x81\x01\x81\x20\x01\x10\x81\x4e\x81\x10\x81\x20" }, { 859, 1, 7, "\x0b\x03\x40\xdc\x16\xac\x53\x00\x00\x00\x00\x00\x9e\x09\x05\x08\xb0\xbd\x1b\xa2\x2f\xcd\x64\x28\x0b\x6b\x55\xdc\x44\x9e\x63\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\xf3\xeb\xf2\x70\x5e\xdd\x3d\xc9\x92\x48\x6e\x5c\xa0\x3a\xbb\x4c\x39\x33\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\x0e\x3e\xd5\x8d\x1f\x55\xa1\x41\x43\xec\x2a\x82\x0c\x14\x73\xc1\xfb\x86\x50\x00\x00\x00\x00\x00\x00\x00\x18\x03\xf0\x9c\xa5\x9a\xa7\x91\x99\x9f\xd5\xd8\xd7\xda\x29\xab\x56\x5f\x40\xc0\x00\x00\x00\x00\x00\x95\x01\x12\xa6\xbd\x19\x89\x0b\x68\x6c\x66\x1d\x84\xa3\x7c\x77\xbe\xf5\x00\x00\x00\x00\x11\x1c\x97\xd1\x01\xee\xb3\x60\xa3\xd8\xed\xc4\xf8\xf5\x73\xb1\x00\x00" }, { 863, 2, 21, "\x81\x01\x01\x09\x81\x2f\x01\xab\x82\x01\xd6\x02\x04\x0e\x82\x07\x9a\x02\x0c\xb2\x82\x13\x90\x02\x1c\x41\x82\x26\x3d\x02\x2f\xe9\x82\x36\xbc\x02\x38\x03\x82\x32\x85\x02\x27\x3d\x82\x19\x83\x02\x0d\x3b\x82\x05\x24\x02\x01\x4c\x81\x2a" }, { 868, 2, 8, "\x01\x01\x81\x22\x01\x12\x01\x10\x01\x07\x01\x10\x01\x12\x81\x22" }, { 871, 2, 22, "\x81\x01\x81\x02\x81\x09\x81\x0b\x81\x09\x01\x01\x81\x02\x01\x06\x81\x28\x81\x08\x81\x45\x01\x16\x81\x1e\x01\x1f\x01\x25\x81\x21\x81\x16\x81\xce\x81\x81\x81\xad\x81\x33\x81\x20" }, { 872, 2, 10, "\x81\x01\x81\x26\x81\x94\x81\x94\x01\x31\x81\x4c\x81\x31\x81\x94\x01\x94\x81\x26" }, { 875, 3, 10, "\x81\x01\x01\x64\x01\x55\x81\x78\x81\x23\x01\x5e\x01\x0f\x01\x0a\x01\x19\x81\x0a" }, { 883, 1, 3, "\x07\x13\x9a\x5b\x6b\x83\x80\x00\x93\x06\xd0\x6a\xa1\x64\xda\x28\xa4\x03\xb0\x6a\x53\x01\x32\x59\x40\x00\x00\x00\x11\x66\x92\xcd\x3b\x80\x67\xce\xd3\x17\x35\x67\x2a\xed\x03\x42\x80\x00" }, { 884, 2, 16, "\x01\x01\x02\x04\xa6\x82\x32\x59\x02\x86\x42\x82\x03\x0f\x03\x05\x0a\xd8\x03\x01\x68\x9e\x03\x02\x92\xfc\x83\x01\xd0\x5e\x83\x02\x92\xfc\x03\x01\x68\x9e\x83\x05\x0a\xd8\x82\x03\x0f\x82\x86\x42\x82\x32\x59\x82\x04\xa6" }, { 888, 2, 12, "\x01\x01\x82\xa6\xc8\x83\x10\x5c\xa2\x83\x67\xe4\x68\x84\x01\x4b\x63\xd1\x84\x02\x79\x9d\x50\x84\x03\x0d\x6c\x5c\x84\x02\x79\x9d\x50\x84\x01\x4b\x63\xd1\x83\x67\xe4\x68\x83\x10\x5c\xa2\x82\xa6\xc8" }, { 895, 2, 16, "\x81\x01\x01\x04\x81\x01\x81\x09\x81\x07\x01\x1a\x81\x11\x01\x03\x81\x2a\x01\x1d\x81\x08\x01\x18\x81\x5f\x01\x1f\x01\x11\x81\x24" }, { 899, 3, 14, "\x81\x01\x01\x6a\x01\xe5\x02\x02\xba\x02\x03\xe6\x02\x06\x14\x02\x07\x08\x02\x06\xe6\x02\x05\xd2\x02\x04\x3e\x02\x02\x9a\x02\x01\x34\x01\x61\x01\x10" }, { 903, 2, 16, "\x01\x01\x81\x23\x02\x01\x2f\x02\x02\x9a\x02\x04\x70\x82\x69\x26\x82\x85\xb0\x03\x03\x6b\x48\x03\x04\xb3\xf0\x83\x0b\x9d\x11\x83\x14\x18\x8b\x03\x0d\xc5\x1d\x03\x25\x5a\x16\x03\x07\x0a\x01\x83\x0c\xb6\xd9\x82\xb8\x12" }, { 904, 2, 8, "\x01\x01\x81\x27\x01\x69\x81\x8a\x01\x6e\x81\x8a\x01\x69\x81\x27" }, { 907, 1, 3, "\x07\x12\xd7\x63\x56\x98\x00\x00\x13\x01\xc1\xc8\x5b\x4b\x67\x8e\xc7\x9a\xf0\xf1\x68\x3f\x94\xb0\x00\x00\x00\x00\x12\x01\x69\xad\x24\x8e\xd2\x87\x32\x82\x48\x61\x00\x92\x3f\x5f\x00\x00\x00" }, { 916, 2, 10, "\x81\x01\x82\x05\x61\x02\x13\xe2\x82\x28\x2f\x02\x22\x07\x82\x2d\x90\x82\x22\x07\x82\x28\x2f\x82\x13\xe2\x82\x05\x61" }, { 919, 2, 19, "\x81\x01\x81\x05\x81\x0a\x81\x05\x81\x09\x81\x2a\x81\x33\x81\x06\x01\x17\x01\x04\x01\x1d\x01\x70\x01\x3f\x81\x93\x81\xb7\x01\x0f\x01\x4d\x81\x11\x81\x25" }, { 920, 2, 20, "\x01\x01\x01\x24\x81\x32\x01\xcc\x81\x3d\x82\x02\x48\x01\x90\x01\x98\x82\x02\x23\x02\x03\x2c\x02\x02\xc6\x82\x03\x2c\x82\x02\x23\x81\x98\x01\x90\x02\x02\x48\x81\x3d\x81\xcc\x81\x32\x81\x24" }, { 923, 3, 10, "\x01\x01\x81\x73\x81\x6e\x81\x1b\x01\xd3\x01\x38\x81\x1d\x81\x51\x01\x1e\x81\x01" }, { 932, 2, 12, "\x01\x01\x81\x27\x01\x12\x01\x65\x01\xee\x82\x04\xef\x02\x07\x5e\x82\x04\xef\x01\xee\x01\x65\x01\x12\x81\x27" }, { 943, 2, 16, "\x01\x01\x01\x05\x01\x08\x01\x01\x00\x81\x0b\x81\x26\x01\x02\x01\x3a\x01\x1c\x81\x3b\x81\x2e\x01\x42\x01\x20\x81\x37\x81\x26" }, { 947, 3, 5, "\x81\x01\x01\x7d\x81\x67\x01\x07\x01\x05" }, { 948, 2, 12, "\x01\x01\x04\xec\xc7\x7d\x58\x06\x01\x6d\x47\x64\x49\xea\x86\x01\x65\x51\x16\x25\xb8\x06\x12\x89\xb5\x88\x07\x4f\x06\x12\x62\xab\x1f\x56\x70\x86\x13\x0b\xfe\xe3\x92\x74\x86\x12\x62\xab\x1f\x56\x70\x06\x12\x89\xb5\x88\x07\x4f\x06\x01\x65\x51\x16\x25\xb8\x06\x01\x6d\x47\x64\x49\xea\x84\xec\xc7\x7d\x58" }, { 952, 2, 8, "\x01\x01\x81\x2a\x01\x4b\x81\x06\x81\x34\x81\x06\x01\x4b\x81\x2a" }, { 955, 1, 4, "\x09\x29\x32\xef\x5b\xaf\xd8\xd0\x00\x00\x18\x15\x37\x39\x40\x34\x31\x9a\x0d\xe1\x29\x8f\xae\x83\xa3\x61\xeb\xc8\xa6\x00\x00\x00\x00\x00\x00\x16\x01\x0f\x46\x8c\x8f\xb2\x0f\x4e\xec\xcf\xe3\x23\xc6\x46\x5e\x91\xe1\x78\x80\x00\x00\x00\x12\x10\xb9\x62\xc4\x01\xb5\x1b\xf5\x44\xe9\x70\x70\xf8\x05\xc5\xec\x00\x00" }, { 964, 2, 12, "\x01\x01\x81\x2b\x01\x4a\x01\x41\x81\xe2\x81\x43\x02\x01\x76\x81\x43\x81\xe2\x01\x41\x01\x4a\x81\x2b" }, { 967, 2, 11, "\x81\x01\x81\x02\x01\x01\x81\x0d\x81\x06\x01\x12\x81\x51\x01\x63\x81\x7a\x01\x44\x81\x2b" }, { 971, 3, 15, "\x81\x01\x01\x87\x82\x01\x1d\x01\x4f\x02\x01\x52\x01\x98\x82\x01\x2c\x81\x64\x01\x3e\x01\xd8\x02\x01\x36\x02\x01\x08\x01\x85\x01\x15\x81\x01" }, { 984, 2, 12, "\x01\x01\x03\x01\x34\xfc\x83\x1c\xa5\x8a\x03\x4e\x7b\x34\x84\x01\xa3\xbd\xf1\x83\x86\x3a\xc8\x83\x1c\xd0\xcc\x03\x86\x3a\xc8\x84\x01\xa3\xbd\xf1\x83\x4e\x7b\x34\x83\x1c\xa5\x8a\x83\x01\x34\xfc" }, { 991, 2, 17, "\x81\x01\x81\x01\x81\x04\x81\x12\x81\x0b\x01\x0e\x81\x15\x81\x3e\x81\x0e\x01\x32\x81\x36\x81\x79\x01\x07\x01\x24\x81\x40\x81\x17\x81\x2b" }, { 995, 3, 8, "\x81\x01\x01\x8c\x02\x01\x21\x01\x42\x01\x0c\x01\x4e\x01\x3b\x01\x0c" }, { 996, 2, 12, "\x01\x01\x83\x01\x4d\x0e\x83\x12\xc2\x76\x03\xb8\x76\x52\x84\x02\xad\xdf\x81\x04\x03\x2c\x4e\xbc\x84\x05\x79\xcc\x14\x04\x03\x2c\x4e\xbc\x84\x02\xad\xdf\x81\x03\xb8\x76\x52\x83\x12\xc2\x76\x83\x01\x4d\x0e" }, { 1003, 1, 4, "\x08\x03\x6c\xf4\x82\x20\x80\x00\x00\x16\x03\x7d\x0e\x50\x12\xcf\x80\x1a\x9a\x5d\x14\xc9\xeb\x12\x4e\x9e\x20\x00\x00\x00\x00\x00\x94\x23\xd1\xd3\xee\xaa\x4c\x84\x24\x64\x85\xb4\x9e\x5b\xd0\x96\xb3\x40\x00\x00\x00\x12\xba\x30\xe9\x0a\xd1\x9d\x08\x67\x18\xdc\x71\xc3\x0c\xee\x97\xf5\x80\x00" }, { 1012, 2, 4, "\x01\x01\x02\x08\x16\x02\x01\xb7\x82\x08\x16" }, { 1015, 2, 16, "\x01\x01\x01\x04\x01\x0c\x01\x0b\x01\x0c\x81\x20\x81\x45\x81\x61\x81\x32\x01\x41\x01\x7e\x01\xac\x01\x42\x81\x10\x81\x51\x81\x2c" }, { 1016, 2, 16, "\x01\x01\x81\x2e\x01\x01\x01\xda\x02\x01\x91\x81\xb8\x82\x0a\xe6\x82\x18\x44\x82\x1d\xf6\x82\x18\x44\x82\x0a\xe6\x81\xb8\x02\x01\x91\x01\xda\x01\x01\x81\x2e" }, { 1023, 2, 16, "\x01\x01\x81\x23\x02\x02\xd5\x82\x0f\x05\x02\x3d\xa9\x82\xbc\x6b\x82\x72\x24\x03\x09\x86\x57\x83\x12\x70\x20\x83\x09\x0b\xe1\x03\x45\xf8\x4e\x83\x4a\x08\x12\x83\x07\x8c\xa8\x03\x3c\x1e\x46\x83\x21\x2e\x74\x83\x01\x89\x84" }, { 1027, 1, 4, "\x09\x03\x82\x1e\xdb\x71\x7e\x90\x00\x00\x18\x06\xb6\x6d\x15\xd2\xb6\x98\xde\x1d\x91\xd4\xf1\xd4\x7c\x9c\x81\x96\x53\x00\x00\x00\x00\x00\x00\x95\x1c\x6d\x8a\x09\x94\xb4\x77\x54\xf6\xed\x65\x93\x5b\x48\xd2\x64\x3a\x80\x00\x00\x00\x13\x02\x5f\xf4\xc8\x7e\x32\xe7\x42\xf8\xdd\xca\xda\x5d\x11\x79\x71\xe4\x00\x00" }, { 1028, 2, 16, "\x01\x01\x81\x33\x01\xcb\x82\x03\x08\x02\x09\x2f\x82\x13\xab\x02\x1d\xa6\x82\x22\x5b\x02\x23\x00\x82\x22\x5b\x02\x1d\xa6\x82\x13\xab\x02\x09\x2f\x82\x03\x08\x01\xcb\x81\x33" }, { 1032, 2, 8, "\x01\x01\x83\x01\x9f\xd4\x83\x21\x41\xac\x03\x72\x1f\xd4\x83\xec\x9c\xaa\x03\x72\x1f\xd4\x83\x21\x41\xac\x83\x01\x9f\xd4" }, { 1039, 2, 23, "\x81\x01\x00\x81\x04\x81\x0e\x81\x19\x81\x06\x01\x0e\x81\x1a\x81\x1f\x01\x30\x01\x3e\x01\x13\x81\x13\x01\x18\x01\x11\x01\x22\x81\x28\x81\xe4\x81\x4c\x01\x04\x81\x1c\x01\x2d\x81\x31" }, { 1047, 2, 16, "\x81\x01\x01\x19\x82\x02\x71\x02\x04\xed\x02\x0a\x9c\x82\x3b\xde\x83\x01\xf8\x6b\x83\x01\xd3\xaf\x83\x05\x12\x02\x83\x0e\x20\xef\x83\x1d\x2e\xb4\x03\x08\x45\x34\x03\x28\x39\x93\x03\x18\xe0\xd0\x83\x2a\x89\x69\x83\x01\xc7\x99" }, { 1048, 2, 6, "\x81\x01\x81\x30\x01\x30\x01\x2e\x81\x30\x81\x30" }, { 1051, 1, 5, "\x0a\x2b\x9f\xce\x19\x37\x44\x5c\x00\x00\x00\x1c\x05\xc9\x8f\xac\x58\x0b\x6e\x78\x4a\x08\xe6\x20\x8a\x6f\x45\xb2\x5d\x43\x99\x40\xf0\x00\x00\x00\x00\x00\x00\x00\x1a\x34\x51\x8d\x31\xe1\xfd\xe8\xf2\x43\x1e\x70\xe1\xa7\x8e\xb7\x86\x1f\xa0\x3b\x00\x40\x00\x00\x00\x00\x00\x16\xc5\xcf\xd7\x55\x1b\x27\x48\x1e\x21\x2e\x27\xfa\x06\x62\x06\x5e\xec\x96\x00\x00\x00\x00\x13\x07\xa6\x02\xe1\xfc\x74\x69\x9c\x16\x2c\xea\xe1\x80\x02\x73\xf3\xf7\x00\x00" }, { 1059, 1, 6, "\x0c\x0c\x44\xf1\x77\xd2\x74\xcc\xcb\x00\x00\x00\x00\xa2\x02\x4f\x4c\xa2\x9f\x9e\x4b\x4c\x09\x77\x2f\x49\x5d\x72\x21\xd0\xc9\x71\x07\x68\x96\xf6\x86\x70\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xc9\x91\x2c\x9f\x88\x31\xc2\x39\x45\x29\xf7\xcf\xab\x36\x02\x30\xa0\x9a\xd1\x08\x2f\x7d\xc8\x38\xd0\x00\x00\x00\x00\x00\x00\x00\x9d\x07\x36\xa4\x54\x28\x6a\xdc\xcb\x94\xb3\x44\x73\x8d\x25\xc5\x64\x9f\x3c\xd9\x80\x2f\x3f\x37\x00\x00\x00\x00\x00\x00\x19\x19\x3e\x0b\xe4\x6b\xd3\xa0\x88\x80\xde\xde\x67\x0e\x19\x0b\xd3\x00\xa2\xd0\x7e\x1a\x80\x00\x00\x00\x13\x0b\x42\xf5\x05\x52\xfd\xe7\x52\xc4\x78\x8c\xb7\xf4\x66\x3c\xe5\xb8\x00\x00" }, { 1060, 2, 8, "\x01\x01\x81\x2f\x81\x99\x82\x01\x0c\x82\x01\x6a\x82\x01\x0c\x81\x99\x81\x2f" }, { 1063, 2, 19, "\x81\x01\x00\x81\x09\x81\x0a\x81\x08\x81\x2d\x81\x27\x01\x07\x81\x2a\x81\x24\x01\x3c\x01\x09\x81\x37\x01\x3f\x81\x0f\x81\x58\x01\x07\x01\x1b\x81\x33" }, { 1064, 2, 20, "\x01\x01\x01\x34\x01\x52\x02\x01\xf0\x02\x04\x2b\x02\x05\xd8\x02\x04\x40\x02\x06\x2c\x02\x01\xfd\x02\x01\x68\x02\x03\xba\x82\x01\x68\x02\x01\xfd\x82\x06\x2c\x02\x04\x40\x82\x05\xd8\x02\x04\x2b\x82\x01\xf0\x01\x52\x81\x34" }, { 1087, 2, 9, "\x81\x01\x81\x08\x81\x1c\x81\x3d\x81\x64\x81\x7c\x81\x8b\x81\x64\x81\x33" }, { 1092, 2, 8, "\x01\x01\x83\x02\x54\xf4\x83\x3c\xcc\x88\x03\x31\x7f\x04\x03\xd9\x31\x2e\x03\x31\x7f\x04\x83\x3c\xcc\x88\x83\x02\x54\xf4" }, { 1096, 2, 12, "\x01\x01\x81\x39\x01\xae\x82\x01\x6b\x02\x02\xdc\x82\x04\x7d\x02\x05\x28\x82\x04\x7d\x02\x02\xdc\x82\x01\x6b\x01\xae\x81\x39" }, { 1099, 1, 6, "\x0b\x56\x54\x90\x3e\xfe\x04\xe9\x00\x00\x00\x00\x9f\x5a\x88\x6c\xd6\xc9\x70\x84\x1a\x98\xb7\x3d\xee\xf9\x62\x11\xa3\x75\x1a\x10\x57\xaf\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\xdf\xb4\xc0\xe2\x67\x74\x54\x3a\x68\x33\xd0\x1f\xc3\x92\xb9\x53\xa5\x8e\x4e\xaa\x3e\xf0\x00\x00\x00\x00\x00\x00\x00\x1b\x05\x17\x8a\xe2\x8f\xd8\xa5\x34\x96\xe1\x74\xfc\x32\xa3\x0c\xa7\xe8\x2f\xfd\x1a\x8c\x40\x00\x00\x00\x00\x00\x97\x1f\xe6\xfa\x1f\xdc\x68\x9c\x40\x7f\xc4\x02\x93\xd9\xf4\xc6\xc3\xf4\x29\xea\x00\x00\x00\x00\x13\x4c\x45\x05\xd9\x1f\xec\xaa\x76\xc7\x62\xac\xe6\x02\x28\x3b\xac\x83\x00\x00" }, { 1103, 2, 23, "\x81\x01\x00\x81\x05\x01\x11\x81\x21\x01\x0e\x81\x35\x01\x22\x01\x13\x81\x8c\x01\x13\x82\x01\x01\x01\x6a\x01\x10\x82\x01\x12\x81\xa5\x82\x02\x03\x01\x1c\x81\x81\x81\x59\x82\x02\x0c\x81\xf4\x81\x32" }, { 1108, 2, 6, "\x81\x01\x82\x0b\xe5\x01\x9c\x82\x16\xb9\x81\x9c\x82\x0b\xe5" }, { 1111, 2, 22, "\x81\x01\x01\x04\x81\x08\x01\x01\x81\x0f\x01\x15\x81\x5f\x01\x2d\x81\x46\x81\x44\x81\x80\x01\x28\x81\xc0\x81\xed\x01\x55\x81\xfc\x81\xd9\x81\x3e\x81\x6b\x81\x95\x81\x51\x81\x36" }, { 1112, 2, 14, "\x81\x01\x81\x34\x01\xc2\x82\x01\x8e\x01\x45\x82\x04\x94\x01\x23\x82\x07\x72\x81\x23\x82\x04\x94\x81\x45\x82\x01\x8e\x81\xc2\x81\x34" }, { 1123, 1, 5, "\x09\x42\x10\x6a\x81\xf8\x14\x00\x00\x00\x9a\x07\x65\x0b\x2c\x12\xf0\xf4\x3b\xd7\x0e\x4e\xe4\x43\x0b\xe3\x91\x03\x4d\xb0\x00\x00\x00\x00\x00\x00\x00\x19\x09\xb6\x95\xb1\xdb\xe1\x12\xac\x84\xde\x72\x65\x07\x73\x10\xd9\x67\xe0\xaa\x80\x00\x00\x00\x00\x00\x16\x3b\xbb\xf2\x51\xf8\x0c\x28\xd6\x42\x0e\x30\xab\x59\x52\xab\x56\x14\x8e\x80\x00\x00\x00\x13\xec\x5a\x0b\x61\xc5\x6b\xc3\x0b\xa6\x36\xff\xf7\xf3\x73\x94\x71\xfa\x00\x00" }, { 1124, 2, 20, "\x01\x01\x81\x3f\x02\x01\x62\x82\x01\xef\x82\x02\xc0\x02\x05\xef\x02\x01\xf6\x82\x05\x49\x82\x0a\x71\x81\x98\x02\x0f\xf0\x81\x98\x82\x0a\x71\x82\x05\x49\x02\x01\xf6\x02\x05\xef\x82\x02\xc0\x82\x01\xef\x02\x01\x62\x81\x3f" }, { 1128, 2, 8, "\x01\x01\x03\x02\xe2\x10\x83\x52\x67\xa4\x83\x03\xdd\x30\x83\xa0\xdf\xba\x03\x03\xdd\x30\x83\x52\x67\xa4\x83\x02\xe2\x10" }, { 1135, 2, 18, "\x81\x01\x81\x01\x01\x08\x01\x09\x81\x2b\x81\x83\x81\x90\x81\x01\x01\xe4\x02\x01\x85\x02\x01\x72\x01\xc7\x81\x40\x82\x01\x62\x82\x02\x00\x82\x01\xb7\x81\xeb\x81\x36" }, { 1144, 2, 12, "\x01\x01\x81\x3c\x01\x30\x81\x18\x81\x18\x81\x54\x82\x01\x86\x81\x54\x81\x18\x81\x18\x01\x30\x81\x3c" }, { 1147, 1, 6, "\x8a\x23\xfd\xfe\x12\x83\x7a\xc0\x00\x00\x00\x1c\x20\x87\x12\x13\x85\x41\x87\x2c\x83\xaa\xec\x7c\x47\x95\x1c\x8b\xf9\xfc\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9b\x01\x59\x1f\x8c\x94\x94\x1e\xab\xd3\x4a\xab\xe4\xde\x22\xd4\x81\x08\x2d\xe0\x90\x00\x00\x00\x00\x00\x00\x00\x19\x29\x03\x45\x97\x2c\xca\x5b\xb5\x67\x79\x58\x01\x47\xf1\xfc\x1f\xdb\x5c\x88\x80\x00\x00\x00\x00\x00\x97\x01\x36\x63\xce\x69\x2b\x86\x05\x25\x16\xe5\x11\x67\x3a\x84\x08\x79\x62\x81\x40\x00\x00\x00\x14\x02\xd3\xad\x3b\x7d\xfe\x65\x15\x02\x4b\x71\x39\x57\xe7\x73\xed\xa8\x9f\x00\x00" }, { 1159, 2, 16, "\x81\x01\x01\x05\x81\x01\x81\x17\x01\x16\x01\x20\x81\x6a\x01\x22\x01\x72\x81\x89\x81\x5f\x01\xf5\x81\x6a\x81\xbf\x01\xbe\x81\x40" }, { 1160, 2, 20, "\x01\x01\x81\x42\x02\x01\x31\x81\x9a\x82\x04\xfc\x02\x06\x46\x01\xcf\x82\x10\x3e\x02\x09\x7f\x02\x0a\xd4\x82\x1d\x08\x02\x0a\xd4\x02\x09\x7f\x82\x10\x3e\x01\xcf\x02\x06\x46\x82\x04\xfc\x81\x9a\x02\x01\x31\x81\x42" }, { 1171, 1, 7, "\x0b\x45\xd1\xf7\x4b\xd3\x4e\xe0\x00\x00\x00\x00\xa0\x05\xbd\x8a\x7f\x11\x13\x4b\xe0\x79\x96\x24\x31\x40\xd7\xc7\x91\x3e\x33\xcb\xe2\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x02\xa8\xb6\xbf\x58\xe2\x9f\x44\x72\xd6\x1f\x75\xb3\x36\x4c\x5d\x62\xb4\x42\xb3\xff\x98\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9d\x29\xfc\xb5\x07\x3e\x40\x2b\x6c\x1c\xc9\x71\xa0\x5b\xa4\x82\x97\x04\x67\x9c\xdb\x4c\x70\x00\x00\x00\x00\x00\x00\x00\x1c\x02\x32\x6d\xf6\xa4\xdf\x54\xb7\xb9\x8b\xeb\x3f\x63\xa2\x52\x97\xf9\x21\x68\x96\xf4\x03\x40\x00\x00\x00\x00\x00\x18\x02\xad\xee\x72\xba\x55\x69\x8b\x5a\x88\x41\x4c\x64\x20\x9a\xd0\x86\xde\x3d\x09\x80\x00\x00\x00\x14\x08\x8e\x23\xfe\x2d\x87\x77\x97\x5c\x7e\x99\x1d\x1d\x6e\x09\x73\xa1\x01\x80\x00" }, { 1172, 2, 18, "\x81\x01\x82\x0f\x29\x03\x01\x49\xfb\x83\x09\x51\x06\x03\x13\x3e\x7d\x83\x05\xa5\x91\x83\x0b\x9e\x7d\x83\x0d\xca\xd6\x03\x06\x77\x32\x03\x25\xf0\x2c\x83\x06\x77\x32\x83\x0d\xca\xd6\x03\x0b\x9e\x7d\x83\x05\xa5\x91\x83\x13\x3e\x7d\x83\x09\x51\x06\x83\x01\x49\xfb\x82\x0f\x29" }, { 1192, 2, 6, "\x81\x01\x81\x41\x81\x05\x01\x72\x01\x05\x81\x41" }, { 1203, 1, 6, "\x0c\x03\x51\x33\xf3\xa0\x70\x36\x88\x00\x00\x00\x00\x21\x3b\xb7\x45\xbc\x5a\x64\xdc\xd2\xe3\x67\x21\xdc\x01\x90\x9d\x34\x5f\x8c\x02\x4b\x94\x7f\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x5b\x99\xd9\x6c\xe3\xee\x54\x49\x93\x5a\x95\xa1\xa7\x8a\xcf\x73\x68\x9d\x8c\x63\x8a\xeb\x86\x37\x80\x00\x00\x00\x00\x00\x00\x00\x9e\x01\xe0\xd4\x11\xe9\xc1\x44\x80\x9f\x00\x9c\x50\x1e\x7e\x5d\x7c\x8e\xec\x98\x6b\x76\x51\xb5\xdf\x60\x00\x00\x00\x00\x00\x1b\x03\x09\x43\x85\x2c\xed\x66\x9c\x31\x6d\x75\x74\x1d\xee\x3e\x6a\xe8\x7b\x69\x44\x20\xb5\xcd\xc0\x00\x00\x00\x14\x24\xcd\x33\x8a\xe1\xef\x15\x96\x3b\xfc\xbb\x19\xed\x91\x87\x7d\xe8\xf5\x80\x00" }, { 1204, 2, 8, "\x01\x01\x02\x11\x3a\x02\x33\x7d\x02\xb2\xaa\x02\x91\x14\x82\xb2\xaa\x02\x33\x7d\x82\x11\x3a" }, { 1207, 2, 18, "\x01\x01\x81\x09\x01\x2a\x81\x79\x01\xfa\x82\x01\xb5\x02\x02\xb8\x82\x04\x0d\x02\x05\x95\x82\x06\xf6\x02\x08\x04\x82\x08\x4f\x02\x07\xa1\x82\x05\xf3\x02\x03\xd9\x82\x02\x18\x01\xe0\x81\x46" }, { 1208, 2, 12, "\x01\x01\x81\x3e\x82\x01\x31\x82\x05\x82\x82\x0e\x66\x82\x18\x4e\x82\x1c\x59\x82\x18\x4e\x82\x0e\x66\x82\x05\x82\x82\x01\x31\x81\x3e" }, { 1219, 1, 6, "\x8b\x0e\xe5\xf6\x7b\x95\x36\x67\x00\x00\x00\x00\x1f\x30\xb0\x3d\x97\x90\xb2\xe9\xde\x4f\x70\xef\x72\x10\xe2\xc1\xd0\x54\x07\x9c\xc0\xaa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1e\x02\xa8\x18\x5a\x4f\xfe\x0d\x09\x18\xe4\x57\x0d\x14\xa5\x73\x7d\xca\x92\xab\x33\x20\x3a\x30\x00\x00\x00\x00\x00\x00\x00\x1c\x2e\x8f\xfa\x8d\xbb\x32\xd5\x63\xb3\x1f\xad\xa3\x39\x9b\x50\x08\xc9\x00\x04\x01\xec\xb4\x40\x00\x00\x00\x00\x00\x98\x60\x1c\x12\x26\x5c\xf1\x83\xd7\x46\x3e\x70\x07\x9d\xd0\xac\x56\x57\x41\xd8\xa7\x00\x00\x00\x00\x14\x4b\xc6\x44\x1f\x45\x5c\xe4\x56\x7d\x69\x52\xb5\x73\x53\x95\xc6\x0e\x4b\x00\x00" }, { 1220, 2, 16, "\x01\x01\x81\x3c\x82\x02\x1c\x82\x09\x24\x82\x17\x6d\x82\x2e\x18\x82\x49\x5c\x82\x5d\x98\x82\x68\x58\x82\x5d\x98\x82\x49\x5c\x82\x2e\x18\x82\x17\x6d\x82\x09\x24\x82\x02\x1c\x81\x3c" }, { 1227, 1, 4, "\x0b\x01\x1f\xeb\x20\xd0\xcf\xb8\xc1\x40\x00\x00\x1d\x03\x4f\x81\xe6\xc4\x1a\xc1\xca\xa7\xb5\x27\xa3\xe7\xf5\x38\x84\xbc\xef\x7c\xf8\x51\xdf\x00\x00\x00\x00\x00\x00\x00\x1b\x0c\xd7\x66\x27\xad\xab\x02\x5c\x5a\x6f\x49\x1d\xea\xe3\x5e\x4e\x62\xfe\x50\x24\x40\x91\x77\xc0\x00\x00\x00\x14\x6c\x89\x91\x9f\x5a\x1a\x88\x46\x3b\xa7\x48\x13\x11\x61\x12\x8c\x8e\xa8\x00\x00" }, { 1236, 2, 12, "\x01\x01\x05\x1c\x8e\xc8\x97\xb8\x06\x8c\xc7\x7a\x3e\xeb\x6a\x07\x0b\x2d\x05\xc3\x2d\x72\x68\x08\x02\x16\x41\x03\x22\x04\x31\x4f\x08\x01\x01\xa7\x84\xb7\xec\xea\x30\x88\x03\x11\xfa\x49\x91\x75\xa9\x74\x88\x01\x01\xa7\x84\xb7\xec\xea\x30\x08\x02\x16\x41\x03\x22\x04\x31\x4f\x87\x0b\x2d\x05\xc3\x2d\x72\x68\x06\x8c\xc7\x7a\x3e\xeb\x6a\x85\x1c\x8e\xc8\x97\xb8" }, { 1240, 2, 8, "\x01\x01\x01\x46\x81\x49\x81\x46\x81\x34\x01\x46\x81\x49\x81\x46" }, { 1243, 1, 4, "\x09\x01\xb1\xc9\xd7\x5b\x05\x00\x00\x00\x98\x02\x3a\xbc\xfa\xfe\xad\x2b\x11\x68\x2b\x04\xce\x9a\xd0\x9f\xce\xf4\x1b\x00\x00\x00\x00\x00\x00\x16\x46\xe2\xd0\x68\xb7\x26\xf4\xc0\x37\x95\xa1\x25\x79\x2b\xac\x88\xd0\xb8\x40\x00\x00\x00\x14\xdd\xe8\x7c\xce\x1e\x72\x80\x59\xa9\x38\x4b\x81\xad\x8d\xe5\x09\x53\x93\x00\x00" }, { 1252, 2, 8, "\x01\x01\x81\x4c\x01\xfd\x82\x02\x04\x02\x02\x64\x82\x02\x04\x01\xfd\x81\x4c" }, { 1255, 2, 12, "\x81\x01\x81\x01\x81\x07\x81\x02\x01\x1a\x81\x09\x81\x51\x81\x12\x01\x0a\x81\xa1\x81\xda\x81\x46" }, { 1267, 1, 6, "\x0a\x49\x65\xc2\x92\x46\x01\x00\x00\x00\x00\x9d\x02\x47\x92\x0a\xf9\x7d\x93\x06\x3c\xa7\xb4\x00\x5b\x56\xc6\x4d\x49\x91\x66\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\x3d\xba\x21\xf1\x97\x1a\x38\xac\xb2\x13\x73\xa2\x76\x4f\xb8\x0d\x33\xa6\x5d\xb0\x00\x00\x00\x00\x00\x00\x00\x99\xc1\x3a\x2d\xb6\x19\xce\x63\x61\xec\xcd\x44\x90\xad\x5a\x6b\x5b\xb3\x0e\xb0\xc0\x00\x00\x00\x00\x00\x18\x01\x4a\xc1\x3e\xe1\x50\x0b\x84\x4e\xb3\xbf\xa5\x59\xef\x3f\xf2\xe5\x6e\x1f\x33\x00\x00\x00\x00\x15\x02\x83\x30\xd9\x3c\xec\x97\x6f\xcb\x0e\xc9\x38\x23\x24\x7c\xfb\xe2\x81\x4f\x00\x00" }, { 1268, 2, 10, "\x81\x01\x82\x15\xe9\x83\x01\x5e\xd9\x83\x09\x23\x8a\x03\x0a\x71\x2f\x83\x09\xa6\x43\x83\x0a\x71\x2f\x83\x09\x23\x8a\x03\x01\x5e\xd9\x82\x15\xe9" }, { 1272, 2, 12, "\x01\x01\x83\x06\x86\x28\x83\xec\xc7\xa2\x04\x01\x21\xe8\xb8\x84\x06\xcd\x6f\xd1\x04\x0e\x3e\x0e\xf0\x84\x15\xf0\xee\x5c\x04\x0e\x3e\x0e\xf0\x84\x06\xcd\x6f\xd1\x04\x01\x21\xe8\xb8\x83\xec\xc7\xa2\x83\x06\x86\x28" }, { 1279, 2, 23, "\x81\x01\x01\x07\x81\x0f\x01\x06\x81\x01\x01\x15\x81\x11\x81\x02\x81\x2e\x01\x0a\x81\x6c\x01\x81\x01\x62\x01\x90\x01\x55\x81\x08\x81\xbb\x01\x52\x82\x01\x6b\x81\xd8\x01\x80\x01\x33\x81\x4d" }, { 1288, 2, 8, "\x01\x01\x81\x4e\x01\x21\x81\x06\x01\xa4\x81\x06\x01\x21\x81\x4e" }, { 1303, 2, 11, "\x81\x01\x81\x08\x81\x1e\x81\x39\x81\x43\x81\x3b\x81\x49\x81\x44\x81\x21\x81\x39\x81\x4f" }, { 1315, 1, 6, "\x0c\x0a\x2d\x7f\xd4\xd2\x3a\x61\x24\x00\x00\x00\x00\x21\x06\xd0\x2a\xc1\x0b\x80\xeb\x78\xd8\x59\xef\x24\x92\xde\x2b\xcf\x06\xcb\x9a\xca\xa2\x0f\x48\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x12\x25\xd0\x64\x70\xc3\xf2\xc2\x98\x9a\x9a\x31\x52\x6a\xbf\xe0\x9a\xc2\xad\xf6\x0d\xee\xcf\x70\x00\x00\x00\x00\x00\x00\x00\x9c\x2e\xfd\x68\x1b\x31\x86\xbe\x31\xff\x8a\x5b\x87\x3a\x6f\x81\x4e\x96\x35\xd8\x0e\x3a\xe6\xc0\x00\x00\x00\x00\x00\x19\x25\x60\xbb\xff\x5f\xb1\xa6\xa4\xc9\x5f\x91\x24\x93\x1c\x30\xf3\x8c\xcd\xc1\xf2\x64\x00\x00\x00\x00\x15\x14\x7c\xba\xe3\x28\x32\x88\x5e\xaf\x2b\x6c\x45\x27\x24\x2b\x1d\xde\x1a\xdf\x00\x00" }, { 1320, 2, 8, "\x01\x01\x03\x08\x7a\x00\x84\x01\x92\xac\x84\x04\x08\xb9\x93\x00\x83\x84\xbb\xfa\x84\x08\xb9\x93\x00\x84\x01\x92\xac\x84\x83\x08\x7a\x00" }, { 1327, 2, 15, "\x81\x01\x81\x06\x81\x10\x81\x18\x81\x26\x01\x01\x81\x18\x01\x03\x81\x34\x81\x14\x81\x0d\x01\x64\x01\x12\x81\x15\x81\x53" }, { 1336, 2, 12, "\x01\x01\x81\x54\x81\x30\x82\x01\x08\x81\x18\x82\x01\x5c\x82\x02\x46\x82\x01\x5c\x81\x18\x82\x01\x08\x81\x30\x81\x54" }, { 1347, 1, 6, "\x0d\x01\x3f\x94\xfc\xe9\xe2\x44\xd3\xd7\x80\x00\x00\x00\xa3\xbf\xea\xd9\xe7\x98\xe5\x59\x1b\x57\x98\x00\x2b\x5c\x59\x94\xeb\xc0\xf8\xcd\xa8\x07\xe0\x14\xf7\xb9\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\x27\xed\x27\xa6\x83\xa0\xeb\x7a\xdd\x4c\xb0\x70\xef\xc0\x35\x93\x2c\xb4\xda\xf1\xe6\xcb\xf4\xaa\x41\x5e\x10\x00\x00\x00\x00\x00\x00\x00\x1f\x3a\xa8\x62\xa9\xc3\x01\x4b\x91\x6d\x24\xe9\x4d\x85\x48\x43\x8d\xf8\x8d\x97\x74\x72\x37\x5f\x21\x3f\xc0\x00\x00\x00\x00\x00\x1c\x37\x6d\x98\x9d\x98\x2a\x38\xc3\x29\x21\x50\xd0\x47\xb0\xf9\x64\xef\x03\xba\x88\xdc\xbc\x79\x35\x80\x00\x00\x00\x15\x51\x41\xa3\x04\xa1\x64\x25\xac\x28\x12\xd6\x1d\x82\xa2\xb5\xe2\x59\x82\x78\x80\x00" }, { 1348, 2, 8, "\x01\x01\x81\x55\x81\x7d\x01\x3c\x01\xea\x01\x3c\x81\x7d\x81\x55" }, { 1351, 2, 24, "\x01\x01\x01\x09\x01\x1e\x01\x31\x01\x2a\x81\x04\x81\x07\x01\x82\x01\xda\x01\xa5\x01\x24\x81\x68\x01\x33\x02\x01\x1f\x02\x01\x34\x01\x01\x81\xca\x01\x7b\x01\xde\x02\x01\x84\x01\xd5\x81\xca\x81\x4c\x81\x56" }, { 1363, 1, 6, "\x8b\x20\xa5\x94\x54\x02\xcb\x65\x00\x00\x00\x00\x1f\x32\xc2\x53\xf1\xa2\x68\xe4\xe7\xde\xe2\x76\x78\x06\xba\xe6\x8b\x73\xdb\xad\xff\xa3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9d\xa1\x55\xb4\x89\xce\x3c\x2c\xf0\xbf\x94\xe0\x43\xd7\x55\xfb\x7b\x21\x75\x25\xd6\x51\xb0\x00\x00\x00\x00\x00\x00\x00\x1b\x8d\x22\xf4\xed\x84\xb0\x65\x77\x00\xa2\xfa\xda\xbc\x49\xeb\xbd\xfb\x3b\xf2\x39\x7c\x80\x00\x00\x00\x00\x00\x98\x43\xb6\x93\x81\x0c\xea\x06\x7e\x29\x7b\xe6\x1d\xcc\xa8\x86\xfe\xe8\xc1\xb9\x29\x80\x00\x00\x00\x15\xa0\xd5\xa1\x71\xaa\x7f\x52\xd0\xdf\x1f\xdd\xe3\x41\x56\xb2\x27\xcc\x8d\x06\x00\x00" }, { 1380, 2, 8, "\x01\x01\x83\x0b\xae\x64\x84\x02\x4d\x62\x08\x84\x09\x51\xbe\x8c\x04\x17\x63\xea\x2e\x84\x09\x51\xbe\x8c\x84\x02\x4d\x62\x08\x83\x0b\xae\x64" }, { 1384, 2, 10, "\x81\x01\x81\x5d\x81\x4e\x01\xdd\x02\x01\x67\x82\x02\x70\x82\x01\x67\x01\xdd\x01\x4e\x81\x5d" }, { 1387, 1, 4, "\x09\x06\xe3\xb9\x11\xa0\x0a\xa0\x00\x00\x19\x05\xd8\x30\x67\x8a\x03\xdc\x59\x1a\x4a\x15\xc7\xe2\x79\xec\x8a\x67\x84\xe4\xe0\x00\x00\x00\x00\x00\x17\x57\xec\x66\x85\xbc\x66\x98\xca\x2d\x4b\x44\x55\x46\x2c\x57\xf4\x52\x14\x6f\xc0\x00\x00\x00\x16\x01\xbc\x8b\xf0\x83\xad\x1f\x82\xe8\xf8\xc0\x7c\x75\xe1\x0d\xce\x94\x68\xea\xb0\x80\x00" }, { 1396, 2, 14, "\x81\x01\x82\x22\x8c\x03\x01\x2f\x01\x83\x04\x0c\x68\x03\x04\x2d\x20\x03\x05\xbc\x68\x83\x0b\xdc\x8e\x83\x05\x3d\xa8\x03\x0b\xdc\x8e\x03\x05\xbc\x68\x83\x04\x2d\x20\x83\x04\x0c\x68\x83\x01\x2f\x01\x82\x22\x8c" }, { 1411, 1, 4, "\x0b\x05\x47\x5f\x4c\x45\x72\x0c\xf1\x40\x00\x00\x1e\x51\x98\xbd\xab\x02\x24\xe2\xb4\x75\x74\x8d\x95\xa2\xc7\x72\x4a\x19\x3c\xc9\x78\x72\x49\x28\xf4\x20\x00\x00\x00\x00\x00\x1a\x0c\x2d\x69\x94\xdd\xa4\xae\x27\x3d\xb5\x15\xbb\x53\x4d\xf1\xac\xbd\xcd\xaf\x89\x78\x8a\xc0\x00\x00\x00\x16\x04\xc2\x03\x1c\x0b\xfa\x7d\x0f\x93\x76\xd8\x71\xfe\x69\xba\x71\x05\x92\x4e\x29\x80\x00" }, { 1412, 2, 16, "\x01\x01\x81\x65\x02\x01\x98\x02\x01\x17\x82\x08\x6f\x82\x08\xd4\x02\x05\x5a\x82\x08\xde\x82\x1b\x08\x82\x08\xde\x02\x05\x5a\x82\x08\xd4\x82\x08\x6f\x02\x01\x17\x02\x01\x98\x81\x65" }, { 1416, 2, 16, "\x01\x01\x83\x0e\x1c\xcc\x84\x02\x2b\x40\x50\x04\x17\x83\xca\x7c\x84\x54\x03\x73\x34\x84\x9e\xc1\x32\xac\x84\x9f\xe9\xf0\x70\x84\xb5\xac\x7b\x04\x85\x01\xb9\xde\xb8\x1a\x84\xb5\xac\x7b\x04\x84\x9f\xe9\xf0\x70\x84\x9e\xc1\x32\xac\x84\x54\x03\x73\x34\x04\x17\x83\xca\x7c\x84\x02\x2b\x40\x50\x83\x0e\x1c\xcc" }, { 1423, 2, 9, "\x81\x01\x01\x05\x81\x16\x01\x25\x81\x41\x01\x2a\x81\x59\x01\x26\x81\x63" }, { 1428, 2, 8, "\x01\x01\x05\xe1\xb1\x28\x46\xd0\x07\x08\x8c\xe0\x72\x22\x89\x5c\x07\x49\x91\x55\x07\xe9\x30\x90\x87\x0d\x32\xb7\xb5\x83\xe1\xba\x87\x49\x91\x55\x07\xe9\x30\x90\x07\x08\x8c\xe0\x72\x22\x89\x5c\x85\xe1\xb1\x28\x46\xd0" }, { 1432, 2, 6, "\x81\x01\x81\x64\x01\x10\x81\x8a\x81\x10\x81\x64" }, { 1435, 1, 4, "\x8b\x01\x50\x6b\x7c\x3d\xe1\xfc\x3a\x70\x00\x00\x1d\x5e\x36\x76\xf9\x80\x59\xc2\x7c\x84\xe6\x9c\x9f\xa9\x76\xe5\xc3\x7a\x43\xea\x3a\x7f\x1d\xf0\x00\x00\x00\x00\x00\x00\x1a\x41\x71\x31\x9e\xdc\xef\x23\xcb\x11\x94\x0f\xe6\x7d\xd1\xf8\x25\xf4\xf6\x06\x8e\x88\x4d\x80\x00\x00\x00\x16\x0c\xec\xdc\xc9\x12\x96\x38\xf6\xbb\x53\x43\x2f\x7f\x01\x82\xa6\xc1\x3e\x75\x60\x00\x00" }, { 1447, 2, 23, "\x81\x01\x81\x02\x81\x10\x81\x22\x81\x44\x81\x3f\x81\x11\x01\x2b\x01\x8b\x01\xa5\x81\x19\x81\xe4\x82\x01\x09\x82\x01\x0e\x81\x4b\x01\xf6\x01\x82\x81\xa1\x81\xf0\x82\x01\x89\x82\x02\x39\x82\x01\x81\x81\x63" }, { 1448, 2, 18, "\x81\x01\x81\x6e\x82\x02\xde\x82\x04\x38\x02\x0a\x4e\x02\x16\x62\x82\x06\xed\x82\x2e\x54\x82\x08\xb4\x02\x37\xf0\x02\x08\xb4\x82\x2e\x54\x02\x06\xed\x02\x16\x62\x82\x0a\x4e\x82\x04\x38\x02\x02\xde\x81\x6e" }, { 1464, 2, 12, "\x01\x01\x83\x12\x17\x58\x84\x04\x46\xfa\xa2\x84\x21\x5c\x74\x38\x85\x01\x12\x15\x7b\xd1\x85\x02\xcd\xaf\x7d\xf0\x85\x03\xd3\x97\xe0\x5c\x85\x02\xcd\xaf\x7d\xf0\x85\x01\x12\x15\x7b\xd1\x84\x21\x5c\x74\x38\x84\x04\x46\xfa\xa2\x83\x12\x17\x58" }, { 1471, 2, 23, "\x81\x01\x81\x05\x81\x03\x01\x03\x81\x2b\x81\x06\x01\x1f\x81\x38\x01\x44\x81\x59\x81\x93\x01\xb4\x82\x01\x12\x01\xf0\x01\xd3\x82\x02\x09\x02\x01\x7f\x82\x01\x13\x82\x01\x23\x01\xf9\x82\x01\x66\x81\x09\x81\x6b" }, { 1480, 2, 12, "\x01\x01\x81\x66\x82\x02\xca\x82\x09\x54\x82\x14\x8e\x82\x20\x82\x82\x25\xda\x82\x20\x82\x82\x14\x8e\x82\x09\x54\x82\x02\xca\x81\x66" }, { 1483, 1, 7, "\x0c\x06\x24\x8d\xf0\x4f\x85\xfd\xc0\x00\x00\x00\x00\xa1\x33\xab\xd9\xec\x1d\x7b\x5a\x99\xac\xb1\x6c\x49\x33\x47\xfc\x32\xc1\xaf\x2a\x9b\x44\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x0b\x12\xb1\x8a\x85\x9d\x38\xb0\xf6\xa7\xd5\xa5\xa4\x2e\xfe\x11\xdb\x1c\x2d\xfa\x13\x0f\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9e\x36\x8a\x40\xf2\x17\x71\xc5\xd8\xbd\xe8\xc9\xbd\x43\x57\x18\xbc\xf6\x7b\x6a\x13\x29\x1e\x10\x00\x00\x00\x00\x00\x00\x00\x1d\x01\x54\x06\x18\x50\x89\x9e\x7b\xfe\xd6\x9b\x66\x0e\xa4\x7e\x65\xd5\x52\x92\x8d\x8d\x05\x83\x80\x00\x00\x00\x00\x00\x9a\x01\x40\x7d\xc9\x24\x5d\xcf\x91\x1a\x08\xb3\x2d\xc2\xcc\xd7\xa5\x18\x61\x68\xbb\x52\xae\x40\x00\x00\x00\x16\x5d\x0d\xfd\x21\xed\xb2\xf9\x88\xec\x95\x2e\xb2\x22\x4b\xb1\xb5\x46\xca\xee\xb1\x00\x00" }, { 1492, 2, 10, "\x81\x01\x82\x30\x24\x82\x2e\xe1\x82\x12\x60\x02\x1a\x6f\x82\x35\x04\x82\x1a\x6f\x82\x12\x60\x02\x2e\xe1\x82\x30\x24" }, { 1495, 2, 20, "\x01\x01\x81\x07\x01\x11\x01\x0b\x81\x57\x01\x20\x01\xea\x81\x97\x82\x01\x99\x01\xde\x02\x01\xf7\x81\x60\x82\x01\x6f\x81\x23\x81\x09\x81\x83\x02\x01\x26\x02\x01\x00\x81\xb2\x81\x6e" }, { 1507, 1, 4, "\x0a\x02\x14\x4d\xca\xcf\xa5\x2c\x30\x00\x00\x9a\x51\xf9\xcd\xaa\xa5\x8b\xfb\x87\x8e\x14\x06\xa9\xf7\xb9\x9e\x67\xa5\x4b\x63\x59\xc0\x00\x00\x00\x00\x00\x18\x96\xa2\xe5\x7e\x41\x15\x72\x93\xc8\x20\x7d\x64\xc1\xed\x90\x20\x34\x03\x6e\x8f\x00\x00\x00\x00\x16\xf6\xb5\x68\xb7\xe3\xa6\x1e\x1b\x0f\xc7\x52\xe9\xb5\x19\xeb\xc2\x61\x30\xa6\x5b\x00\x00" }, { 1508, 2, 16, "\x01\x01\x81\x66\x82\x05\x17\x82\x1e\xda\x82\x70\x17\x83\x01\x1b\xe0\x83\x02\x17\xd6\x83\x03\x0a\x00\x83\x03\x70\x3e\x83\x03\x0a\x00\x83\x02\x17\xd6\x83\x01\x1b\xe0\x82\x70\x17\x82\x1e\xda\x82\x05\x17\x81\x66" }, { 1527, 2, 14, "\x81\x01\x01\x54\x82\x09\x47\x02\x21\x7d\x83\x01\xb5\x60\x03\x07\xe0\xca\x83\x0f\x1f\x69\x03\x4c\x2b\xb0\x84\x01\x5a\xd7\x17\x04\x03\x4b\xcc\x5e\x84\x06\x5e\x90\xba\x04\x09\x22\x6a\xb7\x84\x05\x92\x8a\xd5\x83\x18\xe9\x5b" }, { 1528, 2, 8, "\x01\x01\x81\x78\x01\xf6\x82\x01\xe0\x02\x02\x03\x82\x01\xe0\x01\xf6\x81\x78" }, { 1540, 2, 8, "\x01\x01\x81\x76\x82\x01\x1b\x01\xc6\x02\x02\xd8\x01\xc6\x82\x01\x1b\x81\x76" }, { 1543, 2, 19, "\x81\x01\x01\x09\x81\x18\x01\x06\x01\x2a\x81\x04\x81\x22\x81\x4a\x81\x2e\x01\xee\x01\x31\x81\xb5\x81\xc3\x81\x74\x01\xc1\x02\x01\x13\x81\x6a\x01\x08\x81\x79" }, { 1544, 2, 20, "\x01\x01\x81\x74\x82\x02\x66\x82\x04\x54\x02\x09\x23\x02\x02\x68\x82\x1d\x70\x82\x40\x58\x82\x28\x43\x02\x34\x54\x02\x79\xa2\x02\x34\x54\x82\x28\x43\x82\x40\x58\x82\x1d\x70\x02\x02\x68\x02\x09\x23\x82\x04\x54\x82\x02\x66\x81\x74" }, { 1555, 1, 4, "\x0a\x77\x67\x2f\x66\xf9\x14\x7a\x30\x00\x00\x9d\x05\xb4\x70\x5d\x2f\x31\xb5\x6d\x91\x98\x13\x59\x74\xae\x42\xec\x07\x0e\xd5\x3e\x20\xb5\xdb\x40\x00\x00\x00\x00\x00\x1b\x58\xc7\x14\x3f\x52\x0e\x69\xab\x61\xb0\x09\xa4\x00\xe2\xf9\xe4\x4d\xda\xba\xd1\x08\x0d\x53\x00\x00\x00\x00\x17\x06\x9e\xa6\x1b\x7c\xc7\x0f\xa7\xb4\x6a\x3b\xed\x5a\x2c\x0f\xee\x91\x2b\x78\x4d\x31\x00\x00" }, { 1560, 2, 16, "\x01\x01\x03\x1d\x60\xd8\x84\x08\xa5\x8a\x38\x04\x63\x48\x13\xb8\x85\x01\x58\xf8\x28\x64\x05\x01\x05\x0e\xfc\x18\x05\x02\x85\xe9\x52\x78\x84\x90\xfd\x76\xc8\x85\x03\x15\x41\xae\xba\x04\x90\xfd\x76\xc8\x05\x02\x85\xe9\x52\x78\x85\x01\x05\x0e\xfc\x18\x85\x01\x58\xf8\x28\x64\x84\x63\x48\x13\xb8\x84\x08\xa5\x8a\x38\x83\x1d\x60\xd8" }, { 1563, 1, 6, "\x0d\x01\x39\x3e\xeb\x9a\xff\x00\xfb\x50\x00\x00\x00\x00\xa3\x64\x07\xc2\x49\xb0\x33\xd6\xe0\xe9\xa4\x14\xd0\xcf\xd8\xee\x99\x75\xa6\x88\xcf\x25\xf4\x99\x98\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\x05\x6c\x47\x9f\xb4\xa2\xbf\x51\x83\x00\xb2\x6a\x42\xc6\xfb\xc3\x21\x7b\xee\xa3\xdb\x83\x92\xdc\x3e\x6c\x00\x00\x00\x00\x00\x00\x00\x00\xa0\x05\x1d\xb0\x93\x6f\x2e\xcf\x3e\xfa\x68\x7a\x1e\x43\x9d\x6a\x4d\x07\x14\x40\xb8\xaf\x4b\x7f\x83\xcf\x4a\x00\x00\x00\x00\x00\x00\x1e\x78\xa3\xf9\xf9\xdd\xa3\x16\xb3\x9c\x86\x7f\x56\x22\xa2\x06\x57\x7e\xc5\x5b\x4e\x9d\x38\xab\xe8\xd8\x97\xc0\x00\x00\x00\x17\x09\x19\xb3\x13\x8d\xc0\x3d\x92\xfc\x32\xa0\xf4\x17\xf2\x1b\x36\x3e\x3f\x74\x89\x4e\x00\x00" }, { 1567, 2, 15, "\x81\x01\x01\x01\x81\x0d\x01\x2c\x81\x4c\x01\xb6\x82\x01\x3d\x02\x01\x4a\x82\x01\x96\x02\x02\x0a\x82\x02\x14\x02\x02\x8a\x82\x02\x9e\x02\x01\x91\x81\x81" }, { 1572, 2, 12, "\x01\x01\x83\x1f\x2e\x4e\x84\x07\xc8\xfa\x76\x84\x04\x07\x88\xee\x84\x1b\xce\xc3\x81\x84\x06\x44\xc8\xc4\x84\x2c\x9d\xa4\x14\x84\x06\x44\xc8\xc4\x84\x1b\xce\xc3\x81\x84\x04\x07\x88\xee\x84\x07\xc8\xfa\x76\x83\x1f\x2e\x4e" }, { 1576, 2, 10, "\x81\x01\x81\x7f\x01\x5b\x82\x01\xc2\x81\xd1\x81\xd1\x01\xd1\x82\x01\xc2\x81\x5b\x81\x7f" }, { 1588, 2, 6, "\x81\x01\x82\x42\x4e\x02\x34\x4a\x83\x01\x46\xd0\x82\x34\x4a\x82\x42\x4e" }, { 1591, 2, 22, "\x81\x01\x81\x01\x01\x04\x81\x1d\x81\x79\x81\x2e\x02\x01\x37\x02\x01\x58\x82\x01\x87\x82\x03\x3e\x01\xea\x02\x06\x74\x02\x03\xef\x82\x06\x69\x82\x0b\x64\x82\x02\xae\x02\x07\xb5\x02\x06\x4b\x81\x52\x82\x02\x67\x82\x01\x7b\x81\x80" }, { 1603, 1, 6, "\x0c\x02\xc4\x06\x2d\x04\x6d\xe3\xb0\x00\x00\x00\x00\xa0\x85\xb6\xd8\x85\xc0\x95\x76\xa7\xff\xe1\xc5\x37\x47\x1f\xdf\x6b\xfc\x96\x24\x2e\xb6\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x01\x74\x25\x71\xb8\x8c\x07\xbf\xfa\x38\xb7\xaf\xec\x5a\xa6\xa3\x11\x14\xc4\xde\xa2\xc1\x34\x00\x00\x00\x00\x00\x00\x00\x00\x9c\x87\x70\xad\x3f\x91\x81\x6f\xd0\x11\x4e\x73\x23\xd9\xb7\x84\xa0\x05\xb6\x70\xa0\x23\x94\x00\x00\x00\x00\x00\x00\x1a\xa7\x54\x08\x35\x86\x32\x9c\x55\x8c\x16\xe1\xe1\xc6\xd5\x85\x67\xfd\x0f\xf4\x8a\x5d\xae\xc0\x00\x00\x00\x17\x2c\x25\xfe\x36\x6f\x7c\xee\x3a\xe6\xec\xe2\x02\x29\x23\x1d\xef\xac\x81\x5c\xc4\x30\x00\x00" }, { 1604, 2, 20, "\x01\x01\x81\x87\x01\xbb\x82\x0a\x5e\x02\x18\x10\x82\x3e\x12\x02\x58\xed\x82\xbd\x01\x02\x8c\xb7\x83\x01\x43\x90\x02\x96\x30\x83\x01\x43\x90\x02\x8c\xb7\x82\xbd\x01\x02\x58\xed\x82\x3e\x12\x02\x18\x10\x82\x0a\x5e\x01\xbb\x81\x87" }, { 1608, 2, 16, "\x01\x01\x83\x25\x3a\x94\x84\x08\xfd\x86\x10\x04\x32\x70\x0e\x64\x84\xd3\xb0\x68\xb4\x05\x03\x2e\xf7\xb4\x4c\x85\x08\xce\x35\xa6\xb0\x05\x10\x25\xf5\x77\xe4\x85\x13\xbb\xc8\xd5\x1a\x05\x10\x25\xf5\x77\xe4\x85\x08\xce\x35\xa6\xb0\x05\x03\x2e\xf7\xb4\x4c\x84\xd3\xb0\x68\xb4\x04\x32\x70\x0e\x64\x84\x08\xfd\x86\x10\x83\x25\x3a\x94" }, { 1624, 2, 16, "\x01\x01\x01\x8e\x02\x02\x15\x02\x02\x96\x81\x47\x82\x01\x8c\x81\xf6\x82\x03\xc0\x01\xea\x02\x03\xc0\x81\xf6\x02\x01\x8c\x81\x47\x82\x02\x96\x02\x02\x15\x81\x8e" }, { 1636, 2, 16, "\x01\x01\x81\x8b\x82\x01\x06\x82\x02\x79\x82\x02\x3d\x82\x02\x44\x82\x06\x14\x82\x08\x5c\x01\x64\x82\x08\x5c\x82\x06\x14\x82\x02\x44\x82\x02\x3d\x82\x02\x79\x82\x01\x06\x81\x8b" }, { 1639, 2, 22, "\x81\x01\x81\x02\x81\x0e\x81\x11\x01\x09\x00\x81\x59\x01\x33\x81\x22\x81\x02\x81\x6e\x01\x3a\x82\x01\x50\x01\xea\x82\x02\x8a\x01\x78\x81\xa3\x82\x01\x01\x82\x01\x07\x82\x01\x13\x02\x01\x59\x81\x90" }, { 1640, 2, 16, "\x01\x01\x01\x8a\x82\x02\x09\x02\x0a\x3e\x82\x11\xcf\x82\x14\xc8\x02\x33\xde\x02\x15\x94\x82\x49\xbe\x82\x15\x94\x02\x33\xde\x02\x14\xc8\x82\x11\xcf\x82\x0a\x3e\x82\x02\x09\x81\x8a" }, { 1663, 2, 17, "\x81\x01\x01\x01\x01\x0e\x01\x08\x81\x55\x81\xcb\x81\xe1\x81\xdc\x82\x01\x03\x82\x01\x01\x82\x01\x22\x82\x01\x6d\x82\x01\xb5\x82\x02\x1d\x82\x01\xfb\x82\x01\x3a\x81\x91" }, { 1668, 2, 12, "\x01\x01\x83\x31\xce\xfa\x84\x0e\x99\xb1\x06\x84\x0c\x6c\x7f\x3a\x04\x07\xc8\x58\x3f\x84\x19\xbf\x21\x4c\x84\x47\xa2\x6f\x74\x84\x19\xbf\x21\x4c\x04\x07\xc8\x58\x3f\x84\x0c\x6c\x7f\x3a\x84\x0e\x99\xb1\x06\x83\x31\xce\xfa" }, { 1672, 2, 8, "\x01\x01\x81\x96\x01\x69\x01\x1e\x82\x01\xe4\x01\x1e\x01\x69\x81\x96" }, { 1684, 2, 10, "\x81\x01\x82\x5a\x7b\x82\xe6\x89\x83\x06\xce\x2e\x82\x58\x51\x83\x07\xaa\x99\x02\x58\x51\x83\x06\xce\x2e\x02\xe6\x89\x82\x5a\x7b" }, { 1687, 2, 18, "\x01\x01\x01\x06\x01\x11\x01\x11\x01\x41\x01\x8d\x01\xfc\x02\x01\x89\x02\x01\xb8\x02\x02\x65\x02\x02\xad\x02\x02\x22\x02\x01\xbb\x01\xe3\x01\x52\x01\x08\x81\x8c\x81\x98" }, { 1688, 2, 10, "\x81\x01\x81\x94\x02\x03\x0e\x82\x04\xfe\x82\x11\xf9\x02\x06\x1c\x02\x11\xf9\x82\x04\xfe\x82\x03\x0e\x81\x94" }, { 1720, 2, 12, "\x01\x01\x81\x9c\x82\x03\x30\x82\x06\xa8\x82\x09\x18\x82\x0c\x54\x82\x0f\x06\x82\x0c\x54\x82\x09\x18\x82\x06\xa8\x82\x03\x30\x81\x9c" }, { 1723, 1, 5, "\x0b\x02\x52\x69\x1d\x6f\xfd\x33\x84\x00\x00\x00\x9e\x03\xb5\x06\x6e\x8e\xa9\xa0\xb2\x54\xa6\x99\x82\xe4\x67\xd2\xd7\x38\xfa\x18\x90\x48\x84\x90\x00\x00\x00\x00\x00\x00\x00\x1c\x4d\x5d\x1d\xaa\xbf\x6e\x63\x34\x48\xe8\x5f\x0f\xd4\x32\xe3\xf1\xe1\xbd\x4a\xc9\x04\x62\x40\x00\x00\x00\x00\x00\x1a\x3e\x3c\x24\x93\x65\x45\x86\x17\x10\xbf\xab\x05\xa5\xef\x69\x96\xf7\x3b\xbd\x4c\xef\x9c\x00\x00\x00\x00\x18\x11\x8e\x59\x61\x86\xb3\xd7\x01\xce\x2b\x76\xef\x79\xdb\x26\xe3\x49\x93\x96\x86\x66\x27\x00\x00" }, { 1732, 2, 12, "\x01\x01\x81\xa8\x02\x02\x78\x82\x05\xca\x02\x0a\xb8\x82\x10\x68\x02\x13\x0a\x82\x10\x68\x02\x0a\xb8\x82\x05\xca\x02\x02\x78\x81\xa8" }, { 1747, 1, 5, "\x0a\x2f\x0e\x15\x41\x16\xef\x48\x00\x00\x00\x1c\x04\xa8\x6a\xd4\x65\x8b\xfb\xeb\x1d\x6e\xa3\xa9\x27\x4b\x33\xdd\xca\xe3\x47\xe8\x00\x00\x00\x00\x00\x00\x00\x00\x9b\x0c\x3d\xd5\x89\x34\x40\xdc\xf0\x82\xd2\xf2\x75\xae\x21\xd6\x98\x1b\xfd\xe0\x84\xcb\xa0\x00\x00\x00\x00\x00\x99\xab\x18\x51\x27\x87\x25\x84\x40\xb6\x46\xac\x4f\xc9\x98\x6b\x4e\xcc\xcb\x82\x07\xad\x40\x00\x00\x00\x18\x2b\x66\x8b\x6e\xa9\xc5\x71\xaf\xcd\xec\xca\x2b\xf0\x74\x2f\x9a\x5f\x50\x29\x20\x14\x94\x80\x00" }, { 1752, 2, 8, "\x01\x01\x03\x4a\x39\x10\x84\x18\x97\x2a\xec\x04\x02\xea\xd6\x90\x84\x32\xcd\x2a\x9a\x84\x02\xea\xd6\x90\x84\x18\x97\x2a\xec\x83\x4a\x39\x10" }, { 1768, 2, 8, "\x01\x01\x01\xae\x01\x30\x81\x78\x81\x97\x01\x78\x01\x30\x81\xae" }, { 1780, 2, 8, "\x01\x01\x02\x7a\x61\x03\x01\xc5\xbf\x83\x02\x97\x9c\x83\x02\xf2\x5c\x03\x02\x97\x9c\x03\x01\xc5\xbf\x82\x7a\x61" }, { 1783, 2, 17, "\x81\x01\x81\x07\x81\x1e\x81\x3d\x81\x73\x81\x9e\x81\x5e\x81\x6f\x82\x01\x0c\x82\x01\x9b\x82\x01\xd1\x82\x01\xd9\x82\x01\x3a\x81\x6d\x82\x01\xbe\x82\x01\xf2\x81\xaf" }, { 1796, 2, 20, "\x01\x01\x81\xb1\x82\x03\x1a\x82\x06\xa9\x02\x11\x2b\x82\x1c\x62\x02\x77\x64\x82\xf7\xba\x03\x01\x36\xf5\x83\x01\x0b\xcb\x02\xc2\xea\x83\x01\x0b\xcb\x03\x01\x36\xf5\x82\xf7\xba\x02\x77\x64\x82\x1c\x62\x02\x11\x2b\x82\x06\xa9\x82\x03\x1a\x81\xb1" }, { 1807, 2, 12, "\x81\x01\x01\x05\x81\x16\x01\x1e\x81\x36\x01\x98\x82\x01\x03\x01\xff\x81\x63\x81\xaf\x02\x01\x10\x81\xba" }, { 1812, 2, 12, "\x01\x01\x06\x25\x9b\x4d\x46\x90\x78\x08\x04\xf8\xee\xbd\x50\x15\xb6\x6a\x08\x64\xea\x1f\x72\x08\xa8\xce\xa8\x09\x05\x05\x67\x2d\xd5\xa8\x31\x65\x4f\x09\x09\xbb\x5c\x35\x7a\x82\xfc\xb9\xb0\x09\x17\xf6\xfa\xf7\xf5\xcb\x41\x58\x8c\x89\x09\xbb\x5c\x35\x7a\x82\xfc\xb9\xb0\x09\x05\x05\x67\x2d\xd5\xa8\x31\x65\x4f\x88\x64\xea\x1f\x72\x08\xa8\xce\xa8\x08\x04\xf8\xee\xbd\x50\x15\xb6\x6a\x86\x25\x9b\x4d\x46\x90\x78" }, { 1816, 2, 14, "\x81\x01\x81\xba\x01\xc9\x82\x03\xe8\x82\x01\x40\x81\x48\x82\x06\xc2\x02\x03\xdc\x02\x06\xc2\x81\x48\x02\x01\x40\x82\x03\xe8\x81\xc9\x81\xba" }, { 1828, 2, 8, "\x01\x01\x81\xbd\x82\x01\x29\x82\x02\xac\x82\x02\x42\x82\x02\xac\x82\x01\x29\x81\xbd" }, { 1831, 2, 19, "\x81\x01\x01\x07\x81\x2b\x01\xa9\x82\x01\xda\x02\x03\xc9\x82\x05\x94\x02\x05\xe2\x82\x03\xcd\x01\x61\x02\x01\x19\x02\x01\x96\x82\x07\x9b\x02\x0c\x5a\x82\x0c\x87\x02\x09\x0f\x82\x03\xd3\x02\x01\x2d\x81\xc1" }, { 1843, 1, 6, "\x0c\x03\x41\x49\x24\x86\x8e\xb0\x88\x00\x00\x00\x00\x21\x0e\xb5\xca\x83\xd2\xdf\xad\x8f\x04\xed\xc1\xb0\x29\x30\x62\x3a\xf5\x0d\xf6\x37\x63\x09\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x25\x3e\x49\x8a\x0e\xfc\x21\xbb\x07\xc1\x95\xfd\x67\xcb\x7e\x4f\x7a\x96\x50\x7a\xc2\x7b\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x47\xbb\x72\x42\x02\x44\x05\xfc\x32\x5d\x3c\x5f\x0b\xe0\xe8\x8b\x16\x8c\xd8\x15\x34\x54\x77\x20\x00\x00\x00\x00\x00\x1b\x13\x0d\xce\xd5\xfe\x55\x53\xad\x42\x40\xec\xcc\x20\xce\xa3\x0d\x53\x01\xfb\xd7\x68\xdc\x90\xc0\x00\x00\x00\x19\x05\xf5\x72\xe0\x62\x86\xbf\x36\xf0\xa3\x81\x51\x14\xa1\xca\xf1\x19\x20\x22\x61\x1d\x6a\x25\x80\x00" }, { 1848, 2, 8, "\x01\x01\x83\x73\xbf\x30\x84\x2b\x89\xf9\x6c\x04\x59\xe1\x5e\xf0\x05\x01\x49\xcb\x37\x66\x04\x59\xe1\x5e\xf0\x84\x2b\x89\xf9\x6c\x83\x73\xbf\x30" }, { 1864, 2, 8, "\x01\x01\x81\xcf\x02\x04\x86\x82\x0b\x91\x02\x0f\x32\x82\x0b\x91\x02\x04\x86\x81\xcf" }, { 1867, 1, 5, "\x0c\xde\xd8\x7f\x5c\xb2\xdf\x90\x64\xe4\x00\x00\x00\xa2\x0e\x17\x09\xb5\x20\x2f\x22\x4f\x95\x4e\xe2\x0d\xcc\xbe\x65\x1d\xb5\x36\x7d\xed\xfd\x23\x7c\x76\x7d\xd8\x30\x00\x00\x00\x00\x00\x00\x00\x20\x0d\xd9\x32\x89\xdf\xc5\x98\x73\xe5\xdb\xb7\xce\x80\xfc\xa5\xdf\x20\x3c\x9f\x7e\xc4\x57\x3c\x5d\xe4\x07\x80\x00\x00\x00\x00\x00\x9c\x64\x40\xc6\xa4\xa9\x56\xb2\x49\x8c\x1d\x9f\xb0\x7f\x10\x15\x9b\xd8\x6b\x5f\x2d\x2e\x9d\x10\xd7\x80\x00\x00\x00\x19\x0e\x4c\x7e\x14\x33\x32\x49\x62\xa5\x36\xcd\x46\x1f\x5f\x8d\x83\xec\xc9\x37\x9a\x5e\xf5\x96\x00\x00" }, { 1876, 2, 16, "\x01\x01\x02\xa4\x28\x83\x03\x60\x62\x03\x03\x16\xb0\x03\x20\x87\xd1\x03\x09\x56\x10\x03\x28\xde\x7e\x83\x27\x65\xb8\x03\x5a\x9d\x24\x03\x27\x65\xb8\x03\x28\xde\x7e\x83\x09\x56\x10\x03\x20\x87\xd1\x83\x03\x16\xb0\x83\x03\x60\x62\x82\xa4\x28" }, { 1880, 2, 20, "\x01\x01\x01\xd4\x02\x04\x9e\x82\x02\xf4\x82\x2b\x0d\x02\x1b\x18\x02\x08\x20\x02\x2f\xe8\x02\x11\x7d\x82\x1f\x34\x82\x34\x1a\x02\x1f\x34\x02\x11\x7d\x82\x2f\xe8\x02\x08\x20\x82\x1b\x18\x82\x2b\x0d\x02\x02\xf4\x02\x04\x9e\x81\xd4" }, { 1892, 2, 12, "\x01\x01\x81\xd2\x01\x0f\x82\x0f\x50\x02\x1c\x07\x02\x10\x22\x82\x40\x2e\x02\x10\x22\x02\x1c\x07\x82\x0f\x50\x01\x0f\x81\xd2" }, { 1903, 2, 22, "\x81\x01\x01\x07\x81\x0a\x81\x2d\x01\x67\x01\x03\x81\xe8\x02\x01\x12\x81\x46\x81\x75\x01\x64\x02\x01\x0b\x82\x02\x1d\x02\x02\x26\x82\x01\xe4\x01\xfc\x82\x01\x40\x02\x02\x61\x81\x9d\x82\x02\x4b\x02\x02\x15\x81\xd8" }, { 1912, 2, 8, "\x01\x01\x81\xd8\x81\x5a\x00\x02\x01\x73\x00\x81\x5a\x81\xd8" }, { 1915, 1, 6, "\x0c\xf8\xb6\xa1\x89\x76\x27\x25\x22\x40\x00\x00\x00\x23\x7d\xda\x4c\x46\xcf\xad\x44\x52\xb7\x3a\x2b\x96\x6f\x90\xa0\x2d\x7c\x6c\x35\x7b\x79\x71\xa9\x3c\x64\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\x16\x61\x27\x7d\xdd\x9b\xfc\x9e\xb8\x7b\x31\x0c\x3d\x80\x24\x04\xed\xea\x3e\x82\xe7\xe4\xd6\x7b\x6c\xe8\xf0\x00\x00\x00\x00\x00\x00\x00\xa0\x39\xa1\x6b\xa1\x7f\x5a\xdc\x51\x6b\x83\x6d\xd2\x38\xf9\x48\xf7\xfc\xbb\xbf\x75\x21\x3a\x7d\x0a\x8d\x53\x80\x00\x00\x00\x00\x00\x1e\x40\x51\xaa\xfd\x96\x61\x67\x67\x56\x32\x8c\x4e\xbb\x5d\x17\xff\xa2\x48\x07\xc6\xc4\xd1\xcb\xb3\x63\x2d\xc0\x00\x00\x00\x19\x50\xf8\x42\x10\x80\x70\x78\x5e\x64\x1e\xc0\x53\x67\x6c\x9e\xf2\x35\xa4\x5d\x97\xd4\x3a\xb3\x00\x00" }, { 1924, 2, 16, "\x01\x01\x81\xe2\x02\x04\xf1\x82\x0d\xfe\x02\x15\x39\x82\x11\x80\x82\x06\x86\x02\x20\x60\x82\x32\xae\x02\x20\x60\x82\x06\x86\x82\x11\x80\x02\x15\x39\x82\x0d\xfe\x02\x04\xf1\x81\xe2" }, { 1927, 2, 18, "\x01\x01\x81\x08\x01\x0d\x01\x15\x81\x24\x00\x01\x51\x81\xa5\x02\x01\x5a\x82\x03\x08\x02\x05\x89\x82\x07\xc8\x02\x08\xc1\x82\x08\x28\x02\x06\x27\x82\x04\x3e\x02\x02\x56\x81\xe0" }, { 1928, 2, 20, "\x01\x01\x81\xde\x01\x69\x82\x17\xfa\x02\x2a\x3c\x82\x9f\x7a\x03\x01\x1c\x87\x83\x02\x18\xe2\x03\x03\x10\x4f\x83\x03\xd9\xcc\x03\x04\x43\x08\x83\x03\xd9\xcc\x03\x03\x10\x4f\x83\x02\x18\xe2\x03\x01\x1c\x87\x82\x9f\x7a\x02\x2a\x3c\x82\x17\xfa\x01\x69\x81\xde" }, { 1963, 1, 6, "\x0d\x09\x78\xb7\xff\x20\x9f\xd5\xae\x37\x00\x00\x00\x00\xa4\x56\x9f\x88\xca\xe0\xf1\xc1\xdf\x29\xf4\x72\xd3\xbc\x69\xe9\x8b\x2a\x2b\x89\xb5\xb9\xc0\x77\x0e\x02\x94\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x23\x02\x82\xfa\x81\x76\xb1\x18\x40\x75\x34\x84\x3a\x44\x14\x4e\xef\xbb\xfe\x05\x44\x11\xb5\x1a\xf2\x5d\x9a\xa4\xb0\x00\x00\x00\x00\x00\x00\x00\x21\x04\x8b\x45\xa7\x42\xe6\x90\xa7\xb3\x15\x2c\x2b\xad\xea\xb0\x75\x01\x5b\x6b\x67\x31\xdf\xf1\x80\x7f\x20\x65\x40\x00\x00\x00\x00\x00\x1d\x38\x4e\xcf\xb9\x79\x3a\xbb\xac\x12\x4b\x3f\x43\x0d\xcc\x76\xc6\x4d\xa1\xab\x34\xb5\x8d\x5d\x72\xaf\x00\x00\x00\x00\x1a\x01\xc0\xb5\xf0\xcb\x1d\x39\x7b\x5a\x4e\x67\xea\x0b\x04\x4c\x09\x72\x48\x76\xc0\xcf\xee\xc9\x2f\x00\x00" }, { 1972, 2, 12, "\x01\x01\x02\xda\xa9\x03\x03\x0d\x65\x03\x04\xe4\x02\x83\x04\xa9\x01\x83\x0b\xe2\x03\x03\x03\xed\x76\x03\x0b\xe2\x03\x83\x04\xa9\x01\x83\x04\xe4\x02\x03\x03\x0d\x65\x82\xda\xa9" }, { 1983, 2, 16, "\x81\x01\x81\x80\x82\x24\x68\x83\x03\x16\xda\x83\x1d\x3c\xbd\x83\x84\xda\x9c\x84\x01\x0a\xef\xd6\x83\x62\x49\x86\x03\x01\xa7\x5a\x84\x06\xea\x28\x6c\x84\x09\xee\xaf\x92\x04\x1e\xb2\x4f\x5c\x04\x14\x7b\xf4\xb8\x84\x67\xde\xff\x23\x84\x64\x7b\xc9\xaa\x83\xd4\x1e\xd9" }, { 1992, 2, 8, "\x01\x01\x83\xdc\xb2\x94\x84\x6b\x26\xbd\x8c\x85\x01\x06\x5d\xe1\xec\x85\x01\x94\x20\x2d\xea\x85\x01\x06\x5d\xe1\xec\x84\x6b\x26\xbd\x8c\x83\xdc\xb2\x94" }, { 2008, 2, 14, "\x81\x01\x81\xfa\x81\x8f\x02\x01\xd4\x02\x03\x78\x82\x03\xb4\x82\x07\x32\x02\x04\xec\x02\x07\x32\x82\x03\xb4\x82\x03\x78\x02\x01\xd4\x01\x8f\x81\xfa" }, { 2020, 2, 8, "\x01\x01\x81\xff\x02\x01\x27\x02\x03\xd4\x82\x08\x0a\x02\x03\xd4\x02\x01\x27\x81\xff" }, { 2047, 2, 18, "\x01\x01\x81\x0f\x01\x5e\x82\x01\x40\x02\x02\x93\x82\x03\x54\x02\x02\xce\x82\x01\xe4\x02\x01\xa2\x81\xb6\x82\x01\xf8\x02\x02\xbf\x02\x01\x2c\x82\x05\xdd\x02\x06\x25\x82\x03\x78\x02\x02\x1c\x82\x01\x0a" }, { 2056, 2, 16, "\x01\x01\x82\x01\x05\x82\x06\x9c\x82\x1a\x55\x82\x47\xcf\x82\x91\x20\x82\xe7\xd2\x83\x01\x35\x06\x83\x01\x52\x88\x83\x01\x35\x06\x82\xe7\xd2\x82\x91\x20\x82\x47\xcf\x82\x1a\x55\x82\x06\x9c\x82\x01\x05" }, { 2068, 2, 12, "\x01\x01\x03\x01\x21\x2c\x83\x04\x4d\xc0\x03\x03\x26\x88\x03\x07\x86\xa8\x83\x04\xfb\xfc\x03\x0f\x17\x3e\x03\x04\xfb\xfc\x03\x07\x86\xa8\x83\x03\x26\x88\x83\x04\x4d\xc0\x83\x01\x21\x2c" }, { 2072, 2, 16, "\x01\x01\x02\x01\x10\x82\x01\xae\x02\x19\x68\x02\x09\xc9\x82\x47\x80\x02\x1d\xa2\x02\x6b\x28\x02\x16\x14\x82\x6b\x28\x02\x1d\xa2\x02\x47\x80\x02\x09\xc9\x82\x19\x68\x82\x01\xae\x82\x01\x10" }, { 2095, 2, 16, "\x81\x01\x81\x0a\x81\x2b\x81\x65\x81\xc8\x81\xd3\x81\x64\x01\x0a\x01\xea\x01\xe2\x81\x6e\x82\x01\x93\x82\x01\x42\x82\x01\x91\x82\x03\x20\x82\x01\x18" }, { 2104, 2, 12, "\x01\x01\x82\x01\x20\x02\x01\xb0\x81\x48\x82\x03\x30\x82\x09\x00\x82\x0d\xb6\x82\x09\x00\x82\x03\x30\x81\x48\x02\x01\xb0\x82\x01\x20" }, { 2132, 2, 12, "\x01\x01\x03\x01\x5b\x5c\x03\x38\x73\xf0\x04\x03\xdb\x16\x08\x84\x06\x08\x8f\x08\x04\x01\xd1\xc9\x34\x04\x14\x48\x8f\xbe\x84\x01\xd1\xc9\x34\x84\x06\x08\x8f\x08\x84\x03\xdb\x16\x08\x03\x38\x73\xf0\x83\x01\x5b\x5c" }, { 2143, 2, 13, "\x81\x01\x00\x81\x0c\x81\x2b\x01\x0e\x02\x01\x0c\x02\x01\x8c\x81\x9b\x82\x05\x0c\x82\x08\x71\x82\x08\x0a\x82\x04\x7b\x82\x01\x2b" }, { 2148, 2, 12, "\x01\x01\x84\x01\xb0\xbf\x66\x85\x01\x14\xe3\x98\x46\x85\x0b\xbb\x95\xe1\x26\x85\x33\xe7\x78\x07\xc1\x85\x6b\xd5\x83\x87\xf4\x85\x8f\x4c\xdd\x10\xf4\x85\x6b\xd5\x83\x87\xf4\x85\x33\xe7\x78\x07\xc1\x85\x0b\xbb\x95\xe1\x26\x85\x01\x14\xe3\x98\x46\x84\x01\xb0\xbf\x66" }, { 2152, 2, 10, "\x81\x01\x82\x01\x33\x81\x62\x82\x01\x51\x82\x03\x5d\x02\x02\x18\x02\x03\x5d\x82\x01\x51\x01\x62\x82\x01\x33" }, { 2164, 2, 10, "\x81\x01\x83\x01\x7c\x0d\x83\x04\xb6\xca\x83\x32\x8f\x77\x03\x03\x32\x4b\x83\x83\x60\x28\x83\x03\x32\x4b\x83\x32\x8f\x77\x03\x04\xb6\xca\x83\x01\x7c\x0d" }, { 2167, 2, 18, "\x81\x01\x81\x06\x81\x1b\x81\x20\x81\x66\x01\x07\x01\x07\x01\x59\x01\x2f\x01\x77\x82\x01\x1e\x01\x0e\x01\x84\x81\xa6\x82\x01\x7b\x02\x01\xe7\x01\xef\x82\x01\x3a" }, { 2203, 1, 5, "\x0d\x07\x95\xd6\xbf\x9a\x04\x67\x04\x93\x20\x00\x00\x00\xa4\x46\x12\x50\xd6\x3b\x96\x63\x57\x57\x8f\x67\x06\xb5\xbc\x31\x42\xc3\x46\x54\x3b\x47\x27\x1b\x91\x28\x6a\x9c\x30\x00\x00\x00\x00\x00\x00\x00\x00\x23\x02\xda\x0b\x9b\x60\x50\xe1\xd8\x14\x2c\x30\xcc\x1f\x17\xaf\xb4\x44\x09\x6c\xaf\xa5\x5a\xcb\xfb\x9b\x07\xe7\x61\xd1\xe0\x00\x00\x00\x00\x00\x9f\x03\xdf\xa2\x99\x03\xa3\xa0\xbd\x7a\x3b\x39\x78\x19\xca\x5a\xe7\xf5\xd0\xe4\x49\x35\xce\x9f\x30\xc0\x1b\x3c\x40\x00\x00\x00\x1b\x1a\x90\x86\x59\x5a\xd3\x9e\xab\xcb\x9e\x22\x15\xc1\x71\x59\xa0\x79\x88\xd7\x2e\x08\xbc\xd4\xe8\x50\x80\x00" }, { 2212, 2, 8, "\x01\x01\x82\x01\x4e\x01\x8a\x02\x01\xf0\x01\x7f\x02\x01\xf0\x01\x8a\x82\x01\x4e" }, { 2227, 1, 6, "\x0c\x09\xe5\x2c\x85\xcb\x53\xb5\xa8\x00\x00\x00\x00\x22\x08\xd6\x4c\x06\x51\xb9\x46\x6f\xf1\xc7\x4e\x88\xf3\x71\xbc\x1a\x95\x29\xc2\x47\xf9\x24\x90\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x21\x09\xa6\xc5\xda\xb9\x4d\x9b\x66\x46\xce\xd7\xe5\xf4\xe6\x7f\x15\x41\xf4\xf0\xcc\x39\x32\x6e\x0d\xf8\x80\x00\x00\x00\x00\x00\x00\x00\x1f\x65\xb1\x91\xc8\x01\x3c\xe9\xea\xcc\xa6\xcb\x7d\x55\x09\x6c\x2a\x54\xe1\xbd\x1f\x84\x6f\x28\xc6\xe1\x20\x00\x00\x00\x00\x00\x9d\x75\x80\xbf\x31\xa9\x25\x27\x51\x20\x24\xa7\x09\xef\xf8\x5b\x55\xc1\x9e\xd2\x9e\x7e\xed\x77\xcb\xbd\x40\x00\x00\x00\x1b\x3b\x2e\x5c\x77\x5d\x3e\xec\x86\x55\x50\x50\x35\x9f\xdc\x78\xdd\x7c\xa3\x8e\x8e\x73\x85\x55\x81\x91\x80\x00" }, { 2248, 2, 8, "\x01\x01\x82\x01\x5f\x01\x7e\x82\x03\xb1\x02\x01\x22\x82\x03\xb1\x01\x7e\x82\x01\x5f" }, { 2260, 2, 12, "\x01\x01\x03\x01\xf0\x77\x03\x08\xfd\xcc\x03\x04\x33\x8f\x03\x75\x99\xf0\x83\x02\x60\xd9\x03\xb6\xe8\x0a\x03\x02\x60\xd9\x03\x75\x99\xf0\x83\x04\x33\x8f\x03\x08\xfd\xcc\x83\x01\xf0\x77" }, { 2263, 2, 22, "\x01\x01\x81\x0b\x01\x37\x81\x7a\x01\x68\x01\x7b\x82\x01\x31\x01\xa8\x02\x01\xdb\x82\x04\xc7\x02\x05\x50\x82\x02\x24\x82\x01\xf3\x02\x04\x56\x82\x03\xe9\x02\x01\xa1\x81\x8f\x01\x52\x01\x73\x82\x03\x02\x02\x02\xd8\x82\x01\x68" }, { 2283, 1, 6, "\x0f\x1b\x19\x52\x19\x24\xef\x00\xcd\xed\xba\x15\xc0\x00\x00\x00\x2b\x0c\x42\x8c\xbf\xd6\x42\x70\xbe\x64\x82\xd5\x25\x7b\xdf\xdf\xa4\x97\xfd\xd1\x43\x65\x81\xf7\xbe\x8d\x96\xb3\xef\xc7\x2f\xe0\x97\x9b\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2a\x01\x16\xe5\x9a\xf8\x28\x94\x1c\x0f\x65\x25\xc9\x1b\x58\xc2\x98\x6b\xc1\x3f\xac\x79\xbf\xe0\x88\x53\x4c\xe5\x04\x74\xb7\x85\xb8\xcb\xb8\x30\x00\x00\x00\x00\x00\x00\x00\x27\x11\xfc\x73\x04\xa6\x39\x1a\xc7\xee\x62\x99\x7b\x03\x24\xa2\xdc\x27\xad\xc2\x2e\xc5\x12\x01\x1c\xbc\xcd\x19\x27\xdf\xa8\x1d\x0d\x82\x00\x00\x00\x00\x00\x00\x25\x01\xad\x5f\x42\x78\x29\x8e\xad\x7a\x24\x59\x7e\x0d\x91\x68\xcb\x98\xbb\xe1\xf3\x24\x87\x8c\xea\xdc\xef\x69\xb9\xb8\xd3\x38\x73\x2d\x40\x00\x00\x00\x1c\x01\x79\x4c\x7a\xb3\xf8\xab\xfe\xb8\x8e\x40\x94\xa7\x13\x27\xd3\x27\x99\x77\x80\xfb\x3e\xa3\x2f\x40\x44\x00\x00" }, { 2296, 2, 16, "\x01\x01\x82\x01\x7a\x02\x05\x19\x82\x0c\x72\x02\x24\x31\x82\x47\xb8\x02\x4b\xba\x82\x19\xbc\x82\x0a\x86\x82\x19\xbc\x02\x4b\xba\x82\x47\xb8\x02\x24\x31\x82\x0c\x72\x02\x05\x19\x82\x01\x7a" }, { 2308, 2, 8, "\x01\x01\x82\x01\x78\x82\x06\xfb\x82\x0e\xac\x82\x11\xc4\x82\x0e\xac\x82\x06\xfb\x82\x01\x78" }, { 2335, 2, 14, "\x81\x01\x81\x08\x81\x36\x81\xca\x82\x02\x0e\x82\x04\x23\x82\x06\x46\x82\x08\x9d\x82\x0c\x59\x82\x0f\x2e\x82\x0f\xae\x82\x0d\xd9\x82\x07\x97\x82\x01\x86" }, { 2344, 2, 18, "\x81\x01\x82\x01\x95\x82\x08\x34\x82\x15\xa1\x82\x1b\xb4\x82\x1c\x95\x82\x0f\xf5\x82\x29\xa6\x82\x0e\x40\x82\x30\x4e\x02\x0e\x40\x82\x29\xa6\x02\x0f\xf5\x82\x1c\x95\x02\x1b\xb4\x82\x15\xa1\x02\x08\x34\x82\x01\x95" }, { 2347, 1, 5, "\x0c\x03\x1f\x1e\xc8\xdf\x94\x90\xf7\x72\x00\x00\x00\xa1\x02\x5f\xff\xa8\x30\x86\xd8\xaf\x18\xb5\x16\x13\xc6\x2d\x96\xf0\x3a\xce\x23\x53\xed\x7c\xb4\x59\x27\x70\x00\x00\x00\x00\x00\x00\x00\x9f\x02\x3f\xf0\x35\x6f\xf4\xb0\x21\xa6\xbf\x18\x9f\x1d\x10\x99\x73\x72\x80\x9d\xf0\x12\x8f\x51\x12\x25\x40\x00\x00\x00\x00\x00\x1d\x8e\xd1\xaa\x3e\x0e\x23\xde\x11\x2c\x64\x4a\x5e\xd6\x56\x89\xc7\x5d\xf7\xa6\xe9\x90\x1f\x04\x3d\xd1\x80\x00\x00\x00\x1c\x0b\xe8\xca\x94\xe9\x33\x6d\x0b\x13\xda\x75\x9a\x80\xf0\xfd\x28\x9b\x54\xe7\x4d\xe3\xc8\x43\x56\x22\x28\x80\x00" }, { 2356, 2, 16, "\x01\x01\x03\x02\x84\xd6\x83\x1b\xcb\x69\x03\x7e\x26\x52\x83\x7e\xa9\x4f\x03\xbf\x60\x58\x03\x09\x07\xde\x03\x43\xbe\xdc\x04\x01\xa4\x98\xc2\x83\x43\xbe\xdc\x03\x09\x07\xde\x83\xbf\x60\x58\x83\x7e\xa9\x4f\x83\x7e\x26\x52\x83\x1b\xcb\x69\x83\x02\x84\xd6" }, { 2388, 2, 12, "\x01\x01\x07\x14\xb0\xc7\xac\x69\xc3\x78\x09\x0e\x33\x53\x8c\x7e\xea\x2f\x66\x6a\x09\x01\x30\xc7\x7e\x63\x08\xfb\x6f\xa8\x09\x4d\x27\x02\x1e\x84\x99\x1f\xa5\x4f\x89\x1f\x93\x6e\x38\xfe\xeb\xd0\x28\x50\x09\x2c\x12\xac\x94\x8b\x8b\x11\x78\x8c\x09\x1f\x93\x6e\x38\xfe\xeb\xd0\x28\x50\x09\x4d\x27\x02\x1e\x84\x99\x1f\xa5\x4f\x89\x01\x30\xc7\x7e\x63\x08\xfb\x6f\xa8\x09\x0e\x33\x53\x8c\x7e\xea\x2f\x66\x6a\x87\x14\xb0\xc7\xac\x69\xc3\x78" }, { 2392, 2, 8, "\x01\x01\x02\x01\xa8\x82\x04\x12\x81\x50\x02\x07\x1b\x01\x50\x82\x04\x12\x82\x01\xa8" }, { 2404, 2, 20, "\x01\x01\x82\x01\xb2\x02\x01\x22\x82\x05\x12\x02\x01\x9b\x82\x1e\x34\x82\x42\x44\x82\x9b\x14\x82\xd5\xeb\x83\x01\x35\xc6\x83\x01\x1e\xc2\x83\x01\x35\xc6\x82\xd5\xeb\x82\x9b\x14\x82\x42\x44\x82\x1e\x34\x02\x01\x9b\x82\x05\x12\x02\x01\x22\x82\x01\xb2" }, { 2407, 2, 20, "\x81\x01\x81\x02\x81\x15\x81\x12\x01\x68\x01\x35\x82\x01\xa7\x01\x5e\x02\x01\x7b\x81\x98\x81\x17\x82\x01\xcf\x02\x02\x27\x01\x36\x82\x05\x1a\x02\x08\x3e\x81\xeb\x82\x06\x81\x02\x04\xfc\x82\x01\xb6" }, { 2424, 2, 12, "\x01\x01\x84\x05\x40\xf6\x48\x85\x04\xd9\x8a\x00\x22\x85\x45\xad\x3a\xd1\xe8\x86\x05\xe3\x3a\xa6\xa9\xd1\x86\x12\x2e\xca\x6f\xf8\x50\x86\x1a\x33\x1f\x12\x91\x5c\x86\x12\x2e\xca\x6f\xf8\x50\x86\x05\xe3\x3a\xa6\xa9\xd1\x85\x45\xad\x3a\xd1\xe8\x85\x04\xd9\x8a\x00\x22\x84\x05\x40\xf6\x48" }, { 2440, 2, 12, "\x01\x01\x82\x01\xc8\x02\x02\x7f\x02\x04\x20\x82\x10\x7a\x02\x1f\x08\x82\x26\xfd\x02\x1f\x08\x82\x10\x7a\x02\x04\x20\x02\x02\x7f\x82\x01\xc8" }, { 2443, 1, 6, "\x0d\x81\xf0\xfd\x88\x20\xc4\x5d\xef\x14\xc0\x00\x00\x00\xa6\x0a\x3c\x2d\xb0\x54\x0a\xfe\x64\xc7\xe9\x68\xfd\xc2\x36\x2b\x93\x2d\xf5\xe8\x00\x38\xf1\xcb\x25\x80\x5a\x8e\x79\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x25\x05\xb1\x15\x0a\x35\xd5\xeb\x44\x77\xef\xab\xf5\x52\xdc\xbd\x80\x18\xa0\xe8\xe0\xf2\x05\x6d\x00\x7d\x5f\x94\x0e\xe7\xb0\x00\x00\x00\x00\x00\x00\x00\xa3\x04\xa9\xfa\x09\xf2\x47\xd7\x45\xb5\x33\xa6\x5f\x5d\x80\xed\xd2\xd8\x33\x78\x68\x8e\xbc\x5d\x24\xc3\x84\xaf\xee\x8c\x00\x00\x00\x00\x00\x00\x21\x01\x04\x00\x4a\xae\xa5\xa7\x1e\x07\x58\xaf\xae\xa3\x9f\x4d\x11\xae\x67\xe1\xdf\xba\xd9\x1f\xa8\xef\xb7\x7a\x56\xfe\x40\x00\x00\x00\x1d\x01\x03\x83\x75\xc9\xa7\xeb\xbb\x95\x9b\xb9\x6b\x61\x6a\x8c\xed\xf8\xfa\x3c\x64\xf8\x90\x12\x95\x38\xfb\x44\x00\x00" }, { 2452, 2, 10, "\x81\x01\x83\x03\x41\x46\x03\x07\x0f\x4c\x83\x01\x86\xcc\x83\x03\x34\x0f\x83\x02\x10\x9c\x03\x03\x34\x0f\x83\x01\x86\xcc\x83\x07\x0f\x4c\x83\x03\x41\x46" }, { 2468, 2, 12, "\x01\x01\x82\x01\xd7\x82\x01\x2e\x82\x46\xab\x02\x5f\x6e\x82\xd2\x9f\x03\x01\x07\x5e\x82\xd2\x9f\x02\x5f\x6e\x82\x46\xab\x82\x01\x2e\x82\x01\xd7" }, { 2472, 2, 12, "\x01\x01\x04\x06\x5b\x31\x08\x85\x05\xf5\xbc\x7c\xf6\x05\x11\x4f\x78\xd7\xd8\x85\x0c\x48\xcd\xc1\x31\x85\x13\x8d\x4e\x94\xb0\x85\x01\xb7\x5c\x53\xb4\x05\x13\x8d\x4e\x94\xb0\x85\x0c\x48\xcd\xc1\x31\x85\x11\x4f\x78\xd7\xd8\x85\x05\xf5\xbc\x7c\xf6\x84\x06\x5b\x31\x08" }, { 2488, 2, 12, "\x01\x01\x82\x01\xe0\x82\x08\x10\x82\x19\xc8\x82\x34\xb0\x82\x52\x80\x82\x5d\xf6\x82\x52\x80\x82\x34\xb0\x82\x19\xc8\x82\x08\x10\x82\x01\xe0" }, { 2503, 2, 21, "\x81\x01\x81\x0b\x81\x29\x81\x65\x82\x01\x44\x82\x02\x51\x82\x03\xec\x82\x05\x25\x82\x05\x74\x82\x03\x0f\x01\x17\x02\x03\x24\x02\x04\x2e\x02\x02\xdd\x82\x01\x2d\x82\x06\x03\x82\x08\xe6\x82\x08\x98\x82\x08\x31\x82\x05\x95\x82\x01\xeb" }, { 2515, 1, 6, "\x0f\x03\x30\x83\x96\xcd\x9b\xde\x4a\x4c\x06\x73\x00\x00\x00\x00\xaa\x01\x6f\x58\x65\x39\x37\xf7\x09\x0a\x8c\x57\xd6\x97\xd4\x47\x58\x1f\xb2\x7a\xf3\x39\x71\x29\x15\x56\xeb\x91\x37\x72\x6c\x66\x1d\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x28\x04\x23\x44\x8c\x91\x36\x96\x1f\xde\x60\xa0\x47\xb1\x19\xef\x19\xfa\x0d\xe0\x45\x3c\x5a\x6e\xbf\xa8\x13\x8b\x61\xb1\x1f\x0f\x5f\xf0\x00\x00\x00\x00\x00\x00\x00\x25\x47\x65\xf5\x87\xb0\xab\x90\x65\x14\x4b\xee\x4c\x98\xeb\xf3\x1a\xf3\x02\x41\x9b\xcc\xb7\x67\x93\x8c\xa8\x63\x18\x72\xd9\xa8\x40\x00\x00\x00\x00\x00\x23\x01\xb0\x65\xae\x42\x08\x10\xc1\x03\x2a\x58\xfa\xe1\x22\x94\x50\x8b\xcc\x12\x40\x4f\x39\x36\x3a\xa7\x62\x66\x26\x14\xaf\xf2\x00\x00\x00\x00\x1d\x09\xd3\xdf\xee\xe8\x7c\x56\x5c\xf6\xd1\xb9\x83\xfc\x6c\x72\xf2\x39\x4e\xde\xc8\x46\x7f\x2e\x14\x70\xc2\x1b\x00\x00" }, { 2536, 2, 14, "\x81\x01\x82\x02\x01\x02\x05\x3d\x82\x12\x14\x02\x0d\xc0\x82\x05\xac\x82\x05\x12\x82\x12\xee\x02\x05\x12\x82\x05\xac\x82\x0d\xc0\x82\x12\x14\x82\x05\x3d\x82\x02\x01" }, { 2563, 1, 6, "\x0d\x05\xe6\x59\x93\xc9\x33\x3a\x34\x16\x00\x00\x00\x00\x24\x1e\x4d\x0d\x1f\x61\xb8\x27\xdf\xe3\x81\x4c\xed\x27\x65\x65\x0f\x3c\x7d\xfd\x66\x87\xba\x0a\x72\x15\xd2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x23\x24\x2f\x8c\xfb\x90\xe7\xc5\x38\xa9\x14\xc8\x5d\x84\x1c\x43\x82\xb9\xdc\x58\xf3\xf4\x61\x34\xc4\xa0\xab\xa0\x80\x00\x00\x00\x00\x00\x00\x00\x22\x01\x8b\x13\x9a\x16\xd1\x12\xb7\x85\x4e\x6f\xa4\x28\x43\x5e\xda\x27\xdd\x74\x03\xc4\x8a\x86\xea\x4e\x9e\x99\xf9\x60\x00\x00\x00\x00\x00\x20\x05\x07\x24\xda\xfe\xea\xef\x27\xc9\x58\x76\x55\xdc\xfb\xae\x5d\x53\x07\x8b\xe5\xc6\x0d\xac\xf1\x92\xf0\x06\xc5\xc0\x00\x00\x00\x1d\x2b\xe2\x57\xed\x84\xa6\x01\x08\xd5\x28\xee\xee\xce\xe4\x0d\xf0\xea\x96\x81\x95\x07\x5e\xbf\x5c\x9d\x4d\x1a\x80\x00" }, { 2584, 2, 16, "\x01\x01\x02\x02\x28\x02\x07\x32\x02\x07\x20\x82\x0c\x77\x82\x01\x20\x82\x0b\xbe\x02\x0a\x68\x02\x25\x14\x82\x0a\x68\x82\x0b\xbe\x02\x01\x20\x82\x0c\x77\x82\x07\x20\x02\x07\x32\x82\x02\x28" }, { 2596, 2, 20, "\x01\x01\x82\x02\x2e\x02\x01\xcd\x82\x0a\xd4\x02\x1a\x64\x82\x21\x0c\x82\x18\xf5\x02\x3e\x16\x02\x2b\x37\x02\x15\xf0\x82\xb2\xf8\x02\x15\xf0\x02\x2b\x37\x02\x3e\x16\x82\x18\xf5\x82\x21\x0c\x02\x1a\x64\x82\x0a\xd4\x02\x01\xcd\x82\x02\x2e" }, { 2612, 2, 14, "\x81\x01\x83\x04\xef\x31\x04\x01\x90\x96\x61\x84\x23\xea\xf4\x08\x84\x01\x80\x0b\xa8\x84\x3a\xd6\xec\x78\x05\x01\x18\xaa\xce\x52\x04\x1d\xb1\x98\xd2\x85\x01\x18\xaa\xce\x52\x84\x3a\xd6\xec\x78\x04\x01\x80\x0b\xa8\x84\x23\xea\xf4\x08\x84\x01\x90\x96\x61\x83\x04\xef\x31" }, { 2632, 2, 8, "\x01\x01\x82\x02\x4c\x02\x0a\x62\x82\x15\x00\x02\x1a\x7b\x82\x15\x00\x02\x0a\x62\x82\x02\x4c" }, { 2647, 2, 15, "\x81\x01\x01\x04\x81\x02\x81\x3d\x81\xc1\x81\xad\x82\x01\x4c\x82\x03\x0a\x82\x01\xa6\x01\xf2\x82\x01\x15\x81\x8c\x02\x03\x5b\x01\xa7\x82\x02\x53" }, { 2680, 2, 12, "\x01\x01\x82\x02\x70\x02\x09\x60\x82\x06\x18\x82\x2e\x80\x02\x96\xf0\x82\xd2\xf6\x02\x96\xf0\x82\x2e\x80\x82\x06\x18\x02\x09\x60\x82\x02\x70" }, { 2683, 1, 5, "\x0d\x09\x4f\xe2\x65\xc8\xb8\x55\xd7\x15\x8c\x00\x00\x00\xa4\x9b\xf0\xb8\x7e\x55\x3f\xde\x83\x38\x58\xcb\xa7\x8b\x18\xd4\x50\x7f\x3e\xdf\xa0\xe3\x48\x25\xe6\x24\x60\xaa\x5c\xd0\x00\x00\x00\x00\x00\x00\x00\x23\x2b\xc7\x62\x15\x0d\x3b\xd5\x92\xa9\x30\xb1\xf9\x01\x1c\x41\x6b\xbb\x69\xef\x19\x15\x3b\x68\x4f\xe2\xab\xc4\x41\x21\x40\x00\x00\x00\x00\x00\xa1\x02\x11\xbb\x71\x01\x01\xc6\x6b\x24\x51\x0b\x0d\x86\x4e\xe8\x6c\xd9\x8c\xc7\x5f\x99\xb2\x81\xe6\xe9\xaa\x87\x68\xdf\x00\x00\x00\x00\x1e\x06\xcd\x10\xf9\xc2\xf8\x1b\xe1\xf8\xd5\x77\x9e\x5f\xe3\x75\x87\x52\x95\xc4\xe1\xea\xda\x63\x7a\x2c\x5d\x62\x53\x00\x00" }, { 2692, 2, 12, "\x01\x01\x82\x02\x78\x02\x05\xe8\x82\x07\x6a\x02\x07\xe8\x82\x0c\xf8\x02\x11\xca\x82\x0c\xf8\x02\x07\xe8\x82\x07\x6a\x02\x05\xe8\x82\x02\x78" }, { 2728, 2, 12, "\x01\x01\x02\x02\x90\x82\x07\x18\x82\x03\x38\x02\x17\x28\x02\x01\x00\x82\x21\xf2\x82\x01\x00\x02\x17\x28\x02\x03\x38\x82\x07\x18\x82\x02\x90" }, { 2740, 2, 12, "\x01\x01\x03\x06\xd2\xdb\x03\x11\xb9\x08\x83\xe5\x52\x01\x04\x01\x6e\x47\x94\x04\x01\x97\xd5\xeb\x04\x04\x97\x90\xaa\x84\x01\x97\xd5\xeb\x04\x01\x6e\x47\x94\x03\xe5\x52\x01\x03\x11\xb9\x08\x83\x06\xd2\xdb" }, { 2743, 2, 20, "\x81\x01\x01\x06\x81\x11\x81\x3a\x01\x43\x02\x01\xf5\x02\x01\xef\x82\x04\x1a\x82\x0c\xd6\x82\x0a\xec\x02\x08\xe6\x02\x1e\xcb\x02\x1b\x4c\x82\x01\x2f\x82\x19\xa1\x82\x18\x9f\x82\x08\xc8\x81\xab\x82\x03\x3e\x82\x02\x9e" }, { 2767, 2, 21, "\x81\x01\x81\x0d\x81\x68\x82\x01\xf2\x82\x06\x6f\x82\x0f\xb6\x82\x1e\x87\x82\x30\x57\x82\x40\xf3\x82\x4a\xbf\x82\x4d\x09\x82\x4a\xb8\x82\x4b\x9c\x82\x51\x53\x82\x5a\xba\x82\x5c\xe2\x82\x52\xd8\x82\x3b\x41\x82\x20\xd8\x82\x0c\x75\x82\x02\xaf" }, { 2776, 2, 10, "\x81\x01\x82\x02\xba\x02\x03\xd3\x82\x14\xc4\x82\x05\x8d\x82\x08\xe6\x02\x05\x8d\x82\x14\xc4\x82\x03\xd3\x82\x02\xba" }, { 2787, 1, 6, "\x10\x12\xe9\x61\xff\x28\xe0\x08\x9e\x3e\xae\x2c\x70\x00\x00\x00\x00\xae\x02\x3a\xb4\x7c\xb4\xb6\x01\x0f\xe6\x42\x13\x18\xc1\xdf\xa4\x1c\xdb\xf2\x89\x2f\xaf\x5f\x68\x2d\x92\xbd\x59\x71\x7c\x55\xf7\x78\xcd\xa8\xb2\xda\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2c\x15\xe7\x68\x26\xc3\x29\x55\x4f\x15\xe1\xc9\x37\xc4\xe5\xc9\x89\x67\xd9\x40\x1b\x2b\x68\xc7\x40\x3b\xd2\x1f\x5b\x27\x16\x00\xb4\xb1\x8f\xcf\xb0\x00\x00\x00\x00\x00\x00\x00\x00\xaa\x5a\x6a\x73\xeb\x59\x46\x59\xec\x55\xdb\x23\x47\x8a\xe6\xe9\x68\xf5\x34\x97\xcb\x25\x1f\x2b\xa4\x6c\x96\x45\xb5\x1d\x30\x6b\xa6\x94\x93\xce\x29\xe0\x00\x00\x00\x00\x00\x28\x82\xb2\x60\xb4\x4f\xea\x6d\x88\x8e\x5c\xaf\x2f\x72\x8c\xe9\x1f\xc4\x45\x26\x67\xb8\x21\x7c\x15\x55\x65\xf0\xe1\x68\x71\x2b\xbb\xd5\xee\x2e\xae\xc0\x00\x00\x00\x1e\x9a\x9e\x15\x31\x2e\x75\x38\x97\x0b\xad\xd3\xba\xf5\x41\x0c\x30\x6f\x73\xa0\x6d\xf2\xf0\x2e\xbb\x36\xcd\x12\x39\x80\x00" }, { 2788, 2, 8, "\x01\x01\x82\x02\xc7\x02\x03\x0a\x02\x01\xcb\x82\x04\x0e\x02\x01\xcb\x02\x03\x0a\x82\x02\xc7" }, { 2836, 2, 10, "\x81\x01\x83\x08\xa8\x31\x03\x6f\xe5\x82\x84\x02\x2b\x99\x3f\x83\x07\x0d\x59\x84\x02\x5e\x3e\xd0\x03\x07\x0d\x59\x84\x02\x2b\x99\x3f\x83\x6f\xe5\x82\x83\x08\xa8\x31" }, { 2872, 2, 12, "\x01\x01\x82\x03\x12\x82\x03\xab\x82\x08\x6a\x82\x02\x85\x82\x03\xe4\x02\x04\x0e\x82\x03\xe4\x82\x02\x85\x82\x08\x6a\x82\x03\xab\x82\x03\x12" }, { 2884, 2, 16, "\x01\x01\x82\x03\x26\x02\x16\x8a\x82\x48\x84\x02\x84\xb5\x82\xd6\x4c\x03\x01\x67\xae\x83\x01\xb1\xfa\x03\x01\xb6\x44\x83\x01\xb1\xfa\x03\x01\x67\xae\x82\xd6\x4c\x02\x84\xb5\x82\x48\x84\x02\x16\x8a\x82\x03\x26" }, { 2920, 2, 12, "\x01\x01\x02\x03\x40\x82\x08\x38\x82\x04\x18\x02\x02\x28\x82\x06\x70\x02\x07\xae\x02\x06\x70\x02\x02\x28\x02\x04\x18\x82\x08\x38\x82\x03\x40" }, { 2923, 1, 6, "\x8e\x17\x74\x30\xe2\x05\x89\x9d\x1b\xad\x7b\x00\x00\x00\x00\x28\x5c\xce\xe3\x02\x21\x8d\x88\xf4\x8f\x4f\xf6\xb0\x18\xec\x18\x5d\x22\x27\xc6\x12\x4b\x05\x36\xa9\xbf\x1b\x9d\xbd\xdc\x09\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x02\x0d\xe7\xbf\x2e\x98\xae\xb6\xbf\xa1\x5e\x92\x8d\x65\xa6\x1d\x92\xf3\x53\x78\xa5\x1c\x0a\x79\xd8\x96\xf1\x81\xa6\x82\x1e\x70\x00\x00\x00\x00\x00\x00\x00\x25\x03\x06\xc7\x80\x3d\x3c\xaa\x80\x98\x9c\x76\xd2\x70\xe7\xbe\x5b\x89\xa0\xe5\x9d\xf3\x31\x5b\x12\xb1\xcf\x04\x55\x5d\xb9\x41\x00\x00\x00\x00\x00\x00\xa2\x02\xed\x8d\x78\x0f\xc1\x5e\x7a\xa7\x23\x46\xb1\x91\x7c\x15\x4b\x32\x63\x06\x96\xbe\xbd\x9e\x38\x8a\x0a\xda\xcd\x25\x12\x80\x00\x00\x00\x1f\x20\xec\x5b\x4f\xb8\xfb\x78\xc2\xd9\xff\xab\x28\xcd\x97\x24\x85\x5a\x47\x42\x46\xa1\x1a\x06\xcb\x7b\x78\x7f\x20\x14\x00\x00" }, { 2932, 2, 14, "\x81\x01\x83\x0a\xf0\x8f\x03\x01\x67\x1d\x83\xa7\x14\x5c\x83\xb4\xf9\x60\x84\x02\x38\xb0\xb4\x83\x05\x69\xc2\x83\xf1\x56\x72\x03\x05\x69\xc2\x84\x02\x38\xb0\xb4\x03\xb4\xf9\x60\x83\xa7\x14\x5c\x83\x01\x67\x1d\x83\x0a\xf0\x8f" }, { 2968, 2, 8, "\x01\x01\x02\x03\x76\x02\x05\xff\x02\x03\xc2\x02\x06\x5c\x82\x03\xc2\x02\x05\xff\x82\x03\x76" }, { 2980, 2, 16, "\x01\x01\x82\x03\x7d\x82\x0e\x54\x82\x0b\xf1\x82\x08\xcf\x82\x28\x94\x82\x1b\x16\x02\x0b\x02\x82\x85\x90\x02\x0b\x02\x82\x1b\x16\x82\x28\x94\x82\x08\xcf\x82\x0b\xf1\x82\x0e\x54\x82\x03\x7d" }, { 2983, 2, 20, "\x81\x01\x00\x81\x2b\x81\x20\x82\x01\x52\x01\x1f\x82\x04\x33\x02\x01\xee\x82\x06\xeb\x02\x03\x9e\x82\x08\x7c\x81\x10\x82\x05\x81\x82\x03\x67\x02\x04\xab\x82\x03\x77\x02\x05\x60\x82\x06\xd7\x82\x01\x22\x82\x03\x84" }, { 3007, 2, 20, "\x01\x01\x01\x07\x81\x04\x81\x28\x02\x01\x19\x82\x01\xd1\x01\x70\x02\x01\xde\x82\x04\x56\x02\x04\x6f\x82\x01\x1c\x82\x05\x12\x02\x10\x56\x82\x1d\x5e\x02\x28\xfa\x82\x2d\xd9\x02\x28\xaf\x82\x1b\x62\x02\x0c\x8d\x82\x03\xa2" }, { 3012, 2, 12, "\x01\x01\x84\x30\x44\x33\xb2\x85\x57\xed\x00\xe1\xf6\x85\x1a\x8f\x35\x0f\x12\x05\xbe\x4b\x08\x08\x7f\x85\xef\x1f\x25\x35\x3c\x86\x02\xe9\xc7\xf3\x5d\x14\x85\xef\x1f\x25\x35\x3c\x05\xbe\x4b\x08\x08\x7f\x85\x1a\x8f\x35\x0f\x12\x85\x57\xed\x00\xe1\xf6\x84\x30\x44\x33\xb2" }, { 3028, 2, 10, "\x81\x01\x83\x0d\xc5\x81\x03\x0f\xab\x62\x03\x2e\x79\x31\x83\x29\x57\xb9\x83\x48\x95\x10\x03\x29\x57\xb9\x03\x2e\x79\x31\x83\x0f\xab\x62\x83\x0d\xc5\x81" }, { 3048, 2, 12, "\x01\x01\x04\x36\xe1\x4c\x08\x85\x66\x3c\x66\x3a\x56\x86\x03\xd3\xf9\x6e\x01\x28\x86\x18\xb2\x6f\x50\x1b\xb1\x85\xaa\x77\x5f\xd0\xb0\x86\x29\xff\x4e\x0c\x43\xf4\x05\xaa\x77\x5f\xd0\xb0\x86\x18\xb2\x6f\x50\x1b\xb1\x06\x03\xd3\xf9\x6e\x01\x28\x85\x66\x3c\x66\x3a\x56\x84\x36\xe1\x4c\x08" }, { 3063, 2, 16, "\x81\x01\x02\x01\x8f\x82\xc6\x06\x83\x02\x77\x75\x83\xb2\x6a\xe7\x03\x58\xfb\xd1\x04\x05\xf7\xd3\x65\x04\x76\x6b\x45\x1a\x85\x01\x58\x35\x50\x31\x84\xd8\xf5\x5a\x8d\x05\x01\xc4\x88\xc6\x1d\x85\x12\xbe\x8d\x79\xc2\x05\x28\x60\x97\x37\x25\x05\x38\xfc\x49\xeb\x58\x85\x6f\xd7\x0a\xc4\x15\x84\x39\xe2\x2c\x55" }, { 3103, 2, 20, "\x81\x01\x01\x01\x81\x24\x01\xa6\x82\x01\xe4\x02\x05\x67\x82\x0b\xcb\x02\x11\x80\x82\x11\x3b\x02\x08\xdf\x02\x03\x70\x82\x0a\x97\x02\x06\xd3\x82\x02\x78\x02\x09\x59\x82\x17\x7f\x02\x1f\xaa\x82\x1c\x4d\x02\x0f\xe1\x82\x04\x12" }, { 3112, 2, 14, "\x81\x01\x82\x04\x19\x01\x79\x82\x0d\x20\x02\x03\x48\x82\x0f\x00\x02\x02\x0a\x82\x0c\x1e\x82\x02\x0a\x82\x0f\x00\x82\x03\x48\x82\x0d\x20\x81\x79\x82\x04\x19" }, { 3140, 2, 16, "\x01\x01\x82\x04\x4e\x02\x4c\x51\x83\x01\xbe\xf2\x03\x02\x44\xb9\x03\x07\x5c\x90\x83\x26\xdc\xa6\x03\x52\x24\x40\x83\x67\xc8\xae\x03\x52\x24\x40\x83\x26\xdc\xa6\x03\x07\x5c\x90\x03\x02\x44\xb9\x83\x01\xbe\xf2\x02\x4c\x51\x82\x04\x4e" }, { 3160, 2, 16, "\x01\x01\x02\x04\x52\x82\x0f\xd3\x02\x1b\xb2\x82\x37\x67\x02\x02\xf4\x82\x3c\x96\x02\x13\xc8\x82\x86\xa6\x82\x13\xc8\x82\x3c\x96\x82\x02\xf4\x82\x37\x67\x82\x1b\xb2\x82\x0f\xd3\x82\x04\x52" }, { 3172, 2, 8, "\x01\x01\x82\x04\x60\x82\x17\x0c\x82\x35\x48\x82\x45\x43\x82\x35\x48\x82\x17\x0c\x82\x04\x60" }, { 3208, 2, 12, "\x01\x01\x82\x04\x95\x81\xe1\x02\x0b\x58\x02\x09\xc9\x82\x0a\x53\x82\x10\xf2\x82\x0a\x53\x02\x09\xc9\x02\x0b\x58\x81\xe1\x82\x04\x95" }, { 3220, 2, 16, "\x01\x01\x03\x15\x97\x92\x04\x01\x41\x75\xaf\x04\x04\xb2\x12\x16\x04\x05\x7d\x64\x11\x04\x09\x9d\xe6\x18\x04\x09\x4c\xcc\x7e\x84\x11\xc7\x2e\x5c\x84\x1d\xd5\x0b\xee\x04\x11\xc7\x2e\x5c\x04\x09\x4c\xcc\x7e\x84\x09\x9d\xe6\x18\x04\x05\x7d\x64\x11\x84\x04\xb2\x12\x16\x04\x01\x41\x75\xaf\x83\x15\x97\x92" }, { 3235, 1, 6, "\x0f\x10\xaa\x7f\xf6\x27\x58\x44\x6f\xaf\x2a\xdf\x00\x00\x00\x00\xab\x1b\x6a\x70\xbb\x59\xfa\x11\x8c\x91\x43\xdd\x68\x6d\x23\x38\xef\xe4\x4d\x06\x44\x97\xf8\xa5\x9c\x7a\x08\x53\xbe\x09\x52\x7a\x10\xa7\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2a\x0d\x27\x2f\x4d\xd4\x38\x0f\xbb\x41\xe3\x8e\xff\x40\xa8\xce\xea\x27\x0e\xc7\x7a\x05\xc9\xa3\x3e\xdd\xae\xb8\x66\x74\x8b\xd7\xd9\x08\x93\xf0\x00\x00\x00\x00\x00\x00\x00\xa8\xa6\x54\xd5\xaf\xf3\x3a\x15\xc1\x97\x0a\xad\xea\xeb\xfa\x04\x9e\x81\x71\x2c\x96\xcd\x76\x74\xff\x08\xc7\xbd\x4a\x98\xc0\x49\xea\xf9\xfa\xc0\x00\x00\x00\x00\x00\x27\x28\xa3\x88\x54\xd7\xdc\xbf\xa4\xbf\xfa\x15\x64\x51\x7a\xd5\xb2\xb3\x9b\xdb\xd4\x0c\xd3\x2c\x59\xf8\x3a\xa8\x63\x45\x1d\x22\x67\x25\x29\x9a\x00\x00\x00\x00\x21\x03\x73\xa4\xe1\x5a\x7b\x13\xa8\x73\x9f\xc2\x24\xc1\xa9\x9e\x63\x9e\xd8\x6f\x81\xbf\x78\xda\x06\x7f\x59\xe8\x75\xe3\x1f\xb7\x00\x00" }, { 3256, 2, 12, "\x01\x01\x82\x04\xd4\x82\x12\x90\x82\x4e\xa8\x82\x88\x38\x82\xb5\x5c\x82\xf1\x86\x82\xb5\x5c\x82\x88\x38\x82\x4e\xa8\x82\x12\x90\x82\x04\xd4" }, { 3268, 2, 12, "\x01\x01\x82\x04\xec\x02\x0e\xb0\x82\x1b\xc6\x02\x03\x20\x02\x17\x34\x82\x39\x26\x02\x17\x34\x02\x03\x20\x82\x1b\xc6\x02\x0e\xb0\x82\x04\xec" }, { 3304, 2, 12, "\x01\x01\x02\x05\x24\x02\x20\x00\x02\x51\x28\x02\x48\x48\x02\x3d\xcc\x02\x58\x1e\x82\x3d\xcc\x02\x48\x48\x82\x51\x28\x02\x20\x00\x82\x05\x24" }, { 3343, 2, 19, "\x81\x01\x01\x08\x81\x3c\x01\x7e\x82\x01\x7c\x02\x04\x8c\x82\x0b\x47\x02\x16\x09\x82\x22\x87\x02\x2b\xd5\x82\x30\x65\x02\x2b\x41\x82\x28\x5f\x02\x21\xc1\x82\x25\xc9\x02\x1e\x54\x82\x19\xc8\x02\x0a\x6f\x82\x05\x5b" }, { 3352, 2, 14, "\x81\x01\x82\x05\x6a\x82\x0f\xe7\x82\x29\x68\x82\x27\x20\x82\x44\xe8\x82\x16\xb2\x82\x43\xc4\x02\x16\xb2\x82\x44\xe8\x02\x27\x20\x82\x29\x68\x02\x0f\xe7\x82\x05\x6a" }, { 3367, 2, 20, "\x01\x01\x81\x06\x01\x3d\x81\xdf\x02\x01\x9b\x01\x7b\x82\x08\x7b\x02\x0c\x99\x02\x05\x94\x82\x21\x7b\x02\x16\xc1\x02\x1e\xb0\x82\x31\x3c\x82\x01\xb3\x02\x30\x3b\x82\x11\xa3\x82\x18\x10\x02\x14\x28\x02\x07\x32\x82\x05\x80" }, { 3412, 2, 10, "\x81\x01\x83\x21\x68\x88\x04\x01\x3f\xfe\xef\x84\x04\x74\xc3\x84\x04\x05\x91\xb6\xe7\x84\x01\xe4\x05\x54\x84\x05\x91\xb6\xe7\x84\x04\x74\xc3\x84\x84\x01\x3f\xfe\xef\x83\x21\x68\x88" }, { 3427, 1, 6, "\x0f\x06\xa4\x2c\x12\x2f\x0d\x38\xcb\x70\x94\xd1\x00\x00\x00\x00\xaa\x8a\x84\x6a\x4b\xb2\xa5\x55\xe3\x94\x11\xa2\x31\x8b\x2d\x6a\x0c\xd6\xf2\xff\x33\xd8\x33\x12\x08\xb1\xc7\x64\xe8\x44\x94\x0b\x33\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x29\x07\x5d\x2b\x28\x81\x73\xcf\x95\x03\x02\x49\x81\x73\x22\x70\xc9\xe5\xc4\xbe\x8a\x4f\xbc\xd3\x34\x59\x93\x93\xf5\x33\xb2\xda\x4a\x54\x70\x00\x00\x00\x00\x00\x00\x00\x28\x02\xf7\x2b\x5f\xdd\x2c\xfa\x04\xc4\x81\xaf\xc9\x1a\x77\xb5\x24\x7f\xf0\x80\x93\x88\x26\x06\x3c\x6d\xf2\xbb\x27\x90\xf9\x57\x01\xfc\x6e\x40\x00\x00\x00\x00\x00\x25\x02\x44\x1d\x1f\x54\xb9\x79\x8c\x66\x62\xae\xef\xef\x27\x3c\x6f\x63\xa0\x8c\xef\x46\x0e\x74\x87\xef\x59\x55\x14\x68\x19\xda\x75\x08\x00\x00\x00\x00\x22\x02\x82\x42\x35\xbf\x09\xbc\x0a\x8a\xaa\x3b\x9c\xfd\x29\x4a\x4a\x49\x38\x0b\x6c\x5f\x92\x47\xb3\xe8\xf4\x30\xe0\x2b\x2d\x4b\xab\x00\x00" }, { 3448, 2, 8, "\x01\x01\x82\x06\x06\x02\x09\x7b\x82\x05\x0a\x82\x03\x94\x82\x05\x0a\x02\x09\x7b\x82\x06\x06" }, { 3460, 2, 16, "\x01\x01\x82\x06\x15\x82\x19\x49\x82\x1a\x20\x82\x2b\x25\x82\x40\xd5\x82\x4c\x12\x82\x3b\x95\x82\x7e\xc4\x82\x3b\x95\x82\x4c\x12\x82\x40\xd5\x82\x2b\x25\x82\x1a\x20\x82\x19\x49\x82\x06\x15" }, { 3463, 2, 19, "\x81\x01\x01\x0b\x81\x09\x81\x8a\x81\x43\x02\x01\xb5\x02\x01\xaf\x02\x01\x97\x82\x0c\x95\x02\x06\xd6\x82\x0a\x66\x02\x26\x7b\x82\x1c\xa0\x02\x09\x73\x82\x22\x0d\x02\x18\x3a\x02\x0f\x57\x82\x08\x61\x82\x06\x1d" }, { 3496, 2, 20, "\x01\x01\x02\x06\x56\x82\x11\x9b\x02\x69\x8e\x82\x5e\xfc\x02\xf4\x22\x02\xa2\xb3\x83\x01\x4d\x62\x02\xb8\x27\x83\x01\xad\x6c\x83\x02\x09\x88\x03\x01\xad\x6c\x02\xb8\x27\x03\x01\x4d\x62\x02\xa2\xb3\x82\xf4\x22\x82\x5e\xfc\x82\x69\x8e\x82\x11\x9b\x82\x06\x56" }, { 3508, 2, 10, "\x81\x01\x83\x29\x5d\x94\x03\x85\xeb\x0f\x83\x76\x97\x70\x03\x2d\x37\xaf\x83\x40\x88\xc4\x83\x2d\x37\xaf\x83\x76\x97\x70\x83\x85\xeb\x0f\x83\x29\x5d\x94" }, { 3523, 1, 6, "\x0f\x17\xd1\x0e\xf9\x82\x2a\x57\x6e\x74\xfa\xf0\x00\x00\x00\x00\xaa\x96\x69\x9c\xc7\x10\xba\xfa\x0b\xc8\x6f\x6a\x3d\xcb\x5d\x88\x63\x02\x98\x94\x1e\xb5\xb7\xe1\x82\xeb\x1e\xa9\x5c\xea\xa9\xe4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x29\x02\xaf\xee\x03\x7f\x21\xa3\x33\x79\xe2\xe3\x72\xe0\x64\x8d\x16\x8e\x4d\x75\xbc\x6a\xb4\x54\xe9\x42\x61\x8f\x3c\x07\x92\x01\x03\x94\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x3e\x48\xeb\x1a\xd9\x31\xd0\x92\x82\xeb\xe4\x56\xdc\x99\x34\x29\xb6\x43\x48\xaa\x96\x5b\x29\x0a\x27\x05\xf8\x5b\x69\x9a\xb4\x96\x00\x00\x00\x00\x00\x00\x25\x03\x42\x77\x93\x59\x09\x88\xef\x0a\x52\x03\xbd\x0f\x81\x9c\xb6\x45\x21\xdf\x57\xc2\x53\xd2\x10\x4a\x81\xed\x75\x7b\x4e\x0c\x83\x29\x40\x00\x00\x00\x22\x20\x64\xb0\x8b\x31\xcb\xd2\x18\x9e\xa4\xb1\xb2\x07\x45\xc7\x2b\x5a\x7e\xb4\xd6\x77\x78\x03\xd1\xaf\x6a\x62\x13\x87\xa8\xd3\xb3\x00\x00" }, { 3544, 2, 18, "\x81\x01\x82\x06\xb6\x82\x20\x93\x82\x41\xdc\x82\x16\xc6\x82\x9f\x08\x82\x52\x76\x82\x30\xa8\x02\x0b\x9d\x02\x24\x72\x82\x0b\x9d\x82\x30\xa8\x02\x52\x76\x82\x9f\x08\x02\x16\xc6\x82\x41\xdc\x02\x20\x93\x82\x06\xb6" }, { 3556, 2, 16, "\x01\x01\x82\x06\xca\x02\x0e\x7a\x82\x38\xdc\x03\x01\x05\x25\x83\x01\x8f\x34\x02\xd2\x3e\x02\x3d\xca\x82\x85\x9c\x02\x3d\xca\x02\xd2\x3e\x83\x01\x8f\x34\x03\x01\x05\x25\x82\x38\xdc\x02\x0e\x7a\x82\x06\xca" }, { 3592, 2, 12, "\x01\x01\x82\x07\x0b\x82\x12\xae\x82\x23\x61\x82\x37\x5c\x82\x51\x57\x82\x52\xec\x82\x51\x57\x82\x37\x5c\x82\x23\x61\x82\x12\xae\x82\x07\x0b" }, { 3607, 2, 19, "\x81\x01\x81\x08\x81\x13\x01\x90\x81\x3a\x81\x70\x82\x05\x74\x02\x12\x2c\x82\x14\xe1\x81\x4b\x02\x25\x66\x82\x41\xe0\x02\x3c\xf4\x82\x0f\x4d\x82\x2a\x47\x02\x41\x3b\x82\x32\x0d\x02\x19\x8b\x82\x07\x2f" }, { 3640, 2, 16, "\x01\x01\x82\x07\x68\x82\x30\x36\x82\x59\xd0\x82\x01\x7f\x03\x01\x02\x30\x03\x02\xc2\x4a\x03\x05\x46\x48\x03\x06\xad\x64\x03\x05\x46\x48\x03\x02\xc2\x4a\x03\x01\x02\x30\x82\x01\x7f\x82\x59\xd0\x82\x30\x36\x82\x07\x68" }, { 3652, 2, 12, "\x01\x01\x82\x07\x80\x82\x37\xa0\x82\xbd\x7e\x83\x01\x91\xe0\x83\x02\x6e\x80\x83\x02\xd6\x86\x83\x02\x6e\x80\x83\x01\x91\xe0\x82\xbd\x7e\x82\x37\xa0\x82\x07\x80" }, { 3655, 2, 20, "\x01\x01\x01\x15\x01\xab\x02\x02\xdc\x02\x07\x87\x02\x0a\x32\x82\x04\x80\x82\x31\x47\x82\x65\x1e\x82\x59\x0a\x02\x33\x42\x03\x01\x11\xb7\x03\x01\x9d\x1d\x03\x01\x53\xb7\x02\x5c\x37\x82\x9b\x55\x82\xf2\xae\x82\xa6\xbc\x82\x39\xde\x82\x07\x86" }, { 3688, 2, 18, "\x81\x01\x82\x07\xd7\x82\x18\xbd\x82\x25\x42\x02\x05\xcd\x02\x0f\x09\x82\x47\x2d\x82\x40\x62\x02\x39\xba\x02\x3f\xe4\x82\x39\xba\x82\x40\x62\x02\x47\x2d\x02\x0f\x09\x82\x05\xcd\x82\x25\x42\x02\x18\xbd\x82\x07\xd7" }, { 3752, 2, 16, "\x01\x01\x02\x08\x78\x02\xb6\x8e\x03\x05\x23\x60\x03\x0b\x90\xc1\x03\x14\x2e\x50\x03\x19\xb7\xee\x03\x0e\xbb\xe8\x03\x20\x6c\x84\x83\x0e\xbb\xe8\x03\x19\xb7\xee\x83\x14\x2e\x50\x03\x0b\x90\xc1\x83\x05\x23\x60\x02\xb6\x8e\x82\x08\x78" }, { 3763, 1, 6, "\x8e\x3d\xd3\xff\x9e\xbf\xee\xa5\xc5\x84\xb1\x00\x00\x00\x00\x28\x23\x8f\x88\x89\x08\x6f\x2d\xae\x8b\x83\x2b\x71\x0d\x90\xb0\x64\x93\xc0\x4f\x2b\xe9\x61\x10\xa5\xa0\xc7\x3b\x60\x87\xad\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa8\x01\xbc\x9f\x67\xd9\x90\xa5\xa6\x65\x41\xc0\x8b\x8d\x0d\xb1\xca\x95\xbb\x4e\xaf\x6f\x89\x6b\x48\xa2\x09\xd0\x58\x8a\x9d\x6a\xc6\x50\x00\x00\x00\x00\x00\x00\x00\x26\x8e\xc2\x74\x48\x9b\x4f\xa6\x68\xf9\x4c\xcb\xea\xff\xe7\x66\x97\xe7\x28\x1f\x37\x76\x86\x35\x5d\xf9\xaf\xbe\x51\x96\xa3\x39\x31\xc0\x00\x00\x00\x00\x00\xa5\x0a\xab\x06\x33\x69\x3b\x4a\xcd\xb5\xe8\x0c\xb0\xae\x4b\x49\xe1\x1e\xca\xff\x2d\x50\xf4\x6b\xb6\x0c\x9e\xce\xe8\x9a\x5b\x0f\xfe\xd1\x00\x00\x00\x00\x23\x41\x57\x3b\x50\x86\x52\xc9\x80\x6d\x88\x86\x64\x4c\xc1\xbf\x0c\x10\x77\xb7\xc4\x98\x71\x69\x78\xf1\x33\x1d\x4a\x81\x2a\xd1\xae\xcd\x00\x00" }, { 3768, 2, 12, "\x01\x01\x85\x02\x6c\x4c\x90\xd8\x86\x0a\x4b\xf0\x66\xec\xa2\x06\x26\xcd\xed\xbb\x74\x48\x86\xae\x13\x5f\x80\xb3\xd1\x07\x01\x73\x00\x8e\x40\xbb\x10\x87\x01\xec\x44\xd7\x51\x6c\x5c\x07\x01\x73\x00\x8e\x40\xbb\x10\x86\xae\x13\x5f\x80\xb3\xd1\x06\x26\xcd\xed\xbb\x74\x48\x86\x0a\x4b\xf0\x66\xec\xa2\x85\x02\x6c\x4c\x90\xd8" }, { 3784, 2, 16, "\x01\x01\x82\x08\xb2\x02\x2d\x33\x82\x45\xba\x82\x75\xef\x02\x4c\xc8\x02\xbd\x7e\x02\x5f\x7c\x83\x02\x0e\x56\x02\x5f\x7c\x02\xbd\x7e\x02\x4c\xc8\x82\x75\xef\x82\x45\xba\x02\x2d\x33\x82\x08\xb2" }, { 3796, 2, 12, "\x01\x01\x03\x4d\x33\x22\x84\x05\xe5\x40\x95\x04\x2a\x02\x9e\x86\x04\x36\x3b\xaf\xab\x84\x72\x1e\xa2\x3c\x84\x2b\xb7\x2d\x2e\x04\x72\x1e\xa2\x3c\x04\x36\x3b\xaf\xab\x84\x2a\x02\x9e\x86\x84\x05\xe5\x40\x95\x83\x4d\x33\x22" }, { 3832, 2, 16, "\x01\x01\x82\x09\x1e\x82\x19\x5f\x82\x2a\x96\x82\x03\x2f\x02\xa0\x08\x02\xdf\x1a\x82\x70\xa4\x83\x01\x83\xf6\x82\x70\xa4\x02\xdf\x1a\x02\xa0\x08\x82\x03\x2f\x82\x2a\x96\x82\x19\x5f\x82\x09\x1e" }, { 3880, 2, 12, "\x01\x01\x02\x09\x98\x82\x13\xa8\x82\x1b\x38\x82\x58\x98\x82\x06\xc8\x82\x5c\xd2\x02\x06\xc8\x82\x58\x98\x02\x1b\x38\x82\x13\xa8\x82\x09\x98" }, { 3892, 2, 12, "\x01\x01\x03\x5e\x8b\xd0\x04\x01\xaa\x1d\xd0\x83\x2a\x3e\x58\x04\x05\x49\x92\x70\x03\x1b\x8c\x10\x04\x06\x6c\xe4\x8e\x83\x1b\x8c\x10\x04\x05\x49\x92\x70\x03\x2a\x3e\x58\x04\x01\xaa\x1d\xd0\x83\x5e\x8b\xd0" }, { 3928, 2, 10, "\x81\x01\x82\x0a\x18\x02\x08\x0e\x02\x16\x6e\x82\x11\xf9\x82\x1d\xe4\x02\x11\xf9\x02\x16\x6e\x82\x08\x0e\x82\x0a\x18" }, { 3972, 2, 12, "\x01\x01\x85\x04\x9d\x06\x28\xb2\x86\x18\x18\x35\x01\x82\x76\x07\x01\x82\x6b\x58\xa7\xd1\xee\x87\x0f\x70\xab\xe8\xe8\x83\x81\x07\x0f\x31\xb1\xcd\x22\xd6\xc4\x87\x22\x36\xb4\xd3\xb5\x14\x14\x07\x0f\x31\xb1\xcd\x22\xd6\xc4\x87\x0f\x70\xab\xe8\xe8\x83\x81\x07\x01\x82\x6b\x58\xa7\xd1\xee\x86\x18\x18\x35\x01\x82\x76\x85\x04\x9d\x06\x28\xb2" }, { 3976, 2, 16, "\x01\x01\x82\x0a\x9e\x02\x07\xfb\x82\x5d\xba\x03\x01\x91\x89\x83\x01\x32\xb4\x02\xd2\x4e\x83\x01\x85\xd0\x03\x03\x6f\xa2\x83\x01\x85\xd0\x02\xd2\x4e\x83\x01\x32\xb4\x03\x01\x91\x89\x82\x5d\xba\x02\x07\xfb\x82\x0a\x9e" }, { 3988, 2, 14, "\x81\x01\x83\x73\x80\x9c\x84\x04\x2e\xed\x0f\x84\x18\x56\x6a\x78\x84\x3c\x71\xee\x00\x84\x79\xc4\x92\xc8\x84\x4d\x17\xe1\xde\x84\x40\x5d\x6f\x08\x04\x4d\x17\xe1\xde\x84\x79\xc4\x92\xc8\x04\x3c\x71\xee\x00\x84\x18\x56\x6a\x78\x04\x04\x2e\xed\x0f\x83\x73\x80\x9c" }, { 4015, 2, 20, "\x01\x01\x01\x11\x01\x6d\x02\x01\x03\x02\x01\xc5\x02\x03\x00\x82\x06\x50\x82\x1d\x06\x82\x09\xad\x02\x30\x64\x02\x1e\xa8\x82\x07\x3d\x02\x06\xbb\x82\x40\x46\x82\x4d\x30\x02\x5d\x78\x02\x69\x8a\x82\x29\x90\x82\x39\xbc\x82\x0b\x08" }, { 4072, 2, 18, "\x81\x01\x82\x0b\xb5\x02\x25\x3b\x82\x3b\x9e\x02\x49\x4d\x82\x84\x2d\x02\x55\x63\x83\x01\x78\x6e\x02\x28\xc2\x83\x02\x67\x24\x82\x28\xc2\x83\x01\x78\x6e\x82\x55\x63\x82\x84\x2d\x82\x49\x4d\x82\x3b\x9e\x82\x25\x3b\x82\x0b\xb5" }, { 4120, 2, 12, "\x01\x01\x02\x0c\x4a\x82\x3f\x0d\x02\x56\xd2\x82\x6b\x6e\x02\x3e\x22\x82\x10\x6d\x82\x3e\x22\x82\x6b\x6e\x82\x56\xd2\x82\x3f\x0d\x82\x0c\x4a" }, { 4132, 2, 12, "\x01\x01\x82\x0c\x77\x02\x0d\xd2\x02\x15\x35\x82\x0b\x72\x82\x1a\x3f\x02\x0b\x7e\x82\x1a\x3f\x82\x0b\x72\x02\x15\x35\x02\x0d\xd2\x82\x0c\x77" }, { 4152, 2, 12, "\x01\x01\x85\x08\x08\x65\x9e\xb8\x86\x33\x55\x07\x21\x1e\x22\x87\x01\xa3\xec\xb6\xe2\x17\x18\x87\x05\xd9\xdf\xe4\xea\x21\xd1\x87\x0b\xd9\x1b\x71\x35\x99\xb0\x87\x0e\xdf\xd5\x61\xeb\xc5\x5c\x87\x0b\xd9\x1b\x71\x35\x99\xb0\x87\x05\xd9\xdf\xe4\xea\x21\xd1\x87\x01\xa3\xec\xb6\xe2\x17\x18\x86\x33\x55\x07\x21\x1e\x22\x85\x08\x08\x65\x9e\xb8" }, { 4168, 2, 12, "\x01\x01\x82\x0c\xed\x02\x03\xa2\x82\x6d\x9b\x02\x4f\xc8\x83\x01\x43\xa9\x02\xbe\xc8\x83\x01\x43\xa9\x02\x4f\xc8\x82\x6d\x9b\x02\x03\xa2\x82\x0c\xed" }, { 4180, 2, 16, "\x01\x01\x03\xab\x28\xc2\x04\x0b\x43\x84\x7f\x04\x13\xa3\x88\x66\x84\x0f\x28\x5c\x2f\x84\x15\x64\x29\xa8\x84\x20\x9c\x09\x42\x84\x2a\xc3\x21\x3c\x04\x4b\x44\x02\x72\x04\x2a\xc3\x21\x3c\x84\x20\x9c\x09\x42\x04\x15\x64\x29\xa8\x84\x0f\x28\x5c\x2f\x84\x13\xa3\x88\x66\x04\x0b\x43\x84\x7f\x83\xab\x28\xc2" }, { 4216, 2, 16, "\x01\x01\x82\x0d\x92\x02\x0a\x89\x82\xa2\xea\x03\x02\x11\x81\x83\x03\x2a\xd8\x03\x02\x1c\xea\x03\x01\xa2\x14\x83\x03\xf0\x66\x03\x01\xa2\x14\x03\x02\x1c\xea\x83\x03\x2a\xd8\x03\x02\x11\x81\x82\xa2\xea\x02\x0a\x89\x82\x0d\x92" }, { 4228, 2, 16, "\x01\x01\x82\x0d\xc4\x02\x75\x5b\x83\x01\xd6\x7c\x03\x04\xbb\x05\x83\x08\xda\xb8\x03\x0d\x07\x96\x83\x0f\xf5\xf0\x03\x10\xfb\x26\x83\x0f\xf5\xf0\x03\x0d\x07\x96\x83\x08\xda\xb8\x03\x04\xbb\x05\x83\x01\xd6\x7c\x02\x75\x5b\x82\x0d\xc4" }, { 4324, 2, 16, "\x01\x01\x82\x0f\x1e\x81\x51\x02\xa7\xd6\x82\xdc\x7b\x83\x09\xac\xd4\x83\x0c\x12\x06\x03\x09\x27\x18\x03\x1a\x08\xaa\x03\x09\x27\x18\x83\x0c\x12\x06\x83\x09\xac\xd4\x82\xdc\x7b\x02\xa7\xd6\x81\x51\x82\x0f\x1e" }, { 4327, 2, 19, "\x81\x01\x01\x04\x81\x49\x02\x01\x8b\x82\x02\x67\x82\x03\x40\x02\x09\xe9\x81\x9f\x82\x1a\x5b\x02\x12\x8c\x02\x22\x04\x82\x20\x99\x82\x17\x02\x02\x17\xbd\x82\x05\xaf\x01\x43\x02\x13\x32\x82\x08\xf0\x82\x0f\x29" }, { 4360, 2, 12, "\x01\x01\x82\x0f\xae\x02\x30\x7e\x02\x35\x4c\x83\x03\x07\x26\x03\x08\x85\x96\x83\x0b\xaf\x5a\x03\x08\x85\x96\x83\x03\x07\x26\x02\x35\x4c\x02\x30\x7e\x82\x0f\xae" }, { 4372, 2, 10, "\x81\x01\x83\xfb\x61\x03\x04\x02\x13\x6e\xd5\x84\x03\xd7\x08\x14\x04\x02\x51\x55\x86\x84\x05\x12\xa0\xd2\x84\x02\x51\x55\x86\x84\x03\xd7\x08\x14\x84\x02\x13\x6e\xd5\x83\xfb\x61\x03" }, { 4420, 2, 16, "\x01\x01\x82\x10\x98\x82\x81\xcc\x83\x01\xb8\x70\x83\x04\x10\xf5\x83\x04\xf1\x58\x82\x6c\x24\x03\x07\xea\x20\x03\x0c\xae\x48\x03\x07\xea\x20\x82\x6c\x24\x83\x04\xf1\x58\x83\x04\x10\xf5\x83\x01\xb8\x70\x82\x81\xcc\x82\x10\x98" }, { 4447, 2, 17, "\x81\x01\x01\x0b\x81\x74\x02\x01\xe2\x82\x01\xc5\x82\x05\x89\x02\x0b\x8d\x81\x65\x82\x16\x0f\x02\x0f\x8d\x02\x07\x0d\x82\x24\x0b\x82\x03\x15\x02\x13\xff\x82\x03\x47\x82\x15\xc4\x82\x11\x11" }, { 4468, 2, 14, "\x81\x01\x84\x01\x2f\xae\x8d\x83\x63\xad\x1e\x03\x76\x17\x2d\x84\x09\x0d\x29\xcf\x84\x1b\xd0\xe0\x96\x84\x0d\x3d\x02\x5d\x84\x09\x2f\xd4\x8f\x04\x0d\x3d\x02\x5d\x84\x1b\xd0\xe0\x96\x04\x09\x0d\x29\xcf\x03\x76\x17\x2d\x03\x63\xad\x1e\x84\x01\x2f\xae\x8d" }, { 4516, 2, 16, "\x01\x01\x82\x12\x3f\x82\x4d\xdd\x83\x01\x5a\x54\x83\x01\x28\xd5\x03\x04\x00\x15\x03\x07\xbb\xae\x83\x02\xca\x73\x83\x0c\x41\x9c\x83\x02\xca\x73\x03\x07\xbb\xae\x03\x04\x00\x15\x83\x01\x28\xd5\x83\x01\x5a\x54\x82\x4d\xdd\x82\x12\x3f" }, { 4552, 2, 12, "\x01\x01\x82\x12\xe7\x82\x34\x35\x82\x64\x38\x82\x76\xe3\x82\x79\x71\x82\x6a\xf2\x82\x79\x71\x82\x76\xe3\x82\x64\x38\x82\x34\x35\x82\x12\xe7" }, { 4568, 2, 18, "\x81\x01\x82\x13\x20\x03\x01\x9a\xe0\x83\x0f\x23\xf2\x03\x10\x9c\xa0\x83\x37\xc7\x60\x02\x28\x47\x83\x1f\x1c\x00\x83\x0d\x50\x40\x03\x1b\x4e\x2c\x03\x0d\x50\x40\x83\x1f\x1c\x00\x82\x28\x47\x83\x37\xc7\x60\x83\x10\x9c\xa0\x83\x0f\x23\xf2\x83\x01\x9a\xe0\x82\x13\x20" }, { 4612, 2, 16, "\x01\x01\x82\x14\x07\x82\x4f\x59\x82\x91\xbc\x83\x01\x76\x41\x83\x05\x29\x6b\x83\x0c\x6d\xda\x83\x13\xd2\x23\x83\x16\xda\x78\x83\x13\xd2\x23\x83\x0c\x6d\xda\x83\x05\x29\x6b\x83\x01\x76\x41\x82\x91\xbc\x82\x4f\x59\x82\x14\x07" }, { 4648, 2, 12, "\x01\x01\x02\x14\xc0\x02\x05\x48\x82\x4b\xc8\x02\x6d\x68\x02\x13\x30\x02\x22\xae\x82\x13\x30\x02\x6d\x68\x02\x4b\xc8\x02\x05\x48\x82\x14\xc0" }, { 4687, 2, 16, "\x81\x01\x81\x01\x81\x2e\x02\x01\xf2\x82\x07\xfb\x02\x0e\x94\x82\x0c\xea\x02\x01\x8c\x02\x0a\x3f\x82\x0b\x0b\x82\x0a\xbd\x02\x08\xd1\x02\x0c\x40\x82\x1f\x6d\x02\x2c\x02\x82\x15\x8c" }, { 4708, 2, 12, "\x01\x01\x82\x15\xf4\x82\x7c\x10\x83\x01\x72\xfa\x83\x02\xf3\x00\x83\x04\x64\x74\x83\x05\x04\xa6\x83\x04\x64\x74\x83\x02\xf3\x00\x83\x01\x72\xfa\x82\x7c\x10\x82\x15\xf4" }, { 4712, 2, 16, "\x01\x01\x02\x15\xfc\x83\x01\xa5\xdc\x03\x0c\x7a\x30\x03\x2c\x4f\xb2\x83\x06\xb6\xd4\x83\x45\xac\x60\x03\x1c\x74\xb4\x03\x1e\xb7\x8b\x83\x1c\x74\xb4\x83\x45\xac\x60\x03\x06\xb6\xd4\x03\x2c\x4f\xb2\x83\x0c\x7a\x30\x83\x01\xa5\xdc\x82\x15\xfc" }, { 4792, 2, 12, "\x01\x01\x82\x17\xd6\x02\xdb\x2d\x83\x03\x9c\x1e\x03\x09\x30\x1b\x83\x0f\xa3\x2c\x03\x12\x97\x9e\x83\x0f\xa3\x2c\x03\x09\x30\x1b\x83\x03\x9c\x1e\x02\xdb\x2d\x82\x17\xd6" }, { 4804, 2, 16, "\x01\x01\x82\x18\x1a\x02\xba\x12\x83\x02\x74\x8c\x03\x02\xd9\x5d\x83\x05\x1e\xf4\x03\x05\x03\xe6\x83\x0a\xbe\xf6\x03\x03\xa6\x74\x83\x0a\xbe\xf6\x03\x05\x03\xe6\x83\x05\x1e\xf4\x03\x02\xd9\x5d\x83\x02\x74\x8c\x02\xba\x12\x82\x18\x1a" }, { 4852, 2, 10, "\x81\x01\x84\x02\x7a\x45\x11\x84\x01\xdd\x59\x3e\x84\x06\xba\x86\x1f\x83\x95\xc7\x19\x04\x0e\x50\x2a\xb0\x03\x95\xc7\x19\x84\x06\xba\x86\x1f\x04\x01\xdd\x59\x3e\x84\x02\x7a\x45\x11" }, { 4888, 2, 12, "\x01\x01\x02\x1a\x0c\x82\x11\xe0\x82\x12\x2c\x82\x0d\x98\x82\x31\x94\x02\x2d\x52\x02\x31\x94\x82\x0d\x98\x02\x12\x2c\x82\x11\xe0\x82\x1a\x0c" }, { 4948, 2, 14, "\x81\x01\x84\x02\xf6\xfe\xe3\x04\x0a\x2b\x63\x41\x84\x90\x64\x30\x08\x04\x34\x33\x04\x28\x04\x32\x0e\x45\x08\x05\x01\x99\x0d\x43\x32\x84\x2f\xec\xbb\x6a\x85\x01\x99\x0d\x43\x32\x04\x32\x0e\x45\x08\x84\x34\x33\x04\x28\x84\x90\x64\x30\x08\x84\x0a\x2b\x63\x41\x84\x02\xf6\xfe\xe3" }, { 4984, 2, 16, "\x01\x01\x82\x1c\x86\x03\x01\x0c\xd1\x83\x03\xe4\xde\x03\x04\x47\x61\x02\xe0\x28\x03\x03\x2c\x0a\x03\x01\x47\xcc\x83\x06\xb2\x56\x03\x01\x47\xcc\x03\x03\x2c\x0a\x02\xe0\x28\x03\x04\x47\x61\x83\x03\xe4\xde\x03\x01\x0c\xd1\x82\x1c\x86" }, { 5032, 2, 12, "\x01\x01\x02\x1d\xca\x02\x47\x5e\x02\x80\x5c\x82\x66\x36\x02\xf7\xc2\x03\x01\x66\x5e\x82\xf7\xc2\x82\x66\x36\x82\x80\x5c\x02\x47\x5e\x82\x1d\xca" }, { 5128, 2, 12, "\x01\x01\x82\x20\x7f\x82\xe9\x9a\x83\x03\x4e\x39\x83\x07\xbe\xa0\x83\x0c\xa9\x53\x83\x0e\xdf\x9c\x83\x0c\xa9\x53\x83\x07\xbe\xa0\x83\x03\x4e\x39\x82\xe9\x9a\x82\x20\x7f" }, { 5140, 2, 12, "\x01\x01\x04\x04\x39\x44\x87\x04\x55\x2c\xed\x0c\x84\x67\x7f\xae\xc1\x04\x3c\x84\xa3\x50\x04\x6b\xaa\xa1\xb7\x04\x6d\xa6\x0b\x2a\x84\x6b\xaa\xa1\xb7\x04\x3c\x84\xa3\x50\x04\x67\x7f\xae\xc1\x04\x55\x2c\xed\x0c\x84\x04\x39\x44\x87" }, { 5188, 2, 12, "\x01\x01\x82\x22\x5c\x02\x40\x3b\x82\x23\x7e\x02\x8e\x0b\x82\xfd\x0e\x02\x8e\x22\x82\xfd\x0e\x02\x8e\x0b\x82\x23\x7e\x02\x40\x3b\x82\x22\x5c" }, { 5224, 2, 18, "\x81\x01\x82\x23\x85\x82\xf6\xc0\x83\x02\x7d\x15\x03\x01\x51\x08\x82\x91\x95\x03\x06\x23\xcb\x03\x01\x19\x6a\x83\x0f\x84\x78\x03\x02\x01\xba\x03\x0f\x84\x78\x03\x01\x19\x6a\x83\x06\x23\xcb\x82\x91\x95\x83\x01\x51\x08\x83\x02\x7d\x15\x02\xf6\xc0\x82\x23\x85" }, { 5272, 2, 10, "\x81\x01\x82\x25\x10\x02\x1b\xbe\x02\x15\x2a\x02\x0f\xc7\x82\x06\x7c\x82\x0f\xc7\x02\x15\x2a\x82\x1b\xbe\x82\x25\x10" }, { 5380, 2, 16, "\x01\x01\x82\x28\xd5\x82\x20\x8d\x03\x02\x52\xcc\x83\x03\xde\xc8\x82\x16\xba\x03\x03\x67\xcd\x03\x02\xfa\x83\x83\x08\xf5\x72\x03\x02\xfa\x83\x03\x03\x67\xcd\x82\x16\xba\x83\x03\xde\xc8\x03\x02\x52\xcc\x82\x20\x8d\x82\x28\xd5" }, { 5464, 2, 18, "\x81\x01\x82\x2c\x0a\x83\x01\xaf\x91\x83\x07\x64\x5c\x83\x0d\x85\xf7\x83\x12\xe1\x72\x83\x08\x90\xf9\x83\x0e\x3d\x0c\x83\x04\x6e\xd2\x83\x20\x0c\x58\x03\x04\x6e\xd2\x83\x0e\x3d\x0c\x03\x08\x90\xf9\x83\x12\xe1\x72\x03\x0d\x85\xf7\x83\x07\x64\x5c\x03\x01\xaf\x91\x82\x2c\x0a" }, { 5527, 2, 19, "\x81\x01\x81\x08\x81\x0a\x02\x02\x14\x82\x0f\xb4\x02\x39\x69\x82\x8d\x54\x02\xfa\xe6\x83\x01\x4c\x65\x03\x01\x4c\x6b\x82\xe0\x1a\x02\x10\x57\x02\xba\x09\x82\xff\x0f\x02\xc8\x2e\x82\x43\x1a\x82\x52\x3c\x02\x74\xf2\x82\x2e\x87" }, { 5572, 2, 16, "\x01\x01\x82\x30\x64\x82\x23\x85\x02\xb7\x64\x03\x02\x98\x25\x03\x02\xea\xe8\x03\x01\x3b\xf6\x83\x04\x3e\xf0\x83\x05\x60\x9a\x83\x04\x3e\xf0\x03\x01\x3b\xf6\x03\x02\xea\xe8\x03\x02\x98\x25\x02\xb7\x64\x82\x23\x85\x82\x30\x64" }, { 5608, 2, 14, "\x81\x01\x82\x31\xf3\x82\x51\x56\x02\x58\x9b\x02\xe6\xd9\x82\x60\xba\x83\x01\x60\x95\x02\x53\x07\x03\x01\x60\x95\x82\x60\xba\x82\xe6\xd9\x02\x58\x9b\x02\x51\x56\x82\x31\xf3" }, { 5668, 2, 16, "\x01\x01\x82\x34\x9e\x82\x60\xa9\x03\x01\x2f\x2a\x03\x01\x60\xbd\x83\x07\x1a\x48\x03\x04\xdd\x0a\x03\x08\xcb\x2c\x83\x11\xc7\x5e\x03\x08\xcb\x2c\x03\x04\xdd\x0a\x83\x07\x1a\x48\x03\x01\x60\xbd\x03\x01\x2f\x2a\x82\x60\xa9\x82\x34\x9e" }, { 5752, 2, 16, "\x01\x01\x82\x38\x8e\x83\x02\x54\x4f\x83\x0b\x68\x86\x83\x23\x3a\xef\x83\x51\x43\x38\x83\x96\x00\x66\x83\xdc\x76\x04\x83\xfb\x8d\x16\x83\xdc\x76\x04\x83\x96\x00\x66\x83\x51\x43\x38\x83\x23\x3a\xef\x83\x0b\x68\x86\x83\x02\x54\x4f\x82\x38\x8e" }, { 5812, 2, 14, "\x81\x01\x84\x0d\xdf\x9f\xb5\x04\x0f\x1c\x84\xf0\x84\x77\xda\xf7\x55\x04\x22\xa9\x4e\x8e\x85\x01\x65\x52\xbd\xef\x04\x05\xaa\xf5\xad\x85\x01\xbf\xcf\x01\x0e\x84\x05\xaa\xf5\xad\x85\x01\x65\x52\xbd\xef\x84\x22\xa9\x4e\x8e\x84\x77\xda\xf7\x55\x84\x0f\x1c\x84\xf0\x84\x0d\xdf\x9f\xb5" }, { 5848, 2, 16, "\x01\x01\x02\x3d\x78\x02\x57\x32\x03\x01\xa6\x20\x03\x05\x7b\x49\x03\x03\xd3\x60\x03\x01\x1a\x42\x03\x05\x84\x38\x83\x05\x7e\x6c\x83\x05\x84\x38\x03\x01\x1a\x42\x83\x03\xd3\x60\x03\x05\x7b\x49\x83\x01\xa6\x20\x02\x57\x32\x82\x3d\x78" }, { 5860, 2, 16, "\x01\x01\x82\x3e\x13\x83\x01\x70\x45\x83\x01\x2b\xfc\x83\x02\xaf\xb0\x83\x07\xb4\x76\x83\x0b\xda\xdb\x83\x0e\x42\x7b\x83\x17\xcc\x62\x83\x0e\x42\x7b\x83\x0b\xda\xdb\x83\x07\xb4\x76\x83\x02\xaf\xb0\x83\x01\x2b\xfc\x83\x01\x70\x45\x82\x3e\x13" }, { 5896, 2, 16, "\x01\x01\x82\x40\x08\x82\x44\x3a\x83\x05\x61\xe4\x03\x0d\xcc\x69\x83\x06\x30\xd8\x83\x13\x17\x12\x03\x36\x7a\xc4\x83\x4a\xb2\x3c\x03\x36\x7a\xc4\x83\x13\x17\x12\x83\x06\x30\xd8\x03\x0d\xcc\x69\x83\x05\x61\xe4\x82\x44\x3a\x82\x40\x08" }, { 5992, 2, 16, "\x01\x01\x02\x45\x7e\x03\x01\x5a\xbf\x03\x02\x8e\x2a\x03\x03\x7d\x71\x03\x02\xe9\x98\x03\x01\xe8\xbe\x83\x03\xba\xb4\x83\x03\x84\xae\x03\x03\xba\xb4\x03\x01\xe8\xbe\x83\x02\xe9\x98\x03\x03\x7d\x71\x83\x02\x8e\x2a\x03\x01\x5a\xbf\x82\x45\x7e" }, { 6040, 2, 16, "\x01\x01\x02\x48\x56\x82\x9c\x43\x83\x03\x48\x92\x83\x0b\x9c\xe7\x03\x0b\x75\xf4\x03\x0e\x5a\x6a\x83\x0d\x28\x10\x83\x17\x2c\x86\x03\x0d\x28\x10\x03\x0e\x5a\x6a\x83\x0b\x75\xf4\x83\x0b\x9c\xe7\x03\x03\x48\x92\x82\x9c\x43\x82\x48\x56" }, { 6052, 2, 16, "\x01\x01\x82\x49\x15\x02\x3c\x3f\x82\xe4\x4c\x03\x01\x65\xf4\x83\x02\x12\x82\x03\x02\x47\x61\x82\x6f\x1d\x02\xce\xd6\x82\x6f\x1d\x03\x02\x47\x61\x83\x02\x12\x82\x03\x01\x65\xf4\x82\xe4\x4c\x02\x3c\x3f\x82\x49\x15" }, { 6148, 2, 16, "\x01\x01\x82\x4f\x35\x02\x7d\x57\x83\x01\xaf\xc0\x03\x01\xcf\x1b\x83\x01\x8e\x95\x82\x31\xd2\x03\x02\xe0\xab\x83\x05\xb4\x84\x03\x02\xe0\xab\x82\x31\xd2\x83\x01\x8e\x95\x03\x01\xcf\x1b\x83\x01\xaf\xc0\x02\x7d\x57\x82\x4f\x35" }, { 6232, 2, 12, "\x01\x01\x02\x54\xec\x82\xf7\x90\x82\x17\x0c\x03\x02\xeb\x78\x83\x01\x17\x74\x83\x03\xf3\x6e\x03\x01\x17\x74\x03\x02\xeb\x78\x02\x17\x0c\x82\xf7\x90\x82\x54\xec" }, { 6328, 2, 16, "\x01\x01\x82\x5b\xf2\x02\x58\xa1\x03\x01\xf3\x86\x02\xb0\xd1\x02\x01\xf8\x03\x06\x95\x9a\x03\x04\x52\x04\x83\x01\x88\x76\x03\x04\x52\x04\x03\x06\x95\x9a\x02\x01\xf8\x02\xb0\xd1\x03\x01\xf3\x86\x02\x58\xa1\x82\x5b\xf2" }, { 6388, 2, 14, "\x81\x01\x84\x24\x70\x44\xf3\x04\x86\x7a\xda\x01\x85\x02\x00\xb5\xd2\x48\x05\x03\x9c\xf1\xfe\xa8\x04\x9a\xfd\xd6\x48\x85\x08\x53\x12\x43\x0e\x05\x01\xdb\xf1\x83\xb6\x05\x08\x53\x12\x43\x0e\x04\x9a\xfd\xd6\x48\x85\x03\x9c\xf1\xfe\xa8\x85\x02\x00\xb5\xd2\x48\x84\x86\x7a\xda\x01\x84\x24\x70\x44\xf3" }, { 6472, 2, 12, "\x01\x01\x82\x67\x6b\x83\x01\xfd\x01\x83\x04\xb2\xdc\x83\x07\x0b\xdb\x83\x07\xd0\x79\x83\x07\xc1\xca\x83\x07\xd0\x79\x83\x07\x0b\xdb\x83\x04\xb2\xdc\x83\x01\xfd\x01\x82\x67\x6b" }, { 6532, 2, 16, "\x01\x01\x82\x6c\xa0\x03\x02\xc8\xc8\x83\x09\x80\x50\x03\x16\x9a\x4a\x83\x29\xe5\x30\x03\x3f\xed\xb0\x83\x52\x46\xf0\x03\x59\x90\xeb\x83\x52\x46\xf0\x03\x3f\xed\xb0\x83\x29\xe5\x30\x03\x16\x9a\x4a\x83\x09\x80\x50\x03\x02\xc8\xc8\x82\x6c\xa0" }, { 6568, 2, 14, "\x81\x01\x82\x6f\xd1\x82\xfe\x5a\x82\xd6\x23\x02\x10\x95\x02\x08\x6a\x02\x55\xa7\x03\x01\x2c\x69\x82\x55\xa7\x02\x08\x6a\x82\x10\x95\x82\xd6\x23\x02\xfe\x5a\x82\x6f\xd1" }, { 6628, 2, 16, "\x01\x01\x82\x75\x5a\x02\xb0\x6f\x82\x5c\xe2\x83\x09\xd1\xc3\x83\x0a\x5a\x38\x03\x12\xaf\x2a\x83\x03\xf4\x5c\x83\x2e\x84\x4e\x83\x03\xf4\x5c\x03\x12\xaf\x2a\x83\x0a\x5a\x38\x83\x09\xd1\xc3\x82\x5c\xe2\x02\xb0\x6f\x82\x75\x5a" }, { 6820, 2, 16, "\x01\x01\x82\x88\xc0\x83\x04\x27\x78\x83\x04\xa2\x10\x03\x05\x28\xaa\x03\x03\x31\xf0\x83\x08\x0b\x50\x01\x30\x03\x12\x3e\xcb\x01\x30\x83\x08\x0b\x50\x03\x03\x31\xf0\x03\x05\x28\xaa\x83\x04\xa2\x10\x83\x04\x27\x78\x82\x88\xc0" }, { 6952, 2, 16, "\x01\x01\x02\x97\xc6\x83\x02\x50\x51\x03\x01\xad\x52\x03\x04\x69\x11\x83\x06\x9b\x18\x83\x03\x8f\xe2\x03\x09\x7e\xac\x03\x01\xba\x72\x83\x09\x7e\xac\x83\x03\x8f\xe2\x03\x06\x9b\x18\x03\x04\x69\x11\x83\x01\xad\x52\x83\x02\x50\x51\x82\x97\xc6" }, { 7288, 2, 16, "\x01\x01\x82\xc4\xf8\x83\x03\x33\x06\x83\x07\x14\x30\x83\x0a\x12\x4f\x83\x0d\xa9\x10\x83\x0d\x9a\xa6\x83\x0e\xfc\x88\x83\x0c\x44\x7c\x83\x0e\xfc\x88\x83\x0d\x9a\xa6\x83\x0d\xa9\x10\x83\x0a\x12\x4f\x83\x07\x14\x30\x83\x03\x33\x06\x82\xc4\xf8" }, { 7480, 2, 16, "\x01\x01\x82\xe4\x00\x83\x01\x43\x34\x03\x17\x7e\xa0\x83\x3c\xcd\xd6\x03\x26\x67\x60\x03\x7c\x29\x30\x84\x01\x70\x46\x60\x04\x01\xea\x61\xd3\x84\x01\x70\x46\x60\x03\x7c\x29\x30\x03\x26\x67\x60\x83\x3c\xcd\xd6\x03\x17\x7e\xa0\x83\x01\x43\x34\x82\xe4\x00" }, { 7492, 2, 12, "\x01\x01\x82\xe6\x19\x03\x02\xfc\xd3\x83\x08\x26\x22\x03\x0e\x2c\x2f\x83\x13\xa3\x0d\x03\x16\xb1\x6a\x83\x13\xa3\x0d\x03\x0e\x2c\x2f\x83\x08\x26\x22\x03\x02\xfc\xd3\x82\xe6\x19" }, { 7528, 2, 18, "\x81\x01\x82\xec\x6b\x03\x01\xf4\x77\x83\x0d\x0d\x26\x03\x04\x73\x7d\x83\x04\xd7\x27\x83\x17\xc9\x95\x83\x2c\xc9\x5e\x03\x1c\x32\x16\x83\x02\x30\xd4\x83\x1c\x32\x16\x83\x2c\xc9\x5e\x03\x17\xc9\x95\x83\x04\xd7\x27\x83\x04\x73\x7d\x83\x0d\x0d\x26\x83\x01\xf4\x77\x82\xec\x6b" }, { 7588, 2, 16, "\x01\x01\x82\xf7\x5e\x03\x04\x16\x52\x03\x01\x1f\x84\x83\x0b\xf3\x23\x83\x05\x7f\x6c\x03\x13\x8d\xe6\x03\x06\x96\x36\x83\x0e\x7c\x0c\x03\x06\x96\x36\x03\x13\x8d\xe6\x83\x05\x7f\x6c\x83\x0b\xf3\x23\x03\x01\x1f\x84\x03\x04\x16\x52\x82\xf7\x5e" }, { 7672, 2, 16, "\x01\x01\x83\x01\x07\x6a\x83\x01\x61\xf7\x03\x06\x49\xfe\x03\x19\x68\xf1\x03\x30\x97\x68\x03\x3d\x24\x7a\x03\x37\xd0\xc4\x03\x31\x08\x5a\x03\x37\xd0\xc4\x03\x3d\x24\x7a\x03\x30\x97\x68\x03\x19\x68\xf1\x03\x06\x49\xfe\x83\x01\x61\xf7\x83\x01\x07\x6a" }, { 7780, 2, 16, "\x01\x01\x83\x01\x1d\x6d\x83\x0e\xfb\xd4\x83\x57\xd1\x21\x84\x01\x82\x38\x6f\x84\x04\x4e\x51\xd4\x84\x08\xdf\xa8\x36\x84\x0d\x65\xdc\x9e\x84\x0f\x66\x11\x10\x84\x0d\x65\xdc\x9e\x84\x08\xdf\xa8\x36\x84\x04\x4e\x51\xd4\x84\x01\x82\x38\x6f\x83\x57\xd1\x21\x83\x0e\xfb\xd4\x83\x01\x1d\x6d" }, { 7912, 2, 12, "\x01\x01\x03\x01\x3a\xba\x02\x49\x43\x03\x01\xda\xbe\x02\xb9\xeb\x02\x13\x24\x03\x01\xb4\xa2\x82\x13\x24\x02\xb9\xeb\x83\x01\xda\xbe\x02\x49\x43\x83\x01\x3a\xba" }, { 8008, 2, 16, "\x01\x01\x83\x01\x51\xb0\x82\x96\x8a\x03\x12\x77\x58\x03\x1b\x7d\x59\x83\x2d\xb0\xa0\x83\x67\x3f\x1a\x03\x1b\xaa\xb8\x03\x9a\xb1\x14\x03\x1b\xaa\xb8\x83\x67\x3f\x1a\x83\x2d\xb0\xa0\x03\x1b\x7d\x59\x03\x12\x77\x58\x82\x96\x8a\x83\x01\x51\xb0" }, { 8068, 2, 12, "\x01\x01\x83\x01\x60\xcb\x83\x05\xb7\xb6\x83\x0a\xb4\xff\x83\x09\x95\x02\x83\x01\x51\xa3\x03\x03\xfd\xd6\x83\x01\x51\xa3\x83\x09\x95\x02\x83\x0a\xb4\xff\x83\x05\xb7\xb6\x83\x01\x60\xcb" }, { 8152, 2, 18, "\x81\x01\x83\x01\x77\x04\x03\x01\x39\x00\x83\x06\xb4\xd2\x03\x01\xa7\x20\x83\x11\xbb\x64\x82\x4d\xc9\x83\x1d\xc0\x88\x03\x02\x92\xe0\x83\x23\xae\xf4\x83\x02\x92\xe0\x83\x1d\xc0\x88\x02\x4d\xc9\x83\x11\xbb\x64\x83\x01\xa7\x20\x83\x06\xb4\xd2\x83\x01\x39\x00\x83\x01\x77\x04" }, { 8248, 2, 12, "\x01\x01\x83\x01\x91\xf4\x83\x04\x6c\x80\x83\x02\xf5\x08\x82\x59\x88\x83\x07\x7e\x5c\x83\x0e\x6e\x86\x83\x07\x7e\x5c\x82\x59\x88\x83\x02\xf5\x08\x83\x04\x6c\x80\x83\x01\x91\xf4" }, { 8452, 2, 16, "\x01\x01\x83\x01\xd1\x37\x03\x04\x00\x6a\x83\x1d\x6c\xe9\x03\x6c\x31\x27\x83\xce\xe6\x2c\x04\x01\x2c\x16\xd0\x84\x01\x9d\x51\xd8\x04\x01\xde\x4b\x84\x84\x01\x9d\x51\xd8\x04\x01\x2c\x16\xd0\x83\xce\xe6\x2c\x03\x6c\x31\x27\x83\x1d\x6c\xe9\x03\x04\x00\x6a\x83\x01\xd1\x37" }, { 8488, 2, 18, "\x81\x01\x83\x01\xdd\x47\x83\x03\x74\x4e\x83\x01\x87\x91\x83\x07\x24\x2b\x03\x03\x38\xe2\x03\x1b\xd1\x39\x83\x12\xbd\xff\x03\x0c\x07\x57\x83\x2c\x5c\x16\x83\x0c\x07\x57\x83\x12\xbd\xff\x83\x1b\xd1\x39\x03\x03\x38\xe2\x03\x07\x24\x2b\x83\x01\x87\x91\x03\x03\x74\x4e\x83\x01\xdd\x47" }, { 8548, 2, 16, "\x01\x01\x83\x01\xf2\x06\x03\x03\xcc\x6a\x83\x0b\x85\xc8\x03\x10\xd7\xcd\x83\x1e\x12\xd4\x03\x23\x32\x46\x83\x2f\x46\x9e\x03\x2c\x54\x84\x83\x2f\x46\x9e\x03\x23\x32\x46\x83\x1e\x12\xd4\x03\x10\xd7\xcd\x83\x0b\x85\xc8\x03\x03\xcc\x6a\x83\x01\xf2\x06" }, { 8680, 2, 16, "\x01\x01\x03\x02\x22\x98\x83\x03\x83\xaa\x83\x59\x8e\xd0\x83\xaf\xb5\xc7\x83\x29\x39\xe0\x03\x19\x7e\x86\x03\x3f\x10\x88\x04\x01\x19\x30\xd4\x83\x3f\x10\x88\x03\x19\x7e\x86\x03\x29\x39\xe0\x83\xaf\xb5\xc7\x03\x59\x8e\xd0\x83\x03\x83\xaa\x83\x02\x22\x98" }, { 8932, 2, 16, "\x01\x01\x83\x02\x8b\xa2\x82\x54\xf9\x03\x1a\xf5\x02\x03\x3b\xa7\xe5\x03\x33\xd6\x5c\x82\xb7\x06\x03\x71\x46\x00\x04\x01\x07\x6d\xba\x03\x71\x46\x00\x82\xb7\x06\x03\x33\xd6\x5c\x03\x3b\xa7\xe5\x03\x1a\xf5\x02\x82\x54\xf9\x83\x02\x8b\xa2" }, { 8968, 2, 16, "\x01\x01\x83\x02\x9c\x10\x83\x02\xb2\x8a\x02\x65\x04\x03\x01\x32\x79\x03\x05\xfd\xa8\x03\x09\x8a\xde\x83\x04\x16\x1c\x83\x15\x96\x9c\x83\x04\x16\x1c\x03\x09\x8a\xde\x03\x05\xfd\xa8\x03\x01\x32\x79\x02\x65\x04\x83\x02\xb2\x8a\x83\x02\x9c\x10" }, { 9172, 2, 14, "\x81\x01\x85\x09\x03\xab\xe0\x82\x05\x0e\x56\x1c\xbc\x96\x05\x30\x99\x96\xfe\xd0\x85\x14\xc5\x1e\x63\x80\x85\xd3\xea\x77\xbc\x2e\x05\x3a\x15\x31\x96\x99\x05\xff\xb8\xe2\xaf\xc0\x85\x3a\x15\x31\x96\x99\x85\xd3\xea\x77\xbc\x2e\x05\x14\xc5\x1e\x63\x80\x05\x30\x99\x96\xfe\xd0\x85\x0e\x56\x1c\xbc\x96\x85\x09\x03\xab\xe0\x82" }, { 9208, 2, 16, "\x01\x01\x83\x03\x13\xbc\x83\x02\x0b\x86\x83\x3b\xed\xb8\x03\x36\x6e\x29\x83\xcf\xe7\xc0\x03\x88\xa8\x7a\x83\xf7\xd9\x4c\x04\x01\xfe\xc7\xd4\x83\xf7\xd9\x4c\x03\x88\xa8\x7a\x83\xcf\xe7\xc0\x03\x36\x6e\x29\x83\x3b\xed\xb8\x83\x02\x0b\x86\x83\x03\x13\xbc" }, { 9412, 2, 16, "\x01\x01\x83\x03\x88\xa6\x03\x02\x82\x8f\x03\x17\x82\xa2\x83\x11\x13\x03\x83\x2f\xa7\x88\x03\x20\xd1\xea\x83\x11\xb4\xe4\x83\x7f\xfe\x0e\x83\x11\xb4\xe4\x03\x20\xd1\xea\x83\x2f\xa7\x88\x83\x11\x13\x03\x03\x17\x82\xa2\x03\x02\x82\x8f\x83\x03\x88\xa6" }, { 9508, 2, 16, "\x01\x01\x83\x03\xc5\x07\x03\x0b\xc2\xde\x83\x20\x93\xa9\x03\x42\x42\x4f\x83\x6d\x73\x7c\x03\x9c\x4f\x88\x83\xc1\x29\x78\x03\xcb\xfb\x4c\x83\xc1\x29\x78\x03\x9c\x4f\x88\x83\x6d\x73\x7c\x03\x42\x42\x4f\x83\x20\x93\xa9\x03\x0b\xc2\xde\x83\x03\xc5\x07" }, { 9640, 2, 16, "\x01\x01\x03\x04\x1e\x0e\x83\x2c\x12\xa9\x03\x38\xb5\x5a\x83\x05\xfa\xef\x83\x1d\x62\x08\x83\x6c\x70\x02\x03\x5a\x5c\xac\x83\x0e\x54\xbe\x83\x5a\x5c\xac\x83\x6c\x70\x02\x03\x1d\x62\x08\x83\x05\xfa\xef\x83\x38\xb5\x5a\x83\x2c\x12\xa9\x83\x04\x1e\x0e" }, { 9832, 2, 18, "\x81\x01\x83\x04\xad\x45\x83\x02\xd4\xb0\x83\x17\x7d\x45\x03\x01\x76\x88\x83\x24\x3c\x45\x03\x09\x96\xeb\x03\x08\xf2\x1a\x03\x04\xb4\x38\x03\x33\xfe\x9a\x83\x04\xb4\x38\x03\x08\xf2\x1a\x83\x09\x96\xeb\x83\x24\x3c\x45\x83\x01\x76\x88\x83\x17\x7d\x45\x03\x02\xd4\xb0\x83\x04\xad\x45" }, { 10168, 2, 16, "\x01\x01\x83\x05\xd3\xc6\x03\x0a\xab\x89\x03\x17\x96\xb2\x83\x3b\x12\x0f\x83\x1b\x94\xc8\x03\x7c\x61\x3a\x02\xa9\xbc\x83\x85\x9c\xe6\x02\xa9\xbc\x03\x7c\x61\x3a\x83\x1b\x94\xc8\x83\x3b\x12\x0f\x03\x17\x96\xb2\x03\x0a\xab\x89\x83\x05\xd3\xc6" }, { 10312, 2, 16, "\x01\x01\x83\x06\x65\x61\x83\x03\xe2\x95\x83\x01\xfe\x84\x83\x19\x07\xe1\x83\x35\x25\xc9\x83\x62\x50\x26\x83\x98\xfb\xad\x83\x8b\xca\xdc\x83\x98\xfb\xad\x83\x62\x50\x26\x83\x35\x25\xc9\x83\x19\x07\xe1\x83\x01\xfe\x84\x83\x03\xe2\x95\x83\x06\x65\x61" }, { 10948, 2, 16, "\x01\x01\x83\x09\x93\xfe\x03\x77\xde\xc7\x84\x02\x5a\xd6\xc2\x04\x06\xbd\x40\x45\x84\x0d\x16\x8b\x9c\x04\x13\xa6\x69\x5a\x84\x18\xc9\xa1\xe0\x04\x1a\xd2\x1f\xba\x84\x18\xc9\xa1\xe0\x04\x13\xa6\x69\x5a\x84\x0d\x16\x8b\x9c\x04\x06\xbd\x40\x45\x84\x02\x5a\xd6\xc2\x03\x77\xde\xc7\x83\x09\x93\xfe" }, { 11512, 2, 16, "\x01\x01\x83\x0d\x91\xbe\x83\x8a\xd3\x2f\x84\x02\xaa\xf7\x16\x84\x08\x44\x68\xef\x84\x12\x5d\x6e\x58\x84\x1f\x5f\x32\xa6\x84\x2a\xcb\xa8\xc4\x84\x2f\x64\xa4\x16\x84\x2a\xcb\xa8\xc4\x84\x1f\x5f\x32\xa6\x84\x12\x5d\x6e\x58\x84\x08\x44\x68\xef\x84\x02\xaa\xf7\x16\x83\x8a\xd3\x2f\x83\x0d\x91\xbe" }, { 11608, 2, 18, "\x81\x01\x83\x0e\x62\xd4\x03\x19\x58\xa0\x83\x31\xbf\x4a\x03\x16\x6e\x00\x03\x50\xb8\x0c\x83\x78\xa6\x79\x83\x99\x95\x28\x03\xb1\x55\x20\x03\xd6\xf6\xbc\x83\xb1\x55\x20\x83\x99\x95\x28\x03\x78\xa6\x79\x03\x50\xb8\x0c\x83\x16\x6e\x00\x83\x31\xbf\x4a\x83\x19\x58\xa0\x83\x0e\x62\xd4" }, { 11848, 2, 16, "\x01\x01\x83\x10\xa1\xb1\x83\x4f\x11\x2d\x83\xce\x2a\x7c\x84\x01\x78\xf4\x21\x84\x02\x35\xf3\x71\x84\x02\xf7\x77\xd6\x84\x03\x69\x51\x75\x84\x03\x7b\x92\xdc\x84\x03\x69\x51\x75\x84\x02\xf7\x77\xd6\x84\x02\x35\xf3\x71\x84\x01\x78\xf4\x21\x83\xce\x2a\x7c\x83\x4f\x11\x2d\x83\x10\xa1\xb1" }, { 12772, 2, 16, "\x01\x01\x83\x1c\xb0\x20\x03\xdb\xa6\xcb\x84\x02\xed\xac\x28\x04\x05\x8d\xe9\x9d\x84\x05\x77\x9a\xe8\x83\x12\xf9\x12\x04\x08\x6f\xe1\x88\x84\x0c\x88\xf7\xfa\x04\x08\x6f\xe1\x88\x83\x12\xf9\x12\x84\x05\x77\x9a\xe8\x04\x05\x8d\xe9\x9d\x84\x02\xed\xac\x28\x03\xdb\xa6\xcb\x83\x1c\xb0\x20" }, { 12868, 2, 16, "\x01\x01\x83\x1e\x53\x27\x83\x37\x44\xb9\x83\x7d\x94\xdc\x83\x0c\xe0\xc1\x83\x50\x07\xab\x03\x4c\x85\x66\x84\x01\x25\xf7\x63\x83\x73\x11\xf8\x84\x01\x25\xf7\x63\x03\x4c\x85\x66\x83\x50\x07\xab\x83\x0c\xe0\xc1\x83\x7d\x94\xdc\x83\x37\x44\xb9\x83\x1e\x53\x27" }, { 13192, 2, 16, "\x01\x01\x83\x24\x84\x00\x84\x01\x0c\xdf\x82\x84\x03\x53\x46\x60\x84\x05\x18\x84\x9f\x84\x01\x5b\x27\xa0\x04\x0b\x34\x34\xfe\x04\x1b\x0d\x6e\x00\x04\x22\x7e\x66\x44\x04\x1b\x0d\x6e\x00\x04\x0b\x34\x34\xfe\x84\x01\x5b\x27\xa0\x84\x05\x18\x84\x9f\x84\x03\x53\x46\x60\x84\x01\x0c\xdf\x82\x83\x24\x84\x00" }, { 13288, 2, 16, "\x01\x01\x03\x26\x90\xaa\x83\x7d\x69\x41\x03\x60\x3c\xee\x83\x8c\x4d\x8f\x03\x1e\xdb\xe8\x03\x07\xd8\x9e\x03\x41\xa4\xe4\x83\xd2\x10\x8e\x83\x41\xa4\xe4\x03\x07\xd8\x9e\x83\x1e\xdb\xe8\x83\x8c\x4d\x8f\x83\x60\x3c\xee\x83\x7d\x69\x41\x83\x26\x90\xaa" }, { 14008, 2, 16, "\x01\x01\x83\x39\xba\x96\x03\x44\x04\xc9\x83\x51\xd6\x9e\x04\x01\x05\x67\xb1\x83\x14\xb9\xc8\x03\x88\xcc\x7a\x83\x9d\xe5\x64\x83\x8a\x72\x66\x83\x9d\xe5\x64\x03\x88\xcc\x7a\x83\x14\xb9\xc8\x04\x01\x05\x67\xb1\x83\x51\xd6\x9e\x03\x44\x04\xc9\x83\x39\xba\x96" }, }; #define NUM_CLASS_POLYS (sizeof(_class_poly_data)/sizeof(_class_poly_data[0])) Math-Prime-Util-GMP-0.52/t/0000755000175000017500000000000013674072603013602 5ustar danadanaMath-Prime-Util-GMP-0.52/t/02-can.t0000644000175000017500000000752613663067455014770 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Math::Prime::Util::GMP; use Test::More tests => 1; my @functions = qw( is_prime is_prob_prime is_bpsw_prime is_provable_prime is_provable_prime_with_cert is_aks_prime is_nminus1_prime is_nplus1_prime is_bls75_prime is_ecpp_prime is_pseudoprime is_euler_pseudoprime is_euler_plumb_pseudoprime is_strong_pseudoprime is_lucas_pseudoprime is_strong_lucas_pseudoprime is_extra_strong_lucas_pseudoprime is_almost_extra_strong_lucas_pseudoprime is_perrin_pseudoprime is_frobenius_pseudoprime is_frobenius_underwood_pseudoprime is_frobenius_khashin_pseudoprime is_mersenne_prime is_llr_prime is_proth_prime is_miller_prime miller_rabin_random lucas_sequence lucasu lucasv primes sieve_primes sieve_twin_primes sieve_prime_cluster sieve_range next_prime prev_prime surround_primes trial_factor prho_factor pbrent_factor pminus1_factor pplus1_factor holf_factor squfof_factor ecm_factor qs_factor factor divisors sigma chinese moebius prime_count prime_count_lower prime_count_upper primorial pn_primorial factorial subfactorial multifactorial factorial_sum factorialmod consecutive_integer_lcm partitions bernfrac bernreal harmfrac harmreal stirling zeta li ei riemannr lambertw addreal subreal mulreal divreal logreal expreal powreal rootreal agmreal gcd lcm kronecker valuation binomial gcdext hammingweight invmod sqrtmod addmod mulmod divmod powmod vecsum vecprod exp_mangoldt liouville totient jordan_totient carmichael_lambda sqrtint rootint logint powint mulint addint divint modint divrem tdivrem is_power is_prime_power is_semiprime is_square is_carmichael is_fundamental is_totient is_primitive_root is_polygonal polygonal_nth znorder znprimroot ramanujan_tau Pi Euler todigits random_prime random_nbit_prime random_ndigit_prime random_safe_prime random_strong_prime random_maurer_prime random_shawe_taylor_prime random_maurer_prime_with_cert random_shawe_taylor_prime_with_cert seed_csprng is_csprng_well_seeded irand irand64 drand urandomb urandomm urandomr random_bytes permtonum numtoperm ); can_ok( 'Math::Prime::Util::GMP', @functions); Math-Prime-Util-GMP-0.52/t/26-mod.t0000644000175000017500000001152613663067455015007 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/invmod sqrtmod addmod mulmod divmod powmod/; use Math::BigInt; # Don't use GMP so we don't have to work around bug my $use64 = (~0 > 4294967296 && 18446744073709550592 != ~0); my $extra = defined $ENV{EXTENDED_TESTING} && $ENV{EXTENDED_TESTING}; my @invmods = ( [ 0, 0, undef], [ 1, 0, undef], [ 0, 1, undef], [ 1, 1, 0], [ 45, 59, 21], [ 42, 2017, 1969], [ 42, -2017, 1969], [ -42, 2017, 48], [ -42, -2017, 48], [ 14, 28474, undef], [ 13, "9223372036854775808", "5675921253449092805" ], [ 14, "18446744073709551615", "17129119497016012214" ], ); my @sqrtmods = ( [ 0, 0, undef], [ 1, 0, undef], [ 0, 1, 0], [ 1, 1, 0], [ 58, 101, 19], [ 111, 113, 26], [ "9223372036854775808", "5675921253449092823", "22172359690642254" ], [ "18446744073709551625", "340282366920938463463374607431768211507", "57825146747270203522128844001742059051" ], ); plan tests => 0 + scalar(@invmods) + scalar(@sqrtmods) + 4 + 3 + 1 # addmod + 1 # submod + 2 # mulmod + 2 # divmod + 2 # powmod + 0; ###### invmod foreach my $r (@invmods) { my($a, $n, $exp) = @$r; is( invmod($a,$n), $exp, "invmod($a,$n) = ".((defined $exp)?$exp:"") ); } ###### sqrtmod foreach my $r (@sqrtmods) { my($a, $n, $exp) = @$r; is( sqrtmod($a,$n), $exp, "sqrtmod($a,$n) = ".((defined $exp)?$exp:"") ); } ########################################################################## my $num = ($extra) ? 199 : 39; my @i1 = map { nrand() } 0 .. $num; my @i2 = map { nrand() } 0 .. $num; my @i2t= map { $i2[$_] >> 1 } 0 .. $num; my @i3 = map { my $r = 0; $r = nrand() until $r > 1; $r; } 0 .. $num; my(@exp,@res); ###### add/mul/div/pow with small arguments @exp = map { undef } 0..27; is_deeply([map { addmod($_ & 3, ($_>>2)-3, 0) } 0..27], \@exp, "addmod(..,0)"); is_deeply([map { mulmod($_ & 3, ($_>>2)-3, 0) } 0..27], \@exp, "mulmod(..,0)"); is_deeply([map { divmod($_ & 3, ($_>>2)-3, 0) } 0..27], \@exp, "divmod(..,0)"); is_deeply([map { powmod($_ & 3, ($_>>2)-3, 0) } 0..27], \@exp, "powmod(..,0)"); @exp = map { 0 } 0..27; is_deeply([map { addmod($_ & 3, ($_>>2)-3, 1) } 0..27], \@exp, "addmod(..,1)"); is_deeply([map { mulmod($_ & 3, ($_>>2)-3, 1) } 0..27], \@exp, "mulmod(..,1)"); is_deeply([map { powmod($_ & 3, ($_>>2)-3, 1) } 0..27], \@exp, "powmod(..,1)"); # TODO divmod ###### addmod @exp = (); @res = (); for (0 .. $num) { push @exp, Math::BigInt->new($i1[$_])->badd($i2[$_])->bmod($i3[$_]); push @res, addmod($i1[$_], $i2[$_], $i3[$_]); } is_deeply( \@res, \@exp, "addmod on ".($num+1)." random inputs" ); ###### submod @exp = (); @res = (); for (0 .. $num) { push @exp, Math::BigInt->new($i1[$_])->bsub($i2t[$_])->bmod($i3[$_]); push @res, addmod($i1[$_], -$i2t[$_], $i3[$_]); } is_deeply( \@res, \@exp, "addmod with negative second input on ".($num+1)." random inputs" ); ###### mulmod @exp = (); @res = (); for (0 .. $num) { push @exp, Math::BigInt->new($i1[$_])->bmul($i2[$_])->bmod($i3[$_]); push @res, mulmod($i1[$_], $i2[$_], $i3[$_]); } is_deeply( \@res, \@exp, "mulmod on ".($num+1)." random inputs" ); ###### mulmod (neg) @exp = (); @res = (); for (0 .. $num) { push @exp, Math::BigInt->new($i1[$_])->bmul(-$i2t[$_])->bmod($i3[$_]); push @res, mulmod($i1[$_], -$i2t[$_], $i3[$_]); } is_deeply( \@res, \@exp, "mulmod with negative second input on ".($num+1)." random inputs" ); ###### divmod @exp = (); @res = (); for (0 .. $num) { push @exp, Math::BigInt->new($i2[$_])->bmodinv($i3[$_])->bmul($i1[$_])->bmod($i3[$_]); push @res, divmod($i1[$_], $i2[$_], $i3[$_]); } @exp = map { $_->is_nan() ? undef : $_ } @exp; is_deeply( \@res, \@exp, "divmod on ".($num+1)." random inputs" ); ###### divmod (neg) @exp = (); @res = (); for (0 .. $num) { push @exp, Math::BigInt->new(-$i2t[$_])->bmodinv($i3[$_])->bmul($i1[$_])->bmod($i3[$_]); push @res, divmod($i1[$_], -$i2t[$_], $i3[$_]); } @exp = map { $_->is_nan() ? undef : $_ } @exp; is_deeply( \@res, \@exp, "divmod with negative second input on ".($num+1)." random inputs" ); my $pnum = int($num/2); ###### powmod @exp = (); @res = (); for (0 .. $pnum) { push @exp, Math::BigInt->new($i1[$_])->bmodpow($i2[$_],$i3[$_]); push @res, powmod($i1[$_], $i2[$_], $i3[$_]); } is_deeply( \@res, \@exp, "powmod on ".($pnum+1)." random inputs" ); ###### powmod (neg) @exp = (); @res = (); for (0 .. $pnum) { push @exp, Math::BigInt->new($i1[$_])->bmodpow(-$i2t[$_],$i3[$_]); push @res, powmod($i1[$_], -$i2t[$_], $i3[$_]); } @exp = map { $_->is_nan() ? undef : $_ } @exp; is_deeply( \@res, \@exp, "powmod with negative exponent on ".($pnum+1)." random inputs" ); sub nrand { return Math::Prime::Util::GMP::urandomb($use64 ? 64 : 32); } Math-Prime-Util-GMP-0.52/t/26-ismisc.t0000644000175000017500000000643413666454641015521 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/is_carmichael is_fundamental is_totient is_gaussian_prime is_polygonal polygonal_nth/; plan tests => 0 + 3 # is_carmichael + 4 # is_fundamental + 8 # is_gaussian_prime + 9 # is_totient + 4 # is_polygonal + 0; ###### is_carmichael is_deeply( [grep { is_carmichael($_) } 1 .. 20000], [561,1105,1729,2465,2821,6601,8911,10585,15841], "Carmichael numbers to 20000" ); ok( is_carmichael("1298392318741906953539071949881"), "Large Carmichael" ); ok( is_carmichael("341627175004511735787409078802107169251"), "Larger Carmichael" ); ###### is_fundamental is_deeply( [grep { is_fundamental($_) } -50 .. 0], [-47,-43,-40,-39,-35,-31,-24,-23,-20,-19,-15,-11,-8,-7,-4,-3], "is_fundamental(-50 .. 0)" ); is_deeply( [grep { is_fundamental($_) } 0 .. 50], [1,5,8,12,13,17,21,24,28,29,33,37,40,41,44], "is_fundamental(0 .. 50)" ); is( is_fundamental("147573952589676412937"), 1, "is_fundamental(2^67+9)" ); is( is_fundamental("-147573952589676412884"), 1, "is_fundamental(-2^67+44)" ); ###### is_totient is_deeply( [map { is_totient($_) } 0..40], [0,1,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1], "is_totient 0 .. 40" ); is_deeply( [grep { is_totient( 2**29 + $_ ) } 1 .. 80], [4,10,12,16,32,38,48,64,68,72], "is_fundamental(2^29_1 .. 2^29+80)" ); is( is_totient("9223372036854775836"), 1, "is_totient(2^63+28)" ); is( is_totient("9223372036854775828"), 1, "is_totient(2^63+20)" ); is( is_totient("9223372036854775832"), 0, "is_totient(2^63+24)" ); is( is_totient("9671406556917033397649496"), 1, "is_totient(2^83+88)" ); is( is_totient("9671406556917033397649458"), 0, "is_totient(2^83+50)" ); is( is_totient("9671406556917033397649472"), 1, "is_totient(2^83+64)" ); is( is_totient("1237940039285380274899124224"), 1, "is_totient(2^90)" ); ###### is_gaussian_prime ok( !is_gaussian_prime(29,0), "29 is not a Gaussian Prime" ); ok( is_gaussian_prime(31,0), "31 is a Gaussian Prime" ); ok( !is_gaussian_prime(0,-29), "0-29i is not a Gaussian Prime" ); ok( is_gaussian_prime(0,-31), "0-31i is a Gaussian Prime" ); ok( is_gaussian_prime("113935449173347223991024360434046986411","627493285926801435052159379234172381650"), "large +,+ Gaussian prime" ); ok( is_gaussian_prime("-290396075282846913855817435503353843926","659140811346340744116053113232015528641"), "large -,+ Gaussian prime" ); ok( !is_gaussian_prime("873384195388776562411637","22046886918736165736188"), "large +,+ Gaussian composite" ); ok( !is_gaussian_prime("678713103733782152987023","-66834001678101266508984"), "large +,- Gaussian composite" ); ###### is_polygonal is_deeply( [grep { is_polygonal($_,3) } 1..55], [1,3,6,10,15,21,28,36,45,55], "first 10 triangular numbers" ); is_deeply( [grep { is_polygonal($_,23) } 1..955], [1,23,66,130,215,321,448,596,765,955], "first 10 23-gonal numbers" ); is( polygonal_nth("140737496743936",3), 16777216, "140737496743936 is the 16777216-th triangular number"); is( polygonal_nth("228623681298582551246684960361911294205",5), "12345678901234567890", "identified the 12345678901234567890-th pentagonal number"); Math-Prime-Util-GMP-0.52/t/11-primes.t0000644000175000017500000001620713025437621015506 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/primes sieve_twin_primes sieve_primes sieve_range/; plan tests => 12 + 12 + 1 + 19 + 1 + 1 + 13*1 + 2 + 2; ok(!eval { primes(undef); }, "primes(undef)"); ok(!eval { primes("a"); }, "primes(a)"); ok(!eval { primes(-4); }, "primes(-4)"); ok(!eval { primes(2,undef); }, "primes(2,undef)"); ok(!eval { primes(2,'x'); }, "primes(2,x)"); ok(!eval { primes(2,-4); }, "primes(2,-4)"); ok(!eval { primes(undef,7); }, "primes(undef,7)"); ok(!eval { primes('x',7); }, "primes(x,7)"); ok(!eval { primes(-10,7); }, "primes(-10,7)"); ok(!eval { primes(undef,undef); }, "primes(undef,undef)"); ok(!eval { primes('x','x'); }, "primes(x,x)"); ok(!eval { primes(-10,-4); }, "primes(-10,-4)"); my @small_primes = qw/ 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997 1009 1013 1019 1021 1031 1033 1039 1049 1051 1061 1063 1069 1087 1091 1093 1097 1103 1109 1117 1123 1129 1151 1153 1163 1171 1181 1187 1193 1201 1213 1217 1223 1229 1231 1237 1249 1259 1277 1279 1283 1289 1291 1297 1301 1303 1307 1319 1321 1327 1361 1367 1373 1381 1399 1409 1423 1427 1429 1433 1439 1447 1451 1453 1459 1471 1481 1483 1487 1489 1493 1499 1511 1523 1531 1543 1549 1553 1559 1567 1571 1579 1583 1597 1601 1607 1609 1613 1619 1621 1627 1637 1657 1663 1667 1669 1693 1697 1699 1709 1721 1723 1733 1741 1747 1753 1759 1777 1783 1787 1789 1801 1811 1823 1831 1847 1861 1867 1871 1873 1877 1879 1889 1901 1907 1913 1931 1933 1949 1951 1973 1979 1987 1993 1997 1999 2003 2011 2017 2027 2029 2039 2053 2063 2069 2081 2083 2087 2089 2099 2111 2113 2129 2131 2137 2141 2143 2153 2161 2179 2203 2207 2213 2221 2237 2239 2243 2251 2267 2269 2273 2281 2287 2293 2297 2309 2311 2333 2339 2341 2347 2351 2357 2371 2377 2381 2383 2389 2393 2399 2411 2417 2423 2437 2441 2447 2459 2467 2473 2477 2503 2521 2531 2539 2543 2549 2551 2557 2579 2591 2593 2609 2617 2621 2633 2647 2657 2659 2663 2671 2677 2683 2687 2689 2693 2699 2707 2711 2713 2719 2729 2731 2741 2749 2753 2767 2777 2789 2791 2797 2801 2803 2819 2833 2837 2843 2851 2857 2861 2879 2887 2897 2903 2909 2917 2927 2939 2953 2957 2963 2969 2971 2999 3001 3011 3019 3023 3037 3041 3049 3061 3067 3079 3083 3089 3109 3119 3121 3137 3163 3167 3169 3181 3187 3191 3203 3209 3217 3221 3229 3251 3253 3257 3259 3271 3299 3301 3307 3313 3319 3323 3329 3331 3343 3347 3359 3361 3371 3373 3389 3391 3407 3413 3433 3449 3457 3461 3463 3467 3469 3491 3499 3511 3517 3527 3529 3533 3539 3541 3547 3557 3559 3571 /; my %small_single = ( 0 => [], 1 => [], 2 => [2], 3 => [2, 3], 4 => [2, 3], 5 => [2, 3, 5], 6 => [2, 3, 5], 7 => [2, 3, 5, 7], 11 => [2, 3, 5, 7, 11], 18 => [2, 3, 5, 7, 11, 13, 17], 19 => [2, 3, 5, 7, 11, 13, 17, 19], 20 => [2, 3, 5, 7, 11, 13, 17, 19], ); while (my($high, $expect) = each (%small_single)) { is_deeply( primes($high), $expect, "primes($high) should return [@{$expect}]"); } my %small_range = ( "3 to 9" => [3,5,7], "2 to 20" => [2,3,5,7,11,13,17,19], "30 to 70" => [31,37,41,43,47,53,59,61,67], "70 to 30" => [], "20 to 2" => [], "2 to 2" => [2], "3 to 3" => [3], "2 to 3" => [2,3], "2 to 5" => [2,3,5], "3 to 6" => [3,5], "3 to 7" => [3,5,7], "4 to 8" => [5,7], "2010733 to 2010881" => [2010733,2010881], "2010734 to 2010880" => [], "3088 to 3164" => [3089,3109,3119,3121,3137,3163], "3089 to 3163" => [3089,3109,3119,3121,3137,3163], "3090 to 3162" => [3109,3119,3121,3137], "3842610773 to 3842611109" => [3842610773,3842611109], "3842610774 to 3842611108" => [], ); while (my($range, $expect) = each (%small_range)) { my($low,$high) = $range =~ /(\d+) to (\d+)/; is_deeply( primes($low, $high), $expect, "primes($low,$high) should return [@{$expect}]"); } is_deeply( primes('1693182318746371', '1693182318747671'), [qw/1693182318746371 1693182318747503 1693182318747523 1693182318747553 1693182318747583 1693182318747613 1693182318747631 1693182318747637/], "Primes between 1_693_182_318_746_371 and 1_693_182_318_747_671"); is_deeply( primes('73786976294838206464', '73786976294838206564'), ['73786976294838206473','73786976294838206549'], "primes( 2^66, 2^66 + 100 )" ); is( scalar @{primes(474973,538390)}, 44454 - 39617, "count primes within a range" ); { is_deeply( primes(0, 3572), \@small_primes, "Primes between 0 and 3572" ); is_deeply( primes(2, 20), [2,3,5,7,11,13,17,19], "Primes between 2 and 20" ); is_deeply( primes(30, 70), [31,37,41,43,47,53,59,61,67], "Primes between 30 and 70" ); is_deeply( primes(30, 70), [31,37,41,43,47,53,59,61,67], "Primes between 30 and 70" ); is_deeply( primes(20, 2), [], "Primes between 20 and 2" ); is_deeply( primes(1, 1), [], "Primes between 1 and 1" ); is_deeply( primes(2, 2), [2], "Primes between 2 and 2" ); is_deeply( primes(3, 3), [3], "Primes between 3 and 3" ); is_deeply( primes(2010733, 2010733+148), [2010733,2010733+148], "Primegap 21 inclusive" ); is_deeply( primes(2010733+1, 2010733+148-2), [], "Primegap 21 exclusive" ); is_deeply( primes(3088, 3164), [3089,3109,3119,3121,3137,3163], "Primes between 3088 and 3164" ); is_deeply( primes(3089, 3163), [3089,3109,3119,3121,3137,3163], "Primes between 3089 and 3163" ); is_deeply( primes(3090, 3162), [3109,3119,3121,3137], "Primes between 3090 and 3162" ); } is_deeply( [sieve_primes(1e6,1e6+100,100)], [qw/1000001 1000003 1000009 1000033 1000037 1000039 1000049 1000079 1000081 1000099/], "use sieve_primes to partial sieve a range" ); is_deeply( [sieve_range('6295609118348014841031009747805006052065816763110427',3204+1,3e6)], [qw/0 32 42 54 62 72 134 152 204 224 236 240 254 300 314 342 432 512 530 620 650 666 702 704 720 732 786 806 834 846 926 936 980 986 1014 1022 1034 1050 1080 1112 1122 1142 1170 1194 1206 1230 1274 1292 1296 1334 1374 1376 1422 1470 1476 1506 1530 1544 1574 1586 1632 1674 1686 1752 1772 1836 1842 1890 1902 1932 1946 1976 1986 1994 2030 2042 2060 2064 2100 2102 2136 2172 2244 2246 2276 2312 2346 2360 2370 2396 2424 2462 2490 2504 2532 2552 2610 2640 2700 2702 2760 2772 2790 2832 2886 2930 2942 2982 2996 3026 3042 3060 3092 3164 3204/], "use sieve_range to sieve a large range" ); is_deeply( [sieve_twin_primes("1000000000000000000000000000000","1000000000000000000000000020000")], [qw/1000000000000000000000000001681 1000000000000000000000000004831 1000000000000000000000000018739 1000000000000000000000000019171/], "Sieve twin primes 10^30 10^30+20000"); is_deeply( [sieve_twin_primes("1000000000000000000000000004832","1000000000000000000000000018738")], [], "Sieve twin primes 10^30+4832 10^20+18738 should be empty"); Math-Prime-Util-GMP-0.52/t/26-lambertw.t0000644000175000017500000001610413670136647016040 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/lambertw/; my $extra = defined $ENV{EXTENDED_TESTING} && $ENV{EXTENDED_TESTING}; # gp: \p 47 for(s=1,20,print(lambertw(s/10))) my @lambertw_pos = (qw/ 0.09127652716086226429989572142317956865311922405 0.16891597349910956511647490370581839872844691351 0.23675531078855931687136699131310225298500760689 0.29716775067313854677972696224702134190445810155 0.35173371124919582602490930092995106517146421552 0.40156363678707259466266645379468368662300271601 0.44747025926965500617391369569828820651642372589 0.49006785880157985805409310369058536690518633813 0.52983296563343441213336643954546304857788132270 0.56714329040978387299996866221035554975381578719 0.60230368332423955208141907724781646834018621903 0.63556401636486979588897480666234039281174569563 0.66713184636145511027696303054764416118395622349 0.69718159736485477728463015090916650398040286448 0.72586135776622625704868939927630687970616284950 0.75329800360236163905533048094198675280489216776 0.77960112253110087767947544014073352010915631650 0.80486606240915653539311916942960487067684752791 0.82917633026584003370043580096721870716384212825 0.85260550201372549134647241469531746689845330015 /); # mpu 'say Math::Prime::Util::GMP::lambertw(-$_/100,60) for 1..36;' my @lambertw_neg = (qw/ -.010101527198538753272920187671386239736709039934752358772907 -.020412444055807667259736053907495480041586124956473882211299 -.030942794982848179397910380656115249172758969601628633107179 -.041703408436484473898727338125539767862560100379397457601264 -.052705983551546347959956506179157212894276743965923951598612 -.063963189356172510195294981801688674563926410493711618670952 -.075488778865792205919339159557966811535249322283339165083946 -.087297720861579924040919758660273139926487733500100982854449 -.099406352804544814743535671867866210578206253549365520218783 -.111832559158962964833569456820265842272645362291265863329690 -.124595980455726657756666719621079053135793152710793891521622 -.137718259795895797448508164728412292161457597778234624620631 -.151223335286407083128449581782332753827082968266648724409332 -.165137789266952660984667476981335345353363106097517166766420 -.179491268347984733616995619377229799755123368660617667934835 -.194316992550129530626780651886669951304286727951478697660929 -.209652377677375752685411045492259182117234133891279509923664 -.225539803158920852052247756445805821494725010063047182583317 -.242027569001518737785833894572663806870009909839476525157284 -.259171101819073745056651950215406705713588339700893703221839 -.277034493696194227740540864940868823319654245584378425221794 -.295692493013839673188241480334100976626740236332783148583977 -.315233120146138643576596973887403298103005446463709766170537 -.335761164788902751728680758230526223662054745950766593456372 -.357402956181388903068811104055904753316590555076012043627620 -.380313020330171115830396535587815630136987739456240325380691 -.404683621605071865364325005647866585793186609324244936619702 -.430758874527112757916530656841372138819645982270515538512158 -.458856413481802088194570741325926714770279841019865124786075 -.489402227180214969036231251996293368923410006016359034511466 -.522989949627320353102183624081467090128630010624958933652258 -.560489483078455574363484050411654565701879066488752753655891 -.603266649755133050529005017751062680519867283347993925372013 -.653694501269089483159799753113833884316246499410359482443376 -.716638816456073850588169800003865040611057570138505526161434 -.806084315970817778285521361620992001997459968346671301630487 /); plan tests => 1 + 1 + 2 + 1 + 9 + 1 + 4 + 0; # Zero like(lambertw(0),qr/^(0|0\.0*|\.0+)$/,"LambertW(0) = 0"); # Small near 0 is_deeply( [map { lambertw($_/10,47) } 1 .. 20], [ map { my $v=$_; $v =~ s/^0\./\./; $v; } @lambertw_pos ], "LambertW(0.1, 0.2, ..., 2.0) with 47 digits" ); # Large is(lambertw(567.88,200), '4.7779074500898520857566786498941386921081437132046838176277373693328027204872327756806561733378322233740589247715164285350377396936983330158336745859018884955805599964831794364022417460679608626400255', "LambertW(567.88,200)"); is(lambertw(1e6,200), '11.383358086140052622000156781585004289033774706018865121432386106268986107680188677977093154937176497608379627334858730713524631040595012365827453723027024771329429880161761665512493723379590114648319', "LambertW(1e6,200)"); # Negative is_deeply( [map { lambertw(-$_/100,60) } 1 .. 36], \@lambertw_neg, "LambertW(-0.01, -0.02, ..., -0.36) with 60 digits" ); is(lambertw(-0.367,60),"-.932399184747928483716466190879357208467147999295610926409585", "LambertW(-1/e 3 dig)"); is(lambertw(-0.3678,60),"-.979360714957828477476184443488648168605594922954737936799275", "LambertW(-1/e 4 dig)"); is(lambertw(-0.36787,60),"-.992852729821537244347936437425679636289281963248559781988806", "LambertW(-1/e 5 dig)"); is(lambertw(-0.367879,60), "-.998452103780727259318294980306402273168568357748510198614929",, "LambertW(-1/e 6 dig)"); is(lambertw(-0.3678794,60), "-.999526966607568126260639553879986677897888242792523379259623", "LambertW(-1/e 7 dig)"); is(lambertw(-0.36787944,60), "-.999920198484083397218223112707340646977607183717479410260892", "LambertW(-1/e 8 dig)"); is(lambertw(-0.367879441,60), "-.999969470700548827401043484208206713552686883880847602595116", "LambertW(-1/e 9 dig)"); is(lambertw(-0.3678794411,60), "-.999980292244517017881635617805970344624605830260329876659669", "LambertW(-1/e 10 dig)"); is(lambertw(-0.36787944117,60), "-.999997199775271588621133996800710268311896978469564842091958", "LambertW(-1/e 11 dig)"); is(lambertw("-0.3678794411714423215955237701614608674458111310317678345078368016974614957",100), "-.9999999999999999999999999999999999995059345801068083846704911383511891531411739090792786439206362436", "LambertW(-1/e 73 dig)"); ###### is(lambertw("-0.367879441171443",60), "-1.00000000000000000000000000000000000000000000000000000000000", "LambertW(-1/e - 1e-15 dig) returns -1 without breaking"); is(lambertw("0.00000000000000000001",40), ".0000000000000000000099999999999999999999", "LambertW(1e-20,40)"); is(lambertw("0.00000000000000000001",420), ".000000000000000000009999999999999999999900000000000000000001499999999999999999973333333333333333333854166666666666666655866666666666666666900097222222222222217020952380952380952499577604166666666663910934744268077601475913461502425044090159597857944524611228692354974116996685530680861459528126217117169972234727628521830948376224989995284624307889124814445801797404570553660968546276488076412391640470262269859307100029", "LambertW(1e-20,420)"); is(lambertw("-0.00000000000000000001",420), "-.000000000000000000010000000000000000000100000000000000000001500000000000000000026666666666666666667187500000000000000010800000000000000000233430555555555555560756825396825396825515450620039682539685295414462081128747860393179315476190477741636709956709956747371206986302342206030432921876477432055311897055850700134485297138116940868277300472461303415795557192464848950959136923353074743365175425437840081247801716351284", "LambertW(-1e-20,420)"); Math-Prime-Util-GMP-0.52/t/26-int.t0000644000175000017500000001350113663067455015015 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/powint mulint addint subint divint modint divrem tdivrem absint negint/; use Math::BigInt; # Don't use GMP so we don't have to work around bug my $use64 = (~0 > 4294967296 && 18446744073709550592 != ~0); my $extra = defined $ENV{EXTENDED_TESTING} && $ENV{EXTENDED_TESTING}; my @powints = ( [5, 6, 15625], [2, 16, 65536], ); my @mulints = ( ["13282407956253574712","14991082624209354397","199117675120653046511338473800925208664"], ); my @addints = ( ["1178630961471601951655862","827639478068904540012","1179458600949670856195874"], ["-2555488174170453670799","1726145541361106236340","-829342632809347434459"], ); my @subints = ( ["68719214592","281474976448512","-281406257233920"], ["38631281077","12191281349924010278","-12191281311292729201"], ["-38631281077","12191281349924010278","-12191281388555291355"], ["-38631281077","-12191281349924010278","12191281311292729201"], ["9686117847286759","419039659798583","9267078187488176"], ["14888606332669627740937300680965976203","14888605897080617527808122501731945103","435589010213129178179234031100"], ); my @quotients = ( # trunc, floor, euclidian ["+ +", "39458349850349850394853049583049", "85889", "459410982202026457344398579", "459410982202026457344398579", "459410982202026457344398579"], ["+ -", "39458349850349850394853049583049", "-85889", "-459410982202026457344398579", "-459410982202026457344398580", "-459410982202026457344398579"], ["- +", "-39458349850349850394853049583049", "85889", "-459410982202026457344398579", "-459410982202026457344398580", "-459410982202026457344398580"], ["- -", "-39458349850349850394853049583049", "-85889", "459410982202026457344398579", "459410982202026457344398579", "459410982202026457344398580"], ); plan tests => 0 + 7*4 + scalar(@powints) + 2 # powint + 1 + scalar(@mulints) # mulint + 1 + scalar(@addints) # addint + 1 + scalar(@subints) # subint + 2 + 2 # divint + 2 + 2 # modint + 2 # divrem + 2 # tdivrem + 4 * scalar(@quotients) # signed bigint division + 1 # absint + 1 # negint + 0; ###### powint for my $a (-3 .. 3) { is(powint($a, 0), 1, "powint($a,0) = 1"); is(powint($a, 1), $a, "powint($a,1) = $a"); is(powint($a, 2), $a*$a, "powint($a,2) = " . $a*$a); is(powint($a, 3), $a*$a*$a, "powint($a,3) = " . $a*$a*$a); } foreach my $r (@powints) { my($a, $b, $exp) = @$r; is( powint($a,$b), $exp, "powint($a,$b) = ".((defined $exp)?$exp:"") ); } is(powint(powint(2,32),3),"79228162514264337593543950336","(2^32)^3"); is(powint(3,powint(2,7)),"11790184577738583171520872861412518665678211592275841109096961","3^(2^7)"); ###### mulint { my(@got,@exp); for my $a (-3 .. 3) { for my $b (-3 .. 3) { push @got, mulint($a,$b); push @exp, $a*$b; } } is_deeply( \@got, \@exp, "mulint( -3 .. 3, -3 .. 3)" ); } foreach my $r (@mulints) { my($a, $b, $exp) = @$r; is( mulint($a,$b), $exp, "mulint($a,$b) = ".((defined $exp)?$exp:"") ); } ###### addint { my(@got,@exp); for my $a (-3 .. 3) { for my $b (-3 .. 3) { push @got, addint($a,$b); push @exp, $a+$b; } } is_deeply( \@got, \@exp, "addint( -3 .. 3, -3 .. 3)" ); } foreach my $r (@addints) { my($a, $b, $exp) = @$r; is( addint($a,$b), $exp, "addint($a,$b) = ".((defined $exp)?$exp:"") ); } ###### subint { my(@got,@exp); for my $a (-3 .. 3) { for my $b (-3 .. 3) { push @got, subint($a,$b); push @exp, $a-$b; } } is_deeply( \@got, \@exp, "subint( -3 .. 3, -3 .. 3)" ); } foreach my $r (@subints) { my($a, $b, $exp) = @$r; is( subint($a,$b), $exp, "subint($a,$b) = ".((defined $exp)?$exp:"") ); } ###### divint ok(!eval { divint(0,0); }, "divint(1,0)"); ok(!eval { divint(1,0); }, "divint(1,0)"); # For negative inputs, the div and mod operations might be different than Perl's builtins. # It matches Math::BigInt bdiv / bmod (post 1.997 Sep 2015). my @qpos1024 = map { int(1024/$_) } 1 .. 1025; my @qneg1024 = map { my $d=-1024/$_; my $i = int($d); ($d==$i) ? $i : $i-1; } 1 .. 1025; my @rpos1024 = map { 1024 - $_ * $qpos1024[$_-1] } 1 .. 1025; my @rneg1024 = map { -1024 - $_ * $qneg1024[$_-1] } 1 .. 1025; is_deeply( [map { divint(1024,$_) } 1..1025], \@qpos1024, "divint(1024,x) for 1 .. 1025" ); is_deeply( [map { divint(-1024,$_) } 1..1025], \@qneg1024, "divint(-1024,x) for 1 .. 1025" ); ###### modint ok(!eval { modint(0,0); }, "modint(1,0)"); ok(!eval { modint(1,0); }, "modint(1,0)"); is_deeply( [map { modint(1024,$_) } 1..1025], \@rpos1024, "modint(1024,x) for 1 .. 1025" ); is_deeply( [map { modint(-1024,$_) } 1..1025], \@rneg1024, "modint(-1024,x) for 1 .. 1025" ); ###### divrem ok(!eval { divrem(0,0); }, "divrem(1,0)"); ok(!eval { divrem(1,0); }, "divrem(1,0)"); ###### tdivrem ok(!eval { tdivrem(0,0); }, "tdivrem(1,0)"); ok(!eval { tdivrem(1,0); }, "tdivrem(1,0)"); ###### large values through divint, modint, divrem, tdivrem for my $s (@quotients) { my($signs, $n, $m, $qt, $qf, $qe) = @$s; my($bn,$bm) = map { Math::BigInt->new($_) } ($n,$m); my($rt, $rf, $re) = map { $bn - $bm * $_ } ($qt, $qf, $qe); is( divint($n, $m), $qf, "large divint $signs" ); is( modint($n, $m), $rf, "large modint $signs" ); is_deeply( [divrem($n, $m)], [$qe, $re], "large divrem $signs" ); is_deeply( [tdivrem($n, $m)], [$qt, $rt], "large tdivrem $signs" ); } ###### absint is_deeply([map { absint($_) } -9..9], [map { abs($_) } -9..9], "absint(-9..9)"); ###### negint is_deeply([map { negint($_) } -9..9], [map { -$_ } -9..9], "negint(-9..9)"); Math-Prime-Util-GMP-0.52/t/13-primecount.t0000644000175000017500000001711013663067455016404 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/prime_count prime_count_lower prime_count_upper/; my %pivals = ( 1 => 0, 10 => 4, 100 => 25, 1000 => 168, 10000 => 1229, 65535 => 6542, ); # Generated with: # perl -Mbigint -MMath::Prime::Util -E 'foreach my $e (64 .. 120) { my $start = 2**$e + int(rand(2**($e-1))); my $end = $start + int(rand(2000)); my $c = Math::Prime::Util::PP::prime_count($start, $end); say " [\"$start\", \"$end\", $c]," }' my @tests = ( ["24113483758197309440", "24113483758197310396", 23], ["45490240575506677760", "45490240575506679266", 45], ["75458848506302300160", "75458848506302301114", 18], ["161891136728481923072", "161891136728481923850", 18], ["342679779996280025856", "342679779996280027487", 36], ["759817770139002651712", "759817770139002652700", 26], ["1747599191389174303424", "1747599191389174303464", 1], ["3277252439479060606848", "3277252439479060607688", 12], ["6887003433586725213696", "6887003433586725213705", 0], ["9515645314265862127392", "9515645314265862128163", 15], ["26114788673620260854784", "26114788673620260855763", 17], ["50021095190478561709568", "50021095190478561710552", 16], ["99293609391529723419136", "99293609391529723420902", 20], ["192328541043198946838272", "192328541043198946839023", 18], ["386730387965240293676544", "386730387965240293678117", 29], ["735479117913496587353088", "735479117913496587354687", 32], ["1330998807397722174706176", "1330998807397722174706347", 3], ["2904510561226220349412352", "2904510561226220349413930", 21], ["6847845859597286698824704", "6847845859597286698826460", 26], ["9880100064397462397649408", "9880100064397462397650566", 17], ["27282839498809356795298816", "27282839498809356795300564", 23], ["41281035060688503590597632", "41281035060688503590598867", 15], ["90374604407955267181195264", "90374604407955267181195457", 2], ["200915297903707834362390528", "200915297903707834362391737", 22], ["407168505212786768724781056", "407168505212786768724782199", 16], ["817226365950024137449562112", "817226365950024137449563070", 14], ["1621795554319024274899124224", "1621795554319024274899125678", 18], ["3660769329531840549798248448", "3660769329531840549798250278", 23], ["7314734077273801099596496896", "7314734077273801099596498034", 16], ["10921064834678012199192993792", "10921064834678012199192994171", 5], ["24344155473536054398385987584", "24344155473536054398385988831", 14], ["46348470312928428796771975168", "46348470312928428796771976813", 28], ["90920702154966737593543950336", "90920702154966737593543951561", 19], ["233651247954773375187087900672", "233651247954773375187087901872", 16], ["396231658265327350374175801344", "396231658265327350374175803015", 25], ["734317226076915700748351602688", "734317226076915700748351602878", 0], ["1696551122155337401496703205376", "1696551122155337401496703205528", 1], ["3100618561736693802993406410752", "3100618561736693802993406411961", 22], ["6306554584349917605986812821504", "6306554584349917605986812822041", 9], ["12897043632271155211973625643008", "12897043632271155211973625643214", 3], ["27070533331838590423947251286016", "27070533331838590423947251286519", 5], ["44933719679228300847894502572032", "44933719679228300847894502574007", 26], ["92067632902534481695789005144064", "92067632902534481695789005144486", 7], ["219741981610812063391578010288128", "219741981610812063391578010289366", 22], ["441164516482197726783156020576256", "441164516482197726783156020576737", 5], ["783694033185045453566312041152512", "783694033185045453566312041152692", 1], ["1754258052575393907132624082305024", "1754258052575393907132624082305337", 4], ["3291172491135828814265248164610048", "3291172491135828814265248164611897", 21], ["5255505796082429028530496329220096", "5255505796082429028530496329221910", 27], ["12176969828012415257060992658440192", "12176969828012415257060992658440427", 5], ["22889636161029770514121985316880384", "22889636161029770514121985316881826", 17], ["44359130889092671028243970633760768", "44359130889092671028243970633762444", 17], ["94248617103459242056487941267521536", "94248617103459242056487941267522522", 16], ["191861723074481884112975882535043072", "191861723074481884112975882535043603", 10], ["396766049747924068225951765070086144", "396766049747924068225951765070087394", 10], ["884985931172514936451903530140172288", "884985931172514936451903530140172881", 9], ["1969978340430920872903807060280344576", "1969978340430920872903807060280346393", 17], ); my %pi2n = ( 1 => '1', 2 => '2', 3 => '4', 4 => '6', 5 => '11', 6 => '18', 7 => '31', 8 => '54', 9 => '97', 10 => '172', 11 => '309', 12 => '564', 13 => '1028', 14 => '1900', 15 => '3512', 16 => '6542', 17 => '12251', 18 => '23000', 19 => '43390', 20 => '82025', 21 => '155611', 22 => '295947', 23 => '564163', 24 => '1077871', 25 => '2063689', 26 => '3957809', 27 => '7603553', 28 => '14630843', 29 => '28192750', 30 => '54400028', 31 => '105097565', 32 => '203280221', 33 => '393615806', 34 => '762939111', 35 => '1480206279', 36 => '2874398515', 37 => '5586502348', 38 => '10866266172', 39 => '21151907950', 40 => '41203088796', 41 => '80316571436', 42 => '156661034233', 43 => '305761713237', 44 => '597116381732', 45 => '1166746786182', 46 => '2280998753949', 47 => '4461632979717', 48 => '8731188863470', 49 => '17094432576778', 50 => '33483379603407', 51 => '65612899915304', 52 => '128625503610475', 53 => '252252704148404', 54 => '494890204904784', 55 => '971269945245201', 56 => '1906879381028850', 57 => '3745011184713964', 58 => '7357400267843990', 59 => '14458792895301660', 60 => '28423094496953330', 61 => '55890484045084135', 62 => '109932807585469973', 63 => '216289611853439384', 64 => '425656284035217743', 65 => '837903145466607212', 66 => '1649819700464785589', 67 => '3249254387052557215', 68 => '6400771597544937806', 69 => '12611864618760352880', 70 => '24855455363362685793', 71 => '48995571600129458363', 72 => '96601075195075186855', 73 => '190499823401327905601', 74 => '375744164937699609596', 75 => '741263521140740113483', 76 => '1462626667154509638735', 77 => '2886507381056867953916', 78 => '5697549648954257752872', 79 => '11248065615133675809379', 80 => '22209558889635384205844', 81 => '43860397052947409356492', 82 => '86631124695994360074872', 83 => '171136408646923240987028', 84 => '338124238545210097236684', 85 => '668150111666935905701562', 86 => '1320486952377516565496055', ); plan tests => 4 + scalar (keys %pivals) + scalar @tests + 2*scalar(keys %pi2n); # TODO: error cases is( prime_count(0,1), 0, "prime_count(0,1) == 0"); is( prime_count(0,2), 1, "prime_count(0,2) == 1"); is( prime_count(0,3), 2, "prime_count(0,3) == 2"); is( prime_count(2,2), 1, "prime_count(2,2) == 2"); while (my($n, $pin) = each (%pivals)) { is( prime_count(2, $n), $pin, "Pi($n) = $pin" ); } foreach my $t (@tests) { is( prime_count($t->[0], $t->[1]), $t->[2], "prime_count($t->[0],$t->[1]) = $t->[2]" ); } while (my($n, $pin) = each (%pi2n)) { use bigint; cmp_ok( prime_count_lower(2 ** $n), '<=', $pin, "prime_count_lower(2^$n) <= $pin" ); cmp_ok( prime_count_upper(2 ** $n), '>=', $pin, "prime_count_upper(2^$n) >= $pin" ); } Math-Prime-Util-GMP-0.52/t/26-roots.t0000644000175000017500000000353113025437621015357 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/sqrtint rootint/; use Math::BigInt; # Don't use GMP so we don't have to work around bug my $use64 = (~0 > 4294967296 && 18446744073709550592 != ~0); plan tests => 0 + 3 #sqrtint + 7 #rootint + 0; ###### sqrtint is_deeply( [map { sqrtint($_**2) } 0..10], [0..10], "sqrtint 0-10" ); is_deeply( [map { sqrtint($_**2-1) } 2..20], [2-1..20-1], "sqrtint 2-20 -1" ); is( sqrtint("647307989872865201422284359961937038113215496061434545237"), "25442248129299918480155830589", "sqrtint(13^51)" ); ###### rootint is( rootint("43091031920942300256108314560009772304748698124094750326895058640841523270081624169128280918534127523222564290447104831706207227117677890695945149868732770531628297914633063561406978145215542597509491443634033203125", 23), 2147483645, "rootint( (2^31-3)^23, 23) = 2^31-3" ); is( rootint("43091031920942300256108314560009772304748698124094750326895058640841523270081624169128280918534127523222564290447104831706207227117677890695945149868732770531628297914633063561406978145215542597509491443634033203124", 23), 2147483644, "rootint( (2^31-3)^23-1, 23) = 2^31-3-1" ); is( rootint(Math::BigInt->new(10)->bpow(1000), 1001), 9, "rootint(10^1000,1001) = 9"); is( rootint(Math::BigInt->new(2)->bpow(240), 9), 106528681, "rootint(2^240,9) = 106528681"); is( root_test(2,100), 0, "roots of powers of 2" ); is( root_test(Math::BigInt->new("4294967297"),10), 0, "roots of powers of 2^32+1" ); is( root_test(Math::BigInt->new("18446744073709551617"),10), 0, "roots of powers of 2^64+1" ); # Similar to Pari/GP's test sub root_test { my($base, $max) = @_; my $B = Math::BigInt->new($base); for my $i (2 .. $max) { $B *= $base; my $root = rootint($B+1, $i); return "$i $B: $root should be $base" if $root != $base; } 0; } Math-Prime-Util-GMP-0.52/t/26-combinatorial.t0000644000175000017500000000255713663067455017057 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/permtonum numtoperm/; plan tests => 0 + 7 # permtonum + 7 # numtoperm + 0; ###### permtonum is(permtonum([]),0,"permtonum([])"); is(permtonum([0]),0,"permtonum([0])"); is(permtonum([1,0]),1,"permtonum([1,0])"); is(permtonum([6,3,4,2,5,0,1]),4768,"permtonum([6,3,4,2,5,0,1])"); is(permtonum([reverse(0..14),15..19]),"1790774578500738480","permtonum( 20 )"); is(permtonum([reverse(0..12),reverse(13..25)]),"193228515634198442606207999","permtonum( 26 )"); is(permtonum([16,10,18,0,33,25,34,30,8,13,11,27,22,26,21,17,4,12,29,5,39,31,1,6,7,14,32,28,19,15,23,24,9,20,38,35,3,36,37,2]),"331816865634235984753115643542286324917379756177","permtonum( 40 )"); is_deeply([numtoperm(0,0)],[],"numtoperm(0,0)"); is_deeply([numtoperm(1,0)],[0],"numtoperm(1,0)"); is_deeply([numtoperm(1,1)],[0],"numtoperm(1,1)"); is_deeply([numtoperm(5,15)],[0,3,2,4,1],"numtoperm(5,15)"); is_deeply([numtoperm(5,-2)],[4,3,2,0,1],"numtoperm(5,-2)"); is_deeply([numtoperm(24,987654321)],[0,1,2,3,4,5,6,7,8,9,10,13,11,21,14,20,17,15,12,22,18,19,23,16],"numtoperm(24,987654321)"); is_deeply([numtoperm(40,"168413612234311889416542084240799668239048237663")],[8,11,0,1,35,34,29,38,39,3,32,13,33,25,4,10,17,16,6,2,30,37,12,24,28,36,22,26,18,19,20,23,31,9,27,5,21,15,14,7],"numtoperm(40,...)"); Math-Prime-Util-GMP-0.52/t/90-release-perlcritic.t0000644000175000017500000000106213025437621017765 0ustar danadana#!/usr/bin/perl use strict; use warnings; use Test::More; BEGIN { unless ($ENV{RELEASE_TESTING}) { plan( skip_all => 'these tests are for release candidate testing' ); } } #--------------------------------------------------------------------- eval { require Test::Perl::Critic; }; plan skip_all => "Test::Perl::Critic required for testing PBP compliance" if $@; Test::Perl::Critic->import( -verbose => 10, -severity => 'gentle', # default -force => 0, # default (allow ## no critic) ); all_critic_ok(); Math-Prime-Util-GMP-0.52/t/12-nextprime.t0000644000175000017500000002041413663067455016232 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/next_prime prev_prime surround_primes next_twin_prime powint addint/; my $extra = defined $ENV{EXTENDED_TESTING} && $ENV{EXTENDED_TESTING}; plan tests => 2 + 3*2 + 6 + 1 + 2 + 1 + 2 + 7 + 3*$extra + 2; my @small_primes = qw/ 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997 1009 1013 1019 1021 1031 1033 1039 1049 1051 1061 1063 1069 1087 1091 1093 1097 1103 1109 1117 1123 1129 1151 1153 1163 1171 1181 1187 1193 1201 1213 1217 1223 1229 1231 1237 1249 1259 1277 1279 1283 1289 1291 1297 1301 1303 1307 1319 1321 1327 1361 1367 1373 1381 1399 1409 1423 1427 1429 1433 1439 1447 1451 1453 1459 1471 1481 1483 1487 1489 1493 1499 1511 1523 1531 1543 1549 1553 1559 1567 1571 1579 1583 1597 1601 1607 1609 1613 1619 1621 1627 1637 1657 1663 1667 1669 1693 1697 1699 1709 1721 1723 1733 1741 1747 1753 1759 1777 1783 1787 1789 1801 1811 1823 1831 1847 1861 1867 1871 1873 1877 1879 1889 1901 1907 1913 1931 1933 1949 1951 1973 1979 1987 1993 1997 1999 2003 2011 2017 2027 2029 2039 2053 2063 2069 2081 2083 2087 2089 2099 2111 2113 2129 2131 2137 2141 2143 2153 2161 2179 2203 2207 2213 2221 2237 2239 2243 2251 2267 2269 2273 2281 2287 2293 2297 2309 2311 2333 2339 2341 2347 2351 2357 2371 2377 2381 2383 2389 2393 2399 2411 2417 2423 2437 2441 2447 2459 2467 2473 2477 2503 2521 2531 2539 2543 2549 2551 2557 2579 2591 2593 2609 2617 2621 2633 2647 2657 2659 2663 2671 2677 2683 2687 2689 2693 2699 2707 2711 2713 2719 2729 2731 2741 2749 2753 2767 2777 2789 2791 2797 2801 2803 2819 2833 2837 2843 2851 2857 2861 2879 2887 2897 2903 2909 2917 2927 2939 2953 2957 2963 2969 2971 2999 3001 3011 3019 3023 3037 3041 3049 3061 3067 3079 3083 3089 3109 3119 3121 3137 3163 3167 3169 3181 3187 3191 3203 3209 3217 3221 3229 3251 3253 3257 3259 3271 3299 3301 3307 3313 3319 3323 3329 3331 3343 3347 3359 3361 3371 3373 3389 3391 3407 3413 3433 3449 3457 3461 3463 3467 3469 3491 3499 3511 3517 3527 3529 3533 3539 3541 3547 3557 3559 3571 /; { my @sp = (undef, @small_primes, 3581); my ($pi, $ni) = (0, 1); my @prevexp = map { $pi++ if $_ > $sp[$pi+1]; $sp[$pi]; } (0 .. 3572); my @nextexp = map { $ni++ if $_ >= $sp[$ni ]; $sp[$ni]; } (0 .. 3572); my @prev = map { prev_prime($_) } (0..3572); my @next = map { next_prime($_) } (0..3572); is_deeply( \@prev, \@prevexp, "prev_prime 0..3572" ); is_deeply( \@next, \@nextexp, "next_prime 0..3572" ); } my %primegaps = ( 19609 => 52, 360653 => 96, 2010733 => 148, ); while (my($base, $range) = each (%primegaps)) { is( next_prime($base), $base+$range, "next prime of $base is $base+$range" ); is( prev_prime($base+$range), $base, "prev prime of $base+$range is $base" ); } is( next_prime(19608), 19609, "next prime of 19608 is 19609" ); is( next_prime(19610), 19661, "next prime of 19610 is 19661" ); is( next_prime(19660), 19661, "next prime of 19660 is 19661" ); is( prev_prime(19662), 19661, "prev prime of 19662 is 19661" ); is( prev_prime(19660), 19609, "prev prime of 19660 is 19609" ); is( prev_prime(19610), 19609, "prev prime of 19610 is 19609" ); is( prev_prime(2), undef, "Previous prime of 2 returns undef" ); # Turns out the testing of prev/next from 0-3572 still misses some cases. { my @next = map { next_prime($_) } 2010733 .. 2010880; my @prev = map { prev_prime($_) } 2010734 .. 2010881; is_deeply(\@next,[(2010881)x@next],"next_prime(2010733..2010880) = 2010881"); is_deeply(\@prev,[(2010733)x@prev],"prev_prime(2010734..2010881) = 2010733"); } # Similar test case to 2010870, where m=0 and next_prime is at m=1 is(next_prime(1234567890), 1234567891, "next_prime(1234567890) == 1234567891)"); is( next_prime('87567547898934657346596012842304861297462937562349058673456'), '87567547898934657346596012842304861297462937562349058673779', "next_prime(8756....73456) = 8756....73779"); is( prev_prime('1353175074828899034888345292712068768032725991919855436631156'), '1353175074828899034888345292712068768032725991919855436630917', "prev_prime(1353....31156) = 1353....30917"); ########################################## is_deeply([surround_primes(0)], [undef,2], "surround_primes(2)"); is_deeply([surround_primes(2)], [undef,1], "surround_primes(2)"); is_deeply([surround_primes("29384928409238")], [79,45], "surround_primes(29384928409238)"); is_deeply([surround_primes("18446744073709551616")], [59,13], "surround_primes(2^64)"); is_deeply([surround_primes("36893488147419103273")], [90,90], "surround_primes(2^65+41)"); # Test second arg is_deeply([surround_primes("36893488147419103273",89)], [90,90], "surround_primes(2^65+41,89)"); is_deeply([surround_primes("36893488147419103273",90)], [90,0], "surround_primes(2^65+41,90)"); if ($extra) { my $c163 = "3254185929142547441117000456865810587301677179676494144227638178204588790016877642497284992010196102315442455595356723557223592608572003000275424902281588892769763"; is_deeply([surround_primes($c163,200)], [8776,4916], "surround_primes(d163,200)"); my $c85 = "2642497284992010196102315442455595356723557223592608572003000275424902281588892769763"; is_deeply([surround_primes($c85)], [32,456], "surround_primes(c85)"); is_deeply([surround_primes($c85,200)], [32,0], "surround_primes(c85,200)"); } ########################################## { # Only a subset of the results my @a124001 = (qw/2 1 1 19 7 151 37 139 37 7 277 817 61 1267 97 2371 1549 19 619 97 391 409 649 5527 2731 559 949 427 601 2797 1681 7189 2449 6751 7597 8419 16879 871 5569 10327 16111 2131 6121 23329 5179 4249 2641 2257 3997 8281 18307 7537 41347 25831 3397 7687 6637 7381 16597 9091 23599 27319 4711 22249 6517 7579 4051 1777 12949 38119 17887 3319 38671 829 19219 24721 4489 45469 2581 30511 37759/); my(@got, @exp); for my $i (0 .. $#a124001) { my $n = powint(10,$i); push @exp, addint($n, $a124001[$i]); push @got, next_twin_prime($n); } is_deeply(\@got, \@exp, "twin primes 10^x"); } { my @a113275 = (qw/3 5 17 41 71 311 347 659 2381 5879 13397 18539 24419 62297 187907 687521 688451 850349 2868959 4869911 9923987 14656517 17382479 30752231 32822369 96894041 136283429 234966929 248641037 255949949 390817727 698542487 2466641069 4289385521 19181736269 24215097497 24857578817 40253418059 42441715487 43725662621 65095731749 134037421667 198311685749 223093059731 353503437239 484797803249 638432376191 784468515221 794623899269 1246446371789 1344856591289 1496875686461 2156652267611 2435613754109 4491437003327 13104143169251 14437327538267 18306891187511 18853633225211 23275487664899 23634280586867 38533601831027 43697538391391 56484333976919 74668675816277 116741875898981 136391104728629 221346439666109 353971046703347 450811253543219 742914612256169 1121784847637957 1149418981410179 2543288406389231 2797282815481499/); my @a036062 = (qw/5 11 29 59 101 347 419 809 2549 6089 13679 18911 24917 62927 188831 688451 689459 851801 2870471 4871441 9925709 14658419 17384669 30754487 32825201 96896909 136286441 234970031 248644217 255953429 390821531 698547257 2466646361 4289391551 19181742551 24215103971 24857585369 40253424707 42441722537 43725670601 65095739789 134037430661 198311695061 223093069049 353503447439 484797813587 638432386859 784468525931 794623910657 1246446383771 1344856603427 1496875698749 2156652280241 2435613767159 4491437017589 13104143183687 14437327553219 18306891202907 18853633240931 23275487681261 23634280603289 38533601847617 43697538408287 56484333994001 74668675834661 116741875918727 136391104748621 221346439686641 353971046725277 450811253565767 742914612279527 1121784847661339 1149418981435409 2543288406415499 2797282815510341/); if (!$extra) { $#a113275 = 30; $#a036062 = 30; } is_deeply([map { next_twin_prime($_) } @a113275], \@a036062, "next_twin_prime on record gaps"); } Math-Prime-Util-GMP-0.52/t/92-release-pod-coverage.t0000644000175000017500000000105213025437621020201 0ustar danadana#!/usr/bin/env perl use strict; use warnings; BEGIN { unless ($ENV{RELEASE_TESTING}) { require Test::More; Test::More::plan(skip_all => 'these tests are for release candidate testing'); } } #--------------------------------------------------------------------- use Test::More; eval "use Test::Pod::Coverage 1.08"; plan skip_all => "Test::Pod::Coverage 1.08 required for testing POD coverage" if $@; my @modules = Test::Pod::Coverage::all_modules(); plan tests => scalar @modules; foreach my $m (@modules) { pod_coverage_ok( $m ); } Math-Prime-Util-GMP-0.52/t/20-primorial.t0000644000175000017500000001163313663067455016217 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/primorial pn_primorial factorial factorialmod multifactorial subfactorial factorial_sum addmod/; my @small_primes = qw/ 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 /; sub nth_prime { my $n = shift; return 0 if $n <= 0; die "Out of range for fake nth_prime: $n" unless defined $small_primes[$n-1]; $small_primes[$n-1]; } my @pn_primorials = qw/ 1 2 6 30 210 2310 30030 510510 9699690 223092870 6469693230 200560490130 7420738134810 304250263527210 13082761331670030 614889782588491410 32589158477190044730 1922760350154212639070 117288381359406970983270 7858321551080267055879090 557940830126698960967415390 40729680599249024150621323470 3217644767340672907899084554130 267064515689275851355624017992790 23768741896345550770650537601358310 2305567963945518424753102147331756070 232862364358497360900063316880507363070 23984823528925228172706521638692258396210 2566376117594999414479597815340071648394470 279734996817854936178276161872067809674997230 31610054640417607788145206291543662493274686990 /; my @factorials = (qw/ 1 1 2 6 24 120 720 5040 40320 362880 3628800 39916800 479001600 6227020800 87178291200 1307674368000 20922789888000 355687428096000 6402373705728000 121645100408832000 2432902008176640000 51090942171709440000 1124000727777607680000 25852016738884976640000 620448401733239439360000 15511210043330985984000000 403291461126605635584000000 10888869450418352160768000000 304888344611713860501504000000 8841761993739701954543616000000 265252859812191058636308480000000 /); plan tests => 1 # factorial + 1 # factorialmod + 2 # primorial and pn_primorial + 2 # extra primorial tests + 1 # subfactorial + 1 # factorial_sum + 4; # multifactorial { my @fact = map { factorial($_) } 0 .. $#factorials; is_deeply( \@fact, \@factorials, "factorial 0 .. $#factorials" ); } is_deeply( [map { factorialmod($_>>2,$_) } 10000 .. 10100], [map { addmod(factorial($_>>2),0,$_) } 10000 .. 10100], "factorialmod" ); { my @prim = map { primorial(nth_prime($_)) } 0 .. $#pn_primorials; my @pnprim = map { pn_primorial($_) } 0 .. $#pn_primorials; is_deeply(\@prim, \@pn_primorials, "primorial(nth(...)) 0 - $#pn_primorials"); is_deeply(\@pnprim, \@pn_primorials, "pn_primorial(...) 0 - $#pn_primorials"); } is( primorial(100), '2305567963945518424753102147331756070', "primorial(100)"); is( primorial(541), '4711930799906184953162487834760260422020574773409675520188634839616415335845034221205289256705544681972439104097777157991804380284218315038719444943990492579030720635990538452312528339864352999310398481791730017201031090', "primorial(541)" ); is_deeply( [ map { subfactorial($_) } 0..23 ], [qw/1 0 1 2 9 44 265 1854 14833 133496 1334961 14684570 176214841 2290792932 32071101049 481066515734 7697064251745 130850092279664 2355301661033953 44750731559645106 895014631192902121 18795307255050944540 413496759611120779881 9510425471055777937262/], "subfactoral(n) for 0..23" ); is_deeply( [ map { factorial_sum($_) } 0..22 ], [qw/0 1 2 4 10 34 154 874 5914 46234 409114 4037914 43954714 522956314 6749977114 93928268314 1401602636314 22324392524314 378011820620314 6780385526348314 128425485935180314 2561327494111820314 53652269665821260314/], "factorial_sum(n) for 0..22" ); is_deeply( [ map { multifactorial($_,0) } 0..22 ], [ map { 1 } 0..22 ], "multifactorial(n,0) for 0..22" ); is_deeply( [ map { multifactorial($_,1) } 0..22 ], [ map { factorial($_) } 0..22 ], "multifactorial(n,1) for 0..22" ); is_deeply( [ map { multifactorial($_,2) } 0..26 ], [qw/1 1 2 3 8 15 48 105 384 945 3840 10395 46080 135135 645120 2027025 10321920 34459425 185794560 654729075 3715891200 13749310575 81749606400 316234143225 1961990553600 7905853580625 51011754393600/], "multifactorial(n,2) for 0..26" ); is_deeply( [ map { multifactorial($_,3) } 0..29 ], [qw/1 1 2 3 4 10 18 28 80 162 280 880 1944 3640 12320 29160 58240 209440 524880 1106560 4188800 11022480 24344320 96342400 264539520 608608000 2504902400 7142567040 17041024000 72642169600/], "multifactorial(n,3) for 0..29" ); Math-Prime-Util-GMP-0.52/t/28-urandom.t0000644000175000017500000000637713663067455015707 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::BigInt try=>"GMP,Pari"; use Math::Prime::Util::GMP qw/urandomb urandomr urandomm seed_csprng random_bytes todigits/; my $use64 = (~0 > 4294967295); my $extra = defined $ENV{EXTENDED_TESTING} && $ENV{EXTENDED_TESTING}; my $maxbits = $use64 ? 64 : 32; my @nbit_check = (0..5,8,20,31,32,33,40); my %nbit_range = map { $_ => 1 } grep { $_ <= 8 } @nbit_check; my @large_nbit = (64,128,255,256,257,512,1024,2048,4096,8192,73100); my $nsamples = $extra ? 30000 : 1000; my $rsamples = $extra ? 10000 : 200; plan tests => 0 + scalar(@nbit_check) + scalar(@large_nbit) + scalar(keys %nbit_range) + 4 + 5 + 4 + 3; ######## check_nbit_range($_) for @nbit_check; ######## for my $b (@large_nbit) { my @bits = todigits(urandomb($b),2); ok( scalar(@bits) <= $b, "Random $b-bit in range" ); } ######## check_range(100,110); check_range(128,255); check_range(2**24, 2**25-1); check_range(Math::BigInt->new(10)**24, Math::BigInt->new(10)**25-1); ######## ok(!eval { urandomr(-10,100); }, "urandomr(-10,x)"); ok(!eval { urandomr(100,-10); }, "urandomr(x,-10)"); ok(!eval { urandomr(-1,-1); }, "urandomr(-1,-1)"); is(urandomr(123456,123456), 123456, "urandomr(x,x)=x"); is(urandomr(123457,123456), undef, "urandomr(x,y)=undef if x > y"); ######## ok(!eval { urandomm(-1); }, "urandomm(-1)"); is(urandomm(0), 0, "urandomm(0)=0"); is(urandomm(1), 0, "urandomm(1)=0"); check_range_m(1234567); ######## seed_csprng(55,"BLAKEGrostlJHKeccakSkein--RijndaelSerpentTwofishRC6MARS"); is(unpack("h*",random_bytes( 4)),"538e1f65","random_bytes(4)"); is(unpack("h*",random_bytes(11)),"cbbac4ba12e6aa77bcfe6f","random_bytes(11)"); is(unpack("h*",random_bytes( 0)),"","random_bytes(0)"); ######## sub check_nbit_range { my $b = shift; my $over = ($b < $maxbits) ? (1 << $b) : (Math::BigInt->new(1) << $b); if (!$nbit_range{$b}) { my @s = map { urandomb($b) } 1 .. $nsamples; is(scalar(grep { $_ >= $over } @s), 0, "urandomb($b) values are in range"); } else { # For $b=8 and a uniform random generator, the probability of a given # 8-bit value not being selected is 1-1/256 = 0.99609375. After 1000 # tries, this is 0.01996 or about 2%. After 1000+2000 tries it's ~8e-6. # The proper calculation is more tedious but for $b=8 and $nsamples=1000 # we will find it likely we need a second pass but no more. my %t; for my $try (1..10) { $t{ urandomb($b) }++ for 1 .. $try * $nsamples; last if scalar(keys %t) >= $over; } my @keys = keys %t; is(scalar(grep { $_ >= $over } @keys), 0, "urandomb($b) values are in range"); is(scalar(@keys), $over, "urandomb($b) produces all values in range"); } } sub check_range { my($lo,$hi) = @_; my @s = map { urandomr($lo,$hi) } 1 .. $rsamples; @s = map { ref($hi)->new("$_") } @s if ref($hi); is( scalar(grep { $_ < $lo || $_ > $hi } @s), 0, "urandomr($lo,$hi) values are in range" ); } sub check_range_m { my($hi) = @_; my @s = map { urandomm($hi) } 1 .. $rsamples; @s = map { ref($hi)->new("$_") } @s if ref($hi); is( scalar(grep { $_ > $hi } @s), 0, "urandomm($hi) values are in range" ); } Math-Prime-Util-GMP-0.52/t/19-moebius.t0000644000175000017500000002712413054533437015666 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/moebius liouville totient jordan_totient exp_mangoldt carmichael_lambda znorder znprimroot is_primitive_root chinese ramanujan_tau/; my $extra = defined $ENV{EXTENDED_TESTING} && $ENV{EXTENDED_TESTING}; my @moeb_vals = (qw/ 1 -1 -1 0 -1 1 -1 0 0 1 -1 0 -1 1 1 0 -1 0 -1 0 /); my %totients = ( 123456 => 41088, 123457 => 123456, 123456789 => 82260072, ); my @A000010 = (0,1,1,2,2,4,2,6,4,6,4,10,4,12,6,8,8,16,6,18,8,12,10,22,8,20,12,18,12,28,8,30,16,20,16,24,12,36,18,24,16,40,12,42,20,24,22,46,16,42,20,32,24,52,18,40,24,36,28,58,16,60,30,36,32,48,20,66,32,44); #@totients{0..$#A000010} = @A000010; my @A001615 = (1,3,4,6,6,12,8,12,12,18,12,24,14,24,24,24,18,36,20,36,32,36,24,48,30,42,36,48,30,72,32,48,48,54,48,72,38,60,56,72,42,96,44,72,72,72,48,96,56,90,72,84,54,108,72,96,80,90,60,144,62,96,96,96,84,144,68,108,96); my @A002322 = (0,1,1,2,2,4,2,6,2,6,4,10,2,12,6,4,4,16,6,18,4,6,10,22,2,20,12,18,6,28,4,30,8,10,16,12,6,36,18,12,4,40,6,42,10,12,22,46,4,42,20,16,12,52,18,20,6,18,28,58,4,60,30,6,16,12,10,66,16,22,12,70,6,72,36,20,18,30,12,78,4,54,40,82,6,16,42,28,10,88,12,12,22,30,46,36,8,96,42,30,20,100,16,102,12,12,52,106,18,108,20,36,12,112,18,44,28,12,58,48,4,110,60,40,30,100,6,126,32,42,12,130,10,18,66,36,16,136,22,138,12,46,70,60,12,28,72,42,36,148,20,150,18,48,30,60,12,156,78,52,8,66,54,162,40,20,82,166,6,156,16,18,42,172,28,60,20,58,88,178,12,180,12,60,22,36,30,80,46,18,36,190,16,192,96,12,42,196,30,198,20); my %jordan_totients = ( # A000010 1 => [1, 1, 2, 2, 4, 2, 6, 4, 6, 4, 10, 4, 12, 6, 8, 8, 16, 6, 18, 8, 12, 10, 22, 8, 20, 12, 18, 12, 28, 8, 30, 16, 20, 16, 24, 12, 36, 18, 24, 16, 40, 12, 42, 20, 24, 22, 46, 16, 42, 20, 32, 24, 52, 18, 40, 24, 36, 28, 58, 16, 60, 30, 36, 32, 48, 20, 66, 32, 44], # A007434 2 => [1, 3, 8, 12, 24, 24, 48, 48, 72, 72, 120, 96, 168, 144, 192, 192, 288, 216, 360, 288, 384, 360, 528, 384, 600, 504, 648, 576, 840, 576, 960, 768, 960, 864, 1152, 864, 1368, 1080, 1344, 1152, 1680, 1152, 1848, 1440, 1728, 1584, 2208, 1536], # A059376 3 => [1, 7, 26, 56, 124, 182, 342, 448, 702, 868, 1330, 1456, 2196, 2394, 3224, 3584, 4912, 4914, 6858, 6944, 8892, 9310, 12166, 11648, 15500, 15372, 18954, 19152, 24388, 22568, 29790, 28672, 34580, 34384, 42408, 39312, 50652, 48006, 57096], # A059377 4 => [1, 15, 80, 240, 624, 1200, 2400, 3840, 6480, 9360, 14640, 19200, 28560, 36000, 49920, 61440, 83520, 97200, 130320, 149760, 192000, 219600, 279840, 307200, 390000, 428400, 524880, 576000, 707280, 748800, 923520, 983040, 1171200], # A059378 5 => [1, 31, 242, 992, 3124, 7502, 16806, 31744, 58806, 96844, 161050, 240064, 371292, 520986, 756008, 1015808, 1419856, 1822986, 2476098, 3099008, 4067052, 4992550, 6436342, 7682048, 9762500, 11510052, 14289858, 16671552, 20511148, 23436248, 28629150, 32505856, 38974100, 44015536, 52501944, 58335552, 69343956, 76759038, 89852664, 99168256, 115856200, 126078612, 147008442, 159761600, 183709944, 199526602, 229345006, 245825536, 282458442, 302637500, 343605152, 368321664], # A069091 6 => [1, 63, 728, 4032, 15624, 45864, 117648, 258048, 530712, 984312, 1771560, 2935296, 4826808, 7411824, 11374272, 16515072, 24137568, 33434856, 47045880, 62995968, 85647744, 111608280, 148035888, 187858944, 244125000, 304088904, 386889048], # A069092 7 => [1, 127, 2186, 16256, 78124, 277622, 823542, 2080768, 4780782, 9921748, 19487170, 35535616, 62748516, 104589834, 170779064, 266338304, 410338672, 607159314, 893871738, 1269983744, 1800262812, 2474870590, 3404825446], ); my @liouville_pos = (qw/24 51 94 183 294 629 1488 3684 8006 8510 32539 57240 103138 238565 444456 820134 1185666 3960407 4429677 13719505 29191963 57736144 134185856 262306569 324235872 563441153 1686170713 2489885844/); my @liouville_neg = (qw/23 47 113 163 378 942 1669 2808 8029 9819 23863 39712 87352 210421 363671 562894 1839723 3504755 7456642 14807115 22469612 49080461 132842464 146060791 279256445 802149183 1243577750 3639860654/); push @liouville_pos, (qw/1260238066729040 10095256575169232896/); push @liouville_neg, (qw/1807253903626380 12063177829788352512/); my %mangoldt = ( -13 => 1, 0 => 1, 1 => 1, 2 => 2, 3 => 3, 4 => 2, 5 => 5, 6 => 1, 7 => 7, 8 => 2, 9 => 3, 10 => 1, 11 => 11, 25 => 5, 27 => 3, 399981 => 1, 399982 => 1, 399983 => 399983, 823543 => 7, 83521 => 17, 130321 => 19, ); my @mult_orders = ( [1, 35, 1], [2, 35, 12], [4, 35, 6], [6, 35, 2], [7, 35], [2, "1000000000000031", 81788975100], [1, 1, 1], [0, 0], [1, 0], [25, 0], [1, 1, 1], [19, 1, 1], [1, 19, 1], [2, 19, 18], [3, 20, 4], [57,1000000003,189618], [67,999999749,30612237], [22,999991815,69844], [10,2147475467,31448382], [141,2147475467,1655178], [7410,2147475467,39409], [31407,2147475467,266], [2, "2405286912458753", 1073741824], # Pari #1031 ); my %primroots = ( -11 => 2, 0 => undef, 1 => 0, 2 => 1, 3 => 2, 4 => 3, 5 => 2, 6 => 5, 7 => 3, 8 => undef, 9 => 2, 10 => 3, # 3 is the smallest root. Pari gives the other root 7. 1729 => undef, # Pari goes into an infinite loop. 5109721 => 94, 17551561 => 97, 90441961 => 113, 1407827621 => 2, 1520874431 => 17, 1685283601 => 164, 100000001 => undef, # Without an early exit, this will essentially hang. "2232881419280027" => 6, "14123555781055773271" => 6, "89637484042681" => 335, "9223372036854775837" => 5, ); my %rtau = ( 0 => 0, 1 => 1, 2 => -24, 3 => 252, 4 => -1472, 5 => 4830, 53 => -1596055698, 106 => 38305336752, 243 => 13400796651732, 16089 => "12655813883111729342208", 83456 => "130596522071273977247956992", ); $rtau{123456} = "206775765874925539386458112" if $extra; $rtau{982348} = "598906847188833667374229665444608" if $extra; my @crts = ( [ [], 0 ], [ [[4,5]], 4 ], [ [[77,11]], 0 ], [ [[0,5],[0,6]], 0 ], [ [[14,5],[0,6]], 24 ], [ [[10,11],[4,22],[9,19]], undef ], [ [[77,13],[79,17]], 181 ], [ [[2,3],[3,5],[2,7]], 23 ], [ [[10,11],[4,12],[12,13]], 1000 ], [ [[42,127],[24,128]], 2328 ], # Some tests from Mod::Int [ [[32,126],[23,129]], 410 ], [ [[2328,16256],[410,5418]], 28450328 ], [ [[1,10],[11,100]], 11 ], [ [[11,100],[22,100]], undef ], [ [[1753051086,3243410059],[2609156951,2439462460]], "6553408220202087311"], [ [ ["6325451203932218304","2750166238021308"], ["5611464489438299732","94116455416164094"] ], "1433171050835863115088946517796" ], [ [ ["1762568892212871168","8554171181844660224"], ["2462425671659520000","2016911328009584640"] ], "188079320578009823963731127992320" ], [ [ ["856686401696104448","11943471150311931904"], ["6316031051955372032","13290002569363587072"] ], "943247297188055114646647659888640" ], [ [[-3105579549,3743000622],[-1097075646,1219365911]], "2754322117681955433"], [ [ ["-925543788386357567","243569243147991"], ["-1256802905822510829","28763455974459440"] ], "837055903505897549759994093811" ], [ [ ["-2155972909982577461","8509855219791386062"], ["-5396280069505638574","6935743629860450393"] ], "12941173114744545542549046204020289525" ], [ [[3,5],[2,0]], undef ], # three tests that we handle zeros. [ [[3,0],[2,3]], undef ], [ [[3,5],[3,0],[2,3]], undef ], ); plan tests => 1 + 1 # moeb_vals + 1 + scalar(keys %totients) + scalar(keys %jordan_totients) + 1 # Small Carmichael Lambda + scalar(@liouville_pos) + scalar(@liouville_neg) + scalar(keys %mangoldt) + scalar(@mult_orders) + scalar(keys %primroots) + 1 + 3 # is_primitive_root + scalar(keys %rtau) + scalar(@crts) + 10; ###### moebius ok(!eval { moebius(0); }, "moebius(0)"); { my @moebius = map { moebius($_) } (1 .. scalar @moeb_vals); is_deeply( \@moebius, \@moeb_vals, "moebius 1 .. " . scalar @moeb_vals ); } ###### totient { my @phi = map { totient($_) } (0 .. $#A000010); is_deeply( \@phi, \@A000010, "totient 0 .. $#A000010" ); } while (my($n, $phi) = each (%totients)) { is( totient($n), $phi, "euler_phi($n) == $phi" ); } ###### Jordan Totient while (my($k, $tref) = each (%jordan_totients)) { my @tlist = map { jordan_totient($k, $_) } 1 .. scalar @$tref; is_deeply( \@tlist, $tref, "Jordan's Totient J_$k" ); } ###### Carmichael Lambda { my @lambda = map { carmichael_lambda($_) } (0 .. $#A002322); is_deeply( \@lambda, \@A002322, "carmichael_lambda with range: 0, $#A000010" ); } ###### liouville foreach my $i (@liouville_pos) { is( liouville($i), 1, "liouville($i) = 1" ); } foreach my $i (@liouville_neg) { is( liouville($i), -1, "liouville($i) = -1" ); } ###### Exponential of von Mangoldt while (my($n, $em) = each (%mangoldt)) { is( exp_mangoldt($n), $em, "exp_mangoldt($n) == $em" ); } ###### znorder foreach my $moarg (@mult_orders) { my ($a, $n, $exp) = @$moarg; my $zn = znorder($a, $n); is( $zn, $exp, "znorder($a, $n) = " . ((defined $exp) ? $exp : "") ); } ###### znprimroot while (my($n, $root) = each (%primroots)) { is( znprimroot($n), $root, "znprimroot($n) == " . ((defined $root) ? $root : "") ); } is( znprimroot("-100000898"), 31, "znprimroot(\"-100000898\") == 31" ); ###### is_primitive_root ok(!is_primitive_root(3,"1000000000000000000000000000057"), "3 is not a primitive root mod 10^30+57"); ok( is_primitive_root(5,"1000000000000000000000000000057"), "5 is a primitive root mod 10^30+57"); ok( is_primitive_root(3,"1000000000000000000000000000066"), "3 is a primitive root mod 10^30+66"); ###### Various with specific values is(totient("9082348072348972344232348972345"),"6196599862139600370393700256064", "totient(9082348072348972344232348972345)"); is(jordan_totient(4,"9082348072348972344232348972345"),"6790726211626980360097015112160435536604703765653198944780917706227632058693872718134564711592636975392545473161803366400000", "jordan_totient(4,9082348072348972344232348972345)"); is(carmichael_lambda("9082348072348972344232348972345"),"129095830461241674383202088668", "carmichael_lambda(9082348072348972344232348972345)"); is(totient("9082348072348972344232348972353"),"5682424092695951433712276501440", "totient(9082348072348972344232348972353)"); is(jordan_totient(7,"9082348072348972344232348972353"),"5095518312757196744226274674573606050126361160581316878353842679128612307851086686674388236784494856239490781063311007858142493527563560083079291494558455443094226241877357726178655478871147887413922557679205648656960", "jordan_totient(7,9082348072348972344232348972353)"); is(carmichael_lambda("9082348072348972344232348972353"),"118383835264498988202339093780", "carmichael_lambda(9082348072348972344232348972353)"); is(moebius("9082348072348972344232348972353"),-1,"moebius(9082348072348972344232348972353)"); is(liouville("9082348072348972344232348972353"),-1,"liouville(9082348072348972344232348972353)"); is(znorder(17,"100000000000000000000000065"),"11018158296270848614660","znorder(17,100000000000000000000000065)"); #is(znprimroot("1000000000000000000000000000066"),3,"znprimroot(1000000000000000000000000000066)"); is(znprimroot("9218092345892375982375972365235234234238"),7,"znprimroot(9218092345892375982375972365235234234238)"); ###### Ramanujan Tau while (my($n, $tau) = each (%rtau)) { is( ramanujan_tau($n), $tau, "Ramanujan Tau($n) = $tau" ); } ###### chinese foreach my $carg (@crts) { my($aref, $exp) = @$carg; my $crt = chinese(@$aref); is( $crt, $exp, "crt(".join(",",map { "[@$_]" } @$aref).") = " . ((defined $exp) ? $exp : "") ); } Math-Prime-Util-GMP-0.52/t/26-riemann.t0000644000175000017500000001404013663067455015653 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/zeta riemannr li ei/; my $extra = defined $ENV{EXTENDED_TESTING} && $ENV{EXTENDED_TESTING}; # gp: \p 47 for(s=2,20,print(zeta(s))) my @zeta = (qw/ 1.6449340668482264364724151666460251892189499012 1.2020569031595942853997381615114499907649862923 1.0823232337111381915160036965411679027747509519 1.0369277551433699263313654864570341680570809195 1.0173430619844491397145179297909205279018174900 1.0083492773819228268397975498497967595998635606 1.0040773561979443393786852385086524652589607906 1.0020083928260822144178527692324120604856058514 1.0009945751278180853371459589003190170060195316 1.0004941886041194645587022825264699364686064358 1.0002460865533080482986379980477396709604160885 1.0001227133475784891467518365263573957142751059 1.0000612481350587048292585451051353337474816962 1.0000305882363070204935517285106450625876279487 1.0000152822594086518717325714876367220232373890 1.0000076371976378997622736002935630292130882491 1.0000038172932649998398564616446219397304546972 1.0000019082127165539389256569577951013532585711 1.0000009539620338727961131520386834493459437942/); # gp: # r(n)={1+sum(k=1,2000, log(n)^k / (k*k!*zeta(k+1)))} my %rv = ( 20 => '7.52719634941220484077584239013039997938974169722', 123 => '30.2234556285623332613428945094834980032607831334', 1234 => '201.089189397887171164417491080355409507577355431', 12345 => '1477.18529486278566013620706299851975937829102453', 123456 => '11602.3885324491433573165310800667605102847042681', 1234567 => '95364.7282332640388293270946571187905178500286859', 12345678 => '809199.447325079489265130526492437800991704424795', 123456789 => '7027403.22117008872413898789377520747800808475988', ); my $zeta_prec_tests = 100; my $zeta_prec_dig = 1000; my $zeta_prec_n = 1000; plan tests => 1 + scalar(keys %rv) + 2 + + ($extra ? (1 + $zeta_prec_tests + 1) : 0) + 7 + 5 + 1 # riemannr non-int + 4 # li + 3; # ei is_deeply( [map { zeta($_,46) } 2 .. 20], \@zeta, "Zeta(2 .. 20) with 46 digits" ); while (my($n, $expect) = each (%rv)) { is( riemannr($n, 48), $expect, "R($n) = $expect" ); } is(riemannr("1". "0" x 50, 50), "876268031750784168878176774217251757122246637483.14", "R(10^50)"); is(riemannr("1". "0" x 150, 150), "2903728255736534346416074404628970397529068306125207079032837832579103359053245134597590715919869831753500878534514475936664326796995810651878998118.39", "R(10^150)"); if ($extra) { is(riemannr("1". "0" x 350, 350), "124238489949931370910732336966515100452049936912035624051962859419809563716547103734387992271397051067462245818951391061505694003378122910328376084414945173986152316160543747767431283218881745289606393942682080649781736046589565713497255284652389254462690055319573972816225055328610744389507159949406453088151820588031068114762784097248028765358622.40", "R(10^350)"); } if ($extra) { # Test rounding use Math::BigFloat; for (1 .. $zeta_prec_tests) { my $n = 2 + int(rand($zeta_prec_n-1)); my $dig = 2 + int(rand($zeta_prec_dig-1)); is( zeta($n,$dig), Math::BigFloat->new(zeta($n,$dig+50), $dig+1)->bstr, "Zeta($n) with $dig decimal places" ); } # Sum Zeta { my $sum = Math::BigFloat->new(0); for my $s (2 .. 500) { $sum += Math::BigFloat->new(zeta($s, 550)); } my $sum501 = substr($sum, 0, 501); is( $sum501, "499.99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969450636365003953179480206067863823002105972594276733361063860907187083734752795422981426273793369615862239495314555272426337205519046466787368647760489165307368863382624392677833345083812263612626144778463640578576092058344947523271193232320203051751308405773804068301164552829334912459718853773108065819531889452863987939391855448068890812517763", "sum of Zeta(2 .. 500) to 500 sig dig" ); } } ######################### # Interesting integer values is( zeta( 1), undef, "Zeta(1) is undef"); is( zeta( 0), '-0.5000000000000000000000000000000000000000', "Zeta(0) is -0.5"); is( zeta( -1), '-0.0833333333333333333333333333333333333333', "Zeta(-1) is -1/12"); like(zeta( -2),qr/-?0(\.0*)?/, "Zeta(-2) is 0"); is( zeta( -3), '0.0083333333333333333333333333333333333333', "Zeta(-2) is 1/120"); is( zeta(-13), '-0.0833333333333333333333333333333333333333', "Zeta(-13) is -1/12"); is( zeta(-21), '-281.4601449275362318840579710144927536231884', "Zeta(-21) is -77683/276"); # non-integer values is(zeta(14.8765), '1.0000333260384199701584391778295724313333', "zeta(14.8765)"); is(zeta(0.5,50), '-1.46035450880958681288949915251529801246722933101258', "zeta(0.5)"); is(zeta(-0.5,50), '-0.20788622497735456601730672539704930222626853128767', "zeta(-0.5)"); is(zeta(-1.5,50), '-0.02548520188983303594954298691070474546902498460097', "zeta(-1.5)"); is(zeta(-5.5,50), '-0.00267145801989922459898238195309679265130483737224', "zeta(-5.5)"); #is(zeta(-50.3,50), '1013678293176749028637197.7706625674706214717428202', "zeta(-50.3)"); is(riemannr(123456.78901), "11602.45572750038581778127527882313233341", "riemannr(123456.78901)"); ############ li is(li("1.000000000000000000000000000000000000000000020886719363263",15), "-100.000000000000", "li(1.0000...2088..,15) rounds to -100"); is(li("1.000000000000000000000000000000000000000000020886719363263",25), "-99.99999999999996881196016", "li(1.0000...2088..,25)"); is(li(123456789,71), "7028122.5948718879000781801820670643068975005319034275491399869081030876", "li(123456789,71)"); is(li("1" . "3" x 48, 71), "12143015694679233755826665180456251925892758147.144721437041059310430449", "li(13333....333,71)"); ############ ei is(ei("-.999999",71),"-.21938430227532932486722325953484931808376271553585943741535217668894641", "ei(-.999999)"); is(ei(".0000001",71),"-15.540879886056784427519372537151549799926662195341116860222690550334380", "ei(-.0000001)"); is(ei(123,71),"2147292057663749807443512898798152106344989006252421.1953818484307608884", "ei(123)"); Math-Prime-Util-GMP-0.52/t/21-conseq-lcm.t0000644000175000017500000000664613025437621016257 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/consecutive_integer_lcm/; plan tests => 101 + 1; my @lcms = qw/ 1 1 2 6 12 60 60 420 840 2520 2520 27720 27720 360360 360360 360360 720720 12252240 12252240 232792560 232792560 232792560 232792560 5354228880 5354228880 26771144400 26771144400 80313433200 80313433200 2329089562800 2329089562800 72201776446800 144403552893600 144403552893600 144403552893600 144403552893600 144403552893600 5342931457063200 5342931457063200 5342931457063200 5342931457063200 219060189739591200 219060189739591200 9419588158802421600 9419588158802421600 9419588158802421600 9419588158802421600 442720643463713815200 442720643463713815200 3099044504245996706400 3099044504245996706400 3099044504245996706400 3099044504245996706400 164249358725037825439200 164249358725037825439200 164249358725037825439200 164249358725037825439200 164249358725037825439200 164249358725037825439200 9690712164777231700912800 9690712164777231700912800 591133442051411133755680800 591133442051411133755680800 591133442051411133755680800 1182266884102822267511361600 1182266884102822267511361600 1182266884102822267511361600 79211881234889091923261227200 79211881234889091923261227200 79211881234889091923261227200 79211881234889091923261227200 5624043567677125526551547131200 5624043567677125526551547131200 410555180440430163438262940577600 410555180440430163438262940577600 410555180440430163438262940577600 410555180440430163438262940577600 410555180440430163438262940577600 410555180440430163438262940577600 32433859254793982911622772305630400 32433859254793982911622772305630400 97301577764381948734868316916891200 97301577764381948734868316916891200 8076030954443701744994070304101969600 8076030954443701744994070304101969600 8076030954443701744994070304101969600 8076030954443701744994070304101969600 8076030954443701744994070304101969600 8076030954443701744994070304101969600 718766754945489455304472257065075294400 718766754945489455304472257065075294400 718766754945489455304472257065075294400 718766754945489455304472257065075294400 718766754945489455304472257065075294400 718766754945489455304472257065075294400 718766754945489455304472257065075294400 718766754945489455304472257065075294400 69720375229712477164533808935312303556800 69720375229712477164533808935312303556800 69720375229712477164533808935312303556800 69720375229712477164533808935312303556800 /; foreach my $n (0..100) { is( consecutive_integer_lcm($n), $lcms[$n], "consecutive_integer_lcm($n)" ); } is( consecutive_integer_lcm(2000), '151117794877444315307536308337572822173736308853579339903227904473000476322347234655122160866668946941993951014270933512030194957221371956828843521568082173786251242333157830450435623211664308500316844478617809101158220672108895053508829266120497031742749376045929890296052805527212315382805219353316270742572401962035464878235703759464796806075131056520079836955770415021318508272982103736658633390411347759000563271226062182345964184167346918225243856348794013355418404695826256911622054015423611375261945905974225257659010379414787547681984112941581325198396634685659217861208771400322507388161967513719166366839894214040787733471287845629833993885413462225294548785581641804620417256563685280586511301918399010451347815776570842790738545306707750937624267501103840324470083425714138183905657667736579430274197734179172691637931540695631396056193786415805463680000', "consecutive_integer_lcm(2000)" ); Math-Prime-Util-GMP-0.52/t/24-bernfrac.t0000644000175000017500000002623313061332056015771 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/bernfrac bernreal stirling harmfrac harmreal/; my $extra = defined $ENV{EXTENDED_TESTING} && $ENV{EXTENDED_TESTING}; my @A000367 = (qw/1 1 -1 1 -1 5 -691 7 -3617 43867 -174611 854513 -236364091 8553103 -23749461029 8615841276005 -7709321041217 2577687858367 -26315271553053477373 2929993913841559 -261082718496449122051 1520097643918070802691 -27833269579301024235023 596451111593912163277961 -5609403368997817686249127547 495057205241079648212477525 -801165718135489957347924991853 29149963634884862421418123812691 -2479392929313226753685415739663229 84483613348880041862046775994036021 -1215233140483755572040304994079820246041491/); my @A002445 = (qw/1 6 30 42 30 66 2730 6 510 798 330 138 2730 6 870 14322 510 6 1919190 6 13530 1806 690 282 46410 66 1590 798 870 354 56786730 6 510 64722 30 4686 140100870 6 30 3318 230010 498 3404310 6 61410 272118 1410 6 4501770 6 33330 4326 1590 642 209191710 1518 1671270 42/); # Generated by gp 2.8.0: for(n=0,20,printf("[qw/");for(m=0,n+1,printf("%d ",stirling(n,m,2)));printf("/],\n")) my @stirling2 = ( [qw/1 0/], [qw/0 1 0/], [qw/0 1 1 0/], [qw/0 1 3 1 0/], [qw/0 1 7 6 1 0/], [qw/0 1 15 25 10 1 0/], [qw/0 1 31 90 65 15 1 0/], [qw/0 1 63 301 350 140 21 1 0/], [qw/0 1 127 966 1701 1050 266 28 1 0/], [qw/0 1 255 3025 7770 6951 2646 462 36 1 0/], [qw/0 1 511 9330 34105 42525 22827 5880 750 45 1 0/], [qw/0 1 1023 28501 145750 246730 179487 63987 11880 1155 55 1 0/], [qw/0 1 2047 86526 611501 1379400 1323652 627396 159027 22275 1705 66 1 0/], [qw/0 1 4095 261625 2532530 7508501 9321312 5715424 1899612 359502 39325 2431 78 1 0/], [qw/0 1 8191 788970 10391745 40075035 63436373 49329280 20912320 5135130 752752 66066 3367 91 1 0/], [qw/0 1 16383 2375101 42355950 210766920 420693273 408741333 216627840 67128490 12662650 1479478 106470 4550 105 1 0/], [qw/0 1 32767 7141686 171798901 1096190550 2734926558 3281882604 2141764053 820784250 193754990 28936908 2757118 165620 6020 120 1 0/], [qw/0 1 65535 21457825 694337290 5652751651 17505749898 25708104786 20415995028 9528822303 2758334150 512060978 62022324 4910178 249900 7820 136 1 0/], [qw/0 1 131071 64439010 2798806985 28958095545 110687251039 197462483400 189036065010 106175395755 37112163803 8391004908 1256328866 125854638 8408778 367200 9996 153 1 0/], [qw/0 1 262143 193448101 11259666950 147589284710 693081601779 1492924634839 1709751003480 1144614626805 477297033785 129413217791 23466951300 2892439160 243577530 13916778 527136 12597 171 1 0/], [qw/0 1 524287 580606446 45232115901 749206090500 4306078895384 11143554045652 15170932662679 12011282644725 5917584964655 1900842429486 411016633391 61068660380 6302524580 452329200 22350954 741285 15675 190 1 0/], ); # Generated by gp 2.8.0: lah(n,k)={if(k>n,0,if(k==n,1,binomial(n-1,k-1)*n!/k!))}; for(n=0,20,printf("[qw/");for(m=0,n+1,printf("%d ",lah(n,m)));printf("/],\n")) my @stirling3 = ( [qw/1 0 /], [qw/0 1 0 /], [qw/0 2 1 0 /], [qw/0 6 6 1 0 /], [qw/0 24 36 12 1 0 /], [qw/0 120 240 120 20 1 0 /], [qw/0 720 1800 1200 300 30 1 0 /], [qw/0 5040 15120 12600 4200 630 42 1 0 /], [qw/0 40320 141120 141120 58800 11760 1176 56 1 0 /], [qw/0 362880 1451520 1693440 846720 211680 28224 2016 72 1 0 /], [qw/0 3628800 16329600 21772800 12700800 3810240 635040 60480 3240 90 1 0 /], [qw/0 39916800 199584000 299376000 199584000 69854400 13970880 1663200 118800 4950 110 1 0 /], [qw/0 479001600 2634508800 4390848000 3293136000 1317254400 307359360 43908480 3920400 217800 7260 132 1 0 /], [qw/0 6227020800 37362124800 68497228800 57081024000 25686460800 6849722880 1141620480 122316480 8494200 377520 10296 156 1 0 /], [qw/0 87178291200 566658892800 1133317785600 1038874636800 519437318400 155831195520 29682132480 3710266560 309188880 17177160 624624 14196 182 1 0 /], [qw/0 1307674368000 9153720576000 19833061248000 19833061248000 10908183686400 3636061228800 779155977600 111307996800 10821610800 721440720 32792760 993720 19110 210 1 0 /], [qw/0 20922789888000 156920924160000 366148823040000 396661224960000 237996734976000 87265469491200 20777492736000 3339239904000 371026656000 28857628800 1574052480 59623200 1528800 25200 240 1 0 /], [qw/0 355687428096000 2845499424768000 7113748561920000 8299373322240000 5394592659456000 2157837063782400 565147802419200 100919250432000 12614906304000 1121325004800 71357045760 3243502080 103958400 2284800 32640 272 1 0 /], [qw/0 6402373705728000 54420176498688000 145120470663168000 181400588328960000 126980411830272000 55024845126451200 15721384321843200 3088129063219200 428906814336000 42890681433600 3119322286080 165418606080 6362254080 174787200 3329280 41616 306 1 0 /], ); my @stirling1 = ( [qw/1 0/], [qw/0 1 0/], [qw/0 -1 1 0/], [qw/0 2 -3 1 0/], [qw/0 -6 11 -6 1 0/], [qw/0 24 -50 35 -10 1 0/], [qw/0 -120 274 -225 85 -15 1 0/], [qw/0 720 -1764 1624 -735 175 -21 1 0/], [qw/0 -5040 13068 -13132 6769 -1960 322 -28 1 0/], [qw/0 40320 -109584 118124 -67284 22449 -4536 546 -36 1 0/], [qw/0 -362880 1026576 -1172700 723680 -269325 63273 -9450 870 -45 1 0/], [qw/0 3628800 -10628640 12753576 -8409500 3416930 -902055 157773 -18150 1320 -55 1 0/], [qw/0 -39916800 120543840 -150917976 105258076 -45995730 13339535 -2637558 357423 -32670 1925 -66 1 0/], [qw/0 479001600 -1486442880 1931559552 -1414014888 657206836 -206070150 44990231 -6926634 749463 -55770 2717 -78 1 0/], [qw/0 -6227020800 19802759040 -26596717056 20313753096 -9957703756 3336118786 -790943153 135036473 -16669653 1474473 -91091 3731 -91 1 0/], [qw/0 87178291200 -283465647360 392156797824 -310989260400 159721605680 -56663366760 14409322928 -2681453775 368411615 -37312275 2749747 -143325 5005 -105 1 0/], [qw/0 -1307674368000 4339163001600 -6165817614720 5056995703824 -2706813345600 1009672107080 -272803210680 54631129553 -8207628000 928095740 -78558480 4899622 -218400 6580 -120 1 0/], [qw/0 20922789888000 -70734282393600 102992244837120 -87077748875904 48366009233424 -18861567058880 5374523477960 -1146901283528 185953177553 -23057159840 2185031420 -156952432 8394022 -323680 8500 -136 1 0/], [qw/0 -355687428096000 1223405590579200 -1821602444624640 1583313975727488 -909299905844112 369012649234384 -110228466184200 24871845297936 -4308105301929 577924894833 -60202693980 4853222764 -299650806 13896582 -468180 10812 -153 1 0/], [qw/0 6402373705728000 -22376988058521600 34012249593822720 -30321254007719424 17950712280921504 -7551527592063024 2353125040549984 -557921681547048 102417740732658 -14710753408923 1661573386473 -147560703732 10246937272 -549789282 22323822 -662796 13566 -171 1 0/], [qw/0 -121645100408832000 431565146817638400 -668609730341153280 610116075740491776 -371384787345228000 161429736530118960 -52260903362512720 12953636989943896 -2503858755467550 381922055502195 -46280647751910 4465226757381 -342252511900 20692933630 -973941900 34916946 -920550 16815 -190 1 0/], ); plan tests => 2 + scalar(@stirling3) + scalar(@stirling2) + scalar(@stirling1) + 3 + 2+6 + 4; { my @num = map { (bernfrac(2*$_))[0] } 0 .. $#A000367; my @den = map { (bernfrac(2*$_))[1] } 0 .. $#A002445; is_deeply( \@num, \@A000367, "B_2n numerators 0 .. $#A000367" ); is_deeply( \@den, \@A002445, "B_2n denominators 0 .. $#A002445" ); } { my $n = 0; foreach my $narr (@stirling3) { my @s2 = map { stirling($n,$_,3) } 0..$n+1; is_deeply( \@s2, $narr, "Stirling 3: L($n,0..". ($n+1) .")" ); $n++; } } { my $n = 0; foreach my $narr (@stirling2) { my @s2 = map { stirling($n,$_,2) } 0..$n+1; is_deeply( \@s2, $narr, "Stirling 2: S($n,0..". ($n+1) .")" ); $n++; } } { my $n = 0; foreach my $narr (@stirling1) { my @s1 = map { stirling($n,$_,1) } 0..$n+1; is_deeply( \@s1, $narr, "Stirling 1: s($n,0..". ($n+1) .")" ); $n++; } } # Random large values is( stirling(246,61,3), '16781089031289908648739894658187968503831038435579384473036844176021715959960063309748494851984040210112281911986359570651366793437675293554444919512994972542928372289858529733210971633662476717598808875335617639975100691881555975405754262383248739607900482185116908949278639778972088005321758840374848760552543345287066862821699035121991640194236911712299712310508321119592475284255246533432645238910745625755648000000000000000000000000000000000000000000000', "L(246,61)" ); is( stirling(137,14,2), '119921091552849030298712472784655311636455680166733181212686613915193327160253320582242126677455942135033082921631146726468348015037515052954267400', "S(137,14)" ); is( stirling(99,14,1), '-76185801962487294910690331431878395972434237854033124053130281967496159110075633618163409236750708320666097319441407130017141175404355750702612480000000', "s(99,14)" ); ########### is_deeply( [harmfrac(27)], [qw/312536252003 80313433200/], "harmfrac(27)"); is_deeply( [harmfrac(172)], [qw/79501058066082280981403896527589637839225193778798494740482914683623969349 13880309301456766718169645534485312116208863916210197754275864148562288000/], "harmfrac(172)"); is( harmreal(5,6), "2.28333", "harmreal(5,6)" ); is( harmreal(15,3), "3.32", "harmreal(15,3)" ); is( harmreal(15,25), "3.318228993228993228993229", "harmreal(15,25)" ); is( harmreal(1500,85), "7.890769348288132237024982466533383516587334672793034866299830645277849644355893942483", "harmreal(1500,85)" ); is( harmreal(2502,764), "8.4022611827442616317889358234638600819223549876775756009040579007028304622396704717826054849631311959827336370652350363210214348075460454127806820991887787301726524318112301788039510819911216154119126624804602690267244260972035688366573000214774520753765479437246871327307674220381391918202939677188395567028236867891536047084719881902222764381394522556877103822410093096790602691889769666625414585123756378881628875119610391914967976757016187471943182230789317973147668458937306028722119815966094143929327181951971889166127652438346064969183176053197768023014774945977838767778096364258279792884478027384432419591251420003615953125404288714656235208556151078286913808883501164776686214636296222092373622320260770103224594844688053478029558802715467037435761134100", "harmreal(2502,764)" ); is( harmreal(2502,765), "8.40226118274426163178893582346386008192235498767757560090405790070283046223967047178260548496313119598273363706523503632102143480754604541278068209918877873017265243181123017880395108199112161541191266248046026902672442609720356883665730002147745207537654794372468713273076742203813919182029396771883955670282368678915360470847198819022227643813945225568771038224100930967906026918897696666254145851237563788816288751196103919149679767570161874719431822307893179731476684589373060287221198159660941439293271819519718891661276524383460649691831760531977680230147749459778387677780963642582797928844780273844324195912514200036159531254042887146562352085561510782869138088835011647766862146362962220923736223202607701032245948446880534780295588027154670374357611340997", "harmreal(2502,765)" ); ########### is( bernreal(24), "-86580.25311355311355311355311355311355311", "bern(24)" ); is( bernreal(16,5), "-7.0922", "bern(16,5)" ); is( bernreal(200,7), "-3647077E209", "bern(200,7)" ); is( bernreal(222,260), "1427295874284878567714163200871224998971799130039664528732851045408568226351052228503180915783619081891275551756930326329197981112038254961419750276336559804985081989565349639529368205790276538674423444433770367136781907003735697448421366567512564135.0193252189", "bern(222,260)" ); Math-Prime-Util-GMP-0.52/t/23-gcd.t0000644000175000017500000002344113663067455014761 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/gcd lcm kronecker valuation hammingweight invmod is_power is_prime_power is_square binomial gcdext vecsum vecprod/; my $extra = defined $ENV{EXTENDED_TESTING} && $ENV{EXTENDED_TESTING}; my @gcds = ( [ [], 0], [ [8], 8], [ [9,9], 9], [ [0,0], 0], [ [1, 0, 0], 1], [ [0, 0, 1], 1], [ [17,19], 1 ], [ [54,24], 6 ], [ [42,56], 14], [ [ 9,28], 1 ], [ [48,180], 12], [ [2705353758,2540073744,3512215098,2214052398], 18], [ [2301535282,3609610580,3261189640], 106], [ [694966514,510402262,195075284,609944479], 181], [ [294950648,651855678,263274296,493043500,581345426], 58 ], [ [-30,-90,90], 30], [ [-3,-9,-18], 3], ); my @lcms = ( [ [], 0], [ [8], 8], [ [9,9], 9], [ [0,0], 0], [ [1, 0, 0], 0], [ [0, 0, 1], 0], [ [17,19], 323 ], [ [54,24], 216 ], [ [42,56], 168], [ [ 9,28], 252 ], [ [48,180], 720], [ [36,45], 180], [ [-36,45], 180], [ [-36,-45], 180], [ [30,15,5], 30], [ [2,3,4,5], 60], [ [30245, 114552], 3464625240], [ [11926,78001,2211], 2790719778], [ [1426,26195,3289,8346], 4254749070], ); my @kroneckers = ( [ 109981, 737777, 1], [ 737779, 121080, -1], [-737779, 121080, 1], [ 737779,-121080, -1], [-737779,-121080, -1], [12345,331,-1], [1001,9907,-1], [19,45,1], [8,21,-1], [5,21,1], [5,1237,-1], [10, 49, 1], [123,4567,-1], [3,18,0], [3,-18,0], [-2, 0, 0], [-1, 0, 1], [ 0, 0, 0], [ 1, 0, 1], [ 2, 0, 0], [-2, 1, 1], [-1, 1, 1], [ 0, 1, 1], [ 1, 1, 1], [ 2, 1, 1], [-2,-1,-1], [-1,-1,-1], [ 0,-1, 1], [ 1,-1, 1], [ 2,-1, 1], # Some cases trying to make sure we're not turning UVs into IVs [ 3686556869, 428192857, 1], [-1453096827, 364435739, -1], [ 3527710253, -306243569, 1], [-1843526669, -332265377, 1], [ 321781679, 4095783323, -1], [ 454249403, -79475159, -1], ); my @valuations = ( [-4,2, 2], [0,0, 0], [1,0, 0], [96552,6, 3], [1879048192,2, 28], ); my @binomials = ( [ 0,0, 1 ], [ 0,1, 0 ], [ 1,0, 1 ], [ 1,1, 1 ], [ 1,2, 0 ], [ 13,13, 1 ], [ 13,14, 0 ], [ 35,16, 4059928950 ], # We can do this natively even in 32-bit [ 40,19, "131282408400" ], # We can do this in 64-bit [ 67,31, "11923179284862717872" ], # ...and this [ 228,12, "30689926618143230620" ],# But the result of this is too big. [ 177,78, "3314450882216440395106465322941753788648564665022000" ], [ -10,5, -2002 ], [ -11,22, 64512240 ], [ -12,23, -286097760 ], [ -23,-26, -2300 ], # Kronenburg extension [ -12,-23, -705432 ], # same [ 12,-23, 0 ], [ 12,-12, 0 ], [ -12,0, 1 ], [ 0,-1, 0 ], ); my @gcdexts = ( [ [0, 0], [0, 0, 0] ], [ [0, 28], [0, 1,28] ], [ [ 28,0], [ 1,0,28] ], [ [0,-28], [0,-1,28] ], [ [-28,0], [-1,0,28] ], [ [ 3706259912, 1223661804], [ 123862139,-375156991, 4] ], [ [ 3706259912,-1223661804], [ 123862139, 375156991, 4] ], [ [-3706259912, 1223661804], [-123862139,-375156991, 4] ], [ [-3706259912,-1223661804], [-123862139, 375156991, 4] ], [ [22,242], [1, 0, 22] ], [ [2731583792,3028241442], [-187089956, 168761937, 2] ], [ [42272720,12439910], [-21984, 74705, 70] ], [ ["10139483024654235947","8030280778952246347"], ["-2715309548282941287","3428502169395958570",1] ], ); my @vecsums = ( [ 0 ], [ -1, -1 ], [ 0, 1,-1 ], [ 0, -1,1 ], [ 0, -1,1 ], [ 0, -2147483648,2147483648 ], [ 0, "-4294967296","4294967296" ], [ 0, "-9223372036854775808","9223372036854775808" ], [ "18446744073709551615", "18446744073709551615","-18446744073709551615","18446744073709551615" ], [ "55340232221128654848", "18446744073709551616","18446744073709551616","18446744073709551616" ], [ "18446744073709620400", "18446744073709540400", (1000) x 80 ], [ "22229615424432722482764646042115836201380906995100292325888852211992579", "8940560560432415123818915720822415267807123681474252424566821897853531", "7778547618243732438765515250718016989143156212607337512983395245244477", "2189527014402679437989261998352299668199802723705390949617417617818071", "-3503124593441728232550096334002786135023", "3320980231353895482190953072226607400824266105545861535055220237211523" ], ); my @vecprods = ( [ 1 ], [ 1, 1 ], [ -1, -1 ], [ 2, -1, -2 ], [ 2, -1, -2 ], [ "-2147385345", 32767, -65535 ], [ "-2147385345", 32767, -65535 ], [ "-2147450880", 32768, -65535 ], [ "-2147483648", 32768, -65536 ], [ "6277101735386680763835789423207666416102355444464034512896", "18446744073709551616","18446744073709551616","18446744073709551616" ], [ "-39379245925303999064282306510014189368381156100297892522429483126331668772925108615466135642644100480444268237833039496827424630610878534616461996117558125896627456342217566092980432383889727428817722190472716948287416569075064047381625246037918268748866755509776641498138274065792670793438081730710568979196957310574284265747455825604868707218992022874441687475660523342376167971071980207", "22229615424432722482764646042115836201380906995100292325888852211992579", "8940560560432415123818915720822415267807123681474252424566821897853531", "7778547618243732438765515250718016989143156212607337512983395245244477", "2189527014402679437989261998352299668199802723705390949617417617818071", "-3503124593441728232550096334002786135023", "3320980231353895482190953072226607400824266105545861535055220237211523" ], ); plan tests => scalar(@gcds) + scalar(@lcms) + scalar(@kroneckers) + scalar(@valuations) + 5 + 2 + scalar(@binomials) + scalar(@gcdexts) + scalar(@vecsums) + scalar(@vecprods) + 3 + 3 + 1 + 5 + 3 + 3; foreach my $garg (@gcds) { my($aref, $exp) = @$garg; my $gcd = gcd(@$aref); is( $gcd, $exp, "gcd(".join(",",@$aref).") = $exp" ); } foreach my $garg (@lcms) { my($aref, $exp) = @$garg; my $lcm = lcm(@$aref); is( $lcm, $exp, "lcm(".join(",",@$aref).") = $exp" ); } foreach my $karg (@kroneckers) { my($a, $n, $exp) = @$karg; my $k = kronecker($a, $n); is( $k, $exp, "kronecker($a, $n) = $exp" ); } foreach my $r (@valuations) { my($n, $k, $exp) = @$r; is( valuation($n, $k), $exp, "valuation($n,$k) = $exp" ); } is(hammingweight(0), 0, "hammingweight(0) = 0"); is(hammingweight(1), 1, "hammingweight(1) = 1"); is(hammingweight(2304786), 9, "hammingweight(2304786) = 9"); is(hammingweight(-2304786), 9, "hammingweight(-2304786) = 9"); is(hammingweight("19795792123893480164707100824397222730984965037169701408771662919270303874559"), 128, "hammingweight(<256-bit prime>) = 128"); foreach my $r (@binomials) { my($n, $k, $exp) = @$r; is( binomial($n,$k), $exp, "binomial($n,$k)) = $exp" ); } is_deeply( [map { binomial(10, $_) } -15 .. 15], [qw/0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 10 45 120 210 252 210 120 45 10 1 0 0 0 0 0/], "binomial(10,n) for n in -15 .. 15" ); is_deeply( [map { binomial(-10, $_) } -15 .. 15], [qw/-2002 715 -220 55 -10 1 0 0 0 0 0 0 0 0 0 1 -10 55 -220 715 -2002 5005 -11440 24310 -48620 92378 -167960 293930 -497420 817190 -1307504/], "binomial(-10,n) for n in -15 .. 15" ); foreach my $garg (@gcdexts) { my($aref, $eref) = @$garg; my($x,$y) = @$aref; is_deeply( [gcdext($x,$y)], $eref, "gcdext($x,$y) = [@$eref]" ); } foreach my $r (@vecsums) { my($exp, @vals) = @$r; is( vecsum(@vals), $exp, "vecsum(@vals) = $exp" ); } foreach my $r (@vecprods) { my($exp, @vals) = @$r; is( vecprod(@vals), $exp, "vecprod(@vals) = $exp" ); } is( gcd("921166566073002915606255698642","1168315374100658224561074758384","951943731056111403092536868444"), 14, "gcd(a,b,c)" ); is( gcd("1214969109355385138343690512057521757303400673155500334102084","1112036111724848964580068879654799564977409491290450115714228"), 42996, "gcd(a,b)" ); is( gcd("745845206184162095041321","61540282492897317017092677682588744425929751009997907259657808323805386381007"), 1, "gcd of two primes = 1" ); is( lcm("9999999998987","10000000001011"), "99999999999979999998975857", "lcm(p1,p2)" ); is( lcm("892478777297173184633","892478777297173184633"), "892478777297173184633", "lcm(p1,p1)" ); is( lcm("23498324","32497832409432","328732487324","328973248732","3487234897324"), "1124956497899814324967019145509298020838481660295598696", "lcm(a,b,c,d,e)" ); is( kronecker("878944444444444447324234","216539985579699669610468715172511426009"), -1, "kronecker(..., ...)" ); is( is_power("18475335773296164196"), "0", "is_power(18475335773296164196) == 0" ); is( is_power("1415842012524355766113858481287417543594447475938337587864641453047142843853822559252126433860162253504357722982805134804808530350591698526668732807053601"), "18", "is_power(322396049^18) == 18" ); is( is_power("195820481042341245090221890868767224469265867337457650976172728836917821923718632978263135461761"), "16", "is_power(903111^16) == 16" ); ok( is_power("195820481042341245090221890868767224469265867337457650976172728836917821923718632978263135461761",4), "is_power(903111^16,4) is true" ); is( is_power("894311843364148115560351871258324837202590615410044436950984649"), "2", "is_power(29905047121918201644964877983907^2) == 2" ); is( is_prime_power("18475335773296164196"), "0", "is_prime_power(18475335773296164196) == 0" ); is( is_prime_power("894311843364148115560351871258324837202590615410044436950984649"), 0, "is_prime_power(29905047121918201644964877983907^2) == 0" ); is( is_prime_power("1415842012524355766113858481287417543594447475938337587864641453047142843853822559252126433860162253504357722982805134804808530350591698526668732807053601"), "18", "is_prime_power(322396049^18) == 18" ); is_deeply( [map { is_square($_) } (-4 .. 16)], [0,0,0,0,1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,1], "is_square for -4 .. 16" ); is(is_square(60481729), 1, "60481729 is a square"); is(is_square("1147957727564358902879339073765020815402752648121"), 1, "is_square() = 1"); Math-Prime-Util-GMP-0.52/t/25-const-pi.t0000644000175000017500000000263713663067455015766 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/Pi/; my $PI = '3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420199'; plan tests => 1; is_deeply( [map { Pi($_) } 2 .. 999], [map { piround($_) } 2 .. 999], "Pi(2 .. 999)" ); sub piround { my $n = shift; return 3 if $n == 1; my $pi = substr($PI,0,$n+1); my $roundlen = ($n > 500) ? 8 : 3; substr($pi,-$roundlen,$roundlen)++ if substr($PI,$n+1,1) >= 5; $pi; } Math-Prime-Util-GMP-0.52/t/16-provableprime.t0000644000175000017500000001612413025437621017061 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/is_provable_prime is_provable_prime_with_cert is_aks_prime is_miller_prime is_ecpp_prime is_nminus1_prime is_nplus1_prime is_bls75_prime/; plan tests => 0 + 6 + 38 + 43 + 34 + 2 + 7 # _with_cert + 8 # AKS, Miller, N-1, ECPP + 0; is(is_provable_prime(2) , 2, '2 is prime'); is(is_provable_prime(1) , 0, '1 is not prime'); is(is_provable_prime(0) , 0, '0 is not prime'); is(is_provable_prime(-1), 0, '-1 is not prime'); is(is_provable_prime(-2), 0, '-2 is not prime'); is(is_provable_prime(20), 0, '20 is not prime'); foreach my $n ( qw/2152302898747 3474749660383 341550071728321 341550071728321 3825123056546413051 561 1105 1729 2465 2821 6601 8911 10585 15841 29341 41041 46657 52633 4681 5461 6601 7957 8321 52633 88357 44287 47197 55969 63139 74593 79003 82513 87913 88573 97567 44801 53971 79381 /) { is(is_provable_prime($n), 0, "$n is not prime"); } foreach my $n ( qw/2 3 7 23 89 113 523 887 1129 1327 9551 15683 19609 31397 155921 5 11 29 97 127 541 907 1151 1361 9587 15727 19661 31469 156007 360749 370373 492227 1349651 1357333 2010881 4652507 17051887 20831533 47326913 122164969 189695893 191913031 10726905041 /) { is(is_provable_prime($n), 2, "$n is prime"); } # Generated using: # perl -Iblib/lib -Iblib/arch -Mbignum -MMath::Prime::Util::GMP=:all -E '$|=1; use Time::HiRes qw(gettimeofday tv_interval); foreach my $e (62 .. 1000) { my $n = Math::BigInt->new(2)->bpow($e); $n = next_prime($n); my $s = [gettimeofday]; my $isp = is_prime($n); my $sec = tv_interval($s); printf("%d %s %d %6.2fms\n", $e, "$n", $isp, $sec*1000.0); }' | grep ' 2 ' # after having is_prime do a quick test on all inputs. # Remove all the inputs that take too long. # Then run through GMP-ECPP to make sure. foreach my $n ( qw/9223372036854775837 18446744073709551629 73786976294838206473 147573952589676412931 295147905179352825889 590295810358705651741 1180591620717411303449 2361183241434822606859 18889465931478580854821 37778931862957161709601 75557863725914323419151 302231454903657293676551 604462909807314587353111 38685626227668133590597803 1237940039285380274899124357 9903520314283042199192993897 316912650057057350374175801351 2535301200456458802993406410833 162259276829213363391578010288167 1298074214633706907132624082305051 10384593717069655257060992658440473 1329227995784915872903807060280345027 680564733841876926926749214863536422929 43556142965880123323311949751266331066401 87112285931760246646623899502532662132821 713623846352979940529142984724747568191373381 2854495385411919762116571938898990272765493293 196159429230833773869868419475239575503198607639501078831 3138550867693340381917894711603833208051177722232017256453 12554203470773361527671578846415332832204710888928069025857 102844034832575377634685573909834406561420991602098741459288097 210624583337114373395836055367340864637790190801098222508621955201 14821387422376473014217086081112052205218558037201992197050570753012880593911817 3351951982485649274893506249551461531869841455148098344430890360930441007518386744200468574541725856922507964546621512713438470702986642486608412251521039 /) { is(is_provable_prime($n), 2, "$n is prime"); } is(is_provable_prime('340282366920938463463374607431768211507'), 2, "is_prime(2**128+51) = 2"); is(is_provable_prime('340282366920938463463374607431768211621'), 2, "is_provable_prime(2**128+165) == 2"); is_deeply( [is_provable_prime_with_cert(0)], [0, ''], "is_provable_prime_with_cert(0)"); { my @scert = is_provable_prime_with_cert(2); ok($scert[0] == 2 && $scert[1] =~ /\bType Small\nN 2\b/, "is_provable_prime_with_cert(2)"); } { my @scert = is_provable_prime_with_cert(96953); ok($scert[0] == 2 && $scert[1] =~ /\bType Small\nN 96953\b/, "is_provable_prime_with_cert(96953)"); } my $proof; $proof = < 4294967295); my $extra = defined $ENV{EXTENDED_TESTING} && $ENV{EXTENDED_TESTING}; my $maxbits = $use64 ? 64 : 32; my $samples = $extra ? 100000 : 10000; plan tests => 0 + 2 + ($use64 ? 2 : 0) + 2; ######## # seed_csprng(55,"BLAKEGrostlJHKeccakSkein--RijndaelSerpentTwofishRC6MARS"); ######## { my @s = map { irand } 1 .. $samples; is( scalar(grep { $_ > 4294967295 } @s), 0, "irand values are 32-bit" ); is( scalar(grep { $_ != int($_) } @s), 0, "irand values are integers" ); } ######## if ($use64) { my $bits_on = 0; my $bits_off = 0; my $iter = 0; for (1 .. 6400) { $iter++; my $v = irand64; $bits_on |= $v; $bits_off |= (~$v); last if ~$bits_on == 0 && ~$bits_off == 0; } is( ~$bits_on, 0, "irand64 all bits on in $iter iterations" ); is( ~$bits_off, 0, "irand64 all bits off in $iter iterations" ); } ######## { my $mask = 0; my $v; for (1..1024) { $v = drand; last if $v >= 1; next if $v < .5; for my $b (0..127) { last unless $v; $v *= 2; if ($v >= 1) { $mask |= (1 << $b); $v -= 1; } } } ok($v < 1, "drand values between 0 and 1-eps"); my $k = 0; while ($mask) { $k++; $mask >>= 1; } # Assuming drand is working properly: # k = 24 NV is float # k = 53 NV is double # k = 64 NV is long double # If we used drand48 we'd get 48 with double or long double. ok($k >= 21, "drand supplies at least 21 bits (got $k)"); } Math-Prime-Util-GMP-0.52/t/93-release-spelling.t0000644000175000017500000000170713663067455017467 0ustar danadana#!/usr/bin/env perl use strict; use warnings; BEGIN { unless ($ENV{RELEASE_TESTING}) { require Test::More; Test::More::plan(skip_all => 'these tests are for release candidate testing'); } } #--------------------------------------------------------------------- use Test::More; eval "use Test::Spellunker"; plan skip_all => "Test::Spellunker required for testing POD spelling" if $@; add_stopwords(qw/bigint bigints bignum bignums primorial subfactorial multifactorials gcd lcm kronecker invmod exp irand irand64 drand drand64 urandomm urandomb factorialmod hammingweight numtoperm permtonum semiprime semiprimes coprime k-tuples precalculated premultiplier pseudoprime pseudoprimes p-adic tinyqs -th von PSP-2 pp/); all_pod_files_spelling_ok(); Math-Prime-Util-GMP-0.52/t/28-randomprime.t0000644000175000017500000001436213663067455016550 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::BigInt try=>"GMP,Pari"; use Math::Prime::Util::GMP qw/random_prime random_ndigit_prime random_nbit_prime random_safe_prime random_strong_prime random_maurer_prime random_shawe_taylor_prime random_maurer_prime_with_cert random_shawe_taylor_prime_with_cert is_prime seed_csprng/; my $use64 = (~0 > 4294967295); my $extra = defined $ENV{EXTENDED_TESTING} && $ENV{EXTENDED_TESTING}; my $maxbits = $use64 ? 64 : 32; my @random_to = (2, 3, 4, 5, 6, 7, 8, 9, 100, 1000, 1000000, 4294967295); my @random_nbit_tests = (2 .. 6, 10, 30 .. 34, 62 .. 66, 126 .. 130); push @random_nbit_tests, (256, 512, 1024, 2048) if $extra; my @random_ndigit_tests = (1 .. 25); my @random_safe_tests = (16, 32, 33, 34, 64, 128, 255, 256, 512); my @random_strong_tests = (128, 255, 256, 512); my %ranges = ( "2 to 20" => [2,19], "3 to 7" => [3,7], "20 to 100" => [23,97], "5678 to 9876" => [5683,9871], "27767 to 88493" => [27767,88493], "27764 to 88498" => [27767,88493], "27764 to 88493" => [27767,88493], "27767 to 88498" => [27767,88493], "17051687 to 17051899" => [17051687,17051899], "17051688 to 17051898" => [17051707,17051887], ); my %range_edge = ( "0 to 2" => [2,2], "2 to 2" => [2,2], "2 to 3" => [2,3], "3 to 5" => [3,5], "10 to 20" => [11,19], "8 to 12" => [11,11], "10 to 12" => [11,11], "16706143 to 16706143" => [16706143,16706143], "16706142 to 16706144" => [16706143,16706143], "3842610773 to 3842611109" => [3842610773,3842611109], "3842610772 to 3842611110" => [3842610773,3842611109], ); my %range_edge_empty = ( "0 to 0" => [], "0 to 1" => [], "2 to 1" => [], "3 to 2" => [], "1294268492 to 1294268778" => [], "3842610774 to 3842611108" => [], ); plan tests => 0 + (1 * scalar (keys %range_edge_empty)) + (3 * scalar (keys %range_edge)) + (2 * scalar (keys %ranges)) + (2 * scalar @random_to) + (1 * scalar @random_ndigit_tests) + (1 * scalar @random_nbit_tests) + (2 * scalar @random_safe_tests) + (1 * scalar @random_strong_tests) + (2 * scalar @random_nbit_tests) # proven primes + 6 + 0; my $infinity = 20**20**20; my $nrandom_range_samples = $extra ? 1000 : 50; while (my($range, $expect) = each (%range_edge_empty)) { my($low,$high) = $range =~ /(\d+) to (\d+)/; is( random_prime($low,$high), undef, "primes($low,$high) should return undef" ); } while (my($range, $expect) = each (%range_edge)) { my($low,$high) = $range =~ /(\d+) to (\d+)/; my $got = random_prime($low,$high); ok( is_prime($got), "Prime in range $low-$high is indeed prime" ); cmp_ok( $got, '>=', $expect->[0], "random_prime($low,$high) >= $expect->[0]"); cmp_ok( $got, '<=', $expect->[1], "random_prime($low,$high) <= $expect->[1]"); } while (my($range, $expect) = each (%ranges)) { my($low,$high) = $range =~ /(\d+) to (\d+)/; my $isprime = 1; my $inrange = 1; for (1 .. $nrandom_range_samples) { my $got = random_prime($low,$high); $isprime *= is_prime($got) ? 1 : 0; $inrange *= (($got >= $expect->[0]) && ($got <= $expect->[1])) ? 1 : 0; } ok($isprime, "All returned values for $low-$high were prime" ); ok($inrange, "All returned values for $low-$high were in the range" ); } foreach my $high (@random_to) { my $isprime = 1; my $inrange = 1; for (1 .. $nrandom_range_samples) { my $got = random_prime(0,$high); $isprime *= is_prime($got) ? 1 : 0; $inrange *= (($got >= 2) && ($got <= $high)) ? 1 : 0; } ok($isprime, "All returned values for $high were prime" ); ok($inrange, "All returned values for $high were in the range" ); } foreach my $digits ( @random_ndigit_tests ) { my $n = random_ndigit_prime($digits); ok ( length($n) == $digits && is_prime($n), "$digits-digit random prime '$n' is in range and prime"); } foreach my $bits ( @random_nbit_tests ) { check_bits( random_nbit_prime($bits), $bits, "random $bits-bit" ); } foreach my $bits ( @random_safe_tests ) { my $p = random_safe_prime($bits); my $q = (Math::BigInt->new("$p") - 1) >> 1; check_bits( $p, $bits, "random $bits-bit safe (p)" ); check_bits( $q, $bits-1, "random $bits-bit safe (q)" ); } foreach my $bits ( @random_strong_tests ) { # TODO: Check that p-1 and p+1 have a big factor. Might be really slow. check_bits( random_strong_prime($bits), $bits, "random $bits-bit strong" ); } foreach my $bits ( @random_nbit_tests ) { check_bits( random_maurer_prime($bits), $bits, "random $bits-bit proven (Maurer)" ); check_bits( random_shawe_taylor_prime($bits), $bits, "random $bits-bit proven (Shawe-Taylor)" ); } sub check_bits { my($n, $bits, $what) = @_; $n = Math::BigInt->new("$n"); my $min = Math::BigInt->new(1)->blsft($bits-1); my $max = Math::BigInt->new(1)->blsft($bits)->bdec; ok ( $n >= $min && $n <= $max && is_prime($n), "$bits-bit random $what prime '$n' is in range and prime"); } # Now check with seed seed_csprng(3,"xyz"); is( random_nbit_prime(24), 10207999, "random 20-bit prime with seeded rng" ); is( random_ndigit_prime(9), 842208331, "random 9-digit with seeded rng" ); { my($n,$cert) = random_maurer_prime_with_cert(139); is( $n, "461450530708271369919467043900581427327289", "random Maurer prime" ); is( $cert, "[MPU - Primality Certificate] Version 1.0 Proof for: N 461450530708271369919467043900581427327289 Type BLS3 N 461450530708271369919467043900581427327289 Q 399271657906884417934953679 A 23 Type BLS3 N 399271657906884417934953679 Q 125756461377167 A 3 Type BLS3 N 125756461377167 Q 18944413 A 5 ", "random Maurer prime certificate" ); } { my($n,$cert) = random_shawe_taylor_prime_with_cert(147); is( $n, "175813161209418279279866476297230082927452359", "random Shawe-Taylor prime" ); is( $cert, "[MPU - Primality Certificate] Version 1.0 Proof for: N 175813161209418279279866476297230082927452359 Type Pocklington N 175813161209418279279866476297230082927452359 Q 34388730545435187832661 A 67309515455075813303416848806399820637730471 Type Pocklington N 34388730545435187832661 Q 482980495961 A 23452682901285108721511 Type Pocklington N 482980495961 Q 1061869 A 178206865367 ", "random Shawe-Taylor prime certificate" ); } Math-Prime-Util-GMP-0.52/t/50-factoring.t0000644000175000017500000003107613061332056016163 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/factor is_prime sigma divisors is_semiprime/; my %sigmas = ( 0 => [2,1,1,1], 1 => [1,1,1,1], 2 => [2,3,5,9], 3 => [2,4,10,28], 4 => [3,7,21,73], 5 => [2,6,26,126], 6 => [4,12,50,252], 7 => [2,8,50,344], 8 => [4,15,85,585], 46 => [4,72,2650,109512], 189 => [8,320,41000,7031360], 23948 => [6,41916,752727570,"15665729905692"], 2394823486 => [8,"3918802104","7228222133779519700","15463194466651766947470799224"], ); plan tests => 0 + 57 + 24 + 2 + 6 # individual tets for factoring methods + 7*7 # factor extra tests + 8 # factor in scalar context + scalar(keys %sigmas) + 3 # divisors + 2 # is_semiprime + 0; # On a 64-bit machine, put all 32-bit nums in /tmp/foo, 64-bit in /tmp/foo2 # for i in `sort -n /tmp/foo`; do perl -MMath::Factor::XS=:all -E "say 'is_deeply( [ factor(', $i, ') ], [', join(',', prime_factors($i)), '], \"factor($i)\" );';"; done # for i in `sort -n /tmp/foo2`; do perl -MMath::Factor::XS=:all -E "say 'is_deeply( [ factor(\'', $i, '\') ], [', join(',', prime_factors($i)), '], \"factor($i)\" );';"; done # # For the latter, check every factor to make sure it fits in 32-bit, quote if # not. Run anything larger than 64-bit through Yafu or Pari. # # The obvious point here is that we shouldn't generate tests using our own code, # unless we want to hand verify each case (admittedly not that hard). # #diag "factoring 32-bit numbers"; is_deeply( [ factor(0) ], [0], "factor(0)" ); is_deeply( [ factor(1) ], [], "factor(1)" ); is_deeply( [ factor(2) ], [2], "factor(2)" ); is_deeply( [ factor(3) ], [3], "factor(3)" ); is_deeply( [ factor(4) ], [2,2], "factor(4)" ); is_deeply( [ factor(5) ], [5], "factor(5)" ); is_deeply( [ factor(6) ], [2,3], "factor(6)" ); is_deeply( [ factor(7) ], [7], "factor(7)" ); is_deeply( [ factor(8) ], [2,2,2], "factor(8)" ); is_deeply( [ factor(16) ], [2,2,2,2], "factor(16)" ); is_deeply( [ factor(30) ], [2,3,5], "factor(30)" ); is_deeply( [ factor(57) ], [3,19], "factor(57)" ); is_deeply( [ factor(64) ], [2,2,2,2,2,2], "factor(64)" ); is_deeply( [ factor(210) ], [2,3,5,7], "factor(210)" ); is_deeply( [ factor(377) ], [13,29], "factor(377)" ); is_deeply( [ factor(403) ], [13,31], "factor(403)" ); is_deeply( [ factor(629) ], [17,37], "factor(629)" ); is_deeply( [ factor(779) ], [19,41], "factor(779)" ); is_deeply( [ factor(808) ], [2,2,2,101], "factor(808)" ); is_deeply( [ factor(989) ], [23,43], "factor(989)" ); is_deeply( [ factor(1363) ], [29,47], "factor(1363)" ); is_deeply( [ factor(2310) ], [2,3,5,7,11], "factor(2310)" ); is_deeply( [ factor(2727) ], [3,3,3,101], "factor(2727)" ); is_deeply( [ factor(9592) ], [2,2,2,11,109], "factor(9592)" ); is_deeply( [ factor(12625) ], [5,5,5,101], "factor(12625)" ); is_deeply( [ factor(30030) ], [2,3,5,7,11,13], "factor(30030)" ); is_deeply( [ factor(30107) ], [7,11,17,23], "factor(30107)" ); is_deeply( [ factor(34643) ], [7,7,7,101], "factor(34643)" ); is_deeply( [ factor(78498) ], [2,3,3,7,7,89], "factor(78498)" ); is_deeply( [ factor(134431) ], [11,11,11,101], "factor(134431)" ); is_deeply( [ factor(221897) ], [13,13,13,101], "factor(221897)" ); is_deeply( [ factor(496213) ], [17,17,17,101], "factor(496213)" ); is_deeply( [ factor(510510) ], [2,3,5,7,11,13,17], "factor(510510)" ); is_deeply( [ factor(664579) ], [664579], "factor(664579)" ); is_deeply( [ factor(692759) ], [19,19,19,101], "factor(692759)" ); is_deeply( [ factor(1228867) ], [23,23,23,101], "factor(1228867)" ); is_deeply( [ factor(2214143) ], [1487,1489], "factor(2214143)" ); is_deeply( [ factor(2463289) ], [29,29,29,101], "factor(2463289)" ); is_deeply( [ factor(3008891) ], [31,31,31,101], "factor(3008891)" ); is_deeply( [ factor(5115953) ], [37,37,37,101], "factor(5115953)" ); is_deeply( [ factor(5761455) ], [3,5,7,37,1483], "factor(5761455)" ); is_deeply( [ factor(6961021) ], [41,41,41,101], "factor(6961021)" ); is_deeply( [ factor(8030207) ], [43,43,43,101], "factor(8030207)" ); is_deeply( [ factor(9699690) ], [2,3,5,7,11,13,17,19], "factor(9699690)" ); is_deeply( [ factor(10486123) ], [47,47,47,101], "factor(10486123)" ); is_deeply( [ factor(10893343) ], [1327,8209], "factor(10893343)" ); is_deeply( [ factor(12327779) ], [1627,7577], "factor(12327779)" ); is_deeply( [ factor(50847534) ], [2,3,3,3,19,49559], "factor(50847534)" ); is_deeply( [ factor(114256942) ], [2,57128471], "factor(114256942)" ); is_deeply( [ factor(223092870) ], [2,3,5,7,11,13,17,19,23], "factor(223092870)" ); is_deeply( [ factor(455052511) ], [97,331,14173], "factor(455052511)" ); is_deeply( [ factor(547308031) ], [547308031], "factor(547308031)" ); is_deeply( [ factor(701737021) ], [25997,26993], "factor(701737021)" ); is_deeply( [ factor(999999929) ], [999999929], "factor(999999929)" ); is_deeply( [ factor(2147483647) ], [2147483647], "factor(2147483647)" ); is_deeply( [ factor(4118054813) ], [19,216739727], "factor(4118054813)" ); is_deeply( [ factor(4294967293) ], [9241,464773], "factor(4294967293)" ); #diag "factoring 64-bit numbers"; is_deeply( [ factor('6469693230') ], [2,3,5,7,11,13,17,19,23,29], "factor(6469693230)" ); is_deeply( [ factor('17179869172') ], [2,2,9241,464773], "factor(17179869172)" ); is_deeply( [ factor('37607912018') ], [2,'18803956009'], "factor(37607912018)" ); is_deeply( [ factor('200560490130') ], [2,3,5,7,11,13,17,19,23,29,31], "factor(200560490130)" ); is_deeply( [ factor('346065536839') ], [11,11,163,373,47041], "factor(346065536839)" ); is_deeply( [ factor('600851475143') ], [71,839,1471,6857], "factor(600851475143)" ); is_deeply( [ factor('3204941750802') ], [2,3,3,3,11,277,719,27091], "factor(3204941750802)" ); is_deeply( [ factor('7420738134810') ], [2,3,5,7,11,13,17,19,23,29,31,37], "factor(7420738134810)" ); is_deeply( [ factor('29844570422669') ], [19,19,27259,3032831], "factor(29844570422669)" ); is_deeply( [ factor('279238341033925') ], [5,5,7,13,194899,629773], "factor(279238341033925)" ); is_deeply( [ factor('304250263527210') ], [2,3,5,7,11,13,17,19,23,29,31,37,41], "factor(304250263527210)" ); is_deeply( [ factor('2623557157654233') ], [3,113,136841,56555467], "factor(2623557157654233)" ); is_deeply( [ factor('9007199254740991') ], [6361,69431,20394401], "factor(9007199254740991)" ); is_deeply( [ factor('9007199254740992') ], [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2], "factor(9007199254740992)" ); is_deeply( [ factor('9007199254740993') ], [3,107,'28059810762433'], "factor(9007199254740993)" ); is_deeply( [ factor('9999986200004761') ], [99999931,99999931], "factor(9999986200004761)" ); is_deeply( [ factor('13082761331670030') ], [2,3,5,7,11,13,17,19,23,29,31,37,41,43], "factor(13082761331670030)" ); is_deeply( [ factor('24739954287740860') ], [2,2,5,7,1123,'157358823863'], "factor(24739954287740860)" ); is_deeply( [ factor('99999989237606677') ], [316227731,316227767], "factor(99999989237606677)" ); is_deeply( [ factor('614889782588491410') ], [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47], "factor(614889782588491410)" ); is_deeply( [ factor('999999866000004473') ], [999999929,999999937], "factor(999999866000004473)" ); is_deeply( [ factor('3369738766071892021') ], [204518747,'16476429743'], "factor(3369738766071892021)" ); is_deeply( [ factor('10023859281455311421') ], ['1308520867','7660450463'], "factor(10023859281455311421)" ); is_deeply( [ factor('18446744073709551611') ], [11,59,'98818999','287630261'], "factor(18446744073709551611)" ); # Check perfect squares that make it past early testing is_deeply( [ factor('1524157875323973084894790521049') ], ['1234567890123493','1234567890123493'], "factor(1234567890123493^2)" ); is_deeply( [ factor('823543') ], [qw/7 7 7 7 7 7 7/], "factor 7^7" ); # A good test, but it's slow: # is_deeply( [ factor('148675665359980297048795508874724049089546782584077934753925649') ], ['1234567890123493', '1234567890123493', '9876543210987701', '9876543210987701'], "factor(1234567890123493^2 * 9876543210987701^2)" ); #diag "factor 105-bit number with p-1"; Math::Prime::Util::GMP::_GMP_set_verbose(4); is_deeply( [ sort {$a<=>$b} Math::Prime::Util::GMP::pminus1_factor('22095311209999409685885162322219') ], ['3916587618943361', '5641469912004779'], "p-1 factors 22095311209999409685885162322219" ); Math::Prime::Util::GMP::_GMP_set_verbose(0); is_deeply( [ sort {$a<=>$b} Math::Prime::Util::GMP::pplus1_factor('22095311209999409685885162322219') ], ['3916587618943361', '5641469912004779'], "p+1 factors 22095311209999409685885162322219" ); is_deeply( [ sort {$a<=>$b} Math::Prime::Util::GMP::ecm_factor('16049407357301026788959025956634678743968244330856613525782006075043') ], [qw/99151111 161868154531329727500068314480456792299263740280798402004613/], "ECM factors p8*p60" ); is_deeply( [ sort {$a<=>$b} Math::Prime::Util::GMP::qs_factor('22095311209999409685885162322219') ], ['3916587618943361', '5641469912004779'], "QS factors 22095311209999409685885162322219" ); #diag "factor 736-bit number with HOLF"; is_deeply( [ sort {$a<=>$b} Math::Prime::Util::GMP::holf_factor('185486767418172501041516225455805768237366368964328490571098416064672288855543059138404131637447372942151236559829709849969346650897776687202384767704706338162219624578777915220190863619885201763980069247978050169295918863') ], ['192606732705880508138303165129171270891951231683030125996296974238495711578947569589234612013165893468683239489', '963033663529402540691515825645856354459756158415150629981484871192478557894737847946173060065829467343416197967'], "HOLF factors poorly formed 222-digit semiprime" ); # Test stage 2 of pminus1 is_deeply( [ sort {$a<=>$b} Math::Prime::Util::GMP::pminus1_factor('23113042053749572861737011', 100, 100000) ], ['694059980329', '33301217054459'], "p-1 factors 23113042053749572861737011 in stage 2"); #diag "extra tests for each method"; extra_factor_test("prho_factor", sub {Math::Prime::Util::GMP::prho_factor(shift)}); extra_factor_test("pbrent_factor", sub {Math::Prime::Util::GMP::pbrent_factor(shift)}); extra_factor_test("pminus1_factor",sub {Math::Prime::Util::GMP::pminus1_factor(shift)}); extra_factor_test("pplus1_factor", sub {Math::Prime::Util::GMP::pplus1_factor(shift)}); extra_factor_test("holf_factor", sub {Math::Prime::Util::GMP::holf_factor(shift)}); extra_factor_test("squfof_factor", sub {Math::Prime::Util::GMP::squfof_factor(shift)}); extra_factor_test("ecm_factor", sub {Math::Prime::Util::GMP::ecm_factor(shift)}); sub extra_factor_test { my $fname = shift; my $fsub = shift; is_deeply( [ sort {$a<=>$b} $fsub->(0) ], [0], "$fname(0)" ); is_deeply( [ sort {$a<=>$b} $fsub->(1) ], [1], "$fname(1)" ); is_deeply( [ sort {$a<=>$b} $fsub->(2) ], [2], "$fname(2)" ); is_deeply( [ sort {$a<=>$b} $fsub->(13) ], [13], "$fname(13)" ); is_deeply( [ sort {$a<=>$b} $fsub->(403) ], [13, 31], "$fname(403)" ); is_deeply( [ sort {$a<=>$b} $fsub->(53936983) ], [7013, 7691], "$fname(53936983)" ); # Most of the time taken for this test file comes from this line: is_deeply( [ sort {$a<=>$b} $fsub->('1754012594703269855671') ], ['41110234981', '42666080491'], "$fname(1754012594703269855671)" ); } # Factor in scalar context is( scalar factor(0), 1, "scalar factor(0) should be 1" ); is( scalar factor(1), 0, "scalar factor(1) should be 1" ); is( scalar factor(3), 1, "scalar factor(3) should be 1" ); is( scalar factor(4), 2, "scalar factor(4) should be 2" ); is( scalar factor(5), 1, "scalar factor(5) should be 1" ); is( scalar factor(6), 2, "scalar factor(6) should be 2" ); is( scalar factor(30107), 4, "scalar factor(30107) should be 4" ); is( scalar factor(174636000), 15, "scalar factor(174636000) should be 15" ); # Sigma while (my($n, $s4) = each (%sigmas)) { my @s = map { sigma($n, $_) } 0 .. 3; is_deeply( \@s, $s4, "sigma_{0..3}($n)" ); } is_deeply( [divisors(1)], [1], "divisors(1) in list context" ); is_deeply( [divisors(9283540924)], [qw/1 2 4 7 14 28 331555033 663110066 1326220132 2320885231 4641770462 9283540924/], "divisors(9283540924)" ); is( scalar(divisors(9283540924)), 12, "scalar divisors(9283540924) = 12" ); { my @non = map { is_semiprime($_) } (qw/ 1477624760980458764344489 31065569722765023059646508128204165 345642381828009706799087047071899024928076219 /); is_deeply( \@non, [0,0,0], "is_semiprime for non-semiprimes" ); my @oui = map { is_semiprime($_) } (qw/ 5205293630375513276567563 76608197698048867638852299050055161 659828949060872109888044299185869580687593499 /); is_deeply( \@oui, [1,1,1], "is_semiprime for semiprimes" ); } Math-Prime-Util-GMP-0.52/t/26-logs.t0000644000175000017500000000241613663067455015172 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/logint/; plan tests => 3 + 3; ###### logint is_deeply( [map { logint($_,2) } 1..200], [map { int(log($_)/log(2)+1e-10) } 1..200], "logint base 2: 0 .. 200" ); is_deeply( [map { logint($_,3) } 1..200], [map { int(log($_)/log(3)+1e-10) } 1..200], "logint base 3: 0 .. 200" ); is_deeply( [map { logint($_,5) } 1..200], [map { int(log($_)/log(5)+1e-10) } 1..200], "logint base 5: 0 .. 200" ); is( logint("233349236278210673",7), 20, "logint(60-bit,7)" ); is( logint("8824000603628887473157759741572043613",6), 47, "logint(126-bit,6)" ); is( logint("12841630529324618690287110381024741207371090179054523401854513591767425374457280095597649697919029190278407309341833680028605778112128570812016955380129295876600127312188291407079013497446287431320527980160505080524812571294840028995335345592184264326254446305749914233193992625682904647212036252113576546596062062464401756311648529888232954547576231328407052208485920256657311799529213960967111911206103842380105407308374781735405670900846649002502353725558253344044022532656221148888022031071712032093046661627118122155915729513695717804720429536273861067955818055216144138275313683450748773099367019013281325666619",3), 1291, "logint(2048-bit,3)" ); Math-Prime-Util-GMP-0.52/t/26-digits.t0000644000175000017500000000215413054533437015500 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/todigits/; use Math::BigInt; # Don't use GMP so we don't have to work around bug plan tests => 0 + 12 + 1 + 0; is_deeply([todigits(0)], [], "todigits 0"); is_deeply([todigits(1)], [1], "todigits 1"); is_deeply([todigits(77)], [7,7], "todigits 77"); is_deeply([todigits(77,2)], [1,0,0,1,1,0,1], "todigits 77 base 2"); is_deeply([todigits(77,3)], [2,2,1,2], "todigits 77 base 3"); is_deeply([todigits(77,21)], [3,14], "todigits 77 base 21"); is_deeply([todigits(900,2)], [1,1,1,0,0,0,0,1,0,0], "todigits 900 base 2"); is_deeply([todigits(900,2,0)], [], "todigits 900 base 2 len 0"); is_deeply([todigits(900,2,3)], [1,0,0], "todigits 900 base 2 len 3"); is_deeply([todigits(900,2,32)], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,0,0], "todigits 900 base 2 len 32"); is_deeply([todigits(58127,16)], [14,3,0,15], "todigits 58127 base 16"); is_deeply([todigits(6345354,10,4)], [5,3,5,4], "todigits 6345354 base 10 len 4"); is_deeply([todigits(-24)], [2,4], "todigits ignores sign"); Math-Prime-Util-GMP-0.52/t/27-clusters.t0000644000175000017500000001005113025437621016051 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/sieve_prime_cluster is_prime sieve_primes sieve_twin_primes/; use Math::BigInt try => "GMP,Pari"; my $extra = defined $ENV{EXTENDED_TESTING} && $ENV{EXTENDED_TESTING}; my @tests = ( [ "A001359", [0, 2], [0,200], [3, 5, 11, 17, 29, 41, 59, 71, 101, 107, 137, 149, 179, 191, 197] ], [ "A022004", [0,2,6], [317321,319727], [qw/317321 317771 317957 318677 319127 319727/] ], [ "A022005", [0,4,6], [557857,560293], [qw/557857 558787 559213 560233 560293/] ], ); my @patterns = ( [0,2], [0,2,6], [0,4,6], [0,2,6,8], [0,2,6,8,12], [0,4,6,10,12], [0,4,6,10,12,16], [0,2,8,12,14,18,20], [0,2,6,8,12,18,20], ); my @high_check = ( [ "999999217031", 'A022006', [2,6,8,12] ], [ "999998356957", 'A022007', [4,6,10,12] ], [ "999961920817", 'A022008', [4,6,10,12,16] ], [ "9999956467211", 'A022009', [2,6,8,12,18,20] ], [ "9996858589169", 'A022010', [2,8,12,14,18,20] ], [ "99996813484481", 'A022010', [2,6,8,12,18,20,26] ], [ "99997194198047", 'A022012', [2,6,12,14,20,24,26] ], [ "99996215495153", 'A022013', [6,8,14,18,20,24,26] ], [ "999897629673401", 'A022545', [2,6,8,12,18,20,26,30] ], [ "506946970236647", 'A022546', [2,6,12,14,20,24,26,30] ], [ "291985604331973", 'A022547', [4,6,10,16,18,24,28,30] ], [ "999823346788939", 'A022548', [4,10,12,18,22,24,28,30] ], [ "29997979809623711", 'A027569', [2,6,8,12,18,20,26,30,32] ], [ "29998892234668517", 'A027570', [2,6,12,14,20,24,26,30,32] ], [ "9996248338169127877", 'A213601', [6,10,12,16,22,24,30,34,36,40,42] ], [ "2830868185774228331", 'A213645', [2,6,8,12,18,20,26,30,32,36,42] ], [ "999955337060684083", 'A213646', [4,6,10,16,18,24,28,30,34,36] ], [ "999930334493085881", 'A213647', [2,6,8,12,18,20,26,30,32,36] ], ); #[2,6,8,18,20,30,32,36,38); # Federighi #[2,6,8,12,18,20,26,30,32,36,42,48,50,56); # A257304 #[4,6,10,16,18,24,28,30,34,40,46,48,54,58,60,66); # A257375 #[6,12,16,18,22,28,30,36,40,42,46,48); # A214947 plan tests => scalar(@tests) + 2 + 2 * scalar(@patterns) + scalar(@high_check); for my $t (@tests) { my($what, $tuple, $range, $expect) = @$t; shift @$tuple if $tuple->[0] == 0; my @res = sieve_prime_cluster($range->[0],$range->[1], @$tuple ); is_deeply( \@res, $expect, "$what @$range" ); } is_deeply( [sieve_prime_cluster(1,1e10,2,4)], [3], "Inadmissible pattern (0,2,4) finds (3,5,7)"); is_deeply( [sieve_prime_cluster(1,1e10,2,8,14,26)], [3,5], "Inadmissible pattern (0,2,8,14,26) finds (3,5,11,17,29) and (5,7,13,19,31)"); my($sbeg,$send) = (0, 100000); my $mbeg = Math::BigInt->new(10)**21; my $mend = $mbeg + 10000 + int(rand(100000)); $send += 1000000 if $extra; $mend += 100000 if $extra; my $small = [ [sieve_primes($sbeg,$send)], [sieve_twin_primes($sbeg,$send)] ]; my $large = [ [map { Math::BigInt->new(''.$_) } sieve_primes($mbeg,$mend)], [map { Math::BigInt->new(''.$_) } sieve_twin_primes($mbeg,$mend)] ]; for my $pat (@patterns) { my @pat = @$pat; shift @pat if $pat[0] == 0; my @sieve = sieve_prime_cluster($sbeg,$send,@pat); my @tuple = ktuple($sbeg,$send,$small,@pat); my $num = scalar(@tuple); is_deeply( \@sieve, \@tuple, "Pattern [@pat] $num in range $sbeg .. $send"); } for my $pat (@patterns) { my @pat = @$pat; shift @pat if $pat[0] == 0; my @sieve = sieve_prime_cluster($mbeg,$mend,@pat); my @tuple = ktuple($mbeg,$mend,$large,@pat); my $num = scalar(@tuple); is_deeply( \@sieve, \@tuple, "Pattern [@pat] $num in range $mbeg .. $mend"); } for my $test (@high_check) { my($n,$name,$cl) = @$test; my $delta = Math::BigInt->new(1000000); my @res = sieve_prime_cluster($n-$delta, $n+$delta, @$cl); is_deeply(\@res, [$n], "Window around $name high cluster finds the cluster"); } sub ktuple { my($beg, $end, $prset, @pat) = @_; my @p; if (@pat && $pat[0] == 2) { @p = @{$prset->[1]}; shift @pat; } else { @p = @{$prset->[0]}; } for my $c (@pat) { @p = grep { is_prime($_+$c) } @p; } shift @p while @p && $p[0] < $beg; pop @p while @p && $p[-1] > $end; @p; } Math-Prime-Util-GMP-0.52/t/91-release-pod-syntax.t0000644000175000017500000000062313025437621017736 0ustar danadana#!/usr/bin/perl use strict; use warnings; BEGIN { unless ($ENV{RELEASE_TESTING}) { require Test::More; Test::More::plan(skip_all => 'these tests are for release candidate testing'); } } #--------------------------------------------------------------------- use Test::More; eval "use Test::Pod 1.41"; plan skip_all => "Test::Pod 1.41 required for testing POD" if $@; all_pod_files_ok(); Math-Prime-Util-GMP-0.52/t/25-const-euler.t0000644000175000017500000000340013663067455016457 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/Euler/; my $Euler = '0.577215664901532860606512090082402431042159335939923598805767234884867726777664670936947063291746749514631447249807082480960504014486542836224173997644923536253500333742937337737673942792595258247094916008735203948165670853233151776611528621199501507984793745085705740029921354786146694029604325421519058775535267331399254012967420513754139549111685102807984234877587205038431093997361372553060889331267600172479537836759271351577226102734929139407984301034177717780881549570661075010161916633401522789358679654972520362128792265559536696281763887927268013243101047650596370394739495763890657296792960100901512519595092224350140934987122824794974719564697631850667612906381105182419744486783638086174945516989279230187739107294578155431600500218284409605377243420328547836701517739439870030237033951832869000155819398804270741154222781971652301107356583396734871765049194181230004065469314299929777956930310050308630341856980323108369164002589297089098548682577736428825395492587362959613329857473930237343884707037028441292016641785'; plan tests => 2; is_deeply( [map { Euler($_) } 0 .. 99], [map { constround($Euler,$_) } 0 .. 99], "Euler(0 .. 99)" ); is_deeply( [map { Euler(100*$_) } 1..10], [map { constround($Euler,100*$_) } 1..10], "Euler(100,200,300,...,1000)" ); sub constround { my($fullc,$dig) = @_; $fullc =~ /^(\d+)\.(\d+)$/ or die "const fail"; my($int,$float) = ($1,$2); if ($dig == 0) { $int++ if substr($float,0,3) >= 500; return $int; } my $roundlen = ($dig > 10) ? 8 : 3; my $fc = substr($float,0,$dig); substr($fc,-$roundlen,$roundlen)++ if substr($float,$dig,1) >= 5; "$int.$fc"; } Math-Prime-Util-GMP-0.52/t/01-load.t0000644000175000017500000000016113025437621015115 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More tests => 1; require_ok 'Math::Prime::Util::GMP'; Math-Prime-Util-GMP-0.52/t/22-partitions.t0000644000175000017500000000270313025437621016401 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/partitions/; my $extra = defined $ENV{EXTENDED_TESTING} && $ENV{EXTENDED_TESTING}; my @parts = qw/ 1 1 2 3 5 7 11 15 22 30 42 56 77 101 135 176 231 297 385 490 627 792 1002 1255 1575 1958 2436 3010 3718 4565 5604 6842 8349 10143 12310 14883 17977 21637 26015 31185 37338 44583 53174 63261 75175 89134 105558 124754 147273 173525 204226 /; my %bparts = ( 100 => "190569292", 500 => "2300165032574323995027", 1000 => "24061467864032622473692149727991", 4497 => "16167346574157197963880873560628771195478696427127534310826790306449755", 9988 => "31043825285346179203111322344702502691204288916782299617140664920755263693739998376431336412511604846065386", 13337 => "4841449229081281114351180373774137636239639013054790559544724995314398354517477085116206336008004971541987422037760634642695", 37373 => "885240148270777711759915557428752066370785294706979437063536090533501018735098279767013023483349639513395622225840616033227700794918506274833787569446519667398089943122156454986205555766363295867812094833219935", ); if (!$extra) { my @ns = grep { $_ > 5000 } keys %bparts; foreach my $n (@ns) { delete $bparts{$n} } } plan tests => scalar(@parts) + scalar(keys(%bparts)); foreach my $n (0..$#parts) { is( partitions($n), $parts[$n], "partitions($n)" ); } while (my($n, $epart) = each (%bparts)) { is( partitions($n), $epart, "partitions($n)" ); } Math-Prime-Util-GMP-0.52/t/17-pseudoprime.t0000644000175000017500000006253713663067455016574 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/ is_pseudoprime is_euler_plumb_pseudoprime is_euler_pseudoprime is_strong_pseudoprime is_lucas_pseudoprime is_strong_lucas_pseudoprime is_extra_strong_lucas_pseudoprime is_almost_extra_strong_lucas_pseudoprime is_frobenius_pseudoprime is_frobenius_khashin_pseudoprime is_frobenius_underwood_pseudoprime is_perrin_pseudoprime is_prime is_bpsw_prime lucas_sequence lucasu lucasv miller_rabin_random primes/; my $extra = defined $ENV{EXTENDED_TESTING} && $ENV{EXTENDED_TESTING}; # pseudoprimes from 2-100k for many bases my %pseudoprimes = ( 2 => [ qw/2047 3277 4033 4681 8321 15841 29341 42799 49141 52633 65281 74665 80581 85489 88357 90751 1194649/ ], 3 => [ qw/121 703 1891 3281 8401 8911 10585 12403 16531 18721 19345 23521 31621 44287 47197 55969 63139 74593 79003 82513 87913 88573 97567/ ], 5 => [ qw/781 1541 5461 5611 7813 13021 14981 15751 24211 25351 29539 38081 40501 44801 53971 79381/ ], 7 => [ qw/25 325 703 2101 2353 4525 11041 14089 20197 29857 29891 39331 49241 58825 64681 76627 78937 79381 87673 88399 88831/ ], 11 => [ qw/133 793 2047 4577 5041 12403 13333 14521 17711 23377 43213 43739 47611 48283 49601 50737 50997 56057 58969 68137 74089 85879 86347 87913 88831/ ], 13 => [ qw/85 1099 5149 7107 8911 9637 13019 14491 17803 19757 20881 22177 23521 26521 35371 44173 45629 54097 56033 57205 75241 83333 85285 86347/ ], 17 => [ qw/9 91 145 781 1111 2821 4033 4187 5365 5833 6697 7171 15805 19729 21781 22791 24211 26245 31621 33001 33227 34441 35371 38081 42127 49771 71071 74665 77293 78881 88831 96433 97921 98671/ ], 19 => [ qw/9 49 169 343 1849 2353 2701 4033 4681 6541 6697 7957 9997 12403 13213 13747 15251 16531 18769 19729 24761 30589 31621 31861 32477 41003 49771 63139 64681 65161 66421 68257 73555 96049/ ], 23 => [ qw/169 265 553 1271 2701 4033 4371 4681 6533 6541 7957 8321 8651 8911 9805 14981 18721 25201 31861 34133 44173 47611 47783 50737 57401 62849 82513 96049/ ], 29 => [ qw/15 91 341 469 871 2257 4371 4411 5149 6097 8401 11581 12431 15577 16471 19093 25681 28009 29539 31417 33001 48133 49141 54913 79003/ ], 31 => [ qw/15 49 133 481 931 6241 8911 9131 10963 11041 14191 17767 29341 56033 58969 68251 79003 83333 87061 88183/ ], 37 => [ qw/9 451 469 589 685 817 1333 3781 8905 9271 18631 19517 20591 25327 34237 45551 46981 47587 48133 59563 61337 68101 68251 73633 79381 79501 83333 84151 96727/ ], 61 => [ qw/217 341 1261 2701 3661 6541 6697 7613 13213 16213 22177 23653 23959 31417 50117 61777 63139 67721 76301 77421 79381 80041/ ], 73 => [ qw/205 259 533 1441 1921 2665 3439 5257 15457 23281 24617 26797 27787 28939 34219 39481 44671 45629 64681 67069 76429 79501 93521/ ], 325 => [ qw/341 343 697 1141 2059 2149 3097 3537 4033 4681 4941 5833 6517 7987 8911 12403 12913 15043 16021 20017 22261 23221 24649 24929 31841 35371 38503 43213 44173 47197 50041 55909 56033 58969 59089 61337 65441 68823 72641 76793 78409 85879/ ], 9375 => [ qw/11521 14689 17893 18361 20591 28093 32809 37969 44287 60701 70801 79957 88357 88831 94249 96247 99547/ ], 28178 => [ qw/28179 29381 30353 34441 35371 37051 38503 43387 50557 51491 57553 79003 82801 83333 87249 88507 97921 99811/ ], 75088 => [ qw/75089 79381 81317 91001 100101 111361 114211 136927 148289 169641 176661 191407 195649/ ], 450775 => [ qw/465991 468931 485357 505441 536851 556421 578771 585631 586249 606361 631651 638731 641683 645679/ ], 642735 => [ qw/653251 653333 663181 676651 714653 759277 794683 805141 844097 872191 874171 894671/ ], 9780504 => [ qw/9780505 9784915 9826489 9882457 9974791 10017517 10018081 10084177 10188481 10247357 10267951 10392241 10427209 10511201/ ], 203659041 => [ qw/204172939 204456793 206407057 206976001 207373483 209301121 210339397 211867969 212146507 212337217 212355793 214400629 214539841 215161459/ ], 553174392 => [ qw/553174393 553945231 554494951 554892787 555429169 557058133 557163157 557165209 558966793 559407061 560291719 561008251 563947141/ ], 1005905886 => [ qw/1005905887 1007713171 1008793699 1010415421 1010487061 1010836369 1012732873 1015269391 1016250247 1018405741 1020182041/ ], 1340600841 => [ qw/1345289261 1345582981 1347743101 1348964401 1350371821 1353332417 1355646961 1357500901 1361675929 1364378203 1366346521 1367104639/ ], 1795265022 => [ qw/1795265023 1797174457 1797741901 1804469753 1807751977 1808043283 1808205701 1813675681 1816462201 1817936371 1819050257/ ], 3046413974 => [ qw/3046413975 3048698683 3051199817 3068572849 3069705673 3070556233 3079010071 3089940811 3090723901 3109299161 3110951251 3113625601/ ], 3613982119 => [ qw/3626488471 3630467017 3643480501 3651840727 3653628247 3654142177 3672033223 3672036061 3675774019 3687246109 3690036017 3720856369/ ], psp2 => [ qw/341 561 645 1105 1387 1729 1905 2047 2465 2701 2821 3277 4033 4369 4371 4681 5461 6601 7957 8321 8481 8911 10261 10585 11305 12801 13741 13747 13981 14491 15709 15841 16705 18705 18721 19951 23001 23377 25761 29341/ ], psp3 => [ qw/91 121 286 671 703 949 1105 1541 1729 1891 2465 2665 2701 2821 3281 3367 3751 4961 5551 6601 7381 8401 8911 10585 11011 12403 14383 15203 15457 15841 16471 16531 18721 19345 23521 24046 24661 24727 28009 29161/ ], plumb => [ qw/1729 1905 2047 2465 3277 4033 4681 8321 12801 15841 16705 18705 25761 29341 33153 34945 41041 42799 46657 49141 52633 65281 74665 75361 80581 85489 87249 88357 90751/ ], epsp2 => [ qw/561 1105 1729 1905 2047 2465 3277 4033 4681 6601 8321 8481 10585 12801 15841 16705 18705 25761 29341 30121 33153 34945 41041 42799 46657 49141 52633 62745 65281 74665 75361 80581 85489 87249 88357 90751/ ], epsp3 => [ qw/121 703 1729 1891 2821 3281 7381 8401 8911 10585 12403 15457 15841 16531 18721 19345 23521 24661 28009 29341 31621 41041 44287 46657 47197 49141 50881 52633 55969 63139 63973 74593 75361 79003 82513 87913 88573 93961 97567/ ], epsp29 => [ qw/15 91 341 469 871 2257 4371 4411 5149 5185 6097 8401 8841 11581 12431 15577 15841 16471 19093 22281 25681 27613 28009 29539 31417 33001 41041 46657 48133 49141 54913 57889 79003 98301/ ], lucas => [ qw/323 377 1159 1829 3827 5459 5777 9071 9179 10877 11419 11663 13919 14839 16109 16211 18407 18971 19043/ ], slucas => [ qw/5459 5777 10877 16109 18971 22499 24569 25199 40309 58519 75077 97439 100127 113573 115639 130139/ ], eslucas => [ qw/989 3239 5777 10877 27971 29681 30739 31631 39059 72389 73919 75077 100127 113573 125249 137549 137801 153931 155819/ ], aeslucas1 => [ qw/989 3239 5777 10469 10877 27971 29681 30739 31631 39059 72389 73919 75077 100127 113573 125249 137549 137801 153931 154697 155819/ ], aeslucas2 => [ qw/3239 4531 5777 10877 12209 21899 31631 31831 32129 34481 36079 37949 47849 50959 51641 62479 73919 75077 97109 100127 108679 113573 116899 154697 161027/ ], perrin => [ qw/271441 904631 16532714 24658561 27422714 27664033 46672291 102690901 130944133 196075949 214038533 517697641 545670533 801123451/ ], frobenius => [ qw/4181 5777 6721 10877 13201 15251 34561 51841 64079 64681 67861 68251 75077 90061 96049 97921 100127/ ], frob35 => [ qw/13333 44801 486157 1615681 3125281 4219129 9006401 12589081 13404751 15576571 16719781/ ], ); my $num_pseudoprimes = 0; foreach my $ppref (values %pseudoprimes) { $num_pseudoprimes += scalar @$ppref; } # 323 and 377 are Lucas pseudoprimes, but not strong Lucas pseudoprimes my @small_lucas_trials = (2, 9, 16, 100, 102, 323, 377, 2047, 2048, 5781, 9000, 14381); my %large_pseudoprimes = ( '75792980677' => [ qw/2/ ], '21652684502221' => [ qw/2 7 37 61 9375/ ], '3825123056546413051' => [ qw/2 3 5 7 11 13 17 19 23 29 31 325 9375/ ], '318665857834031151167461' => [ qw/2 3 5 7 11 13 17 19 23 29 31 37 325 9375/ ], '3317044064679887385961981' => [ qw/2 3 5 7 11 13 17 19 23 29 31 37 73 325 9375/ ], '6003094289670105800312596501' => [ qw/2 3 5 7 11 13 17 19 23 29 31 37 61 325 9375/ ], '59276361075595573263446330101' => [ qw/2 3 5 7 11 13 17 19 23 29 31 37 325 9375/ ], '564132928021909221014087501701' => [ qw/2 3 5 7 11 13 17 19 23 29 31 37 325 9375/ ], ); my $num_large_pseudoprime_tests = 0; foreach my $psrp (keys %large_pseudoprimes) { $num_large_pseudoprime_tests += scalar @{$large_pseudoprimes{$psrp}}; } my %lucas_sequences = ( "323 1 1 324" => [0,2,1], "323 4 1 324" => [170,308,1], "323 4 5 324" => [194,156,115], "323 3 1 324" => [0,2,1], "323 3 1 81" => [0,287,1], "323 5 -1 81" => [153,195,322], "49001 25 117 24501" => [20933,18744,19141], "18971 10001 -1 4743" => [5866,14421,18970], ); my @primes128 = (qw/ 216807359884357411648908138950271200947 339168371495941440319562622097823889491 175647712566579256193079384409148729569 213978050035770705635718665804334250861 282014465653257435172223280631326130957 285690571631805499387265005140705006349 197905182544375865664507026666258550257 257978530672690459726721542547822424119 271150181404520740107101159842415035273 262187868871349017397376949493643287923 /); my @comp128 = (qw/ 331692821169251128612023074084933636563 291142820834608911820232911620629416673 222553723073325022732878644722536036431 325464724689480915638128579172743588243 326662586910428159613180378374675586479 197395185602458924846767613337087999977 194157480002729115387621030269291379439 180664716097986611402007784149669477223 248957328957166865967197552940796547567 276174467950103435998583356206846142651 /); plan tests => 0 + 9 + 3 + 6 + $num_pseudoprimes + 1 # mr base 2 2-4k + 9 # mr with large bases + 3 # multiple bases + scalar @small_lucas_trials + scalar(keys %lucas_sequences) + 7 # lucasu lucasv # + $num_large_pseudoprime_tests + 18*$extra # Large Carmichael numbers + 2 # M-R-random + 5 * scalar(@primes128) # strong probable prime tests + 5 * scalar(@comp128) # strong probable prime tests + 15 # Check Frobenius for small primes + 2 # mrr with seed and neg bases + 0; eval { is_strong_pseudoprime(2047); }; like($@, qr/no base/i, "is_strong_pseudoprime with no base fails"); eval { no warnings; is_strong_pseudoprime(2047, undef); }; like($@, qr/(defined|empty)/i, "is_strong_pseudoprime with base undef fails"); eval { is_strong_pseudoprime(2047, ''); }; like($@, qr/(positive|empty)/i, "is_strong_pseudoprime with base '' fails"); eval { is_strong_pseudoprime(2047,0); }; like($@, qr/invalid/i, "is_strong_pseudoprime with base 0 fails"); eval { is_strong_pseudoprime(2047,1); }; like($@, qr/invalid/i, "is_strong_pseudoprime with base 1 fails"); eval { is_strong_pseudoprime(2047,-7); }; like($@, qr/positive/i, "is_strong_pseudoprime with base -7 fails"); eval { no warnings; is_strong_pseudoprime(undef, 2); }; like($@, qr/(defined|empty)/i, "is_strong_pseudoprime(undef,2) is invalid"); eval { is_strong_pseudoprime('', 2); }; like($@, qr/(positive|empty)/i, "is_strong_pseudoprime('',2) is invalid"); eval { is_strong_pseudoprime(-7, 2); }; like($@, qr/positive/i, "is_strong_pseudoprime(-7,2) is invalid"); eval { no warnings; is_strong_lucas_pseudoprime(undef); }; like($@, qr/empty string/i, "is_strong_lucas_pseudoprime(undef) is invalid"); eval { is_strong_lucas_pseudoprime(''); }; like($@, qr/empty string/i, "is_strong_lucas_pseudoprime('') is invalid"); eval { is_strong_lucas_pseudoprime(-7); }; like($@, qr/integer/i, "is_strong_lucas_pseudoprime(-7) is invalid"); is( is_strong_pseudoprime(0, 2), 0, "spsp(0, 2) shortcut composite"); is( is_strong_pseudoprime(1, 2), 0, "spsp(1, 2) shortcut composite"); is( is_strong_pseudoprime(2, 2), 1, "spsp(2, 2) shortcut prime"); is( is_strong_pseudoprime(3, 2), 1, "spsp(2, 2) shortcut prime"); is( is_strong_lucas_pseudoprime(1), 0, "slpsp(1) shortcut composite"); is( is_strong_lucas_pseudoprime(3), 1, "slpsp(3) shortcut prime"); # Check that each strong pseudoprime base b makes it through MR with that base while (my($base, $ppref) = each (%pseudoprimes)) { foreach my $p (@$ppref) { if ($base =~ /^psp(\d+)/) { my $base = $1; ok(is_pseudoprime($p, $base), "$p is a pseudoprime to base $base"); } elsif ($base =~ /^epsp(\d+)/) { my $base = $1; ok(is_euler_pseudoprime($p, $base), "$p is an Euler pseudoprime to base $base"); } elsif ($base =~ /^aeslucas(\d+)/) { my $inc = $1; ok(is_almost_extra_strong_lucas_pseudoprime($p,$inc), "$p is an almost extra strong Lucas pseudoprime (increment $inc)"); } elsif ($base eq 'eslucas') { ok(is_extra_strong_lucas_pseudoprime($p), "$p is an extra strong Lucas pseudoprime"); } elsif ($base eq 'slucas') { ok(is_strong_lucas_pseudoprime($p), "$p is a strong Lucas-Selfridge pseudoprime"); } elsif ($base eq 'lucas') { ok(is_lucas_pseudoprime($p), "$p is a Lucas-Selfridge pseudoprime"); } elsif ($base eq 'plumb') { ok(is_euler_plumb_pseudoprime($p), "$p is an Euler-Plumb pseudoprime"); } elsif ($base eq 'perrin') { ok(is_perrin_pseudoprime($p), "$p is a Perrin pseudoprime"); } elsif ($base eq 'frobenius') { ok(is_frobenius_pseudoprime($p,1,-1), "$p is a Frobenius (1,-1) pseudoprime"); } elsif ($base eq 'frob35') { ok(is_frobenius_pseudoprime($p,3,-5), "$p is a Frobenius (3,-5) pseudoprime"); } else { ok(is_strong_pseudoprime($p, $base), "Pseudoprime (base $base) $p passes MR"); } } } # Verify MR base 2 for all small numbers { my $mr2fail = 0; for (2 .. 4032) { next if $_ == 2047 || $_ == 3277; if (is_prime($_)) { if (!is_strong_pseudoprime($_,2)) { $mr2fail = $_; last; } } else { if (is_strong_pseudoprime($_,2)) { $mr2fail = $_; last; } } } is($mr2fail, 0, "MR base 2 matches is_prime for 2-4032 (excl 2047,3277)"); } # Verify MR for bases >= n is( is_strong_pseudoprime( 3, 3), 1, "spsp( 3, 3)"); is( is_strong_pseudoprime( 11, 11), 1, "spsp( 11, 11)"); is( is_strong_pseudoprime( 89, 5785), 1, "spsp( 89, 5785)"); is( is_strong_pseudoprime(257, 6168), 1, "spsp(257, 6168)"); is( is_strong_pseudoprime(367, 367), 1, "spsp(367, 367)"); is( is_strong_pseudoprime(367, 1101), 1, "spsp(367, 1101)"); is( is_strong_pseudoprime(49001, 921211727), 0, "spsp(49001, 921211727)"); is( is_strong_pseudoprime( 331, 921211727), 1, "spsp( 331, 921211727)"); is( is_strong_pseudoprime(49117, 921211727), 1, "spsp(49117, 921211727)"); is(is_pseudoprime(162401, 2, 3, 5, 7, 11, 13), 1, "162401 is a Fermat pseudoprime to bases 2,3,5,7,11,13"); is(is_euler_pseudoprime(1857241, 2, 3, 5, 7, 11, 13), 1, "1857241 is an Euler pseudoprime to bases 2,3,5,7,11,13"); is(is_strong_pseudoprime("3474749660383", 2, 3, 5, 7, 11, 13), 1, "3474749660383 is a strong pseudoprime to bases 2,3,5,7,11,13"); # Verify Lucas for some small numbers for my $n (@small_lucas_trials) { next if $n == 5459 || $n == 5777 || $n == 10877 || $n == 16109 || $n == 18971; if (is_prime($n)) { # Technically if it is a prime it isn't a pseudoprime. ok(is_strong_lucas_pseudoprime($n), "$n is a prime and a strong Lucas-Selfridge pseudoprime"); } else { ok(!is_strong_lucas_pseudoprime($n), "$n is not a prime and not a strong Lucas-Selfridge pseudoprime"); } } while (my($params, $expect) = each (%lucas_sequences)) { my ($n, $p, $q, $k) = split(' ', $params); is_deeply( [lucas_sequence($n,$p,$q,$k)], $expect, "Lucas sequence $params" ); } { is( lucasu(1,-1,1001), "70330367711422815821835254877183549770181269836358732742604905087154537118196933579742249494562611733487750449241765991088186363265450223647106012053374121273867339111198139373125598767690091902245245323403501", "Fibonacci(1001)" ); is( lucasv(1,-1,1001), "157263483085297728693212310227264801375310590871102293547568363266227647954095037360550009174721122072079595635402411260638605742511929970292048335339367003086933714987796078672982630775099044177835579021861251", "Lucas(1001)" ); # Two examples used in primality proofs by Broadhurst and de Water my($n, $str); $n = lucasu(9,-1,3671); $str = $n; substr($str, 15, -15, "..."); is( $str, "244000543463515...617812356676529", "lucasu(9,-1,3671)" ); $n = lucasu(287,-1,3079); $str = $n; substr($str, 15, -15, "..."); is( $str, "238068250883464...633235555322189", "lucasu(287,-1,3079)" ); is( lucasv(80,1,71), "1301877113746131144509980743600829473173742739374514641352770534569341664593745336690230666043630253570208103530328102099934784158714320", "lucasv(80,1,71)" ); $n = lucasv(63,1,13217); $str = $n; substr($str, 15, -15, "..."); is( $str, "273696635948516...411235453749183", "lucasv(63,1,13217)" ); $n = lucasv(10,8,88321); $str = $n; substr($str, 15, -15, "..."); is( $str, "580334188745259...957502147624960", "lucasv(10,8,88321)" ); } if ($extra) { my $n; # Jacobsen 2015, using Bleichenbacher method $n = "341627175004511735787409078802107169251"; is( is_strong_pseudoprime($n, 2..52), 1, "341..251 is spsp(1..52)" ); is( is_strong_pseudoprime($n, 53), 0, "341..251 is found composite by base 53" ); $n = "18424122547908777179569267097345139960751"; is( is_strong_pseudoprime($n, 2..66), 1, "184..751 is spsp(1..66)" ); is( is_strong_pseudoprime($n, 67), 0, "184..751 is found composite by base 67" ); # my $p1 = Math::BigInt->new("2059068011050051"); # $n = $p1 * (49*($p1-1)+1) * (125*($p1-1)+1); $n = "53470982963692324858209985576229320155194985131251"; is( is_strong_pseudoprime($n, 2..72), 1, "534..251 is spsp(1..72)" ); is( is_strong_pseudoprime($n, 73), 0, "534..251 is found composite by base 73" ); # Zhang 2004 $n = "9688312712744590973050578123260748216127001625571"; is( is_strong_pseudoprime($n, 2..70), 1, "968..571 is spsp(1..70)" ); is( is_strong_pseudoprime($n, 71), 0, "968..571 is found composite by base 71" ); # Bleichenbacher $n = "68528663395046912244223605902738356719751082784386681071"; is( is_strong_pseudoprime($n, @{primes(2,100)}), 1, "685..071 is spsp(1..100)" ); is( is_strong_pseudoprime($n, 101), 0, "685..071 is found composite by base 101" ); # Arnault 1994, strong pseudoprime to all bases up to 306 #my $p1 = Math::BigInt->new("29674495668685510550154174642905332730771991799853043350995075531276838753171770199594238596428121188033664754218345562493168782883"); #$n = $p1* (313 * ($p1-1) + 1) * (353 * ($p1-1) + 1); $n = "2887148238050771212671429597130393991977609459279722700926516024197432303799152733116328983144639225941977803110929349655578418949441740933805615113979999421542416933972905423711002751042080134966731755152859226962916775325475044445856101949404200039904432116776619949629539250452698719329070373564032273701278453899126120309244841494728976885406024976768122077071687938121709811322297802059565867"; is( is_strong_pseudoprime($n, @{primes(2,306)}), 1, "Arnault-397 Carmichael is spsp(1..306)" ); is( is_strong_pseudoprime($n, 307), 0, "Arnault-397 Carmichael is found composite by base 307" ); # Strong pseudoprime to first 100 bases $n = "197475704297076769879318479365782605729426528421984294554780711762857505669370986517424096751829488980502254269692200841641288349940843678305321105903510536750100514089183274534482451736946316424510377404498460285069545777656519289729095553895011368091845754887799208568313368087677010037387886257331969473598709629563758316982529541918503729974147573401550326647431929654622465970387164330994694720288156577774827473110333350092369949083055692184067330157343079442986832268281420578909681133401657075403304506177944890621300718745594728786819988830295725434492922853465829752746870734788604359697581532651202427729467"; is( is_strong_pseudoprime($n, @{primes(2,546)}), 1, "197...467 is spsp(1..546)" ); is( is_strong_pseudoprime($n, 547), 0, "197...467 is found composite by base 547" ); # Strong pseudoprime to first 150 bases $n = "2504564851231996223418611498583553580586431162725714036294663419005627942030045018144967085826016995812748308972856014960994030057096300272690934546847718913274308904632162037753108744756079484071197757334474410667077275268095650646955133107287726653142089063491101528203219286279619714745365476456016263876476506935633902632378276445418807506643579691598485378380707876204179521868647423847956174718793857337275560326966743283833603259339320266954292802259534246253628396748505321522751546284902630334444060405092248083998624231344891540701484875133564504847404605998928272819163447443703835478321841022013831138852193839499198235152203734163783925867691241340516136948911294063782761240713332883707486122030071233696262539897861764349350102562679795879652984483644711085101952997260985769555028200212433179592354351467963621580674595217679045289986395851940360535530808265791863676735166100444465385760336851651312776349197351443263637225179385994064241024523629682623814114793546441523513505946466820080716059467"; is( is_strong_pseudoprime($n, @{primes(2,876)}), 1, "250...467 is spsp(1..876)" ); is( is_strong_pseudoprime($n, 877), 0, "250..467 is found composite by base 877" ); # Strong pseudoprime to first 168 bases # N = (n+1) * (37*n+1) * (41*n+1) $n = "2809386136371438866496346539320857607283794588353401165473007394921174159995576890097633348301878401799853448496604965862616291048652062065394646956750323263193037964463262192320342740843556773326129475220032687577421757298519461662249735906372935033549531355723541168448473213797808686850657266188854910604399375221284468243956369013816289853351613404802033369894673267294395882499368769744558478456847832293372532910707925159549055961870528474205973317584333504757691137280936247019772992086410290579840045352494329434008415453636962234340836064927449224611783307531275541463776950841504387756099277118377038405235871794332425052938384904092351280663156507379159650872073401637805282499411435158581593146712826943388219341340599170371727498381901415081480224172469034841153893464174362543356514320522139692755430021327765409775374978255770027259819794532960997484676733140078317807018465818200888425898964847614568913543667470861729894161917981606153150551439410460813448153180857197888310572079656577579695814664713878369660173739371415918888444922272634772987239224582905405240454751027613993535619787590841842251056960329294514093407010964283471430374834873427180817297408975879673867"; is( is_strong_pseudoprime($n, @{primes(2,1008)}), 1, "280...867 is spsp(1..1008)" ); is( is_strong_pseudoprime($n, 1009), 0, "280..867 is found composite by base 1009" ); } { my @mrs = map { miller_rabin_random($_, 0) } 0 .. 999; my @expect = (1) x 1000; is_deeply( [@mrs], [@expect], "Miller-Rabin with 0 random bases" ); } { # This is the number above which fails the first 168 bases. my $n = "2809386136371438866496346539320857607283794588353401165473007394921174159995576890097633348301878401799853448496604965862616291048652062065394646956750323263193037964463262192320342740843556773326129475220032687577421757298519461662249735906372935033549531355723541168448473213797808686850657266188854910604399375221284468243956369013816289853351613404802033369894673267294395882499368769744558478456847832293372532910707925159549055961870528474205973317584333504757691137280936247019772992086410290579840045352494329434008415453636962234340836064927449224611783307531275541463776950841504387756099277118377038405235871794332425052938384904092351280663156507379159650872073401637805282499411435158581593146712826943388219341340599170371727498381901415081480224172469034841153893464174362543356514320522139692755430021327765409775374978255770027259819794532960997484676733140078317807018465818200888425898964847614568913543667470861729894161917981606153150551439410460813448153180857197888310572079656577579695814664713878369660173739371415918888444922272634772987239224582905405240454751027613993535619787590841842251056960329294514093407010964283471430374834873427180817297408975879673867"; # 33 random bases on a 3948 bit number => p < 1e-200. # This is why we use k random bases and not the first k bases. my $isprime = miller_rabin_random($n, 33); is($isprime, 0, "Miller-Rabin with 100 uniform random bases for n returns prime" ); } for my $p (@primes128) { is( is_euler_plumb_pseudoprime($p), 1, "prime $p passes Euler-Plumb primality test"); is( is_frobenius_pseudoprime($p), 1, "prime $p passes Frobenius primality test"); is( is_frobenius_khashin_pseudoprime($p), 1, "prime $p passes Frobenius Khashin primality test"); is( is_frobenius_underwood_pseudoprime($p), 1, "prime $p passes Frobenius Underwood primality test"); is( is_bpsw_prime($p), 1, "prime $p passes BPSW primality test"); } for my $p (@comp128) { is( is_euler_plumb_pseudoprime($p), 0, "composite $p fails Euler-Plumb primality test"); is( is_frobenius_pseudoprime($p), 0, "composite $p fails Frobenius primality test"); is( is_frobenius_khashin_pseudoprime($p), 0, "composite $p fails Frobenius Khashin primality test"); is( is_frobenius_underwood_pseudoprime($p), 0, "composite $p fails Frobenius Underwood primality test"); is( is_bpsw_prime($p), 0, "composite $p fails BPSW primality test"); } # Frobenius has some issues. Test for my $p (2,3,5,7,11,13,17,19,23,29,31,37,41,43,47) { is( is_frobenius_pseudoprime($p,37,-13), 1, "prime $p is a Frobenius (37,-13) pseudoprime" ); } # Test miller_rabin_random with a passed in seed value is(miller_rabin_random("5948714251747610466954817160823054375857",30,"0x6c7b06f2333c8390"), 1, "miller_rabin_random with a seed"); # Test mrr with a negative number of bases ok(!eval { miller_rabin_random(10007,-4); }, "MRR(10007,-4)"); Math-Prime-Util-GMP-0.52/t/26-real.t0000644000175000017500000001765713663067455015166 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/logreal expreal powreal rootreal agmreal addreal subreal mulreal divreal/; my $extra = defined $ENV{EXTENDED_TESTING} && $ENV{EXTENDED_TESTING}; # gp: \p 71 for(s=1,20,print(log(s/10))) my @log_pos = (qw/ -2.3025850929940456840179914546843642076011014886287729760333279009675726 -1.6094379124341003746007593332261876395256013542685177219126478914741790 -1.2039728043259359926227462177618385029536109308060235242986335673300783 -0.91629073187415506518352721176801107145010121990826246779196788198078537 -0.69314718055994530941723212145817656807550013436025525412068000949339362 -0.51082562376599068320551409630366193487811079644576827017795355783668469 -0.35667494393873237891263871124118447796401675904691178757393775102999275 -0.22314355131420975576629509030983450337460108554800721367128787248739174 -0.10536051565782630122750098083931279830612037298327407256393923369258402 0.00000000000000000000000000000000000000000000000000000000000000000000000 0.09531017980432486004395212328076509222060536530864419918523980816300101 0.18232155679395462621171802515451463319738933791448698394272645165670893 0.26236426446749105203549598688095439720416645613143414038571760969589206 0.33647223662121293050459341021699209011148337531334346654674225846340088 0.40546510810816438197801311546434913657199042346249419761401432414410067 0.47000362924573555365093703114834206470089904881224804044939213700600188 0.53062825106217039623154316318876232798710152395697181126390983691471997 0.58778666490211900818973114061886376976937976137698118155674077580080960 0.64185388617239477599103597720348932963627777267035584250463233544172009 0.69314718055994530941723212145817656807550013436025525412068000949339362 /); my @log_neg = (qw/ 2.3025850929940456840179914546843642076011014886287729760333279009675726 1.6094379124341003746007593332261876395256013542685177219126478914741790 1.2039728043259359926227462177618385029536109308060235242986335673300783 0.91629073187415506518352721176801107145010121990826246779196788198078537 0.69314718055994530941723212145817656807550013436025525412068000949339362 0.51082562376599068320551409630366193487811079644576827017795355783668469 0.35667494393873237891263871124118447796401675904691178757393775102999275 0.22314355131420975576629509030983450337460108554800721367128787248739174 0.10536051565782630122750098083931279830612037298327407256393923369258402 0.00000000000000000000000000000000000000000000000000000000000000000000000 -0.09531017980432486004395212328076509222060536530864419918523980816300101 -0.18232155679395462621171802515451463319738933791448698394272645165670893 -0.26236426446749105203549598688095439720416645613143414038571760969589206 -0.33647223662121293050459341021699209011148337531334346654674225846340088 -0.40546510810816438197801311546434913657199042346249419761401432414410067 -0.47000362924573555365093703114834206470089904881224804044939213700600188 -0.53062825106217039623154316318876232798710152395697181126390983691471997 -0.58778666490211900818973114061886376976937976137698118155674077580080960 -0.64185388617239477599103597720348932963627777267035584250463233544172009 -0.69314718055994530941723212145817656807550013436025525412068000949339362 /); plan tests => 1+2+2+3 # logreal + 6 # expreal + 7 # powreal + 6 # rootreal + 5 # agmreal + 4 # add,sub,mul,div ; ######## log ok(!eval { logreal(0); }, "log(0)"); # Small around 1 is_deeply( [map { logreal($_/10,71) } 1 .. 20], [ map { my $v=$_; $v=~s/^0\./\./; $v=~s/^-0\./-\./; $v; } @log_pos ], "log(0.1, 0.2, ..., 2.0) with 71 digits" ); is_deeply( [map { logreal(-$_/10,71) } 1 .. 20], [ map { my $v=$_; $v=~s/^0\./\./; $v=~s/^-0\./-\./; $v; } @log_neg ], "log(-0.1, -0.2, ..., -2.0) with 71 digits" ); is(logreal(2,200), '.69314718055994530941723212145817656807550013436025525412068000949339362196969471560586332699641868754200148102057068573368552023575813055703267075163507596193072757082837143519030703862389167347112335', "logreal(2,200)"); is(logreal("1"."0"x1000,200), '2302.5850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983419677840422862486334095254650828067566662873690987816894829072083255546808437998948262331985283935', "logreal(10^1000,200)"); is(logreal(5,71),'1.6094379124341003746007593332261876395256013542685177219126478914741790',"logreal(5,71)"); is(logreal(10,71),'2.3025850929940456840179914546843642076011014886287729760333279009675726',"logreal(10,71)"); is(logreal(21,71),'3.0445224377234229965005979803657054342845752874046106401940844835750742',"logreal(21,71)"); ######## exp is(expreal(1,71),'2.7182818284590452353602874713526624977572470936999595749669676277240766',"expreal(1,71)"); is(expreal(12.5,71),'268337.28652087445695647967378715040272579062274906405277947593333627473',"expreal(12.5,71)"); is(expreal(100,71),'26881171418161354484126255515800135873611118.773741922415191608615280287',"expreal(100,71)"); is(expreal(100,12),'268811714182E32',"expreal(100,12)"); is(expreal(-118.5,71),'.00000000000000000000000000000000000000000000000000034364014567198602057',"expreal(-118.5,71)"); is(expreal("-394.84010945715266885",200),'.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000033351796227864913872998321605',"expreal(-394.84010945715266885,200)"); ######## pow is(powreal(0,2.2,20),'.00000000000000000000',"powreal(0,2.2,20)"); is(powreal(1,2.2,20),'1.0000000000000000000',"powreal(1,2.2,20)"); is(powreal(-1,2.2,20),'-1.0000000000000000000',"powreal(-1,2.2,20)"); is(powreal(2,-5.01,60),'.031034140482407371922912819277752330350669761418765540014674',"powreal(2,-5.01,60)"); is(powreal(2,5,2),32,"powreal(2,5,2)"); is(powreal(2,-5,5),".03125","powreal(2,-5,5)"); is(powreal(1234.5678, 9.87654321, 60), "3415709626357388739894539947448.87170455872193676278327545082", "powreal(1234.5678, 9.87654321, 60)"); ######## root is(rootreal(0,2,20),'.00000000000000000000',"rootreal(0,2,20)"); is(rootreal(1,2,20),'1.0000000000000000000',"rootreal(1,2,20)"); is(rootreal(2,2,20),'1.4142135623730950488',"rootreal(2,2,20)"); is(rootreal(2,3,20),'1.2599210498948731648',"rootreal(2,3,20)"); is(rootreal(2,2,80),'1.4142135623730950488016887242096980785696718753769480731766797379907324784621070',"rootreal(2,2,80)"); is(rootreal(100.19,17,80),'1.3112803450586508207655195395037621220588179920316817022058520019614000795229155',"rootreal(100.19,17,80)"); ######## agm is(agmreal(1,'1.4142135623730950488016887242096980785696718753769480731766797379907325',71), '1.1981402347355922074399224922803238782272126632156515582636749529464052', "AGM(1, sqrt(2)) = reciprocal of Gauss's constant"); is(agmreal(1,'0.707106781186547524400844362104849039284835937688474036588339868995366239',72), '.847213084793979086606499123482191636481445910326942185060579372659734005', "AGM(1, 1/sqrt(2))"); is(agmreal(0.5,1,71), '.72839551552345343459321619163254098748693197161065279539708619163396323', "AGM(0.5, 1)"); is(agmreal(6,24,30), '13.4581714817256154207668131570', "AGM(6, 24)"); is(agmreal(-6,24,30), undef, "AGM with negative argument returns undef"); ######## add, sub, mul, div { my $x='31622.7766016837933199889354443271853371955513932521682685750485279259444'; my $y='0.64185388617239477599103597720348932963627777267035584250463233544172009'; is(addreal($x, $y, 70), '31623.41845556996571476492648030438882652518767102483862441755316026139', "addreal"); is(subreal($x, $y, 70), '31622.13474779762092521294440834998184786591511547949791273254389559050', "subreal"); is(mulreal($x, $y, 70), '20297.20205335221837411759117382787166239120864815030509715811057060388', "mulreal"); is(divreal($x, $y, 70), '49267.87432925235753958333652192275718354249610085655599278344889912783', "divreal"); } Math-Prime-Util-GMP-0.52/t/10-isprime.t0000644000175000017500000002117213025437621015653 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/is_prime/; plan tests => 0 + 6 + 19 + 1 + 10 + 29 + 22 + 23 + 16 + 15 + 28 + 32 + 8 + 6 + 10 + 2 + 0; # Some of these tests were inspired by Math::Primality's tests ok( is_prime(2), '2 is prime'); ok(!is_prime(1), '1 is not prime'); ok(!is_prime(0), '0 is not prime'); ok(!is_prime(-1), '-1 is not prime'); ok(!is_prime(-2), '-2 is not prime'); ok(!is_prime(20), '20 is not prime'); # powers of 2 foreach my $k (2 .. 20) { my $k2 = 2**$k; ok(!is_prime($k2), "2**$k=$k2 is not prime"); } my @small_primes = qw/ 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997 1009 1013 1019 1021 1031 1033 1039 1049 1051 1061 1063 1069 1087 1091 1093 1097 1103 1109 1117 1123 1129 1151 1153 1163 1171 1181 1187 1193 1201 1213 1217 1223 1229 1231 1237 1249 1259 1277 1279 1283 1289 1291 1297 1301 1303 1307 1319 1321 1327 1361 1367 1373 1381 1399 1409 1423 1427 1429 1433 1439 1447 1451 1453 1459 1471 1481 1483 1487 1489 1493 1499 1511 1523 1531 1543 1549 1553 1559 1567 1571 1579 1583 1597 1601 1607 1609 1613 1619 1621 1627 1637 1657 1663 1667 1669 1693 1697 1699 1709 1721 1723 1733 1741 1747 1753 1759 1777 1783 1787 1789 1801 1811 1823 1831 1847 1861 1867 1871 1873 1877 1879 1889 1901 1907 1913 1931 1933 1949 1951 1973 1979 1987 1993 1997 1999 2003 2011 2017 2027 2029 2039 2053 2063 2069 2081 2083 2087 2089 2099 2111 2113 2129 2131 2137 2141 2143 2153 2161 2179 2203 2207 2213 2221 2237 2239 2243 2251 2267 2269 2273 2281 2287 2293 2297 2309 2311 2333 2339 2341 2347 2351 2357 2371 2377 2381 2383 2389 2393 2399 2411 2417 2423 2437 2441 2447 2459 2467 2473 2477 2503 2521 2531 2539 2543 2549 2551 2557 2579 2591 2593 2609 2617 2621 2633 2647 2657 2659 2663 2671 2677 2683 2687 2689 2693 2699 2707 2711 2713 2719 2729 2731 2741 2749 2753 2767 2777 2789 2791 2797 2801 2803 2819 2833 2837 2843 2851 2857 2861 2879 2887 2897 2903 2909 2917 2927 2939 2953 2957 2963 2969 2971 2999 3001 3011 3019 3023 3037 3041 3049 3061 3067 3079 3083 3089 3109 3119 3121 3137 3163 3167 3169 3181 3187 3191 3203 3209 3217 3221 3229 3251 3253 3257 3259 3271 3299 3301 3307 3313 3319 3323 3329 3331 3343 3347 3359 3361 3371 3373 3389 3391 3407 3413 3433 3449 3457 3461 3463 3467 3469 3491 3499 3511 3517 3527 3529 3533 3539 3541 3547 3557 3559 3571 /; my %small_primes; map { $small_primes{$_} = 1; } @small_primes; { my @isprime = map { !!is_prime($_) } (0..3572); my @exprime = map { !!defined $small_primes{$_} } (0..3572); is_deeply( \@isprime, \@exprime, "is_prime 0..3572" ); } map { ok(!is_prime($_), "A006945 number $_ is not prime") } qw/9 2047 1373653 25326001 3215031751 2152302898747 3474749660383 341550071728321 341550071728321 3825123056546413051/; map { ok(!is_prime($_), "Carmichael Number $_ is not prime") } qw/561 1105 1729 2465 2821 6601 8911 10585 15841 29341 41041 46657 52633 62745 63973 75361 101101 340561 488881 852841 1857241 6733693 9439201 17236801 23382529 34657141 56052361 146843929 216821881/; map { ok(!is_prime($_), "Pseudoprime (base 2) $_ is not prime" ) } qw/341 561 645 1105 1387 1729 1905 2047 2465 2701 2821 3277 4033 4369 4371 4681 5461 6601 7957 8321 52633 88357/; map { ok(!is_prime($_), "Pseudoprime (base 3) $_ is not prime" ) } qw/121 703 1891 3281 8401 8911 10585 12403 16531 18721 19345 23521 31621 44287 47197 55969 63139 74593 79003 82513 87913 88573 97567/; map { ok(!is_prime($_), "Pseudoprime (base 5) $_ is not prime" ) } qw/781 1541 5461 5611 7813 13021 14981 15751 24211 25351 29539 38081 40501 44801 53971 79381/; map { ok(is_prime($_), "Primegap start $_ is prime" ) } qw/2 3 7 23 89 113 523 887 1129 1327 9551 15683 19609 31397 155921/; map { ok(is_prime($_), "Primegap end $_ is prime" ) } qw/5 11 29 97 127 541 907 1151 1361 9587 15727 19661 31469 156007 360749 370373 492227 1349651 1357333 2010881 4652507 17051887 20831533 47326913 122164969 189695893 191913031 10726905041/; map { ok(is_prime($_), "Primegap end $_ is prime" ) } qw/387096383 436273291 1294268779 1453168433 2300942869 3842611109 4302407713 20678048681 22367085353 25056082543 42652618807 127976334671 182226896239 241160624143 297501075799 303371455241 304599508537 416608695821 461690510011 614487453523 738832927927 1346294310749 1408695493609 1968188556461 2614941710599 7177162611713 13829048559701 19581334192423 42842283925351 90874329411493 171231342420521 1425172824437699411/; map { ok(is_prime($_), "Primegap start $_ is prime" ) } qw/41437872381314257606025664648551531 2533428381785258181145396408525147 6429801387755251608076552195160813 41553317381222258299076384479889759 36315406071322208317982870602883 45578379712061211117046756353187 853188381785258606010648985968457 888753381785258606882214366477061/; map { ok(is_prime($_), "Large prime $_ is prime" ) } qw/225024267640198977569930286413453544441731198242501 117012619172903468336363755054149226979817746816041 531137992816767098689588206552468627329593117727031923199444138200403559860852242739162502265229285668889329486246501015346579337652707239409519978766587351943831270835393219031728127 92751329613360357106269703807871171087102857318174669180345062763478315192734600581256686043065309145579066294614789483004809764977045757613701500430172705662998376708484136826337990209855359024352422688815970711638591317382567474931186571722543217265405033315880950490013269952667650366965082529384527374177 32260744804243979022151766262161234411163230832614876909266661009538736040353215637132894501612353010543647977249384696464608093622417037943487940297713136625578440884358987868505411720686648801150726329314235915696991593215969719047680808482063865275910410329176506289872973203004139815308900515515244012185782792865548320042281725631557473818091156913398618606687353487817756951894689296125125745219508443864021389470338722761499570221166792212754530607135317650463501248358538246234526221292291399209816873396728066128587613467291339613990745570031925686037674992827058364602015693306309221496407276025345897341847 741396953013654360447130328344036195463451575964208809937212804294129714670068945580433523222395982402982697545970774900776520388371921559613345658117858514521005297959953114279118002815246386498175953512848112483829848122269294444605330839657412152438182209874755797291767504531960060238286549305381539583199152421722832641143066110744833138611455286547147404482909367418917279008726128416147000372123061195691620902127739725422428617685907314016736926212798020427887587562043320485749196280067057894293080208114019557078624547720775548197602227651474547221582994513675272163167738690346545549988775205966423807402030104516784101084806845639397870429182441506430010222493085299118475419254862008744168191879396758301572743283703529570334803330960201229624052255881219905504918044357793149162118185478553170626317902665884547746435111999694067410243494584529487741658481642249023103753134680734412840328449909896847175077758262986499427135151069709448521414215035574272868281224727572369419529536625125298888387473824456936636521457187215362102409447089422614360505828034680296548026192715652255266408626555770777003931789812374333546088379306076791601248774333377106632994883876629562024348840502578094204183502272143692446875343057 /; map { ok(!is_prime($_), "Large composite $_ is not prime" ) } qw/777777777777777777777777 877777777777777777777777 87777777777777777777777795475 890745785790123461234805903467891234681234 318665857834031151167461 3317044064679887385961981 6003094289670105800312596501 59276361075595573263446330101 564132928021909221014087501701 1543267864443420616877677640751301 /; is(is_prime('43556142965880123323311949751266331066401'), 2, "is_prime(2**135+33) = 2"); is(is_prime('2417860862601296277930091'), 2, "is_prime is deterministic for 81-bit input"); Math-Prime-Util-GMP-0.52/t/26-mersenne.t0000644000175000017500000000106513025437621016025 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/is_mersenne_prime/; my $extra = defined $ENV{EXTENDED_TESTING} && $ENV{EXTENDED_TESTING}; my @A000043 = (2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279); push @A000043, (2203, 2281, 3217, 4253, 4423, 9689, 9941) if $extra; #push @A000043, (11213, 19937, 21701, 23209, 44497, 86243) if $extra; plan tests => 1; is_deeply( [grep { is_mersenne_prime($_) } 0 .. $A000043[-1]], \@A000043, "Find Mersenne primes from 0 to $A000043[-1]" ); Math-Prime-Util-GMP-0.52/t/15-probprime.t0000644000175000017500000000471713025437621016215 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/is_prime is_prob_prime/; my $extra = defined $ENV{EXTENDED_TESTING} && $ENV{EXTENDED_TESTING}; plan tests => 0 + 6 + 5 + 5 + 29 + 22 + 23 + 16 + 15 + 28 + 1 * $extra + 0; # Some of these tests were inspired by Math::Primality's tests ok(is_prob_prime(2) == 2, '2 is prime'); ok(is_prob_prime(1) == 0, '1 is not prime'); ok(is_prob_prime(0) == 0, '0 is not prime'); ok(is_prob_prime(-1) == 0, '-1 is not prime'); ok(is_prob_prime(-2) == 0, '-2 is not prime'); ok(is_prob_prime(20) == 0, '20 is not prime'); map { ok(!is_prob_prime($_), "A006945 number $_ is not prime") } qw/9 2047 1373653 25326001 3215031751/; map { ok(!is_prob_prime($_), "A006945 number $_ is not prime") } qw/2152302898747 3474749660383 341550071728321 341550071728321 3825123056546413051/; map { ok(!is_prob_prime($_), "Carmichael Number $_ is not prime") } qw/561 1105 1729 2465 2821 6601 8911 10585 15841 29341 41041 46657 52633 62745 63973 75361 101101 340561 488881 852841 1857241 6733693 9439201 17236801 23382529 34657141 56052361 146843929 216821881/; map { ok(!is_prob_prime($_), "Pseudoprime (base 2) $_ is not prime" ) } qw/341 561 645 1105 1387 1729 1905 2047 2465 2701 2821 3277 4033 4369 4371 4681 5461 6601 7957 8321 52633 88357/; map { ok(!is_prob_prime($_), "Pseudoprime (base 3) $_ is not prime" ) } qw/121 703 1891 3281 8401 8911 10585 12403 16531 18721 19345 23521 31621 44287 47197 55969 63139 74593 79003 82513 87913 88573 97567/; map { ok(!is_prob_prime($_), "Pseudoprime (base 5) $_ is not prime" ) } qw/781 1541 5461 5611 7813 13021 14981 15751 24211 25351 29539 38081 40501 44801 53971 79381/; map { ok(is_prob_prime($_)==2, "Primegap start $_ is prime" ) } qw/2 3 7 23 89 113 523 887 1129 1327 9551 15683 19609 31397 155921/; map { ok(is_prob_prime($_)==2, "Primegap end $_ is prime" ) } qw/5 11 29 97 127 541 907 1151 1361 9587 15727 19661 31469 156007 360749 370373 492227 1349651 1357333 2010881 4652507 17051887 20831533 47326913 122164969 189695893 191913031 10726905041/; if ($extra) { # Test tree sieve my $n = '18446744073709551427' . '0' x 476468 . '1'; my @f = Math::Prime::Util::GMP::trial_factor($n, 50000000); is($f[0], 913589, "Trial factor of 476489-digit number"); } Math-Prime-Util-GMP-0.52/gmp_main.c0000644000175000017500000016356313674067073015315 0ustar danadana#include #include #include #include #include "ptypes.h" #include "gmp_main.h" #include "primality.h" #include "prime_iterator.h" #include "ecpp.h" #include "factor.h" #include "real.h" #define FUNC_gcd_ui 1 #define FUNC_mpz_logn 1 #include "utility.h" static mpz_t _bgcd; static mpz_t _bgcd2; static mpz_t _bgcd3; #define BGCD_PRIMES 168 #define BGCD_LASTPRIME 997 #define BGCD_NEXTPRIME 1009 #define BGCD2_PRIMES 1229 #define BGCD2_NEXTPRIME 10007 #define BGCD3_PRIMES 4203 #define BGCD3_NEXTPRIME 40009 #define NSMALLPRIMES 168 static const unsigned short sprimes[NSMALLPRIMES] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997}; #define TSTAVAL(arr, val) (arr[(val) >> 6] & (1U << (((val)>>1) & 0x1F))) #define SETAVAL(arr, val) arr[(val) >> 6] |= 1U << (((val)>>1) & 0x1F) void _GMP_init(void) { /* For real use of randomness we need to be seeded properly. * This gives us a start until someone calls seed_csprng(). * We could try to improve this duct-tape in various ways. */ unsigned long seed = time(NULL); init_randstate(seed); prime_iterator_global_startup(); mpz_init(_bgcd); _GMP_pn_primorial(_bgcd, BGCD_PRIMES); /* mpz_primorial_ui(_bgcd, 1000) */ mpz_init_set_ui(_bgcd2, 0); mpz_init_set_ui(_bgcd3, 0); _init_factor(); } void _GMP_destroy(void) { _GMP_memfree(); prime_iterator_global_shutdown(); clear_randstate(); mpz_clear(_bgcd); mpz_clear(_bgcd2); mpz_clear(_bgcd3); } void _GMP_memfree(void) { free_float_constants(); destroy_ecpp_gcds(); free_borwein_zeta(); } static const unsigned char next_wheel[30] = {1,7,7,7,7,7,7,11,11,11,11,13,13,17,17,17,17,19,19,23,23,23,23,29,29,29,29,29,29,1}; static const unsigned char prev_wheel[30] = {29,29,1,1,1,1,1,1,7,7,7,7,11,11,13,13,13,13,17,17,19,19,19,19,23,23,23,23,23,23}; static const unsigned char wheel_advance[30] = {1,6,5,4,3,2,1,4,3,2,1,2,1,4,3,2,1,2,1,4,3,2,1,6,5,4,3,2,1,2}; static const unsigned char wheel_retreat[30] = {1,2,1,2,3,4,5,6,1,2,3,4,1,2,1,2,3,4,1,2,1,2,3,4,1,2,3,4,5,6}; /*****************************************************************************/ static int is_tiny_prime(uint32_t n) { uint32_t f, limit; if (n < 11) { if (n == 2 || n == 3 || n == 5 || n == 7) return 2; else return 0; } if (!(n%2) || !(n%3) || !(n%5) || !(n%7)) return 0; if (n < 121) /* 11*11 */ return 2; if (!(n%11) || !(n%13) || !(n%17) || !(n%19) || !(n%23) || !(n%29) || !(n%31) || !(n%37) || !(n%41) || !(n%43) || !(n%47) || !(n%53)) return 0; if (n < 3481) /* 59*59 */ return 2; f = 59; limit = (uint32_t) (sqrt((double)n)); while (f <= limit) { if ( !(n%f) || !(n%(f+2)) || !(n%(f+8)) || !(n%(f+12)) ) return 0; f += 14; if ( !(n%f) || !(n%(f+4)) || !(n%(f+6)) || !(n%(f+10)) ) return 0; f += 16; } return 2; } int primality_pretest(mpz_t n) { if (mpz_cmp_ui(n, 100000) < 0) return is_tiny_prime((uint32_t)mpz_get_ui(n)); /* Check for tiny divisors */ if (mpz_even_p(n)) return 0; if (sizeof(unsigned long) < 8) { if (mpz_gcd_ui(NULL, n, 3234846615UL) != 1) return 0; /* 3-29 */ } else { if (mpz_gcd_ui(NULL, n, 4127218095UL*3948078067UL)!=1) return 0;/* 3-53 */ if (mpz_gcd_ui(NULL, n, 4269855901UL*1673450759UL)!=1) return 0;/* 59-101 */ } { UV log2n = mpz_sizeinbase(n,2); mpz_t t; mpz_init(t); /* Do a GCD with all primes < 1009 */ mpz_gcd(t, n, _bgcd); if (mpz_cmp_ui(t, 1)) { mpz_clear(t); return 0; } /* No divisors under 1009 */ if (mpz_cmp_ui(n, BGCD_NEXTPRIME*BGCD_NEXTPRIME) < 0) { mpz_clear(t); return 2; } /* If we're reasonably large, do a gcd with more primes */ if (log2n > 700) { if (mpz_sgn(_bgcd3) == 0) { _GMP_pn_primorial(_bgcd3, BGCD3_PRIMES); mpz_divexact(_bgcd3, _bgcd3, _bgcd); } mpz_gcd(t, n, _bgcd3); if (mpz_cmp_ui(t, 1)) { mpz_clear(t); return 0; } } else if (log2n > 300) { if (mpz_sgn(_bgcd2) == 0) { _GMP_pn_primorial(_bgcd2, BGCD2_PRIMES); mpz_divexact(_bgcd2, _bgcd2, _bgcd); } mpz_gcd(t, n, _bgcd2); if (mpz_cmp_ui(t, 1)) { mpz_clear(t); return 0; } } mpz_clear(t); /* Do more trial division if we think we should. * According to Menezes (section 4.45) as well as Park (ISPEC 2005), * we want to select a trial limit B such that B = E/D where E is the * time for our primality test (one M-R test) and D is the time for * one trial division. Example times on my machine came out to * log2n = 840375, E= 6514005000 uS, D=1.45 uS, E/D = 0.006 * log2n * log2n = 465618, E= 1815000000 uS, D=1.05 uS, E/D = 0.008 * log2n * log2n = 199353, E= 287282000 uS, D=0.70 uS, E/D = 0.01 * log2n * log2n = 99678, E= 56956000 uS, D=0.55 uS, E/D = 0.01 * log2n * log2n = 33412, E= 4289000 uS, D=0.30 uS, E/D = 0.013 * log2n * log2n = 13484, E= 470000 uS, D=0.21 uS, E/D = 0.012 * log2n * Our trial division could also be further improved for large inputs. */ if (log2n > 16000) { double dB = (double)log2n * (double)log2n * 0.005; if (BITS_PER_WORD == 32 && dB > 4200000000.0) dB = 4200000000.0; if (_GMP_trial_factor(n, BGCD3_NEXTPRIME, (UV)dB)) return 0; } else if (log2n > 4000) { if (_GMP_trial_factor(n, BGCD3_NEXTPRIME, 80*log2n)) return 0; } else if (log2n > 1600) { if (_GMP_trial_factor(n, BGCD3_NEXTPRIME, 30*log2n)) return 0; } } return 1; } /*****************************************************************************/ /* Controls how many numbers to sieve. Little time impact. */ #define NPS_MERIT 30.0 /* Controls how many primes to use. Big time impact. */ static UV _nps_depth(UV log2n, UV log2log2n) { double d; if (log2n < 100) return 1000; d = 0.75 * (double)log2n * (double)(log2n >> 5) * (double)log2log2n; /* Make sure we don't try to sieve too far. */ if (d >= (double)(UV_MAX>>1)) return (UV_MAX>>1); return (UV) d; } static void next_prime_with_sieve(mpz_t n) { UV i, log2n, log2log2n, width, depth; uint32_t* comp; mpz_t t, base; log2n = mpz_sizeinbase(n, 2); for (log2log2n = 1, i = log2n; i >>= 1; ) log2log2n++; width = (UV) (NPS_MERIT/1.4427 * (double)log2n + 0.5); depth = _nps_depth(log2n, log2log2n); if (width & 1) width++; /* Make width even */ mpz_add_ui(n, n, mpz_even_p(n) ? 1 : 2); /* Set n to next odd */ mpz_init(t); mpz_init(base); while (1) { mpz_set(base, n); comp = partial_sieve(base, width, depth); /* sieve range to depth */ for (i = 1; i <= width; i += 2) { if (!TSTAVAL(comp, i)) { mpz_add_ui(t, base, i); /* We found a candidate */ if (_GMP_BPSW(t)) { mpz_set(n, t); mpz_clear(t); mpz_clear(base); Safefree(comp); return; } } } Safefree(comp); /* A huge gap found, so sieve another range */ mpz_add_ui(n, n, width); } } static void prev_prime_with_sieve(mpz_t n) { UV i, j, log2n, log2log2n, width, depth; uint32_t* comp; mpz_t t, base; log2n = mpz_sizeinbase(n, 2); for (log2log2n = 1, i = log2n; i >>= 1; ) log2log2n++; width = (UV) (NPS_MERIT/1.4427 * (double)log2n + 0.5); depth = _nps_depth(log2n, log2log2n); mpz_sub_ui(n, n, mpz_even_p(n) ? 1 : 2); /* Set n to prev odd */ width = 64 * ((width+63)/64); /* Round up to next 64 */ mpz_init(t); mpz_init(base); while (1) { mpz_sub_ui(base, n, width-2); /* gmp_printf("sieve from %Zd to %Zd width %lu\n", base, n, width); */ comp = partial_sieve(base, width, depth); /* sieve range to depth */ /* if (mpz_odd_p(base)) croak("base off after partial"); if (width & 1) croak("width is odd after partial"); */ for (j = 1; j < width; j += 2) { i = width - j; if (!TSTAVAL(comp, i)) { mpz_add_ui(t, base, i); /* We found a candidate */ if (_GMP_BPSW(t)) { mpz_set(n, t); mpz_clear(t); mpz_clear(base); Safefree(comp); return; } } } Safefree(comp); /* A huge gap found, so sieve another range */ mpz_sub_ui(n, n, width); } } /* Modifies argument */ void _GMP_next_prime(mpz_t n) { if (mpz_cmp_ui(n, 29) < 0) { /* small inputs */ UV m = mpz_get_ui(n); m = (m < 2) ? 2 : (m < 3) ? 3 : (m < 5) ? 5 : next_wheel[m]; mpz_set_ui(n, m); } else if (mpz_sizeinbase(n,2) > 120) { next_prime_with_sieve(n); } else { UV m23 = mpz_fdiv_ui(n, 223092870UL); /* 2*3*5*7*11*13*17*19*23 */ UV m = m23 % 30; do { UV skip = wheel_advance[m]; mpz_add_ui(n, n, skip); m23 += skip; m = next_wheel[m]; } while ( !(m23% 7) || !(m23%11) || !(m23%13) || !(m23%17) || !(m23%19) || !(m23%23) || !_GMP_is_prob_prime(n) ); } } /* Modifies argument */ void _GMP_prev_prime(mpz_t n) { UV m, m23; if (mpz_cmp_ui(n, 29) <= 0) { /* small inputs */ m = mpz_get_ui(n); m = (m < 3) ? 0 : (m < 4) ? 2 : (m < 6) ? 3 : (m < 8) ? 5 : prev_wheel[m]; mpz_set_ui(n, m); } else if (mpz_sizeinbase(n,2) > 200) { prev_prime_with_sieve(n); } else { m23 = mpz_fdiv_ui(n, 223092870UL); /* 2*3*5*7*11*13*17*19*23 */ m = m23 % 30; m23 += 223092870UL; /* No need to re-mod inside the loop */ do { UV skip = wheel_retreat[m]; mpz_sub_ui(n, n, skip); m23 -= skip; m = prev_wheel[m]; } while ( !(m23% 7) || !(m23%11) || !(m23%13) || !(m23%17) || !(m23%19) || !(m23%23) || !_GMP_is_prob_prime(n) ); } } void surround_primes(mpz_t n, UV* prev, UV* next, UV skip_width) { UV i, j, log2n, log2log2n, width, depth, fprev, fnext, search_merits; uint32_t* comp; mpz_t t, base; int neven, found; log2n = mpz_sizeinbase(n, 2); for (log2log2n = 1, i = log2n; i >>= 1; ) log2log2n++; if (log2n < 64) { mpz_init(t); mpz_set(t, n); _GMP_prev_prime(t); mpz_sub(t, n, t); *prev = mpz_get_ui(t); mpz_set(t, n); _GMP_next_prime(t); mpz_sub(t, t, n); *next = mpz_get_ui(t); mpz_clear(t); return; } mpz_init(t); mpz_init(base); fprev = fnext = 0; neven = mpz_even_p(n); j = 1 + !neven; /* distance from n we're looking. */ for (found = 0, search_merits = 20; !found; search_merits *= 2) { double logn = mpz_logn(n); if (BITS_PER_WORD == 32 && log2n > 16600) depth = UVCONST( 2500000000); else if (BITS_PER_WORD == 64 && log2n > 203600) depth = UVCONST(6000000000000); else if (log2n > 900) depth = (UV) ((-.05L+(log2n/8000.0L)) * logn * logn * log(logn)); else depth = _nps_depth(log2n, log2log2n); width = (UV) (search_merits * logn + 0.5); width = 64 * ((width+63)/64); /* Round up to next 64 */ if (neven) width++; /* base will always be odd */ mpz_sub_ui(base, n, width); /* printf("merits %lu width %lu depth %lu skip_width %lu\n", search_merits, width, depth, skip_width); */ /* gmp_printf("partial sieve width %lu depth %lu\n", 2*width+1, depth); */ comp = partial_sieve(base, 2*width+1, depth); for (; j < width; j += 2) { if (!fprev) { if (!TSTAVAL(comp, width+1-j)) { mpz_sub_ui(t, n, j); if ( (skip_width == 0) ? _GMP_BPSW(t) : miller_rabin_ui(t,2) ) { fprev = j; if (fnext || (skip_width != 0 && j <= skip_width)) break; } } } if (!fnext) { if (!TSTAVAL(comp, width+1+j)) { mpz_add_ui(t, n, j); if ( (skip_width == 0) ? _GMP_BPSW(t) : miller_rabin_ui(t,2) ) { fnext = j; if (fprev || (skip_width != 0 && j <= skip_width)) break; } } } } Safefree(comp); if ( (fprev && fnext) || (skip_width != 0 && j <= skip_width && (fprev || fnext)) ) found = 1; } mpz_clear(base); mpz_clear(t); *prev = fprev; *next = fnext; } /*****************************************************************************/ #define LAST_TRIPLE_PROD \ ((ULONG_MAX <= 4294967295UL) ? UVCONST(1619) : UVCONST(2642231)) #define LAST_DOUBLE_PROD \ ((ULONG_MAX <= 4294967295UL) ? UVCONST(65521) : UVCONST(4294967291)) void _GMP_pn_primorial(mpz_t prim, UV n) { UV i = 0, al = 0, p = 2; mpz_t* A; if (n <= 4) { /* tiny input */ p = (n == 0) ? 1 : (n == 1) ? 2 : (n == 2) ? 6 : (n == 3) ? 30 : 210; mpz_set_ui(prim, p); } else if (n < 200) { /* simple linear multiply */ PRIME_ITERATOR(iter); mpz_set_ui(prim, 1); while (n-- > 0) { if (n > 0) { p *= prime_iterator_next(&iter); n--; } mpz_mul_ui(prim, prim, p); p = prime_iterator_next(&iter); } prime_iterator_destroy(&iter); } else { /* tree mult array of products of 8 UVs */ PRIME_ITERATOR(iter); New(0, A, n, mpz_t); while (n-- > 0) { if (p <= LAST_TRIPLE_PROD && n > 0) { p *= prime_iterator_next(&iter); n--; } if (p <= LAST_DOUBLE_PROD && n > 0) { p *= prime_iterator_next(&iter); n--; } /* each array entry holds the product of 8 UVs */ if ((i & 7) == 0) mpz_init_set_ui( A[al++], p ); else mpz_mul_ui(A[al-1],A[al-1], p ); i++; p = prime_iterator_next(&iter); } mpz_product(A, 0, al-1); mpz_set(prim, A[0]); for (i = 0; i < al; i++) mpz_clear(A[i]); Safefree(A); prime_iterator_destroy(&iter); } } void _GMP_primorial(mpz_t prim, UV n) { #if (__GNU_MP_VERSION > 5) || (__GNU_MP_VERSION == 5 && __GNU_MP_VERSION_MINOR >= 1) mpz_primorial_ui(prim, n); #else if (n <= 4) { UV p = (n == 0) ? 1 : (n == 1) ? 1 : (n == 2) ? 2 : (n == 3) ? 6 : 6; mpz_set_ui(prim, p); } else { mpz_t *A; UV nprimes, i, al; UV *primes = sieve_to_n(n, &nprimes); /* Multiply native pairs until we overflow the native type */ while (nprimes > 1 && ULONG_MAX/primes[0] > primes[nprimes-1]) { i = 0; while (nprimes > i+1 && ULONG_MAX/primes[i] > primes[nprimes-1]) primes[i++] *= primes[--nprimes]; } if (nprimes <= 8) { /* Just multiply if there are only a few native values left */ mpz_set_ui(prim, primes[0]); for (i = 1; i < nprimes; i++) mpz_mul_ui(prim, prim, primes[i]); } else { /* Create n/4 4-way products, then use product tree */ New(0, A, nprimes/4 + 1, mpz_t); for (i = 0, al = 0; i < nprimes; al++) { mpz_init_set_ui(A[al], primes[i++]); if (i < nprimes) mpz_mul_ui(A[al], A[al], primes[i++]); if (i < nprimes) mpz_mul_ui(A[al], A[al], primes[i++]); if (i < nprimes) mpz_mul_ui(A[al], A[al], primes[i++]); } mpz_product(A, 0, al-1); mpz_set(prim, A[0]); for (i = 0; i < al; i++) mpz_clear(A[i]); Safefree(A); } Safefree(primes); } #endif } /*****************************************************************************/ void stirling(mpz_t r, unsigned long n, unsigned long m, UV type) { mpz_t t, t2; unsigned long j; if (type < 1 || type > 3) croak("stirling type must be 1, 2, or 3"); if (n == m) { mpz_set_ui(r, 1); } else if (n == 0 || m == 0 || m > n) { mpz_set_ui(r,0); } else if (m == 1) { switch (type) { case 1: mpz_fac_ui(r, n-1); if (!(n&1)) mpz_neg(r, r); break; case 2: mpz_set_ui(r, 1); break; case 3: default: mpz_fac_ui(r, n); break; } } else { mpz_init(t); mpz_init(t2); mpz_set_ui(r,0); if (type == 3) { /* Lah: binomial(n k) * binomial(n-1 k-1) * (n-k)!*/ mpz_bin_uiui(t, n, m); mpz_bin_uiui(t2, n-1, m-1); mpz_mul(r, t, t2); mpz_fac_ui(t2, n-m); mpz_mul(r, r, t2); } else if (type == 2) { mpz_t binom; mpz_init_set_ui(binom, m); mpz_ui_pow_ui(r, m, n); /* Use symmetry to halve the number of loops */ for (j = 1; j <= ((m-1)>>1); j++) { mpz_ui_pow_ui(t, j, n); mpz_ui_pow_ui(t2, m-j, n); if (m&1) mpz_sub(t, t2, t); else mpz_add(t, t2, t); mpz_mul(t, t, binom); if (j&1) mpz_sub(r, r, t); else mpz_add(r, r, t); mpz_mul_ui(binom, binom, m-j); mpz_divexact_ui(binom, binom, j+1); } if (!(m&1)) { mpz_ui_pow_ui(t, j, n); mpz_mul(t, t, binom); if (j&1) mpz_sub(r, r, t); else mpz_add(r, r, t); } mpz_clear(binom); mpz_fac_ui(t, m); mpz_divexact(r, r, t); } else { mpz_bin_uiui(t, n-1+1, n-m+1); mpz_bin_uiui(t2, n-m+n, n-m-1); mpz_mul(t2, t2, t); for (j = 1; j <= n-m; j++) { stirling(t, n-m+j, j, 2); mpz_mul(t, t, t2); if (j & 1) mpz_sub(r, r, t); else mpz_add(r, r, t); mpz_mul_ui(t2, t2, n+j); mpz_divexact_ui(t2, t2, n-m+j+1); mpz_mul_ui(t2, t2, n-m-j); mpz_divexact_ui(t2, t2, n+j+1); } } mpz_clear(t2); mpz_clear(t); } } /* Goetgheluck method. Also thanks to Peter Luschny. */ void binomial(mpz_t r, UV n, UV k) { UV fi, nk, sqrtn, piN, prime, i, j; UV* primes; mpz_t* mprimes; if (k > n) { mpz_set_ui(r, 0); return; } if (k == 0 || k == n) { mpz_set_ui(r, 1); return; } if (k > n/2) k = n-k; sqrtn = (UV) (sqrt((double)n)); fi = 0; nk = n-k; primes = sieve_to_n(n, &piN); #define PUSHP(p) \ do { \ if ((j++ % 8) == 0) mpz_init_set_ui(mprimes[fi++], p); \ else mpz_mul_ui(mprimes[fi-1], mprimes[fi-1], p); \ } while (0) New(0, mprimes, (piN+7)/8, mpz_t); for (i = 0, j = 0; i < piN; i++) { prime = primes[i]; if (prime > nk) { PUSHP(prime); } else if (prime > n/2) { /* nothing */ } else if (prime > sqrtn) { if (n % prime < k % prime) PUSHP(prime); } else { UV N = n, K = k, p = 1, s = 0; while (N > 0) { s = (N % prime) < (K % prime + s) ? 1 : 0; if (s == 1) p *= prime; N /= prime; K /= prime; } if (p > 1) PUSHP(p); } } Safefree(primes); mpz_product(mprimes, 0, fi-1); mpz_set(r, mprimes[0]); for (i = 0; i < fi; i++) mpz_clear(mprimes[i]); Safefree(mprimes); } void multifactorial(mpz_t r, UV n, UV k) { if (k == 0) { mpz_set_ui(r, 1); return; } if (k == 1) { mpz_fac_ui(r, n); return; } #if (__GNU_MP_VERSION > 5) || (__GNU_MP_VERSION == 5 && __GNU_MP_VERSION_MINOR >= 1) mpz_mfac_uiui(r, n, k); #else /* Naive code. Slow with large n and small k. * See Luschny or mpz_mfac_uiui for better. */ mpz_set_ui(r, (n > 1) ? n : 1); while (n > k) { n -= k; mpz_mul_ui(r, r, n); } #endif } void factorial_sum(mpz_t r, UV n) { mpz_t t; UV k; if (n == 0) { mpz_set_ui(r,0); return; } mpz_set_ui(r,1); mpz_init_set_ui(t,1); for (k = 1; k < n; k++) { mpz_mul_ui(t, t, k); mpz_add(r, r, t); } mpz_clear(t); } void subfactorial(mpz_t r, UV n) { UV k; if (n == 0) { mpz_set_ui(r,1); return; } if (n == 1) { mpz_set_ui(r,0); return; } /* We could loop using Pochhammer, but that's much slower. */ mpz_set_ui(r,0); for (k = 2; k <= n; k++) { mpz_mul_ui(r, r, k); if (k & 1) mpz_sub_ui(r, r, 1); else mpz_add_ui(r, r, 1); } } void falling_factorial(mpz_t r, UV x, UV n) { mpz_t t; if (n == 0) { mpz_set_ui(r,1); return; } mpz_init(t); mpz_bin_uiui(t, x, n); mpz_fac_ui(r, n); mpz_mul(r, r, t); mpz_clear(t); } void rising_factorial(mpz_t r, UV x, UV n) { falling_factorial(r, x+n-1, n); } void factorialmod(mpz_t r, UV N, mpz_t m) { mpz_t t; UV i, D = N; if (mpz_cmp_ui(m,N) <= 0 || mpz_cmp_ui(m,1) <= 0) { mpz_set_ui(r,0); return; } mpz_init(t); mpz_tdiv_q_2exp(t, m, 1); if (mpz_cmp_ui(t, N) < 0 && _GMP_is_prime(m)) D = mpz_get_ui(m) - N - 1; if (D < 2 && N > D) { if (D == 0) mpz_sub_ui(r, m, 1); else mpz_set_ui(r, 1); mpz_clear(t); return; } if (D == N && D > 5000000) { /* TODO: tune this threshold */ mpz_t *factors; int j, nfactors, *exponents, reszero; nfactors = factor(m, &factors, &exponents); /* Find max factor */ mpz_set_ui(t, 0); for (j = 0; j < nfactors; j++) { if (exponents[j] > 1) mpz_pow_ui(factors[j], factors[j], exponents[j]); if (mpz_cmp(factors[j], t) > 0) mpz_set(t, factors[j]); } reszero = (mpz_cmp_ui(t, N) <= 0); clear_factors(nfactors, &factors, &exponents); if (reszero) { mpz_clear(t); mpz_set_ui(r,0); return; } } mpz_set_ui(t,1); for (i = 2; i <= D && mpz_sgn(t); i++) { mpz_mul_ui(t, t, i); if ((i & 15) == 0) mpz_mod(t, t, m); } mpz_mod(r, t, m); if (D != N && mpz_sgn(r)) { if (!(D&1)) mpz_sub(r, m, r); mpz_invert(r, r, m); } mpz_clear(t); } void partitions(mpz_t npart, UV n) { mpz_t psum, *part; UV *pent, i, j, k, d = (UV) sqrt(n+1); if (n <= 3) { mpz_set_ui(npart, (n == 0) ? 1 : n); return; } New(0, pent, 2*d+2, UV); pent[0] = 0; pent[1] = 1; for (i = 1; i <= d; i++) { pent[2*i ] = ( i *(3*i+1)) / 2; pent[2*i+1] = ((i+1)*(3*i+2)) / 2; } New(0, part, n+1, mpz_t); mpz_init_set_ui(part[0], 1); mpz_init(psum); for (j = 1; j <= n; j++) { mpz_set_ui(psum, 0); for (k = 1; pent[k] <= j; k++) { if ((k+1) & 2) mpz_add(psum, psum, part[ j - pent[k] ]); else mpz_sub(psum, psum, part[ j - pent[k] ]); } mpz_init_set(part[j], psum); } mpz_set(npart, part[n]); mpz_clear(psum); for (i = 0; i <= n; i++) mpz_clear(part[i]); Safefree(part); Safefree(pent); } void consecutive_integer_lcm(mpz_t m, UV B) { UV i, p, p_power, pmin; mpz_t t[8]; PRIME_ITERATOR(iter); /* Create eight sub-products to combine at the end. */ for (i = 0; i < 8; i++) mpz_init_set_ui(t[i], 1); i = 0; /* For each prime, multiply m by p^floor(log B / log p), which means * raise p to the largest power e such that p^e <= B. */ if (B >= 2) { p_power = 2; while (p_power <= B/2) p_power *= 2; mpz_mul_ui(t[i&7], t[i&7], p_power); i++; } p = prime_iterator_next(&iter); while (p <= B) { pmin = B/p; if (p > pmin) break; p_power = p*p; while (p_power <= pmin) p_power *= p; mpz_mul_ui(t[i&7], t[i&7], p_power); i++; p = prime_iterator_next(&iter); } while (p <= B) { mpz_mul_ui(t[i&7], t[i&7], p); i++; p = prime_iterator_next(&iter); } /* combine the eight sub-products */ for (i = 0; i < 4; i++) mpz_mul(t[i], t[2*i], t[2*i+1]); for (i = 0; i < 2; i++) mpz_mul(t[i], t[2*i], t[2*i+1]); mpz_mul(m, t[0], t[1]); for (i = 0; i < 8; i++) mpz_clear(t[i]); prime_iterator_destroy(&iter); } void exp_mangoldt(mpz_t res, mpz_t n) { if (prime_power(res, n) < 1) mpz_set_ui(res, 1); } int is_carmichael(mpz_t n) { mpz_t nm1, t, *factors; int i, res, nfactors, *exponents; /* small or even */ if (mpz_cmp_ui(n,561) < 0 || mpz_even_p(n)) return 0; /* divisible by small square */ for (i = 1; i < 9; i++) if (mpz_divisible_ui_p(n, sprimes[i] * sprimes[i])) return 0; mpz_init(nm1); mpz_sub_ui(nm1, n, 1); /* Korselt's criterion for small divisors */ for (i = 2; i < 20; i++) if (mpz_divisible_ui_p(n, sprimes[i]) && !mpz_divisible_ui_p(nm1, sprimes[i]-1)) { mpz_clear(nm1); return 0; } mpz_init_set_ui(t, 2); mpz_powm(t, t, nm1, n); if (mpz_cmp_ui(t, 1) != 0) { /* if 2^(n-1) mod n != 1, fail */ mpz_clear(t); mpz_clear(nm1); return 0; } /* If large enough, use probable test */ if (mpz_sizeinbase(n,10) > 50) { res = !_GMP_is_prime(n); /* It must be a composite */ for (i = 20; res && i <= 100; i++) { UV p = sprimes[i]; UV gcd = mpz_gcd_ui(NULL, n, p); if (gcd == 1) { /* For each non prime factor it passes a Fermat test */ if (mpz_set_ui(t,p), mpz_powm(t,t,nm1,n), mpz_cmp_ui(t, 1) != 0) res = 0; } else { /* For each prime factor it meets Korselt criterion */ if (gcd != p || !mpz_divisible_ui_p(nm1, p-1)) res = 0; } } mpz_clear(t); mpz_clear(nm1); return res; } nfactors = factor(n, &factors, &exponents); res = (nfactors > 2); /* must have 3+ factors */ for (i = 0; res && i < nfactors; i++) { /* must be square free */ if (exponents[i] > 1) res = 0; } for (i = 0; res && i < nfactors; i++) { /* p-1 | n-1 for all p */ mpz_sub_ui(t, factors[i], 1); if (!mpz_divisible_p(nm1, t)) res = 0; } clear_factors(nfactors, &factors, &exponents); mpz_clear(t); mpz_clear(nm1); return res; } int is_fundamental(mpz_t n) { int r, neg = (mpz_sgn(n) < 0), ret = 0; if (neg) mpz_neg(n,n); r = mpz_fdiv_ui(n,16); if (r != 0) { int r4 = r & 3; if (!neg && r4 == 1 && moebius(n) != 0) ret = 1; if ( neg && r4 == 3 && moebius(n) != 0) ret = 1; if (r4 == 0 && ((!neg && r != 4) || (neg && r != 12))) { mpz_t t; mpz_init(t); mpz_tdiv_q_2exp(t, n, 2); if (moebius(t) != 0) ret = 1; mpz_clear(t); } } if (neg) mpz_neg(n,n); return ret; } int _totpred(mpz_t n, mpz_t maxd) { int i, res, ndivisors; mpz_t N, r, d, p, *D; if (mpz_odd_p(n)) return 0; if (mpz_cmp_ui(n,2) == 0) return 1; if (mpz_popcount(n) == 1) return 1; /* n > 0 is a power of 2 */ mpz_init(N); mpz_init(p); mpz_tdiv_q_2exp(N, n, 1); res = 0; mpz_add_ui(p, n, 1); if (mpz_cmp(N, maxd) < 0 && _GMP_is_prime(p)) { res = 1; } else { mpz_init(d); mpz_init(r); D = divisor_list(&ndivisors, N); for (i = 0; res == 0 && i < ndivisors && mpz_cmp(D[i],maxd) < 0; i++) { mpz_set(d, D[i]); mpz_mul_2exp(p,d,1); mpz_add_ui(p,p,1); if (!_GMP_is_prime(p)) continue; mpz_divexact(r, N, d); while (1) { if (mpz_cmp(r, p) == 0 || _totpred(r, d)) { res = 1; break; } if (!mpz_divisible_p(r, p)) break; mpz_divexact(r, r, p); } } mpz_clear(r); mpz_clear(d); for (i = 0; i < ndivisors; i++) mpz_clear(D[i]); Safefree(D); } mpz_clear(p); mpz_clear(N); return res; } int is_totient(mpz_t n) { if (mpz_sgn(n) == 0 || mpz_odd_p(n)) return !mpz_cmp_ui(n,1) ? 1 : 0; return _totpred(n, n); } void polygonal_nth(mpz_t r, mpz_t n, UV k) { mpz_t D, t; UV R; if (k < 3 || mpz_sgn(n) < 0) { mpz_set_ui(r,0); return; } if (mpz_cmp_ui(n,1) <= 0) { mpz_set_ui(r,1); return; } if (k == 4) { if (mpz_perfect_square_p(n)) mpz_sqrt(r, n); else mpz_set_ui(r, 0); return; } mpz_init(D); if (k == 3) { mpz_mul_2exp(D, n, 3); mpz_add_ui(D, D, 1); } else if (k == 5) { mpz_mul_ui(D, n, (8*k-16)); mpz_add_ui(D, D, 1); } else { mpz_mul_ui(D, n, (8*k-16)); mpz_init_set_ui(t, k-4); mpz_mul(t, t, t); mpz_add(D, D, t); mpz_clear(t); } if (mpz_perfect_square_p(D)) { mpz_sqrt(D, D); if (k == 3) mpz_sub_ui(D, D, 1); else mpz_add_ui(D, D, k-4); R = 2*k-4; if (mpz_divisible_ui_p(D, R)) { mpz_divexact_ui(r, D, R); mpz_clear(D); return; } } mpz_clear(D); mpz_set_ui(r, 0); } static void word_tile(uint32_t* source, uint32_t from, uint32_t to) { while (from < to) { uint32_t words = (2*from > to) ? to-from : from; memcpy(source+from, source, sizeof(uint32_t)*words); from += words; } } static void sievep_ui(uint32_t* comp, UV pos, UV p, UV len, int verbose) { if (!(pos & 1)) pos += p; if (verbose > 3) { for ( ; pos < len; pos += 2*p ) { if (!TSTAVAL(comp, pos)) { printf("factor: %"UVuf" at %"UVuf"\n", p, pos); SETAVAL(comp, pos); } } } else { for ( ; pos < len; pos += 2*p ) SETAVAL(comp, pos); } } /* Find first multiple of p after start */ #define sievep(comp, start, p, len, verbose) \ sievep_ui(comp, (p) - mpz_fdiv_ui((start),(p)), p, len, verbose) uint32_t* partial_sieve(mpz_t start, UV length, UV maxprime) { uint32_t* comp; UV p, wlen, pwlen; int _verbose = get_verbose_level(); PRIME_ITERATOR(iter); /* mpz_init(t); mpz_add_ui(t, start, (length & 1) ? length-1 : length-2); gmp_printf("partial sieve start %Zd length %lu mark %Zd to %Zd\n", start, length, start, t); */ MPUassert(mpz_odd_p(start), "partial sieve given even start"); MPUassert(length > 0, "partial sieve given zero length"); mpz_sub_ui(start, start, 1); if (length & 1) length++; if (mpz_cmp_ui(start, maxprime) <= 0) { mpz_t t; mpz_init(t); mpz_add_ui(t, start, length+1); mpz_sqrt(t, t); maxprime = mpz_get_ui(t); mpz_clear(t); } /* Allocate odds-only array in uint32_t units */ wlen = (length+63)/64; New(0, comp, wlen, uint32_t); p = prime_iterator_next(&iter); /* Mark 3, 5, ... by tiling as long as we can. */ pwlen = (wlen < 3) ? wlen : 3; memset(comp, 0x00, pwlen*sizeof(uint32_t)); while (p <= maxprime) { sievep(comp, start, p, pwlen*64, _verbose); p = prime_iterator_next(&iter); if (pwlen*p >= wlen) break; word_tile(comp, pwlen, pwlen*p); pwlen *= p; } word_tile(comp, pwlen, wlen); /* Sieve up to their limit. * * Simple code for this: * for ( ; p <= maxprime; p = prime_iterator_next(&iter)) * sievep(comp, start, p, length); * We'll save some time for large start values by doubling up primes. */ { UV p1, p2; UV doublelim = (1UL << (sizeof(unsigned long) * 4)) - 1; UV ulim = (maxprime > ULONG_MAX) ? ULONG_MAX : maxprime; if (doublelim > maxprime) doublelim = maxprime; /* Do 2 primes at a time. Fewer mpz remainders. */ for ( p1 = p, p2 = prime_iterator_next(&iter); p2 <= doublelim; p1 = prime_iterator_next(&iter), p2 = prime_iterator_next(&iter) ) { UV p1p2 = p1 * p2; UV ddiv = mpz_fdiv_ui(start, p1p2); sievep_ui(comp, p1 - (ddiv % p1), p1, length, _verbose); sievep_ui(comp, p2 - (ddiv % p2), p2, length, _verbose); } if (p1 <= maxprime) sievep(comp, start, p1, length, _verbose); for (p = p2; p <= ulim; p = prime_iterator_next(&iter)) sievep(comp, start, p, length, _verbose); if (p < maxprime) { /* UV is 64-bit, GMP's ui functions are 32-bit. Sigh. */ UV lastp, pos; mpz_t mp, rem; mpz_init(rem); mpz_init_set_ui(mp, (p >> 16) >> 16); mpz_mul_2exp(mp, mp, 32); mpz_add_ui(mp, mp, p & 0xFFFFFFFFUL); for (lastp = p; p <= maxprime; lastp=p, p=prime_iterator_next(&iter)) { mpz_add_ui(mp, mp, p-lastp); /* Calc mp = p */ mpz_fdiv_r(rem, start, mp); /* Calc start % mp */ if (mpz_cmp_ui(rem, ULONG_MAX) <= 0) { /* pos = p - (start % p) */ pos = p - mpz_get_ui(rem); } else { p1 = mpz_fdiv_q_ui(rem, rem, 2147483648UL); p1 += ((UV)mpz_get_ui(rem)) << 31; pos = p - p1; } sievep_ui(comp, pos, p, length, _verbose); } mpz_clear(mp); mpz_clear(rem); } } prime_iterator_destroy(&iter); return comp; } /*****************************************************************************/ static unsigned long small_prime_count(unsigned long n) { unsigned long i; for (i = 0; i <= NSMALLPRIMES; i++) if (n < sprimes[i]) break; return i; } void prime_count_lower(mpz_t pc, mpz_t n) { mpf_t x, logx, logx2, t, s; unsigned long bits = 7 + DIGS2BITS(mpz_sizeinbase(n,10)); unsigned long N = mpz_get_ui(n); if (mpz_cmp_ui(n, 1000) < 0) { mpz_set_ui(pc, small_prime_count(N)); return; } mpf_init2(x, bits); mpf_init2(logx, bits); mpf_init2(logx2, bits); mpf_init2(t, bits); mpf_init2(s, bits); mpf_set_z(x, n); mpf_log(logx, x); mpf_mul(logx2, logx, logx); if (mpz_cmp_ui(n, 300000) < 0) { double a = (N < 33000) ? 1190 : (N < 70200) ? 947 : (N < 176000) ? 904 : 829; mpf_set(s, logx); mpf_sub_ui(s, s, 1); mpf_ui_div(t, 1, logx); mpf_sub(s, s, t); mpf_set_d(t, 2.85); mpf_div(t, t, logx2); mpf_sub(s, s, t); mpf_set_d(t, 13.15); mpf_mul(logx2, logx2, logx); mpf_div(t, t, logx2); mpf_sub(s, s, t); mpf_set_d(t, a); mpf_mul(logx2, logx2, logx); mpf_div(t, t, logx2); mpf_add(s, s, t); mpf_div(x, x, s); } else if (mpf_cmp_d(x, 1e19) < 0) { /* Büthe 2015 1.9 1511.02032v2.pdf */ double a = 2.50; double b = (N < 88783) ? 4.0 : (N < 300000) ? -3.0 : (N < 303000) ? 5.0 : (N < 1100000) ? -7.0 : (N < 4500000) ? -37.0 : (N < 10200000) ? -70.0 : (N < 36900000) ? -53.0 : (N < 38100000) ? -29.0 : -84.0; mpf_set_str(s, "1.95", 10); if (N >= 4000000000UL) { mpf_set_str(t, "3.9", 10); mpf_div(t, t, logx); mpf_add(s, s, t); mpf_set_str(t, "19.5", 10); mpf_div(t, t, logx2); mpf_add(s, s, t); } else { mpf_set_d(t, a); mpf_div(t, t, logx); mpf_add(s, s, t); mpf_set_d(t, b); mpf_div(t, t, logx2); mpf_add(s, s, t); } mpf_sqrt(t, x); mpf_div(t, t, logx); mpf_mul(s, s, t); li(t, x, 20); mpf_sub(x, t, s); } else if (mpf_cmp_d(x, 5.5e25) < 0) { /* Büthe 2014 v3 7.2 1410.7015v3.pdf */ mpf_sqrt(t, x); /* Axler 2017 2.2 1703.08032.pdf */ mpf_mul(s, logx, t); const_pi(t, 30); mpf_mul_2exp(t, t, 3); mpf_div(s, s, t); li(t, x, 30); mpf_sub(x, t, s); } else { /* Axler 2017 1.3 https://arxiv.org/pdf/1703.08032.pdf */ mpf_set(s, logx); mpf_sub_ui(s, s, 1); mpf_ui_div(t, 1, logx); mpf_sub(s, s, t); mpf_set_str(t, "2.85", 10); mpf_div(t, t, logx2); mpf_sub(s, s, t); mpf_set_str(t, "13.15", 10); mpf_mul(logx2, logx2, logx); mpf_div(t, t, logx2); mpf_sub(s, s, t); mpf_set_str(t, "70.7", 10); mpf_mul(logx2, logx2, logx); mpf_div(t, t, logx2); mpf_sub(s, s, t); mpf_set_str(t, "458.7275", 10); mpf_mul(logx2, logx2, logx); mpf_div(t, t, logx2); mpf_sub(s, s, t); mpf_set_str(t, "3428.7225", 10); mpf_mul(logx2, logx2, logx); mpf_div(t, t, logx2); mpf_sub(s, s, t); mpf_div(x, x, s); } if (!mpf_integer_p(x)) mpf_add_ui(x, x, 1); /* ceil */ mpz_set_f(pc,x); mpf_clear(logx2); mpf_clear(logx); mpf_clear(x); mpf_clear(t); mpf_clear(s); } void prime_count_upper(mpz_t pc, mpz_t n) { mpf_t x, logx, logx2, t, s; unsigned long bits = 7 + DIGS2BITS(mpz_sizeinbase(n,10)); unsigned long N = mpz_get_ui(n); if (mpz_cmp_ui(n, 1000) < 0) { mpz_set_ui(pc, small_prime_count(N)); return; } if (mpz_cmp_ui(n, 15900) < 0) { if (N < 7) { mpz_set_ui(pc, 0 + (N >= 2) + (N >= 3) + (N >= 5)); } else { double a = (N < 1621) ? 1.048 : (N < 5000) ? 1.071 : 1.098; double X = 1.0 + ((double)N) / (log((double)N) - a); mpz_set_d(pc, X); } return; } mpf_init2(x, bits); mpf_init2(logx, bits); mpf_init2(logx2, bits); mpf_init2(t, bits); mpf_init2(s, bits); mpf_set_z(x, n); mpf_log(logx, x); mpf_mul(logx2, logx, logx); if (mpz_cmp_ui(n, 821800000UL) < 0) { double a = (N < 356000) ? 2.54 : (N < 48000000) ? 2.51 : (N < 400000000) ? 2.47 : 2.37; mpf_set_ui(s, 1); mpf_ui_div(t, 1, logx); mpf_add(s, s, t); mpf_set_d(t, a); mpf_div(t, t, logx2); mpf_add(s, s, t); mpf_div(t, x, logx); mpf_mul(x, t, s); } else if (mpf_cmp_d(x, 1e19) < 0) { /* Büthe 2015 1.10 1511.02032v2.pdf */ double a = (mpf_cmp_d(x, 1100000000.0) < 0) ? 0.032 : (mpf_cmp_d(x, 10010000000.0) < 0) ? 0.027 : (mpf_cmp_d(x, 101260000000.0) < 0) ? 0.021 : 0.0; if (a > 0) { mpf_sqrt(t, x); mpf_mul(s, logx, t); mpf_set_d(t, a); mpf_mul(s, s, t); const_pi(t, 25); mpf_mul_2exp(t, t, 3); mpf_div(s, s, t); li(t, x, 25); mpf_sub(x, t, s); } else { li(x, x, 25); } } else if (mpf_cmp_d(x, 5.5e25) < 0) { /* Büthe 2014 v3 7.2 1410.7015v3.pdf */ mpf_sqrt(t, x); /* Axler 2017 2.2 1703.08032.pdf */ mpf_mul(s, logx, t); const_pi(t, 30); mpf_mul_2exp(t, t, 3); mpf_div(s, s, t); li(t, x, 30); mpf_add(x, t, s); } else { /* Axler 2017 1.2 https://arxiv.org/pdf/1703.08032.pdf */ mpf_set(s, logx); mpf_sub_ui(s, s, 1); mpf_ui_div(t, 1, logx); mpf_sub(s, s, t); mpf_set_str(t, "3.15", 10); mpf_div(t, t, logx2); mpf_sub(s, s, t); mpf_set_str(t, "12.85", 10); mpf_mul(logx2, logx2, logx); mpf_div(t, t, logx2); mpf_sub(s, s, t); mpf_set_str(t, "71.3", 10); mpf_mul(logx2, logx2, logx); mpf_div(t, t, logx2); mpf_sub(s, s, t); mpf_set_str(t, "463.2275", 10); mpf_mul(logx2, logx2, logx); mpf_div(t, t, logx2); mpf_sub(s, s, t); mpf_set_str(t, "4585", 10); mpf_mul(logx2, logx2, logx); mpf_div(t, t, logx2); mpf_sub(s, s, t); mpf_div(x, x, s); } /* floor */ mpz_set_f(pc,x); mpf_clear(logx2); mpf_clear(logx); mpf_clear(x); mpf_clear(t); mpf_clear(s); } /*****************************************************************************/ void count_primes(mpz_t count, mpz_t lo, mpz_t hi) { uint32_t* comp; UV i, cnt, hbits, depth, width; mpz_t shi, t; mpz_set_ui(count, 0); if (mpz_cmp_ui(lo,2) <= 0) { if (mpz_cmp_ui(hi,2) >= 0) mpz_add_ui(count,count,1); mpz_set_ui(lo,3); } if (mpz_cmp(lo,hi) > 0) return; mpz_init(t); if (mpz_add_ui(t, lo, 100000), mpz_cmp(t,hi) > 0) { mpz_sub_ui(lo,lo,1); for (cnt = 0; mpz_cmp(lo, hi) <= 0; _GMP_next_prime(lo)) cnt++; mpz_add_ui(count,count,cnt-1); mpz_clear(t); return; } /* Determine a reasonable depth for sieve. */ hbits = mpz_sizeinbase(hi,2); depth = (hbits < 100) ? 50000000UL : ((UV)hbits)*UVCONST(500000); if (hbits < 64) { mpz_sqrt(t, hi); if (mpz_cmp_ui(t,depth) < 0) depth = mpz_get_ui(t); } /* Count small inputs directly. We should do this faster. */ if (mpz_cmp_ui(lo, depth) <= 0) { mpz_sub_ui(lo,lo,1); for (cnt = 0; mpz_cmp_ui(lo, depth) <= 0; _GMP_next_prime(lo)) cnt++; mpz_add_ui(count,count,cnt-1); } /* Ensure endpoints are odd */ if (mpz_even_p(lo)) mpz_add_ui(lo,lo,1); if (mpz_even_p(hi)) mpz_sub_ui(hi,hi,1); mpz_init(shi); while (mpz_cmp(lo,hi) <= 0) { mpz_add_ui(shi, lo, 1000000000UL); if (mpz_cmp(shi, hi) > 0) mpz_set(shi, hi); mpz_sub(t, shi, lo); width = mpz_get_ui(t) + 1; comp = partial_sieve(lo, width, depth); for (i = 1, cnt = 0; i <= width; i += 2) { if (!TSTAVAL(comp, i) && (mpz_add_ui(t, lo, i), _GMP_BPSW(t))) cnt++; } Safefree(comp); mpz_add_ui(lo, shi, 2); mpz_add_ui(count, count, cnt); } mpz_clear(shi); mpz_clear(t); } typedef struct { uint32_t nmax; uint32_t nsize; UV* list; } vlist; #define INIT_VLIST(v) \ v.nsize = 0; \ v.nmax = 1024; \ New(0, v.list, v.nmax, UV); #define RESIZE_VLIST(v, size) \ do { if (v.nmax < size) Renew(v.list, v.nmax = size, UV); } while (0) #define PUSH_VLIST(v, n) \ do { \ if (v.nsize >= v.nmax) \ Renew(v.list, v.nmax += 1024, UV); \ v.list[v.nsize++] = n; \ } while (0) #define ADDVAL32(v, n, max, val) \ do { if (n >= max) Renew(v, max += 1024, UV); v[n++] = val; } while (0) #define SWAPL32(l1, n1, m1, l2, n2, m2) \ { UV t_, *u_ = l1; l1 = l2; l2 = u_; \ t_ = n1; n1 = n2; n2 = t_; \ t_ = m1; m1 = m2; m2 = t_; } UV* sieve_primes(mpz_t inlow, mpz_t high, UV k, UV *rn) { mpz_t t, low; int test_primality = 0, k_primality = 0, force_full = 0, width2, hbits; uint32_t* comp; vlist retlist; if (mpz_cmp_ui(inlow, 2) < 0) mpz_set_ui(inlow, 2); if (mpz_cmp(inlow, high) > 0) { *rn = 0; return 0; } mpz_init(t); mpz_sub(t, high, inlow); width2 = mpz_sizeinbase(t,2); hbits = mpz_sizeinbase(high,2); mpz_sqrt(t, high); /* No need for k to be > sqrt(high) */ /* If auto-setting k or k >= sqrt(n), pick a good depth and test primality */ if (k == 0 || mpz_cmp_ui(t, k) <= 0) { test_primality = 1; k = (hbits < 100) ? 50000000UL : ((UV)hbits)*UVCONST(500000); /* For small widths we're much better off with smaller sieves. */ if (width2 <= 23) k /= 2; if (width2 <= 21) k /= 2; if (width2 <= 19) k /= 2; if (width2 <= 17) k /= 2; if (width2 <= 15) k /= 2; if (width2 <= 13) k /= 2; if (width2 <= 11) k /= 2; } /* For smallist n and large ranges, force full sieve */ if (test_primality && hbits >= 40 && hbits < 56 && (width2 * 2.8) >= hbits) force_full = 1; if (test_primality && hbits >= 56 && hbits < 64 && (width2 * 2.6) >= hbits) force_full = 1; if (test_primality && hbits >= 64 && hbits <= 82 && (width2 * 2.5) >= hbits && sizeof(unsigned long) > 4) force_full = 1; /* If k >= sqrtn, sieving is enough. Use k=sqrtn, turn off post-sieve test */ if (force_full || mpz_cmp_ui(t, k) <= 0) { k = mpz_get_ui(t); k_primality = 1; /* Our sieve is complete */ test_primality = 0; /* Don't run BPSW */ } INIT_VLIST(retlist); /* If we want small primes, do it quickly */ if ( (k_primality || test_primality) && mpz_cmp_ui(high,2000000000U) <= 0 ) { UV ulow = mpz_get_ui(inlow), uhigh = mpz_get_ui(high); if (uhigh < 1000000U || uhigh/ulow >= 4) { UV n, Pi, *primes; primes = sieve_to_n(mpz_get_ui(high), &Pi); RESIZE_VLIST(retlist, Pi); for (n = 0; n < Pi; n++) { if (primes[n] >= ulow) PUSH_VLIST(retlist, primes[n]-ulow); } Safefree(primes); mpz_clear(t); *rn = retlist.nsize; return retlist.list; } } mpz_init_set(low, inlow); if (k < 2) k = 2; /* Should have been handled by quick return */ /* Include all primes up to k, since they will get filtered */ if (mpz_cmp_ui(low, k) <= 0) { UV n, Pi, *primes, ulow = mpz_get_ui(low); primes = sieve_to_n(k, &Pi); RESIZE_VLIST(retlist, Pi); for (n = 0; n < Pi; n++) { if (primes[n] >= ulow) PUSH_VLIST(retlist, primes[n]-ulow); } Safefree(primes); } if (mpz_even_p(low)) mpz_add_ui(low, low, 1); if (mpz_even_p(high)) mpz_sub_ui(high, high, 1); if (mpz_cmp(low, high) <= 0) { UV i, length, offset; mpz_sub(t, high, low); length = mpz_get_ui(t) + 1; /* Get bit array of odds marked with composites(k) marked with 1 */ comp = partial_sieve(low, length, k); mpz_sub(t, low, inlow); offset = mpz_get_ui(t); for (i = 1; i <= length; i += 2) { if (!TSTAVAL(comp, i)) { if (!test_primality || (mpz_add_ui(t,low,i),_GMP_BPSW(t))) PUSH_VLIST(retlist, i - offset); } } Safefree(comp); } mpz_clear(low); mpz_clear(t); *rn = retlist.nsize; return retlist.list; } void next_twin_prime(mpz_t res, mpz_t n) { mpz_t low, t; mpz_init(t); if (mpz_cmp_ui(n, 1000000) < 0) { UV p, ulow = mpz_get_ui(n), last = 0; PRIME_ITERATOR(iter); prime_iterator_setprime(&iter, ulow); while (1) { p = prime_iterator_next(&iter); if (p-last == 2 && last > 0) { mpz_set_ui(res, last); break; } last = p; } prime_iterator_destroy(&iter); } else { UV i, starti, l2, length, depth, found = 0; uint32_t* comp; mpz_init(low); mpz_add_ui(low, n, 1); if (mpz_even_p(low)) mpz_add_ui(low, low, 1); l2 = mpz_sizeinbase(low,2); if (l2 <= 6000) { depth = (l2/160.0) * l2 * l2; length = 3 * 0.634 * l2 * l2; /* we will resieve sometimes */ if (length % 2) length++; /* low is odd, length must be even */ } else { depth = UVCONST(1350000000); length = UVCONST( 91296000); } while (!found) { starti = (6 - mpz_fdiv_ui(low,6)) % 6; comp = partial_sieve(low, length + 2, depth); for (i = starti; i <= length && !found; i += 6) { if (!TSTAVAL(comp, i) && !TSTAVAL(comp, i+2)) { if ( (mpz_add_ui(t,low,i), miller_rabin_ui(t,2)) && (mpz_add_ui(t,t,2), miller_rabin_ui(t,2)) && (mpz_add_ui(t,low,i), _GMP_is_lucas_pseudoprime(t,2)) && (mpz_add_ui(t,t,2), _GMP_is_lucas_pseudoprime(t,2)) ) { mpz_add_ui(res, low, i); found = 1; } } } Safefree(comp); mpz_add_ui(low, low, length+1); } mpz_clear(low); } mpz_clear(t); } UV* sieve_twin_primes(mpz_t low, mpz_t high, UV twin, UV *rn) { mpz_t t; UV i, length, k, starti = 1, skipi = 2; uint32_t* comp; vlist retlist; /* Twin offset will always be even, so we will never return 2 */ MPUassert( !(twin & 1), "twin prime offset is even" ); if (mpz_cmp_ui(low, 3) <= 0) mpz_set_ui(low, 3); if (mpz_even_p(low)) mpz_add_ui(low, low, 1); if (mpz_even_p(high)) mpz_sub_ui(high, high, 1); i = twin % 6; if (i == 2 || i == 4) { skipi = 6; starti = ((twin%6)==2) ? 5 : 1; } /* If no way to return any more results, leave now */ if (mpz_cmp(low, high) > 0 || (i == 1 || i == 3 || i == 5)) { *rn = 0; return 0; } INIT_VLIST(retlist); mpz_init(t); /* Use a much higher k value than we do for primes */ k = 80000 * mpz_sizeinbase(high,2); /* No need for k to be > sqrt(high) */ mpz_sqrt(t, high); if (mpz_cmp_ui(t, k) < 0) k = mpz_get_ui(t); /* Handle small primes that will get sieved out */ if (mpz_cmp_ui(low, k) <= 0) { UV p, ulow = mpz_get_ui(low); PRIME_ITERATOR(iter); for (p = 2; p <= k; p = prime_iterator_next(&iter)) { if (p < ulow) continue; if (mpz_set_ui(t, p+twin), _GMP_BPSW(t)) PUSH_VLIST(retlist, p-ulow+1); } prime_iterator_destroy(&iter); } mpz_sub(t, high, low); length = mpz_get_ui(t) + 1; starti = ((starti+skipi) - mpz_fdiv_ui(low,skipi) + 1) % skipi; /* Get bit array of odds marked with composites(k) marked with 1 */ comp = partial_sieve(low, length + twin, k); for (i = starti; i <= length; i += skipi) { if (!TSTAVAL(comp, i) && !TSTAVAL(comp, i+twin)) { /* Add to list if both t,t+2 pass MR and if both pass ES Lucas */ if ( (mpz_add_ui(t,low,i), miller_rabin_ui(t,2)) && (mpz_add_ui(t,t,twin), miller_rabin_ui(t,2)) && (mpz_add_ui(t,low,i), _GMP_is_lucas_pseudoprime(t,2)) && (mpz_add_ui(t,t,twin), _GMP_is_lucas_pseudoprime(t,2)) ) PUSH_VLIST(retlist, i); } } Safefree(comp); mpz_clear(t); *rn = retlist.nsize; return retlist.list; } #define addmodded(r,a,b,n) do { r = a + b; if (r >= n) r -= n; } while(0) UV* sieve_cluster(mpz_t low, mpz_t high, uint32_t* cl, UV nc, UV *rn) { mpz_t t, savelow; vlist retlist; UV i, ppr, nres, allocres; uint32_t const targres = 4000000; uint32_t const maxpi = 168; UV *residues, *cres; uint32_t pp_0, pp_1, pp_2, *resmod_0, *resmod_1, *resmod_2; uint32_t rem_0, rem_1, rem_2, remadd_0, remadd_1, remadd_2; uint32_t pi, startpi = 1; uint32_t lastspr = sprimes[maxpi-1]; uint32_t c, smallnc; UV ibase = 0, num_mr = 0, num_lucas = 0; char crem_0[53*59], crem_1[61*67], crem_2[71*73], *VPrem; int run_pretests = 0; int _verbose = get_verbose_level(); if (nc == 1) return sieve_primes(low, high, 0, rn); if (nc == 2) return sieve_twin_primes(low, high, cl[1], rn); if (mpz_even_p(low)) mpz_add_ui(low, low, 1); if (mpz_even_p(high)) mpz_sub_ui(high, high, 1); if (mpz_cmp(low, high) > 0) { *rn = 0; return 0; } INIT_VLIST(retlist); mpz_init(t); /* Handle small values that would get sieved away */ if (mpz_cmp_ui(low, lastspr) <= 0) { UV ui_low = mpz_get_ui(low); UV ui_high = (mpz_cmp_ui(high,lastspr) > 0) ? lastspr : mpz_get_ui(high); for (pi = 0; pi < maxpi; pi++) { UV p = sprimes[pi]; if (p > ui_high) break; if (p < ui_low) continue; for (c = 1; c < nc; c++) if (!(mpz_set_ui(t, p+cl[c]), _GMP_is_prob_prime(t))) break; if (c == nc) PUSH_VLIST(retlist, p-ui_low+1); } } if (mpz_odd_p(low)) mpz_sub_ui(low, low, 1); if (mpz_cmp_ui(high, lastspr) <= 0) { mpz_clear(t); *rn = retlist.nsize; return retlist.list; } /* Determine the primorial size and acceptable residues */ New(0, residues, allocres = 1024, UV); { UV remr, *res2, allocres2, nres2, maxppr; /* Calculate residues for a small primorial */ for (pi = 2, ppr = 1, i = 0; i <= pi; i++) ppr *= sprimes[i]; remr = mpz_fdiv_ui(low, ppr); nres = 0; for (i = 1; i <= ppr; i += 2) { UV remi = remr + i; for (c = 0; c < nc; c++) { if (gcd_ui(remi + cl[c], ppr) != 1) break; } if (c == nc) ADDVAL32(residues, nres, allocres, i); } /* Raise primorial size until we have plenty of residues */ New(0, res2, allocres2 = 1024, UV); mpz_sub(t, high, low); maxppr = (mpz_sizeinbase(t,2) >= BITS_PER_WORD) ? UV_MAX : (UVCONST(1) << mpz_sizeinbase(t,2)); #if BITS_PER_WORD == 64 while (pi++ < 14) { #else while (pi++ < 8) { #endif uint32_t j, p = sprimes[pi]; UV r, newppr = ppr * p; if (nres == 0 || nres > targres/(p/2) || newppr > maxppr) break; if (_verbose > 1) printf("cluster sieve found %"UVuf" residues mod %"UVuf"\n", nres, ppr); remr = mpz_fdiv_ui(low, newppr); nres2 = 0; for (i = 0; i < p; i++) { for (j = 0; j < nres; j++) { r = i*ppr + residues[j]; for (c = 0; c < nc; c++) { UV v = remr + r + cl[c]; if ((v % p) == 0) break; } if (c == nc) ADDVAL32(res2, nres2, allocres2, r); } } ppr = newppr; SWAPL32(residues, nres, allocres, res2, nres2, allocres2); } startpi = pi; Safefree(res2); } if (_verbose) printf("cluster sieve using %"UVuf" residues mod %"UVuf"\n", nres, ppr); /* Return if not admissible, maybe with a single small value */ if (nres == 0) { Safefree(residues); mpz_clear(t); *rn = retlist.nsize; return retlist.list; } mpz_init_set(savelow, low); if (mpz_sizeinbase(low, 2) > 310) run_pretests = 1; if (run_pretests && mpz_sgn(_bgcd2) == 0) { _GMP_pn_primorial(_bgcd2, BGCD2_PRIMES); mpz_divexact(_bgcd2, _bgcd2, _bgcd); } /* Pre-mod the residues with first two primes for fewer modulos every chunk */ { uint32_t p1 = sprimes[startpi+0], p2 = sprimes[startpi+1]; uint32_t p3 = sprimes[startpi+2], p4 = sprimes[startpi+3]; uint32_t p5 = sprimes[startpi+4], p6 = sprimes[startpi+5]; pp_0 = p1*p2; pp_1 = p3*p4; pp_2 = p5*p6; memset(crem_0, 1, pp_0); memset(crem_1, 1, pp_1); memset(crem_2, 1, pp_2); /* Mark remainders that indicate a composite for this residue. */ for (i = 0; i < p1; i++) { crem_0[i*p1]=0; crem_0[i*p2]=0; } for ( ; i < p2; i++) { crem_0[i*p1]=0; } for (i = 0; i < p3; i++) { crem_1[i*p3]=0; crem_1[i*p4]=0; } for ( ; i < p4; i++) { crem_1[i*p3]=0; } for (i = 0; i < p5; i++) { crem_2[i*p5]=0; crem_2[i*p6]=0; } for ( ; i < p6; i++) { crem_2[i*p5]=0; } for (c = 1; c < nc; c++) { uint32_t c1=cl[c], c2=cl[c], c3=cl[c], c4=cl[c], c5=cl[c], c6=cl[c]; if (c1 >= p1) c1 %= p1; if (c2 >= p2) c2 %= p2; for (i = 1; i <= p1; i++) { crem_0[i*p1-c1]=0; crem_0[i*p2-c2]=0; } for ( ; i <= p2; i++) { crem_0[i*p1-c1]=0; } if (c3 >= p3) c3 %= p3; if (c4 >= p4) c4 %= p4; for (i = 1; i <= p3; i++) { crem_1[i*p3-c3]=0; crem_1[i*p4-c4]=0; } for ( ; i <= p4; i++) { crem_1[i*p3-c3]=0; } if (c5 >= p5) c5 %= p5; if (c6 >= p6) c6 %= p6; for (i = 1; i <= p5; i++) { crem_2[i*p5-c5]=0; crem_2[i*p6-c6]=0; } for ( ; i <= p6; i++) { crem_2[i*p5-c5]=0; } } New(0, resmod_0, nres, uint32_t); New(0, resmod_1, nres, uint32_t); New(0, resmod_2, nres, uint32_t); for (i = 0; i < nres; i++) { resmod_0[i] = residues[i] % pp_0; resmod_1[i] = residues[i] % pp_1; resmod_2[i] = residues[i] % pp_2; } } /* Precalculate acceptable residues for more primes */ MPUassert( lastspr <= 1024, "cluster sieve internal" ); New(0, VPrem, maxpi * 1024, char); memset(VPrem, 1, maxpi * 1024); for (pi = startpi+6; pi < maxpi; pi++) VPrem[pi*1024] = 0; for (pi = startpi+6, smallnc = 0; pi < maxpi; pi++) { uint32_t p = sprimes[pi]; char* prem = VPrem + pi*1024; while (smallnc < nc && cl[smallnc] < p) smallnc++; for (c = 1; c < smallnc; c++) prem[p-cl[c]] = 0; for ( ; c < nc; c++) prem[p-(cl[c]%p)] = 0; } New(0, cres, nres, UV); rem_0 = mpz_fdiv_ui(low,pp_0); remadd_0 = ppr % pp_0; rem_1 = mpz_fdiv_ui(low,pp_1); remadd_1 = ppr % pp_1; rem_2 = mpz_fdiv_ui(low,pp_2); remadd_2 = ppr % pp_2; /* Loop over their range in chunks of size 'ppr' */ while (mpz_cmp(low, high) <= 0) { uint32_t r, nr, remr, ncres; unsigned long ui_low = (mpz_sizeinbase(low,2) > 8*sizeof(unsigned long)) ? 0 : mpz_get_ui(low); /* Reduce the allowed residues for this chunk using more primes */ { /* Start making a list of this chunk's residues using three pairs */ for (r = 0, ncres = 0; r < nres; r++) { addmodded(remr, rem_0, resmod_0[r], pp_0); if (crem_0[remr]) { addmodded(remr, rem_1, resmod_1[r], pp_1); if (crem_1[remr]) { addmodded(remr, rem_2, resmod_2[r], pp_2); if (crem_2[remr]) { cres[ncres++] = residues[r]; } } } } addmodded(rem_0, rem_0, remadd_0, pp_0); addmodded(rem_1, rem_1, remadd_1, pp_1); addmodded(rem_2, rem_2, remadd_2, pp_2); } /* Sieve through more primes one at a time, removing residues. */ for (pi = startpi+6; pi < maxpi && ncres > 0; pi++) { uint32_t p = sprimes[pi]; uint32_t rem = (ui_low) ? (ui_low % p) : mpz_fdiv_ui(low,p); char* prem = VPrem + pi*1024; /* Check divisibility of each remaining residue with this p */ if (startpi <= 9 || cres[ncres-1] < 4294967295U) { /* Residues are 32-bit */ for (r = 0, nr = 0; r < ncres; r++) { if (prem[ (rem+(uint32_t)cres[r]) % p ]) cres[nr++] = cres[r]; } } else { /* Residues are 64-bit */ for (r = 0, nr = 0; r < ncres; r++) { if (prem[ (rem+cres[r]) % p ]) cres[nr++] = cres[r]; } } ncres = nr; } if (_verbose > 2) printf("cluster sieve range has %u residues left\n", ncres); /* Now check each of the remaining residues for inclusion */ for (r = 0; r < ncres; r++) { i = cres[r]; mpz_add_ui(t, low, i); if (mpz_cmp(t, high) > 0) break; /* Pretest each element if the input is large enough */ if (run_pretests) { for (c = 0; c < nc; c++) if (mpz_add_ui(t, low, i+cl[c]), mpz_gcd(t,t,_bgcd2), mpz_cmp_ui(t,1)) break; if (c != nc) continue; } /* PRP test. Split BPSW in two for faster rejection. */ for (c = 0; c < nc; c++) if (! (mpz_add_ui(t, low, i+cl[c]), num_mr++, miller_rabin_ui(t,2)) ) break; if (c != nc) continue; for (c = 0; c < nc; c++) if (! (mpz_add_ui(t, low, i+cl[c]), num_lucas++, _GMP_is_lucas_pseudoprime(t,2)) ) break; if (c != nc) continue; PUSH_VLIST(retlist, ibase + i); } ibase += ppr; mpz_add_ui(low, low, ppr); } if (_verbose) printf("cluster sieve ran %"UVuf" MR and %"UVuf" Lucas tests (pretests %s)\n", num_mr, num_lucas, run_pretests ? "on" : "off"); mpz_set(low, savelow); Safefree(cres); Safefree(VPrem); Safefree(resmod_0); Safefree(resmod_1); Safefree(resmod_2); Safefree(residues); mpz_clear(savelow); mpz_clear(t); *rn = retlist.nsize; return retlist.list; } static uint32_t* _todigits32(uint32_t *ndigits, uint32_t n, uint32_t base) { uint32_t bits[32]; uint32_t *digits, i, d; for (d = 0; n; n /= base) bits[d++] = n % base; New(0, digits, d, uint32_t); for (i = 0; i < d; i++) digits[i] = bits[d-i-1]; *ndigits = d; return digits; } static uint32_t* _todigits_base2(uint32_t *ndigits, mpz_t n) { uint32_t *digits, d, bits = mpz_sizeinbase(n, 2); New(0, digits, bits, uint32_t); for (d = 0; d < bits; d++) digits[d] = mpz_tstbit(n,bits-d-1); *ndigits = d; return digits; } /* Algorithm 1.26 FastIntegerOutput from MCA v0.5.9 */ uint32_t* todigits(uint32_t *ndigits, mpz_t n, uint32_t base) { uint32_t* digits, *rdigits, *qdigits; uint32_t k, nlen, rlen, qlen, zlen, i, j; mpz_t Q, R; if (base == 2) return _todigits_base2(ndigits, n); if (mpz_cmp_ui(n, 0xFFFFFFFFUL) <= 0) return _todigits32(ndigits, mpz_get_ui(n), base); mpz_init(Q); mpz_init(R); nlen = logint(n, base) + 1; /* Find k s.t. B^(2k-2) <= n <= B^(2k) */ k = ((nlen-1) >> 1) + 1; /* Compute Q,R = DivRem(n, base^k) */ mpz_ui_pow_ui(Q, base, k); mpz_tdiv_qr(Q, R, n, Q); /* In theory we could do this all in place, avoiding the allocations * and copying. */ qdigits = todigits(&qlen, Q, base); rdigits = todigits(&rlen, R, base); zlen = k - rlen; if (qlen + rlen + zlen != nlen) croak("todigits: internal sizes wrong!"); mpz_clear(Q); mpz_clear(R); /* Allocate exactly as much space as needed. */ New(0, digits, nlen, uint32_t); j = 0; for (i = 0; i < qlen; i++) digits[j++] = qdigits[i]; for (i = 0; i < zlen; i++) digits[j++] = 0; for (i = 0; i < rlen; i++) digits[j++] = rdigits[i]; Safefree(rdigits); Safefree(qdigits); *ndigits = nlen; return digits; } Math-Prime-Util-GMP-0.52/XS.xs0000644000175000017500000012365313674067160014261 0ustar danadana #include "EXTERN.h" #include "perl.h" #include "XSUB.h" /* We're not using anything for which we need ppport.h */ #include #include #include "ptypes.h" #include "gmp_main.h" #include "primality.h" #include "squfof126.h" #include "ecm.h" #include "simpqs.h" #include "bls75.h" #include "ecpp.h" #include "aks.h" #include "utility.h" #include "factor.h" #include "isaac.h" #include "random_prime.h" #include "real.h" #define _GMP_ECM_FACTOR(n, f, b1, ncurves) \ _GMP_ecm_factor_projective(n, f, b1, 0, ncurves) /* Instead of trying to suck in lots of Math::BigInt::GMP and be terribly * clever (and brittle), just do all C<->Perl bigints via strings. It's * crude but seems to work pretty well. */ static void validate_string_number(CV* cv, const char* var, const char* s) { const char* p; if (s == 0) croak("%s (%s): null string pointer as input", GvNAME(CvGV(cv)),var); if (*s == 0) croak("%s (%s): empty string as input", GvNAME(CvGV(cv)),var); p = s; while (*p != 0) { if (!isdigit(*p)) croak("%s (%s): input '%s' must be a positive integer", GvNAME(CvGV(cv)), var, s); p++; } } #define VALIDATE_AND_SET(var, str) \ do { \ const char* s = str; \ if (*s == '+') s++; \ validate_string_number(cv,#var,s); \ mpz_init_set_str(var, s, 10); \ } while (0) #define VSETNEG_ERR 0 #define VSETNEG_POS 1 #define VSETNEG_OK 2 static int validate_and_set_signed(CV* cv, mpz_t v, const char* vname, const char* s, int negflag) { int neg = (s && *s == '-'); if (s && *s == '+') s++; validate_string_number(cv, vname, (neg && negflag != VSETNEG_ERR) ? s+1 : s); mpz_init_set_str(v, (neg && negflag == VSETNEG_POS) ? s+1 : s, 10); return neg; } static char* cert_with_header(char* proof, mpz_t n) { char *str, *strptr; if (proof == 0) { New(0, str, 1, char); str[0] = '\0'; } else { New(0, str, strlen(proof) + 100 + mpz_sizeinbase(n,10), char); strptr = str; strptr += gmp_sprintf(strptr, "[MPU - Primality Certificate]\nVersion 1.0\n\nProof for:\nN %Zd\n\n", n); strcat(strptr, proof); Safefree(proof); } return str; } MODULE = Math::Prime::Util::GMP PACKAGE = Math::Prime::Util::GMP PROTOTYPES: ENABLE void _GMP_init() void _GMP_destroy() void _GMP_memfree() void _GMP_set_verbose(IN int v) PPCODE: set_verbose_level(v); void seed_csprng(IN UV bytes, IN unsigned char* seed) PPCODE: isaac_init(bytes, seed); UV irand() ALIAS: irand64 = 1 is_csprng_well_seeded = 2 CODE: switch (ix) { #if BITS_PER_WORD >= 64 case 0: RETVAL = isaac_rand32(); break; case 1: RETVAL = (((UV)isaac_rand32()) << 32) | isaac_rand32(); break; #else case 0: case 1: RETVAL = isaac_rand32(); break; #endif case 2: default: RETVAL = isaac_seeded(); break; } OUTPUT: RETVAL NV drand(NV m = 1.0) CODE: RETVAL = m * drand64(); OUTPUT: RETVAL int is_pseudoprime(IN char* strn, ...) ALIAS: is_euler_pseudoprime = 1 is_strong_pseudoprime = 2 PREINIT: int i; mpz_t n, a; CODE: if (items < 2) croak("%s: no bases", GvNAME(CvGV(cv))); validate_string_number(cv,"n",strn); if (strn[1] == 0) { switch (strn[0]) { case '2': case '3': case '5': case '7': XSRETURN_IV(1); break; case '0': case '1': case '4': case '6': case '8': XSRETURN_IV(0); break; default: break; /* let 9 fall through */ } } for (i = 1; i < items; i++) { const char* strbase = SvPV_nolen(ST(i)); validate_string_number(cv, "base", strbase); if (strbase[1] == '\0' && (strbase[0] == '0' || strbase[0] == '1')) croak("Base %s is invalid", strbase); } mpz_init_set_str(n, strn, 10); for (i = 1; i < items; i++) { mpz_init_set_str(a, SvPV_nolen(ST(i)), 10); switch (ix) { case 0: RETVAL = is_pseudoprime(n, a); break; case 1: RETVAL = is_euler_pseudoprime(n, a); break; case 2: default: RETVAL = miller_rabin(n, a); break; } mpz_clear(a); if (!RETVAL) break; } mpz_clear(n); OUTPUT: RETVAL int miller_rabin_random(IN char* strn, IN IV nbases = 1, IN char* seedstr = 0) PREINIT: mpz_t n; CODE: if (nbases < 0) croak("Parameter '%"IVdf"' must be a positive integer\n", nbases); VALIDATE_AND_SET(n, strn); RETVAL = miller_rabin_random(n, nbases, seedstr); mpz_clear(n); OUTPUT: RETVAL #define PRIMALITY_START(name, small_retval, test_small_factors) \ /* Negative numbers return 0 */ \ if ((strn != 0) && (strn[0] == '-') ) \ XSRETURN_IV(0); \ validate_string_number(cv, "n", strn); \ /* Handle single digit numbers */ \ if (strn[1] == 0) { \ int q_is_prime = 0; \ switch (strn[0]) { \ case '2': case '3': case '5': case '7': q_is_prime = small_retval; \ break; \ } \ XSRETURN_IV(q_is_prime); \ } \ /* Test for small multiples while it is still a string */ \ if (test_small_factors) { \ UV digsum = 0; \ int i, slen = strlen(strn); \ /* Multiples of 2 and 5 return 0 */ \ switch (strn[slen-1]-'0') { \ case 0: case 2: case 4: case 5: case 6: case 8: \ XSRETURN_IV(0); break; \ } \ /* Multiples of 3 return 0 */ \ for (i = 0; i < slen; i++) digsum += strn[i]-'0'; \ if (digsum % 3 == 0) XSRETURN_IV(0); \ } \ mpz_init_set_str(n, strn, 10); int is_lucas_pseudoprime(IN char* strn) ALIAS: is_strong_lucas_pseudoprime = 1 is_extra_strong_lucas_pseudoprime = 2 is_frobenius_underwood_pseudoprime = 3 is_frobenius_khashin_pseudoprime = 4 is_euler_plumb_pseudoprime = 5 PREINIT: mpz_t n; CODE: if ((strn != 0) && (strn[0] == '-') ) croak("Parameter '%s' must be a positive integer\n", strn); PRIMALITY_START("is_lucas_pseudoprime", 1, 0); switch (ix) { case 0: RETVAL = _GMP_is_lucas_pseudoprime(n, 0); break; case 1: RETVAL = _GMP_is_lucas_pseudoprime(n, 1); break; case 2: RETVAL = _GMP_is_lucas_pseudoprime(n, 2); break; case 3: RETVAL = _GMP_is_frobenius_underwood_pseudoprime(n); break; case 4: RETVAL = _GMP_is_frobenius_khashin_pseudoprime(n); break; case 5: default:RETVAL = is_euler_plumb_pseudoprime(n); break; } mpz_clear(n); OUTPUT: RETVAL int is_almost_extra_strong_lucas_pseudoprime(IN char* strn, IN UV increment = 1) PREINIT: mpz_t n; CODE: if ((strn != 0) && (strn[0] == '-') ) croak("Parameter '%s' must be a positive integer\n", strn); if (increment == 0 || increment > 65535) croak("Increment parameter must be >0 and < 65536"); PRIMALITY_START("is_almost_extra_strong_lucas_pseudoprime", 1, 0); RETVAL = _GMP_is_almost_extra_strong_lucas_pseudoprime(n, increment); mpz_clear(n); OUTPUT: RETVAL int is_frobenius_pseudoprime(IN char* strn, IN IV P = 0, IN IV Q = 0) PREINIT: mpz_t n; CODE: if ((strn != 0) && (strn[0] == '-') ) croak("Parameter '%s' must be a positive integer\n", strn); PRIMALITY_START("is_frobenius_pseudoprime", 1, 0); RETVAL = is_frobenius_pseudoprime(n, P, Q); mpz_clear(n); OUTPUT: RETVAL int is_prime(IN char* strn) ALIAS: is_prob_prime = 1 is_aks_prime = 2 is_llr_prime = 3 is_proth_prime = 4 is_nminus1_prime = 5 is_nplus1_prime = 6 is_bls75_prime = 7 is_ecpp_prime = 8 is_bpsw_prime = 9 PREINIT: mpz_t n; int ret; CODE: /* Returns arg for single-dig primes, 0 for multiples of 2, 3, 5, or neg */ PRIMALITY_START("is_prime", 2, 1); switch (ix) { case 0: ret = _GMP_is_prime(n); break; case 1: ret = _GMP_is_prob_prime(n); break; case 2: ret = is_aks_prime(n); break; case 3: ret = llr(n); break; case 4: ret = proth(n); break; case 5: ret = (_GMP_primality_bls_nm1(n, 100, 0) == 2) ? 1 : 0; break; case 6: ret = (_GMP_primality_bls_np1(n, 100, 0) == 2) ? 1 : 0; break; case 7: ret = (bls75_hybrid(n, 100, 0) == 2) ? 1 : 0; break; case 8: ret = _GMP_ecpp(n, 0); break; case 9: default:ret = _GMP_BPSW(n); break; } RETVAL = ret; mpz_clear(n); OUTPUT: RETVAL void _is_provable_prime(IN char* strn, IN int wantproof = 0) ALIAS: is_miller_prime = 1 is_perrin_pseudoprime = 2 PREINIT: int result; mpz_t n; PPCODE: PRIMALITY_START("is_provable_prime", 2, ix != 2); if (ix == 1) { result = is_miller_prime(n, wantproof); /* Assume GRH or not */ mpz_clear(n); XSRETURN_IV(result); } if (ix == 2) { result = is_perrin_pseudoprime(n, wantproof); /* Restricted or not */ mpz_clear(n); XSRETURN_IV(result); } if (wantproof == 0) { result = _GMP_is_provable_prime(n, 0); XPUSHs(sv_2mortal(newSViv( result ))); } else { char* prooftext = 0; result = _GMP_is_provable_prime(n, &prooftext); XPUSHs(sv_2mortal(newSViv( result ))); if (prooftext) { XPUSHs(sv_2mortal(newSVpv(prooftext, 0))); Safefree(prooftext); } else { XPUSHs(sv_2mortal(newSVpv("", 0))); } } mpz_clear(n); int _validate_ecpp_curve(IN char* stra, IN char* strb, IN char* strn, IN char* strpx, IN char* strpy, IN char* strm, IN char* strq) PREINIT: mpz_t a, b, n, px, py, m, q, t1, t2; CODE: VALIDATE_AND_SET(a, stra); VALIDATE_AND_SET(b, strb); /* Unused */ VALIDATE_AND_SET(n, strn); VALIDATE_AND_SET(px, strpx); VALIDATE_AND_SET(py, strpy); VALIDATE_AND_SET(m, strm); VALIDATE_AND_SET(q, strq); mpz_init(t1); mpz_init(t2); RETVAL = (ecpp_check_point(px, py, m, q, a, n, t1, t2) == 2) ? 1 : 0; mpz_clear(t1); mpz_clear(t2); mpz_clear(a); mpz_clear(b); mpz_clear(n); mpz_clear(px); mpz_clear(py); mpz_clear(m); mpz_clear(q); OUTPUT: RETVAL UV is_power(IN char* strn, IN UV a = 0) PREINIT: mpz_t n; int isneg; CODE: isneg = validate_and_set_signed(cv, n, "n", strn, VSETNEG_POS); RETVAL = 0; if (!isneg || (a == 0 || a & 1)) { RETVAL = is_power(n, a); } if (isneg && a == 0 && RETVAL != 0) { UV r = RETVAL; while (!(r & 1)) r >>= 1; RETVAL = (r == 1) ? 0 : r; } mpz_clear(n); OUTPUT: RETVAL #define XPUSH_MPZ(n) \ do { \ /* Push as a scalar if <= min(ULONG_MAX,UV_MAX), string otherwise */ \ UV _v = mpz_get_ui(n); \ if (!mpz_cmp_ui(n, _v)) { \ XPUSHs(sv_2mortal(newSVuv( _v ))); \ } else { \ char* str; \ int nsize = mpz_sizeinbase(n, 10) + 2; \ New(0, str, nsize, char); \ mpz_get_str(str, 10, n); \ XPUSHs(sv_2mortal(newSVpv(str, 0))); \ Safefree(str); \ } \ } while (0) void next_prime(IN char* strn) ALIAS: prev_prime = 1 next_twin_prime = 2 PREINIT: mpz_t n; PPCODE: VALIDATE_AND_SET(n, strn); if (ix == 1 && mpz_cmp_ui(n,3) < 0) { mpz_clear(n); XSRETURN_UNDEF; } if (ix == 0) _GMP_next_prime(n); else if (ix == 1) _GMP_prev_prime(n); else next_twin_prime(n, n); XPUSH_MPZ(n); mpz_clear(n); void prime_count(IN char* strlo, IN char* strhi = 0) ALIAS: random_prime = 1 urandomr = 2 PREINIT: mpz_t lo, hi, res; int retundef; PPCODE: if (strhi == 0) { mpz_init_set_ui(lo, 0); VALIDATE_AND_SET(hi, strlo); } else { if (*strlo == '+') strlo++; if (*strhi == '+') strhi++; validate_string_number(cv, "lo", strlo); validate_string_number(cv, "hi", strhi); mpz_init_set_str(lo, strlo, 10); mpz_init_set_str(hi, strhi, 10); } if (ix == 2 && mpz_sizeinbase(hi,2) <= 32) { uint32_t ulo = mpz_get_ui(lo), uhi = mpz_get_ui(hi); if (ulo <= uhi) { mpz_clear(lo); mpz_clear(hi); XSRETURN_IV( ulo + isaac_rand(uhi-ulo+1) ); } } retundef = 0; mpz_init(res); if (ix == 0) { count_primes(res, lo, hi); } else if (ix == 1) { retundef = !mpz_random_prime(res, lo, hi); } else { if (mpz_cmp(lo,hi) > 0) { retundef = 1; } else { mpz_sub(hi,hi,lo); mpz_add_ui(hi,hi,1); mpz_isaac_urandomm(res, hi); mpz_add(res,res,lo); } } if (!retundef) XPUSH_MPZ(res); mpz_clear(res); mpz_clear(hi); mpz_clear(lo); if (retundef) XSRETURN_UNDEF; void totient(IN char* strn) ALIAS: carmichael_lambda = 1 exp_mangoldt = 2 bernfrac = 3 harmfrac = 4 znprimroot = 5 ramanujan_tau = 6 sqrtint = 7 is_prime_power = 8 prime_count_lower = 9 prime_count_upper = 10 urandomm = 11 negint = 12 absint = 13 PREINIT: mpz_t res, n; PPCODE: if (ix == 12 || ix == 13) { if (strn != 0 && strn[0] == '-') { VALIDATE_AND_SET(res, strn+1); } else { VALIDATE_AND_SET(res, strn); if (ix == 12) mpz_neg(res, res); } XPUSH_MPZ(res); mpz_clear(res); return; } if (strn != 0 && strn[0] == '-') { /* If input is negative... */ if (ix == 2) XSRETURN_IV(1); /* exp_mangoldt return 1 */ if (ix == 5) strn++; /* znprimroot flip sign */ if (ix == 8) XSRETURN_IV(0); /* is_prime_power return 0 */ } VALIDATE_AND_SET(n, strn); mpz_init(res); switch (ix) { case 0: totient(res, n); break; case 1: carmichael_lambda(res, n); break; case 2: exp_mangoldt(res, n); break; case 3: bernfrac(n, res, n); XPUSH_MPZ(n); break; case 4: harmfrac(n, res, n); XPUSH_MPZ(n); break; case 5: znprimroot(res, n); if (!mpz_sgn(res) && mpz_cmp_ui(n,1) != 0) { mpz_clear(n); mpz_clear(res); XSRETURN_UNDEF; } break; case 6: ramanujan_tau(res, n); break; case 7: mpz_sqrt(res, n); break; case 8: mpz_set_ui(res, prime_power(res, n)); break; case 9: prime_count_lower(res, n); break; case 10: prime_count_upper(res, n); break; case 11: default: mpz_isaac_urandomm(res, n); break; } XPUSH_MPZ(res); mpz_clear(n); mpz_clear(res); void harmreal(IN char* strn, IN UV prec = 40) ALIAS: bernreal = 1 logreal = 2 expreal = 3 zeta = 4 li = 5 ei = 6 riemannr = 7 lambertw = 8 surround_primes = 9 PREINIT: mpz_t n; mpf_t f; char* res; PPCODE: if (ix == 9) { /* surround_primes */ UV prev, next; VALIDATE_AND_SET(n, strn); next = 1 + (mpz_sgn(n)==0); if (mpz_cmp_ui(n,2) > 0) { surround_primes(n, &prev, &next, (items == 1) ? 0 : prec); XPUSHs(sv_2mortal(newSVuv(prev))); } else { XPUSHs(sv_2mortal(newSV(0))); } XPUSHs(sv_2mortal(newSVuv(next))); mpz_clear(n); } else if (ix <= 1) { VALIDATE_AND_SET(n, strn); res = (ix == 0) ? harmreal(n, prec) : bernreal(n, prec); mpz_clear(n); XPUSHs(sv_2mortal(newSVpv(res, 0))); Safefree(res); } else { unsigned long bits = 64 + (unsigned long)(3.32193 * prec); unsigned long bits2 = 64 + (unsigned long)(3.32193 * strlen(strn)); if (bits2 > bits) bits = bits2; mpf_init2(f, bits); if (mpf_set_str(f, strn, 10) != 0) croak("Not valid base-10 floating point input: %s", strn); res = 0; switch (ix) { case 2: res = logreal(f, prec); break; case 3: res = expreal(f, prec); break; case 4: res = zetareal(f, prec); break; case 5: res = lireal(f, prec); break; case 6: res = eireal(f, prec); break; case 7: res = riemannrreal(f, prec); break; case 8: default: res = lambertwreal(f, prec); break; } mpf_clear(f); if (res == 0) XSRETURN_UNDEF; XPUSHs(sv_2mortal(newSVpv(res, 0))); Safefree(res); } void powreal(IN char* strn, IN char* strx, IN UV prec = 40) ALIAS: rootreal = 1 agmreal = 2 addreal = 3 subreal = 4 mulreal = 5 divreal = 6 PREINIT: mpf_t n, x; char* res; unsigned long bits, bits2, bits3; PPCODE: bits = 64 + (unsigned long)(3.32193 * prec); bits2 = 64 + (unsigned long)(3.32193 * strlen(strn)); bits3 = 64 + (unsigned long)(3.32193 * strlen(strx)); if (bits2 > bits) bits = bits2; if (bits3 > bits) bits = bits3; mpf_init2(n, bits); if (mpf_set_str(n, strn, 10) != 0) croak("Not valid base-10 floating point input: %s", strn); mpf_init2(x, bits); if (mpf_set_str(x, strx, 10) != 0) croak("Not valid base-10 floating point input: %s", strx); switch (ix) { case 0: res = powreal(n, x, prec); break; case 1: res = rootreal(n, x, prec); break; case 2: res = agmreal(n, x, prec); break; case 3: res = addreal(n, x, prec); break; case 4: res = subreal(n, x, prec); break; case 5: res = mulreal(n, x, prec); break; case 6: default: res = divreal(n, x, prec); break; } mpf_clear(n); mpf_clear(x); if (res == 0) XSRETURN_UNDEF; XPUSHs(sv_2mortal(newSVpv(res, 0))); Safefree(res); void gcd(...) PROTOTYPE: @ ALIAS: lcm = 1 vecsum = 2 vecprod = 3 PREINIT: int i; mpz_t ret, n; PPCODE: if (items == 0) XSRETURN_IV( (ix == 3) ? 1 : 0); if (ix == 1 || ix == 3) { mpz_t* list; New(0, list, items, mpz_t); for (i = 0; i < items; i++) { char* strn = SvPV_nolen(ST(i)); validate_and_set_signed(cv, list[i], "arg", strn, VSETNEG_OK); } if (ix == 1) mpz_veclcm(list, 0, items-1); else mpz_product(list, 0, items-1); XPUSH_MPZ(list[0]); for (i = 0; i < items; i++) mpz_clear(list[i]); Safefree(list); XSRETURN(1); } mpz_init_set_ui(ret, (ix == 1 || ix == 3) ? 1 : 0); for (i = 0; i < items; i++) { char* strn = SvPV_nolen(ST(i)); validate_and_set_signed(cv, n, "arg", strn, (ix <= 1) ? VSETNEG_POS : VSETNEG_OK); switch (ix) { case 0: mpz_gcd(ret, ret, n); break; case 1: mpz_lcm(ret, ret, n); break; case 2: mpz_add(ret, ret, n); break; case 3: default: mpz_mul(ret, ret, n); break; } mpz_clear(n); } XPUSH_MPZ(ret); mpz_clear(ret); int kronecker(IN char* stra, IN char* strb) ALIAS: valuation = 1 is_gaussian_prime = 2 PREINIT: mpz_t a, b; CODE: validate_and_set_signed(cv, a, "a", stra, VSETNEG_OK); validate_and_set_signed(cv, b, "b", strb, VSETNEG_OK); if (ix == 0) { RETVAL = mpz_kronecker(a, b); } else if (ix == 1) { mpz_abs(a,a); mpz_abs(b,b); if (mpz_cmp_ui(a,1) <= 0 || mpz_cmp_ui(b,1) <= 0) { RETVAL = 0; } else if (mpz_cmp_ui(b,2) == 0) { RETVAL = mpz_scan1(a, 0); } else { RETVAL = mpz_remove(a, a, b); } } else { mpz_abs(a,a); mpz_abs(b,b); if (mpz_sgn(a) == 0) { RETVAL = (mpz_fdiv_ui(b,4) == 3) ? _GMP_is_prime(b) : 0; } else if (mpz_sgn(b) == 0) { RETVAL = (mpz_fdiv_ui(a,4) == 3) ? _GMP_is_prime(a) : 0; } else { mpz_mul(a, a, a); mpz_mul(b, b, b); mpz_add(a, a, b); RETVAL = (!mpz_cmp_ui(a,2)) ? 2 : (mpz_fdiv_ui(a,4) == 1) ? _GMP_is_prime(a) : 0; } } mpz_clear(b); mpz_clear(a); OUTPUT: RETVAL void moebius(IN char* strn, IN char* stro = 0) PREINIT: mpz_t n; PPCODE: validate_and_set_signed(cv, n, "n", strn, VSETNEG_OK); if (stro == 0) { int result = moebius(n); mpz_clear(n); XSRETURN_IV(result); } else { /* Ranged result */ mpz_t nhi; validate_and_set_signed(cv, nhi, "nhi", stro, VSETNEG_OK); while (mpz_cmp(n, nhi) <= 0) { XPUSHs(sv_2mortal(newSViv( moebius(n) ))); mpz_add_ui(n, n, 1); } mpz_clear(n); mpz_clear(nhi); } void lucasu(IN IV P, IN IV Q, IN char* strk) ALIAS: lucasv = 1 PREINIT: mpz_t u, v, k; PPCODE: VALIDATE_AND_SET(k, strk); /* We could call mpz_fib_ui / mpz_lucnum_ui when P=1,Q=-1, * but it is only 10-15% faster so let's not special case. */ mpz_init(u); mpz_init(v); lucasuv(u, v, P, Q, k); XPUSH_MPZ( ((ix == 0) ? u : v) ); mpz_clear(v); mpz_clear(u); mpz_clear(k); int liouville(IN char* strn) ALIAS: is_square = 1 is_semiprime = 2 is_totient = 3 is_carmichael = 4 is_fundamental = 5 hammingweight = 6 PREINIT: mpz_t n; int isneg; CODE: isneg = validate_and_set_signed( cv, n, "n", strn, (ix == 0) ? VSETNEG_ERR : (ix == 6) ? VSETNEG_POS : VSETNEG_OK ); if (isneg && (ix == 1 || ix == 2 || ix == 3 || ix == 4)) { RETVAL = 0; } else { switch (ix) { case 0: RETVAL = liouville(n); break; case 1: RETVAL = is_power(n,2); break; case 2: RETVAL = is_semiprime(n); break; case 3: RETVAL = is_totient(n); break; case 4: RETVAL = is_carmichael(n); break; case 5: RETVAL = is_fundamental(n); break; case 6: default: RETVAL = mpz_popcount(n); break; } } mpz_clear(n); OUTPUT: RETVAL void invmod(IN char* stra, IN char* strb) ALIAS: binomial = 1 gcdext = 2 jordan_totient = 3 znorder = 4 sqrtmod = 5 is_primitive_root = 6 is_polygonal = 7 polygonal_nth = 8 rootint = 9 logint = 10 powint = 11 mulint = 12 addint = 13 subint = 14 divint = 15 modint = 16 tdivrem = 17 divrem = 18 factorialmod = 19 multifactorial = 20 PREINIT: mpz_t a, b, t; int retundef; PPCODE: validate_and_set_signed(cv, a, "a", stra, VSETNEG_OK); validate_and_set_signed(cv, b, "b", strb, VSETNEG_OK); retundef = 0; switch (ix) { /* undef if a|b = 0, 0 if b is 1, else result of mpz_invert */ case 0:{ if (!mpz_sgn(b) || !mpz_sgn(a)) retundef = 1; else if (!mpz_cmp_ui(b,1)) mpz_set_ui(a,0); else retundef = !mpz_invert(a,a,b); } break; case 1:{ unsigned long n, k; if (mpz_sgn(b) < 0) { /* Handle negative k */ if (mpz_sgn(a) >= 0 || mpz_cmp(b,a) > 0) mpz_set_ui(a, 0); else mpz_sub(b, a, b); } n = mpz_get_ui(a); k = mpz_get_ui(b); if (k > n || k == 0 || k == n || mpz_sgn(a) < 0) { mpz_bin_ui(a, a, k); } else { if (k > n/2) k = n-k; /* Note: mpz_bin_uiui is *much* faster than mpz_bin_ui. * It is a bit faster than our code for small values, and * a tiny bit slower for larger values. */ if (n > 50000 && k > 1000) binomial(a, n, k); else mpz_bin_uiui(a, n, k); } } break; case 2:{ mpz_init(t); if (mpz_sgn(a) == 0 && mpz_sgn(b) == 0) { mpz_set_ui(t, 0); /* This changed in GMP 5.1.2. Enforce new result. */ } else { gcdext(a, t, b, a, b); } XPUSH_MPZ(t); XPUSH_MPZ(b); mpz_clear(t); } break; case 3: jordan_totient(a, b, mpz_get_ui(a)); break; case 4: znorder(a, a, b); if (!mpz_sgn(a)) retundef = 1; break; case 5: retundef = !sqrtmod(a, a, b); break; case 6: mpz_set_si(a, is_primitive_root(a, b, 0) ); break; case 7: if (mpz_cmp_ui(b,3) < 0) croak("is_polygonal: k must be >= 3"); polygonal_nth(a, a, mpz_get_ui(b)); mpz_set_si(a, mpz_sgn(a)); break; case 8: if (mpz_cmp_ui(b,3) < 0) croak("polygonal_nth: k must be >= 3"); polygonal_nth(a, a, mpz_get_ui(b)); break; case 9: if (mpz_sgn(b) <= 0) croak("rootint: k must be > 0"); if (mpz_sgn(a) < 0) croak("rootint: n must be >= 0"); mpz_root(a, a, mpz_get_ui(b)); break; case 10:if (mpz_cmp_ui(b,2) < 0) croak("rootint: base must be > 1"); if (mpz_sgn(a) <= 0) croak("rootint: n must be > 0"); mpz_set_ui(a, logint(a, mpz_get_ui(b))); break; case 11:if (mpz_sgn(b) < 0) croak("powint: exponent must be >= 0"); mpz_pow_ui(a, a, mpz_get_ui(b)); break; case 12:mpz_mul(a, a, b); break; case 13:mpz_add(a, a, b); break; case 14:mpz_sub(a, a, b); break; case 15:if (mpz_sgn(b) == 0) croak("divint: divide by zero"); mpz_fdiv_q(a, a, b); break; case 16:if (mpz_sgn(b) == 0) croak("modint: divide by zero"); mpz_fdiv_r(a, a, b); break; case 17:if (mpz_sgn(b) == 0) croak("tdivrem: divide by zero"); mpz_tdiv_qr(b, a, a, b); /* t is t-quotient, a is t-remainder */ XPUSH_MPZ(b); break; case 18:mpz_init_set(t, b); if (mpz_sgn(b) == 0) croak("divrem: divide by zero"); mpz_tdiv_qr(t, a, a, b); /* t is t-quotient, a is t-remainder */ if (mpz_sgn(a) < 0) { /* Change from trunc to Euclidean */ if (mpz_sgn(b) > 0) { mpz_sub_ui(t, t, 1); mpz_add(a, a, b); } else { mpz_add_ui(t, t, 1); mpz_sub(a, a, b); } } XPUSH_MPZ(t); mpz_clear(t); break; case 19:if (mpz_sgn(b) < 0) retundef = 1; else factorialmod(a, mpz_get_ui(a), b); break; case 20: default:if (mpz_sgn(a) < 0 || mpz_sgn(b) < 0) retundef = 1; else multifactorial(a, mpz_get_ui(a), mpz_get_ui(b)); break; } if (!retundef) XPUSH_MPZ(a); mpz_clear(b); mpz_clear(a); if (retundef) XSRETURN_UNDEF; void addmod(IN char* stra, IN char* strb, IN char* strn) ALIAS: mulmod = 1 powmod = 2 divmod = 3 PREINIT: mpz_t a, b, n; int retundef; PPCODE: validate_and_set_signed(cv, a, "a", stra, VSETNEG_OK); validate_and_set_signed(cv, b, "b", strb, VSETNEG_OK); validate_and_set_signed(cv, n, "n", strn, VSETNEG_ERR); retundef = (mpz_sgn(n) <= 0); if (!retundef && ix == 3) { if (!mpz_sgn(n) || !mpz_sgn(b)) retundef = 1; else if (!mpz_cmp_ui(b,1)) mpz_set_ui(b,0); else retundef = !mpz_invert(b,b,n); } if (!retundef && ix == 2 && mpz_sgn(b) < 0) { if (!mpz_cmp_ui(n,1)) mpz_set_ui(b,0); else retundef = !mpz_invert(a,a,n); mpz_abs(b,b); } if (retundef) { mpz_clear(n); mpz_clear(b); mpz_clear(a); XSRETURN_UNDEF; } if (ix == 0) { mpz_add(a,a,b); mpz_mod(a,a,n); } else if (ix == 1 || ix == 3) { mpz_mul(a,a,b); mpz_mod(a,a,n); } else if (ix == 2) { mpz_powm(a, a, b, n); } XPUSH_MPZ(a); mpz_clear(n); mpz_clear(b); mpz_clear(a); int is_mersenne_prime(IN UV n) CODE: RETVAL = lucas_lehmer(n); OUTPUT: RETVAL void Pi(IN UV n) ALIAS: Euler = 1 random_bytes = 2 PREINIT: UV prec; PPCODE: if (ix == 2) { /* random_bytes */ char* sptr; SV* sv = newSV(n == 0 ? 1 : n); SvPOK_only(sv); SvCUR_set(sv, n); sptr = SvPVX(sv); isaac_rand_bytes(n, (unsigned char*)sptr); sptr[n] = '\0'; PUSHs(sv_2mortal(sv)); XSRETURN(1); } if (ix == 0 && n == 0) XSRETURN(0); if (ix == 0 && n == 1) XSRETURN_IV(3); if (ix == 1 && n == 0) XSRETURN_IV(1); prec = (ix == 0) ? n+1 : n+2; if (GIMME_V == G_VOID) { mpf_t c; mpf_init2(c, 7+prec*3.32193); if (ix == 0) const_pi(c, prec); else const_euler(c, prec); mpf_clear(c); } else { char* cstr = (ix == 0) ? piconst(n) : eulerconst(n); XPUSHs(sv_2mortal(newSVpvn(cstr, prec))); Safefree(cstr); } void random_nbit_prime(IN UV n) ALIAS: random_safe_prime = 1 random_strong_prime = 2 random_maurer_prime = 3 random_maurer_prime_with_cert = 4 random_shawe_taylor_prime = 5 random_shawe_taylor_prime_with_cert = 6 random_ndigit_prime = 7 urandomb = 8 factorial = 9 factorial_sum = 10 subfactorial = 11 partitions = 12 primorial = 13 pn_primorial = 14 consecutive_integer_lcm = 15 PREINIT: mpz_t p; char* proof; PPCODE: if (ix == 8 && n <= BITS_PER_WORD) { UV v = irand64(n); ST(0) = sv_2mortal(newSVuv(v)); XSRETURN(1); } mpz_init(p); proof = 0; switch (ix) { case 0: mpz_random_nbit_prime(p, n); break; case 1: mpz_random_safe_prime(p, n); break; case 2: mpz_random_strong_prime(p, n); break; case 3: mpz_random_maurer_prime(p, n, 0); break; case 4: mpz_random_maurer_prime(p, n, &proof); proof = cert_with_header(proof, p); break; case 5: mpz_random_shawe_taylor_prime(p, n, 0); break; case 6: mpz_random_shawe_taylor_prime(p, n, &proof); proof = cert_with_header(proof, p); break; case 7: mpz_random_ndigit_prime(p, n); break; case 8: mpz_isaac_urandomb(p, n); break; case 9: mpz_fac_ui(p, n); break; /* swing impl in 5.1+, so fast */ case 10: factorial_sum(p, n); break; case 11: subfactorial(p, n); break; case 12: partitions(p, n); break; case 13: _GMP_primorial(p, n); break; case 14: _GMP_pn_primorial(p, n); break; case 15: default: consecutive_integer_lcm(p, n); break; } XPUSH_MPZ(p); mpz_clear(p); if (proof) { XPUSHs(sv_2mortal(newSVpv(proof, 0))); Safefree(proof); } void stirling(IN UV n, IN UV m, IN UV type = 1) PREINIT: mpz_t r; PPCODE: mpz_init(r); stirling(r, n, m, type); XPUSH_MPZ( r ); mpz_clear(r); void chinese(...) PROTOTYPE: @ PREINIT: int i, doretval; mpz_t* an; mpz_t ret, lcm; PPCODE: if (items == 0) XSRETURN_IV(0); mpz_init_set_ui(ret, 0); New(0, an, 2*items, mpz_t); for (i = 0; i < items; i++) { AV* av; SV** psva; SV** psvn; char* strn; if (!SvROK(ST(i)) || SvTYPE(SvRV(ST(i))) != SVt_PVAV || av_len((AV*)SvRV(ST(i))) != 1) croak("chinese arguments are two-element array references"); av = (AV*) SvRV(ST(i)); psva = av_fetch(av, 0, 0); psvn = av_fetch(av, 1, 0); strn = SvPV_nolen(*psva); validate_and_set_signed(cv, an[i+0], "a", strn, VSETNEG_OK); strn = SvPV_nolen(*psvn); validate_and_set_signed(cv, an[i+items], "b", strn, VSETNEG_OK); } mpz_init(lcm); doretval = chinese(ret, lcm, an, an+items, items); if (doretval) XPUSH_MPZ(ret); for (i = 0; i < items; i++) { mpz_clear(an[i+0]); mpz_clear(an[i+items]); } Safefree(an); mpz_clear(lcm); mpz_clear(ret); if (!doretval) XSRETURN_UNDEF; void permtonum(SV* svp) PREINIT: AV *av; char* seen; UV val, *V; int plen, n, i, j, k; mpz_t f, t, num; PPCODE: if ((!SvROK(svp)) || (SvTYPE(SvRV(svp)) != SVt_PVAV)) croak("permtonum argument must be an array reference"); av = (AV*) SvRV(svp); plen = av_len(av); if (plen < 0) XSRETURN_IV(0); Newz(0, seen, plen+1, char); New(0, V, plen+1, UV); for (i = 0; i <= plen; i++) { SV **iv = av_fetch(av, i, 0); if (iv == 0) break; val = SvUV(*iv); if (val > (UV)plen || seen[val] != 0) break; seen[val] = 1; V[i] = val; } Safefree(seen); if (i <= plen) croak("permtonum invalid permutation array"); mpz_init(f); mpz_init(t); mpz_init_set_ui(num, 0); n = plen+1; mpz_fac_ui(f, n-1); for (i = 0; i < n-1; i++) { for (j = i+1, k = 0; j < n; j++) if (V[j] < V[i]) k++; mpz_mul_ui(t, f, k); mpz_add(num, num, t); mpz_divexact_ui(f, f, n-i-1); } Safefree(V); XPUSH_MPZ(num); mpz_clear(num); mpz_clear(t); mpz_clear(f); void numtoperm(IN UV n, IN char* strk) PREINIT: mpz_t k, f, p; UV i, j, tv, *perm; PPCODE: if (n == 0) XSRETURN_EMPTY; validate_and_set_signed(cv, k, "k", strk, VSETNEG_OK); mpz_init(f); mpz_init(p); New(0, perm, n, UV); for (i = 0; i < n; i++) perm[i] = i; mpz_fac_ui(f, n); mpz_mod(k,k,f); for (i = 0; i < n-1; i++) { mpz_divexact_ui(f, f, n-i); mpz_tdiv_qr(p, k, k, f); if (mpz_sgn(p)) { for (j = i + mpz_get_ui(p), tv = perm[j]; j > i; j--) perm[j] = perm[j-1]; perm[i] = tv; } } EXTEND(SP, (IV)n); for (i = 0; i < n; i++) PUSHs(sv_2mortal(newSVuv( perm[i] ))); Safefree(perm); mpz_clear(p); mpz_clear(f); mpz_clear(k); void sieve_prime_cluster(IN char* strlow, IN char* strhigh, ...) ALIAS: sieve_primes = 1 sieve_twin_primes = 2 PREINIT: mpz_t low, seghigh, high, t; UV i, nc, nprimes, maxseg, *list; PPCODE: VALIDATE_AND_SET(low, strlow); VALIDATE_AND_SET(high, strhigh); mpz_init(seghigh); mpz_init(t); nc = items-1; maxseg = ((UV_MAX > ULONG_MAX) ? ULONG_MAX : UV_MAX); /* Loop as needed */ while (mpz_cmp(low, high) <= 0) { mpz_add_ui(seghigh, low, maxseg - 1); if (mpz_cmp(seghigh, high) > 0) mpz_set(seghigh, high); mpz_set(t, seghigh); /* Save in case it is modified */ if (ix == 1) { UV k = (nc <= 1) ? 0 : SvUV(ST(2)); list = sieve_primes(low, seghigh, k, &nprimes); } else if (ix == 2) { list = sieve_twin_primes(low, seghigh, 2, &nprimes); } else { uint32_t *cl; New(0, cl, nc, uint32_t); cl[0] = 0; for (i = 1; i < nc; i++) { UV cval = SvUV(ST(1+i)); if (cval & 1) croak("sieve_prime_cluster: values must be even"); if (cval > 2147483647UL) croak("sieve_prime_cluster: values must be 31-bit"); if (cval <= cl[i-1]) croak("sieve_prime_cluster: values must be increasing"); cl[i] = cval; } list = sieve_cluster(low, seghigh, cl, nc, &nprimes); Safefree(cl); } mpz_set(seghigh, t); /* Restore the value we used */ if (list != 0) { for (i = 0; i < nprimes; i++) { mpz_add_ui(t, low, list[i]); XPUSH_MPZ( t ); } Safefree(list); } mpz_add_ui(low, seghigh, 1); } mpz_clear(t); mpz_clear(seghigh); mpz_clear(high); mpz_clear(low); void sieve_range(IN char* strn, IN UV width, IN UV depth) PREINIT: mpz_t low, seghigh, high, t; UV i, nprimes, maxseg, offset, *list; PPCODE: if (width == 0) XSRETURN(0); if (depth == 0) depth = 1; VALIDATE_AND_SET(low, strn); mpz_init(high); mpz_add_ui(high, low, width-1); mpz_init(seghigh); mpz_init(t); maxseg = ((UV_MAX > ULONG_MAX) ? ULONG_MAX : UV_MAX); offset = 0; /* Deal with 0 and 1 inside range */ if (mpz_cmp_ui(low,2) < 0) { offset = 2 - mpz_get_ui(low); width = (width < offset) ? 0 : width - offset; mpz_set_ui(low,2); } /* Deal with depth < 2 (no sieving) */ if (depth < 2) { for (i = 0; i < width; i++) XPUSHs(sv_2mortal(newSVuv(offset + i))); mpz_add_ui(low, high, 1); } /* Loop as needed */ while (mpz_cmp(low, high) <= 0) { mpz_add_ui(seghigh, low, maxseg - 1); if (mpz_cmp(seghigh, high) > 0) mpz_set(seghigh, high); mpz_set(t, seghigh); /* Save in case it is modified */ list = sieve_primes(low, seghigh, depth, &nprimes); mpz_set(seghigh, t); /* Restore the value we used */ if (list != 0) { for (i = 0; i < nprimes; i++) { XPUSHs(sv_2mortal(newSVuv( offset + list[i] ))); } Safefree(list); } mpz_add_ui(low, seghigh, 1); offset += maxseg; } mpz_clear(t); mpz_clear(seghigh); mpz_clear(high); mpz_clear(low); void lucas_sequence(IN char* strn, IN IV P, IN IV Q, IN char* strk) PREINIT: mpz_t U, V, Qk, n, k, t; PPCODE: VALIDATE_AND_SET(n, strn); VALIDATE_AND_SET(k, strk); mpz_init(U); mpz_init(V); mpz_init(Qk); mpz_init(t); lucas_seq(U, V, n, P, Q, k, Qk, t); XPUSH_MPZ(U); XPUSH_MPZ(V); XPUSH_MPZ(Qk); mpz_clear(n); mpz_clear(k); mpz_clear(U); mpz_clear(V); mpz_clear(Qk); mpz_clear(t); #define SET_UV_VIA_MPZ_STRING(uva, sva, name) \ { \ mpz_t t; \ char* stra = SvPV_nolen(sva); \ validate_string_number(cv, name, stra); \ mpz_init_set_str(t, stra, 10); \ uva = mpz_get_ui(t); \ mpz_clear(t); \ } void trial_factor(IN char* strn, ...) ALIAS: prho_factor = 1 pbrent_factor = 2 pminus1_factor = 3 pplus1_factor = 4 holf_factor = 5 squfof_factor = 6 ecm_factor = 7 qs_factor = 8 PREINIT: mpz_t n; UV arg1, arg2, uf; static const UV default_arg1[] = {0, 64000000,64000000,5000000,5000000,256000000,100000000,0, 0 }; /*Trial,Rho, Brent, P-1, P+1, HOLF, SQUFOF, ECM,QS */ PPCODE: VALIDATE_AND_SET(n, strn); { int cmpr = mpz_cmp_ui(n,1); if (cmpr <= 0) { mpz_clear(n); XSRETURN_IV( (cmpr < 0) ? 0 : 1 ); } } arg1 = default_arg1[ix]; arg2 = 0; if (items >= 2) SET_UV_VIA_MPZ_STRING(arg1, ST(1), "specific factor arg 1"); if (items >= 3) SET_UV_VIA_MPZ_STRING(arg2, ST(2), "specific factor arg 2"); while (mpz_even_p(n)) { XPUSHs(sv_2mortal(newSVuv(2))); mpz_divexact_ui(n, n, 2); } while (mpz_divisible_ui_p(n, 3)) { XPUSHs(sv_2mortal(newSVuv(3))); mpz_divexact_ui(n, n, 3); } while (mpz_divisible_ui_p(n, 5)) { XPUSHs(sv_2mortal(newSVuv(5))); mpz_divexact_ui(n, n, 5); } if (mpz_cmp_ui(n,1) > 0 && !_GMP_is_prob_prime(n)) { mpz_t f; int success = 0; mpz_init(f); switch (ix) { case 0: if (arg1 == 0) arg1 = 2147483647; uf = _GMP_trial_factor(n, 2, arg1); mpz_set_ui(f, uf); success = (uf > 0); break; case 1: success = _GMP_prho_factor(n, f, 3, arg1); break; case 2: success = _GMP_pbrent_factor(n, f, 3, arg1); break; case 3: if (arg2 == 0) arg2 = arg1*10; success = _GMP_pminus1_factor(n, f, arg1,arg2); break; case 4: if (arg2 == 0) arg2 = arg1*10; success = _GMP_pplus1_factor(n, f, 0,arg1,arg2); break; case 5: success = _GMP_holf_factor(n, f, arg1); break; case 6: success = squfof126(n, f, arg1); break; case 7: if (arg2 == 0) arg2 = 100; if (arg1 == 0) { success = _GMP_ECM_FACTOR(n, f, 1000, 40) || _GMP_ECM_FACTOR(n, f, 10000, 40) || _GMP_ECM_FACTOR(n, f, 100000, 40) || _GMP_ECM_FACTOR(n, f, 1000000, 40) || _GMP_ECM_FACTOR(n, f, 10000000,100); } else { success = _GMP_ECM_FACTOR(n, f, arg1, arg2); } break; case 8: default:{ mpz_t farray[66]; int i, nfactors; for (i = 0; i < 66; i++) mpz_init(farray[i]); nfactors = _GMP_simpqs(n, farray); for (i = 0; i < nfactors; i++) XPUSH_MPZ(farray[i]); for (i = 0; i < 66; i++) mpz_clear(farray[i]); if (nfactors > 0) mpz_set_ui(n, 1); } break; } if (success) { mpz_divexact(n, n, f); if (mpz_cmp(f,n) > 0) /* print smallest first */ mpz_swap(n, f); XPUSH_MPZ(f); } mpz_clear(f); } if (mpz_cmp_ui(n,1) > 0) XPUSH_MPZ(n); mpz_clear(n); void factor(IN char* strn) ALIAS: divisors = 1 PREINIT: mpz_t n; mpz_t* factors; int* exponents; int nfactors, i, j; PPCODE: VALIDATE_AND_SET(n, strn); if (ix == 0) { nfactors = factor(n, &factors, &exponents); if (GIMME_V == G_SCALAR) { for (i = 0, j = 0; i < nfactors; i++) j += exponents[i]; PUSHs(sv_2mortal(newSVuv(j))); } else { for (i = 0; i < nfactors; i++) { for (j = 0; j < exponents[i]; j++) { XPUSH_MPZ(factors[i]); } } } clear_factors(nfactors, &factors, &exponents); } else { if (GIMME_V == G_SCALAR) { sigma(n, n, 0); XPUSH_MPZ(n); } else { factors = divisor_list(&nfactors, n); EXTEND(SP, nfactors); for (i = 0; i < nfactors; i++) { XPUSH_MPZ(factors[i]); mpz_clear(factors[i]); } Safefree(factors); } } mpz_clear(n); void sigma(IN char* strn, IN UV k = 1) PREINIT: mpz_t n; PPCODE: VALIDATE_AND_SET(n, strn); sigma(n, n, k); XPUSH_MPZ(n); mpz_clear(n); void todigits(IN char* strn, int base=10, int length=-1) PREINIT: mpz_t n; uint32_t d, *digits; PPCODE: if (base < 2) croak("invalid base: %d", base); if (strn[0] == '-' || strn[0] == '+') strn++; validate_string_number(cv, "n", strn); if (base == 10) { uint32_t l = strlen(strn); New(0, digits, l, uint32_t); for (d = 0; d < l; d++) digits[d] = strn[d]-'0'; } else { mpz_init_set_str(n, strn, 10); digits = todigits(&d, n, (uint32_t)base); mpz_clear(n); } if (length > 0 || d > 1 || digits[0] != 0) { if (length < 0) length = d; EXTEND(SP, length); for (; length > (int)d; length--) PUSHs(sv_2mortal(newSVuv( 0 ))); for (; length > 0; length--) PUSHs(sv_2mortal(newSVuv( digits[d-length] ))); } Safefree(digits); Math-Prime-Util-GMP-0.52/META.json0000644000175000017500000000325513674072603014765 0ustar danadana{ "abstract" : "Utilities related to prime numbers, using GMP", "author" : [ "Dana A Jacobsen " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Math-Prime-Util-GMP", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "recommends" : { "Math::Prime::Util" : "0.68" }, "requires" : { "Carp" : "0", "Exporter" : "5.57", "Fcntl" : "0", "XSLoader" : "0.01", "base" : "0", "perl" : "5.006002" } }, "test" : { "requires" : { "Math::BigInt" : "1.88", "Test::More" : "0.45" } } }, "provides" : { "Math::Prime::Util::GMP" : { "file" : "lib/Math/Prime/Util/GMP.pm", "version" : "0.52" } }, "release_status" : "stable", "resources" : { "homepage" : "https://github.com/danaj/Math-Prime-Util-GMP", "license" : [ "http://dev.perl.org/licenses/" ], "repository" : { "url" : "https://github.com/danaj/Math-Prime-Util-GMP" } }, "version" : "0.52", "x_serialization_backend" : "JSON::PP version 4.02" } Math-Prime-Util-GMP-0.52/ecm.c0000644000175000017500000004723113663067455014265 0ustar danadana #include #include #include #include #include #include "ptypes.h" #include "ecm.h" #include "utility.h" #include "prime_iterator.h" #define USE_PRAC #define TEST_FOR_2357(n, f) \ { \ if (mpz_divisible_ui_p(n, 2)) { mpz_set_ui(f, 2); return 1; } \ if (mpz_divisible_ui_p(n, 3)) { mpz_set_ui(f, 3); return 1; } \ if (mpz_divisible_ui_p(n, 5)) { mpz_set_ui(f, 5); return 1; } \ if (mpz_divisible_ui_p(n, 7)) { mpz_set_ui(f, 7); return 1; } \ if (mpz_cmp_ui(n, 121) < 0) { return 0; } \ } /* P3 = P1 + P2 */ static void _ec_add_AB(mpz_t n, struct ec_affine_point P1, struct ec_affine_point P2, struct ec_affine_point *P3, mpz_t m, mpz_t t1, mpz_t t2) { if (!mpz_cmp(P1.x, P2.x)) { mpz_add(t2, P1.y, P2.y); mpz_mod(t1, t2, n); if (!mpz_cmp_ui(t1, 0) ) { mpz_set_ui(P3->x, 0); mpz_set_ui(P3->y, 1); return; } } mpz_sub(t1, P2.x, P1.x); mpz_mod(t2, t1, n); /* t1 = 1/deltay mod n */ if (!mpz_invert(t1, t2, n)) { /* We've found a factor! In multiply, gcd(mult,n) will be a factor. */ mpz_set_ui(P3->x, 0); mpz_set_ui(P3->y, 1); return; } mpz_sub(m, P2.y, P1.y); mpz_mod(t2, m, n); /* t2 = deltay mod n */ mpz_mul(m, t1, t2); mpz_mod(m, m, n); /* m = deltay / deltax mod n */ /* x3 = m^2 - x1 - x2 mod n */ mpz_mul(t1, m, m); mpz_sub(t2, t1, P1.x); mpz_sub(t1, t2, P2.x); mpz_mod(P3->x, t1, n); /* y3 = m(x1 - x3) - y1 mod n */ mpz_sub(t1, P1.x, P3->x); mpz_mul(t2, m, t1); mpz_sub(t1, t2, P1.y); mpz_mod(P3->y, t1, n); } /* P3 = 2*P1 */ static void _ec_add_2A(mpz_t a, mpz_t n, struct ec_affine_point P1, struct ec_affine_point *P3, mpz_t m, mpz_t t1, mpz_t t2) { /* m = (3x1^2 + a) * (2y1)^-1 mod n */ mpz_mul_ui(t1, P1.y, 2); if (!mpz_invert(m, t1, n)) { mpz_set_ui(P3->x, 0); mpz_set_ui(P3->y, 1); return; } mpz_mul_ui(t1, P1.x, 3); mpz_mul(t2, t1, P1.x); mpz_add(t1, t2, a); mpz_mul(t2, m, t1); mpz_tdiv_r(m, t2, n); /* x3 = m^2 - 2x1 mod n */ mpz_mul(t1, m, m); mpz_mul_ui(t2, P1.x, 2); mpz_sub(t1, t1, t2); mpz_tdiv_r(P3->x, t1, n); /* y3 = m(x1 - x3) - y1 mod n */ mpz_sub(t1, P1.x, P3->x); mpz_mul(t2, t1, m); mpz_sub(t1, t2, P1.y); mpz_tdiv_r(P3->y, t1, n); } int ec_affine_multiply(mpz_t a, mpz_t k, mpz_t n, struct ec_affine_point P, struct ec_affine_point *R, mpz_t d) { int found = 0; struct ec_affine_point A, B, C; mpz_t t, t2, t3, mult; mpz_init(A.x); mpz_init(A.y); mpz_init(B.x); mpz_init(B.y); mpz_init(C.x); mpz_init(C.y); mpz_init(t); mpz_init(t2); mpz_init(t3); mpz_init_set_ui(mult, 1); /* holds intermediates, gcd at end */ mpz_set(A.x, P.x); mpz_set(A.y, P.y); mpz_set_ui(B.x, 0); mpz_set_ui(B.y, 1); /* Binary ladder multiply. */ while (mpz_cmp_ui(k, 0) > 0) { if (mpz_odd_p(k)) { mpz_sub(t, B.x, A.x); mpz_mul(t2, mult, t); mpz_mod(mult, t2, n); if ( !mpz_cmp_ui(A.x, 0) && !mpz_cmp_ui(A.y, 1) ) { /* nothing */ } else if ( !mpz_cmp_ui(B.x, 0) && !mpz_cmp_ui(B.y, 1) ) { mpz_set(B.x, A.x); mpz_set(B.y, A.y); } else { _ec_add_AB(n, A, B, &C, t, t2, t3); /* If the add failed to invert, then we have a factor. */ mpz_set(B.x, C.x); mpz_set(B.y, C.y); } mpz_sub_ui(k, k, 1); } else { mpz_mul_ui(t, A.y, 2); mpz_mul(t2, mult, t); mpz_mod(mult, t2, n); _ec_add_2A(a, n, A, &C, t, t2, t3); mpz_set(A.x, C.x); mpz_set(A.y, C.y); mpz_tdiv_q_2exp(k, k, 1); } } mpz_gcd(d, mult, n); found = (mpz_cmp_ui(d, 1) && mpz_cmp(d, n)); mpz_tdiv_r(R->x, B.x, n); mpz_tdiv_r(R->y, B.y, n); mpz_clear(mult); mpz_clear(t); mpz_clear(t2); mpz_clear(t3); mpz_clear(A.x); mpz_clear(A.y); mpz_clear(B.x); mpz_clear(B.y); mpz_clear(C.x); mpz_clear(C.y); return found; } int _GMP_ecm_factor_affine(mpz_t n, mpz_t f, UV B1, UV ncurves) { mpz_t a, mk; struct ec_affine_point X, Y; UV B, curve, q; TEST_FOR_2357(n, f); mpz_init(a); mpz_init(mk); mpz_init(X.x); mpz_init(X.y); mpz_init(Y.x); mpz_init(Y.y); for (B = 100; B < B1*5; B *= 5) { if (B*5 > 2*B1) B = B1; for (curve = 0; curve < ncurves; curve++) { PRIME_ITERATOR(iter); mpz_isaac_urandomm(a, n); mpz_set_ui(X.x, 0); mpz_set_ui(X.y, 1); for (q = 2; q < B; q = prime_iterator_next(&iter)) { UV k = q; UV kmin = B / q; while (k <= kmin) k *= q; mpz_set_ui(mk, k); if (ec_affine_multiply(a, mk, n, X, &Y, f)) { prime_iterator_destroy(&iter); mpz_clear(a); mpz_clear(X.x); mpz_clear(X.y); mpz_clear(Y.x); mpz_clear(Y.y); return 1; } mpz_set(X.x, Y.x); mpz_set(X.y, Y.y); /* Check that we're not starting over */ if ( !mpz_cmp_ui(X.x, 0) && !mpz_cmp_ui(X.y, 1) ) break; } prime_iterator_destroy(&iter); } } mpz_clear(a); mpz_clear(mk); mpz_clear(X.x); mpz_clear(X.y); mpz_clear(Y.x); mpz_clear(Y.y); return 0; } /*******************************************************************/ /* A better ECM, with a stage 2. * Heavily inspired by GMP-ECM, written by Paul Zimmermann (1998), * especially the stage 2 method. Also see "The elliptic curve * integer factorization method" by Bosma and Lenstra as well as many * other articles. */ static mpz_t b, ecn; /* used throughout ec mult */ static mpz_t u, v, w; /* temporaries */ static mpz_t x1, z1, x2, z2; /* used by ec_mult and stage2 */ #define mpz_mulmod(r, a, b, n, t) \ do { mpz_mul(t, a, b); mpz_mod(r, t, n); } while (0) /* (x2:z2) = (x1:z1) + (x2:z2) */ static void ec_add(mpz_t x2, mpz_t z2, mpz_t x1, mpz_t z1, mpz_t xinit) { mpz_sub(u, x2, z2); mpz_add(v, x1, z1); mpz_mulmod(u, u, v, ecn, w); /* u = (x2 - z2) * (x1 + z1) % n */ mpz_add(v, x2, z2); mpz_sub(w, x1, z1); mpz_mulmod(v, v, w, ecn, x2); /* v = (x2 + z2) * (x1 - z1) % n */ mpz_add(w, u, v); mpz_mulmod(x2, w, w, ecn, z2); /* x2 = (u+v)^2 % n */ mpz_sub(w, u, v); mpz_mulmod(z2, w, w, ecn, v); /* z2 = (u-v)^2 % n */ mpz_mulmod(z2, xinit, z2, ecn, v); /* z2 *= X1. */ /* Per Montgomery 1987, we set Z1 to 1, so no need for x2 *= Z1 */ /* 5 mulmods, 6 adds */ } /* This version assumes no normalization, so uses an extra mulmod. */ /* (xout:zout) = (x1:z1) + (x2:z2) */ static void ec_add3(mpz_t xout, mpz_t zout, mpz_t x1, mpz_t z1, mpz_t x2, mpz_t z2, mpz_t xin, mpz_t zin) { mpz_sub(u, x2, z2); mpz_add(v, x1, z1); mpz_mulmod(u, u, v, ecn, w); /* u = (x2 - z2) * (x1 + z1) % n */ mpz_add(v, x2, z2); mpz_sub(w, x1, z1); mpz_mulmod(v, v, w, ecn, v); /* v = (x2 + z2) * (x1 - z1) % n */ mpz_add(w, u, v); /* w = u+v */ mpz_sub(v, u, v); /* v = u-v */ mpz_mulmod(w, w, w, ecn, u); /* w = (u+v)^2 % n */ mpz_mulmod(v, v, v, ecn, u); /* v = (u-v)^2 % n */ mpz_set(u, xin); mpz_mulmod(xout, w, zin, ecn, w); mpz_mulmod(zout, v, u, ecn, w); /* 6 mulmods, 6 adds */ } /* (x2:z2) = 2(x1:z1) */ static void ec_double(mpz_t x2, mpz_t z2, mpz_t x1, mpz_t z1) { mpz_add(u, x1, z1); mpz_mulmod(u, u, u, ecn, w); /* u = (x1+z1)^2 % n */ mpz_sub(v, x1, z1); mpz_mulmod(v, v, v, ecn, w); /* v = (x1-z1)^2 % n */ mpz_mulmod(x2, u, v, ecn, w); /* x2 = uv % n */ mpz_sub(w, u, v); /* w = u-v = 4(x1 * z1) */ mpz_mulmod(u, b, w, ecn, z2); mpz_add(u, u, v); /* u = (v+b*w) mod n */ mpz_mulmod(z2, w, u, ecn, v); /* z2 = (w*u) mod n */ /* 5 mulmods, 4 adds */ } /* See http://alexandria.tue.nl/extra2/200311829.pdf for lots of discussion * and algorithms for various addition chains. */ #ifndef USE_PRAC static void ec_mult(UV k, mpz_t x, mpz_t z) { int l, r; r = --k; l = -1; while (r != 1) { r >>= 1; l++; } if (k & ( UVCONST(1)<= 1) { if (k & ( UVCONST(1)<=n ) return(ADD*n); d = n - r; e = 2 * r - n; c = DUP + ADD; /* initial double and final add */ while (d != e) { if (d < e) { r = d; d = e; e = r; } if (4 * d <= 5 * e && ((d + e) % 3) == 0) { /*C1*/ d = (2 * d - e) / 3; e = (e - d) / 2; c += 3 * ADD; /* 3 adds */ } else if (4 * d <= 5 * e && (d - e) % 6 == 0) { /*C2*/ d = (d - e) / 2; c += ADD + DUP; /* one add, one double */ } else if (d <= 4 * e) { /*C3*/ d -= e; c += ADD; /* one add */ } else if ((d + e) % 2 == 0) { /*C4*/ d = (d - e) / 2; c += ADD + DUP; /* one add, one double */ } else if (d % 2 == 0) { /*C5*/ d /= 2; c += ADD + DUP; /* one add, one double */ } else if (d % 3 == 0) { /*C6*/ d = d / 3 - e; c += 3 * ADD + DUP; /* three adds, one double */ } else if ((d + e) % 3 == 0) { /*C7*/ d = (d - 2 * e) / 3; c += 3 * ADD + DUP; /* three adds, one double */ } else if ((d - e) % 3 == 0) { /*C8*/ d = (d - e) / 3; c += 3 * ADD + DUP; /* three adds, one double */ } else { /*C9*/ e /= 2; c += ADD + DUP; /* one add, one double */ } } return(c); } #define SWAP(a, b) \ t = x##a; x##a = x##b; x##b = t; t = z##a; z##a = z##b; z##b = t; /* PRAC: computes kP from P=(x:z) and puts the result in (x:z). Assumes k>2.*/ static void ec_mult(UV k, mpz_t x, mpz_t z) { unsigned int d, e, r, i; __mpz_struct *xA, *zA, *xB, *zB, *xC, *zC, *xT, *zT, *xT2, *zT2, *t; static double const val[] = {1.61803398875, 1.72360679775, 1.618347119656, 1.617914406529, 1.58017872826}; /* chooses the best value of val */ r = ADD * k; i = 0; for (d = 0; d < 5; d++) { e = lucas_cost(k, val[d]); if (e < r) { r = e; i = d; } } r = (unsigned int)((double)k / val[i] + 0.5); /* A=(x:z) B=(x1:z1) C=(x2:z2) T=T1=(x3:z3) T2=(x4:z4) */ xA=x; zA=z; xB=x1; zB=z1; xC=x2; zC=z2; xT=x3; zT=z3; xT2=x4; zT2=z4; /* first iteration always begins by Condition 3, then a swap */ d = k - r; e = 2 * r - k; mpz_set(xB,xA); mpz_set(zB,zA); /* B=A */ mpz_set(xC,xA); mpz_set(zC,zA); /* C=A */ ec_double(xA,zA,xA,zA); /* A=2*A */ while (d != e) { if (d < e) { r = d; d = e; e = r; SWAP(A,B); } /* do the first line of Table 4 whose condition qualifies */ if (4 * d <= 5 * e && ((d + e) % 3) == 0) { /* condition 1 */ d = (2 * d - e) / 3; e = (e - d) / 2; ec_add3(xT,zT,xA,zA,xB,zB,xC,zC); /* T = f(A,B,C) */ ec_add3(xT2,zT2,xT,zT,xA,zA,xB,zB); /* T2= f(T,A,B) */ ec_add3(xB,zB,xB,zB,xT,zT,xA,zA); /* B = f(B,T,A) */ SWAP(A,T2); } else if (4 * d <= 5 * e && (d - e) % 6 == 0) { /* condition 2 */ d = (d - e) / 2; ec_add3(xB,zB,xA,zA,xB,zB,xC,zC); /* B = f(A,B,C) */ ec_double(xA,zA,xA,zA); /* A = 2*A */ } else if (d <= (4 * e)) { /* condition 3 */ d -= e; ec_add3(xC,zC,xB,zB,xA,zA,xC,zC); /* C = f(B,A,C) */ SWAP(B,C); } else if ((d + e) % 2 == 0) { /* condition 4 */ d = (d - e) / 2; ec_add3(xB,zB,xB,zB,xA,zA,xC,zC); /* B = f(B,A,C) */ ec_double(xA,zA,xA,zA); /* A = 2*A */ } else if (d % 2 == 0) { /* condition 5 */ d /= 2; ec_add3(xC,zC,xC,zC,xA,zA,xB,zB); /* C = f(C,A,B) */ ec_double(xA,zA,xA,zA); /* A = 2*A */ } else if (d % 3 == 0) { /* condition 6 */ d = d / 3 - e; ec_double(xT,zT,xA,zA); /* T = 2*A */ ec_add3(xT2,zT2,xA,zA,xB,zB,xC,zC); /* T2= f(A,B,C) */ ec_add3(xA,zA,xT,zT,xA,zA,xA,zA); /* A = f(T,A,A) */ ec_add3(xC,zC,xT,zT,xT2,zT2,xC,zC); /* C = f(T,T2,C) */ SWAP(B,C); } else if ((d + e) % 3 == 0) { /* condition 7 */ d = (d - 2 * e) / 3; ec_add3(xT,zT,xA,zA,xB,zB,xC,zC); /* T = f(A,B,C) */ ec_add3(xB,zB,xT,zT,xA,zA,xB,zB); /* B = f(T1,A,B) */ ec_double(xT,zT,xA,zA); ec_add3(xA,zA,xA,zA,xT,zT,xA,zA); /* A = 3*A */ } else if ((d - e) % 3 == 0) { /* condition 8 */ d = (d - e) / 3; ec_add3(xT,zT,xA,zA,xB,zB,xC,zC); /* T = f(A,B,C) */ ec_add3(xC,zC,xC,zC,xA,zA,xB,zB); /* C = f(A,C,B) */ SWAP(B,T); ec_double(xT,zT,xA,zA); ec_add3(xA,zA,xA,zA,xT,zT,xA,zA); /* A = 3*A */ } else { /* condition 9 */ e /= 2; ec_add3(xC,zC,xC,zC,xB,zB,xA,zA); /* C = f(C,B,A) */ ec_double(xB,zB,xB,zB); /* B = 2*B */ } } ec_add3(xA,zA,xA,zA,xB,zB,xC,zC); if (x!=xA) { mpz_set(x,xA); mpz_set(z,zA); } } #endif /* PRAC */ #define NORMALIZE(f, u, v, x, z, n) \ mpz_gcdext(f, u, NULL, z, n); \ found = mpz_cmp_ui(f, 1); \ if (found) break; \ mpz_mulmod(x, x, u, n, v); \ mpz_set_ui(z, 1); static int ec_stage2(UV B1, UV B2, mpz_t x, mpz_t z, mpz_t f) { UV D, i, m; mpz_t* nqx = 0; mpz_t g, one; int found; PRIME_ITERATOR(iter); do { NORMALIZE(f, u, v, x, z, ecn); D = sqrt( (double)B2 / 2.0 ); if (D%2) D++; /* We really only need half of these. Only even values used. */ Newz(0, nqx, 2*D+1, mpz_t); mpz_init_set(nqx[1], x); mpz_init_set_ui(g, 1); mpz_init_set_ui(one, 1); for (i = 2; i <= 2*D; i++) { if (i % 2) { mpz_set(x2, nqx[(i+1)/2]); mpz_set_ui(z2, 1); ec_add(x2, z2, nqx[(i-1)/2], one, x); } else { ec_double(x2, z2, nqx[i/2], one); } mpz_init_set(nqx[i], x2); NORMALIZE(f, u, v, nqx[i], z2, ecn); } if (found) break; mpz_set(x1, x); mpz_set(z1, z); mpz_set(x, nqx[2*D-1]); mpz_set_ui(z, 1); /* See Zimmermann, "20 Years of ECM" slides, 2006, page 11-12 */ for (m = 1; m < B2+D; m += 2*D) { if (m != 1) { mpz_set(x2, x1); mpz_set(z2, z1); ec_add(x1, z1, nqx[2*D], one, x); NORMALIZE(f, u, v, x1, z1, ecn); mpz_set(x, x2); mpz_set(z, z2); } if (m+D > B1 && m >= D) { prime_iterator_setprime(&iter, m-D-1); for (i = prime_iterator_next(&iter); i < m; i = prime_iterator_next(&iter)) { /* if (m+D-i<1 || m+D-i>2*D) croak("index %lu range\n",i-(m-D)); */ mpz_sub(w, x1, nqx[m+D-i]); mpz_mulmod(g, g, w, ecn, u); } for ( ; i <= m+D; i = prime_iterator_next(&iter)) { if (i > m && !prime_iterator_isprime(&iter, m+m-i)) { /* if (i-m<1 || i-m>2*D) croak("index %lu range\n",i-(m-D)); */ mpz_sub(w, x1, nqx[i-m]); mpz_mulmod(g, g, w, ecn, u); } } mpz_gcd(f, g, ecn); found = mpz_cmp_ui(f, 1); if (found) break; } } } while (0); prime_iterator_destroy(&iter); if (nqx != 0) { for (i = 1; i <= 2*D; i++) { if (nqx[i] != 0) mpz_clear(nqx[i]); } Safefree(nqx); mpz_clear(g); mpz_clear(one); } if (found && !mpz_cmp(f, ecn)) found = 0; return (found) ? 2 : 0; } int _GMP_ecm_factor_projective(mpz_t n, mpz_t f, UV B1, UV B2, UV ncurves) { mpz_t sigma, a, x, z; UV i, curve, q, k; int found = 0; int _verbose = get_verbose_level(); TEST_FOR_2357(n, f); if (B2 < B1) B2 = 100*B1; /* time(S1) == time(S2) ~ 125 */ mpz_init_set(ecn, n); mpz_init(x); mpz_init(z); mpz_init(a); mpz_init(b); mpz_init(u); mpz_init(v); mpz_init(w); mpz_init(sigma); mpz_init(x1); mpz_init(z1); mpz_init(x2); mpz_init(z2); #ifdef USE_PRAC mpz_init(x3); mpz_init(z3); mpz_init(x4); mpz_init(z4); #endif if (_verbose>2) gmp_printf("# ecm trying %Zd (B1=%lu B2=%lu ncurves=%lu)\n", n, (unsigned long)B1, (unsigned long)B2, (unsigned long)ncurves); for (curve = 0; curve < ncurves; curve++) { PRIME_ITERATOR(iter); do { mpz_isaac_urandomm(sigma, n); } while (mpz_cmp_ui(sigma, 5) <= 0); mpz_mul_ui(w, sigma, 4); mpz_mod(v, w, n); /* v = 4σ */ mpz_mul(x, sigma, sigma); mpz_sub_ui(w, x, 5); mpz_mod(u, w, n); /* u = σ^2-5 */ mpz_mul(x, u, u); mpz_mulmod(x, x, u, n, w); /* x = u^3 */ mpz_mul(z, v, v); mpz_mulmod(z, z, v, n, w); /* z = v^3 */ mpz_mul(b, x, v); mpz_mul_ui(w, b, 4); mpz_mod(b, w, n); /* b = 4 u^3 v */ mpz_sub(a, v, u); mpz_mul(w, a, a); mpz_mulmod(w, w, a, n, w); mpz_mul_ui(a, u, 3); mpz_add(a, a, v); mpz_mul(w, w, a); mpz_mod(a, w, n); /* a = ((v-u)^3 * (3*u + v)) % n */ mpz_gcdext(f, u, NULL, b, n); found = mpz_cmp_ui(f, 1); if (found) { if (!mpz_cmp(f, n)) { found = 0; continue; } break; } mpz_mul(a, a, u); mpz_sub_ui(a, a, 2); mpz_mod(a, a, n); mpz_add_ui(b, a, 2); if (mpz_mod_ui(w, b, 2)) mpz_add(b, b, n); mpz_tdiv_q_2exp(b, b, 1); if (mpz_mod_ui(w, b, 2)) mpz_add(b, b, n); mpz_tdiv_q_2exp(b, b, 1); /* Use sigma to collect possible factors */ mpz_set_ui(sigma, 1); /* Stage 1 */ for (q = 2; q < B1; q *= 2) ec_double(x, z, x, z); mpz_mulmod(sigma, sigma, x, ecn, w); i = 15; for (q = prime_iterator_next(&iter); q < B1; q = prime_iterator_next(&iter)) { /* PRAC is a little faster with: * for (k = 1; k <= B1/q; k *= q) * ec_mult(q, x, z); * but binary multiplication is much slower that way. */ for (k = q; k <= B1/q; k *= q) ; ec_mult(k, x, z); mpz_mulmod(sigma, sigma, x, ecn, w); if (i++ % 32 == 0) { mpz_gcd(f, sigma, ecn); if (mpz_cmp_ui(f, 1)) break; } } prime_iterator_destroy(&iter); /* Find factor in S1 */ do { NORMALIZE(f, u, v, x, z, n); } while (0); if (!found) { mpz_gcd(f, sigma, ecn); found = mpz_cmp_ui(f, 1); } if (found) { if (!mpz_cmp(f, n)) { found = 0; continue; } break; } /* Stage 2 */ if (!found && B2 > B1) found = ec_stage2(B1, B2, x, z, f); if (found) { if (!mpz_cmp(f, n)) { found = 0; continue; } break; } } if (_verbose>2) { if (found) gmp_printf("# ecm: %Zd in stage %d\n", f, found); else gmp_printf("# ecm: no factor\n"); } mpz_clear(ecn); mpz_clear(x); mpz_clear(z); mpz_clear(a); mpz_clear(b); mpz_clear(u); mpz_clear(v); mpz_clear(w); mpz_clear(sigma); mpz_clear(x1); mpz_clear(z1); mpz_clear(x2); mpz_clear(z2); #ifdef USE_PRAC mpz_clear(x3); mpz_clear(z3); mpz_clear(x4); mpz_clear(z4); #endif return found; } Math-Prime-Util-GMP-0.52/isaac.h0000644000175000017500000000046713054533725014576 0ustar danadana#ifndef MPU_ISAAC_H #define MPU_ISAAC_H #include "ptypes.h" extern void isaac_init(uint32_t bytes, const unsigned char* data); extern uint32_t isaac_rand32(void); extern uint32_t isaac_rand(uint32_t n); extern void isaac_rand_bytes(uint32_t bytes, unsigned char* data); extern int isaac_seeded(void); #endif Math-Prime-Util-GMP-0.52/primality.h0000644000175000017500000000312413054533437015521 0ustar danadana#ifndef MPU_GMPPRIMALITY_H #define MPU_GMPPRIMALITY_H #include #include "ptypes.h" extern int is_pseudoprime(mpz_t n, mpz_t a); extern int is_euler_pseudoprime(mpz_t n, mpz_t a); extern int miller_rabin(mpz_t n, mpz_t a); extern int miller_rabin_ui(mpz_t n, unsigned long a); extern int miller_rabin_random(mpz_t n, UV numbases, char* seedstr); extern int _GMP_is_lucas_pseudoprime(mpz_t n, int strength); extern int _GMP_is_almost_extra_strong_lucas_pseudoprime(mpz_t n, UV incr); extern int _GMP_is_frobenius_underwood_pseudoprime(mpz_t n); extern int _GMP_is_frobenius_khashin_pseudoprime(mpz_t n); extern int is_perrin_pseudoprime(mpz_t n, int restricted); extern int is_euler_plumb_pseudoprime(mpz_t n); extern int is_frobenius_pseudoprime(mpz_t n, IV P, IV Q); extern int is_frobenius_cp_pseudoprime(mpz_t n, UV ntests); extern void lucas_seq(mpz_t U, mpz_t V, mpz_t n, IV P, IV Q, mpz_t k, mpz_t Qk, mpz_t t); extern void alt_lucas_seq(mpz_t U, mpz_t V, mpz_t n, IV P, IV Q, mpz_t k, mpz_t Qk, mpz_t t); extern void lucasuv(mpz_t Uh, mpz_t Vl, IV P, IV Q, mpz_t k); extern int lucas_lehmer(UV p); extern int llr(mpz_t N); extern int proth(mpz_t N); extern int is_proth_form(mpz_t N); extern int _GMP_BPSW(mpz_t n); extern int is_deterministic_miller_rabin_prime(mpz_t n); /* assumes n is BPSW */ extern int is_miller_prime(mpz_t n, int assume_grh); extern int is_bpsw_dmr_prime(mpz_t n); extern int _GMP_is_prime(mpz_t n); extern int _GMP_is_prob_prime(mpz_t n); extern int _GMP_is_provable_prime(mpz_t n, char ** prooftext); #endif Math-Prime-Util-GMP-0.52/pbrent63.h0000644000175000017500000000031313663067455015157 0ustar danadana#ifndef MPU_PBRENT63_H #define MPU_PBRENT63_H #include #include "ptypes.h" extern int pbrent63(mpz_t n, mpz_t f, UV rounds); extern int uvpbrent63(UV n, UV *factors, UV rounds, UV a); #endif Math-Prime-Util-GMP-0.52/.travis.yml0000644000175000017500000000072013025437621015442 0ustar danadanalanguage: "perl" perl: - "5.22" - "5.16" - "5.10" addons: apt: packages: - libgmp-dev - libmpfr-dev before_install: - cpanm Test::Pod # optional dependency install: - cpanm -v --installdeps --notest --mirror http://cpan.mirrors.travis-ci.org . script: "perl Makefile.PL; make test" # branches: # only: # - master notifications: recipients: - dana@acm.org email: on_success: change on_failure: always #env: Math-Prime-Util-GMP-0.52/squfof126.c0000644000175000017500000001766113665605622015255 0ustar danadana /* GMP version of Racing SQUFOF for up to 126-bit inputs. * Oct 2017 - Dana Jacobsen * * Based heavily on Ben Buhrow's racing SQUFOF implementation. * All factoring operations use 64-bit unsigned longs so it's quite fast. * * Realistically it has decent performance up to about 80 bits. * From 54 to 80 it is faster to first try p-1 to B1 = 1k-16k. * * As of 2017, the fastest method for 64-bit is x86-64 Pollard-Rho. * After that, a tinyqs such as Jason P's cofactorize-siqs seems fastest. */ #include #include #include "ptypes.h" #include "squfof126.h" #define TEST_FOR_2357(n, f) \ { \ if (mpz_divisible_ui_p(n, 2)) { mpz_set_ui(f, 2); return 1; } \ if (mpz_divisible_ui_p(n, 3)) { mpz_set_ui(f, 3); return 1; } \ if (mpz_divisible_ui_p(n, 5)) { mpz_set_ui(f, 5); return 1; } \ if (mpz_divisible_ui_p(n, 7)) { mpz_set_ui(f, 7); return 1; } \ if (mpz_cmp_ui(n, 121) < 0) { return 0; } \ } /* Pick type for 64-bit core, plus methods to get/set from GMP */ #if HAVE_STD_U64 #define SQUFOF_TYPE uint64_t #elif BITS_PER_WORD == 64 #define SQUFOF_TYPE UV #else #define SQUFOF_TYPE unsigned long long #endif static INLINE SQUFOF_TYPE mpz_get64(mpz_t n) { SQUFOF_TYPE v = mpz_getlimbn(n,0); if (GMP_LIMB_BITS < 64 || sizeof(mp_limb_t) < sizeof(SQUFOF_TYPE)) v |= ((SQUFOF_TYPE)mpz_getlimbn(n,1)) << 32; return v; } static INLINE void mpz_set64(mpz_t n, SQUFOF_TYPE v) { if (v <= 0xFFFFFFFFUL || sizeof(unsigned long int) >= sizeof(SQUFOF_TYPE)) { mpz_set_ui(n, v); } else { uint32_t upper = (v >> 32), lower = v & 0xFFFFFFFFUL; mpz_set_ui(n, upper); mpz_mul_2exp(n, n, 32); mpz_add_ui(n, n, lower); } } typedef struct { int valid; SQUFOF_TYPE P; SQUFOF_TYPE bn; SQUFOF_TYPE Qn; SQUFOF_TYPE Q0; SQUFOF_TYPE b0; SQUFOF_TYPE it; SQUFOF_TYPE imax; SQUFOF_TYPE mult; } mult_t; /* Return 0 or factor */ static SQUFOF_TYPE squfof_unit(mpz_t n, mult_t* mult_save, mpz_t t) { SQUFOF_TYPE imax,i,j,Q0,Qn,bn,b0,P,bbn,Ro,S,So,t1,t2; P = mult_save->P; bn = mult_save->bn; Qn = mult_save->Qn; Q0 = mult_save->Q0; b0 = mult_save->b0; i = mult_save->it; imax = i + mult_save->imax; #define SQUARE_SEARCH_ITERATION \ t1 = P; \ P = bn*Qn - P; \ t2 = Qn; \ Qn = Q0 + bn*(t1-P); \ Q0 = t2; \ bn = (b0 + P) / Qn; \ i++; while (1) { if (i & 0x1) { SQUARE_SEARCH_ITERATION; } /* i is now even */ while (1) { /* We need to know P, bn, Qn, Q0, iteration count, i from prev */ if (i >= imax) { /* save state and try another multiplier. */ mult_save->P = P; mult_save->bn = bn; mult_save->Qn = Qn; mult_save->Q0 = Q0; mult_save->it = i; return 0; } SQUARE_SEARCH_ITERATION; /* Even iteration */ /* Check if Qn is a perfect square */ t2 = Qn & 127; if (!((t2*0x8bc40d7d) & (t2*0xa1e2f5d1) & 0x14020a)) { t1 = (uint32_t) sqrt(Qn); if (Qn == t1*t1) break; } SQUARE_SEARCH_ITERATION; /* Odd iteration */ } S = t1; mult_save->it = i; /* Reduce to G0 */ Ro = P + S*((b0 - P)/S); /* So = (n - (UV)Ro*(UV)Ro)/(UV)S; */ mpz_set64(t, Ro); mpz_mul(t, t, t); mpz_sub(t, n, t); mpz_div_ui(t, t, S); /* S is 32-bit so this is ok */ So = mpz_get64(t); bbn = (b0+Ro)/So; #define SYMMETRY_POINT_ITERATION \ t1 = Ro; \ Ro = bbn*So - Ro; \ if (Ro == t1) break; \ t2 = So; \ So = S + bbn*(t1-Ro); \ S = t2; \ bbn = (b0+Ro)/So; /* Search for symmetry point, occurs at approximately i/2 */ j = 0; while (1) { SYMMETRY_POINT_ITERATION; SYMMETRY_POINT_ITERATION; SYMMETRY_POINT_ITERATION; SYMMETRY_POINT_ITERATION; if (j++ > imax) { mult_save->valid = 0; return 0; } } mpz_set64(t, Ro); mpz_gcd(t, t, n); t1 = mpz_get64(t); if (t1 > 1) return t1; } } /* Gower and Wagstaff 2008: * http://www.ams.org/journals/mcom/2008-77-261/S0025-5718-07-02010-8/ * Section 5.3. I've added some with 13,17,19. Sorted by F(). */ static const SQUFOF_TYPE squfof_multipliers[] = #if 0 { 3*5*7*11, 3*5*7, 3*5*11, 3*5, 3*7*11, 3*7, 5*7*11, 5*7, 3*11, 3, 5*11, 5, 7*11, 7, 11, 1 }; #endif #if 0 { 3*5*7*11, 3*5*7, 3*5*7*11*13, 3*5*7*13, 3*5*7*11*17, 3*5*11, 3*5*7*17, 3*5, 3*5*7*11*19, 3*5*11*13,3*5*7*19, 3*5*7*13*17, 3*5*13, 3*7*11, 3*7, 5*7*11, 3*7*13, 5*7, 3*5*17, 5*7*13, 3*5*19, 3*11, 3*7*17, 3, 3*11*13, 5*11, 3*7*19, 3*13, 5, 5*11*13, 5*7*19, 5*13, 7*11, 7, 3*17, 7*13, 11, 1 }; #endif #if 1 { 33*1680, 11*1680, 66*1680, 3*1680, 2*1680, 6*1680, 22*1680, 78*1680, 1*1680, 26*1680, 39*1680, 13*1680,102*1680, 30*1680, 34*1680, 10*1680, 15*1680, 51*1680, 5*1680, 57*1680, 17*1680, 19*1680, 3*5*7*11, 3*5*7, 3*5*7*11*13, 3*5*7*13, 3*5*7*11*17, 3*5*11, 3*5*7*17, 3*5, 3*5*7*11*19, 3*5*11*13,3*5*7*19, 3*5*7*13*17, 3*5*13, 3*7*11, 3*7, 5*7*11, 3*7*13, 5*7, 3*5*17, 5*7*13, 3*5*19, 3*11, 3*7*17, 3, 3*11*13, 5*11, 3*7*19, 3*13, 5, 5*11*13, 5*7*19, 5*13, 7*11, 7, 3*17, 7*13, 11, 1 }; #endif #define NSQUFOF_MULT (sizeof(squfof_multipliers)/sizeof(squfof_multipliers[0])) int squfof126(mpz_t n, mpz_t f, UV rounds) { mpz_t t, nn64; mult_t mult_save[NSQUFOF_MULT]; SQUFOF_TYPE i, mult, f64, f64red, sqrtnn64, rounds_done = 0; int mults_racing = NSQUFOF_MULT; const uint32_t max_bits = 2 * sizeof(SQUFOF_TYPE)*8 - 2; if (sizeof(SQUFOF_TYPE) < 8 || mpz_sizeinbase(n,2) > max_bits) { mpz_set(f, n); return 0; } TEST_FOR_2357(n, f); for (i = 0; i < NSQUFOF_MULT; i++) { mult_save[i].valid = -1; mult_save[i].it = 0; } mpz_init(t); mpz_init(nn64); /* Process the multipliers a little at a time: 0.5 * (n*mult)^1/5 */ while (mults_racing > 0 && rounds_done < rounds) { for (i = 0; i < NSQUFOF_MULT && rounds_done < rounds; i++) { if (mult_save[i].valid == 0) continue; mult = squfof_multipliers[i]; mpz_mul_ui(nn64, n, mult); if (mult_save[i].valid == -1) { if (mpz_sizeinbase(nn64,2) > max_bits) { mult_save[i].valid = 0; /* This multiplier would overflow */ mults_racing--; continue; } mpz_sqrt(t,nn64); sqrtnn64 = mpz_get64(t); mpz_mul(t,t,t); mpz_sub(t, nn64, t); mult_save[i].valid = 1; mult_save[i].Q0 = 1; mult_save[i].b0 = sqrtnn64; mult_save[i].P = sqrtnn64; mult_save[i].Qn = mpz_get64(t); /* nn64 - isqrt(nn64)^2 */ if (mult_save[i].Qn == 0) { mpz_clear(t); mpz_clear(nn64); mpz_set64(f, sqrtnn64); return 1; /* nn64 is a perfect square */ } mpz_root(t, nn64, 5); mult_save[i].bn = (2 * sqrtnn64) / mult_save[i].Qn; /* n < 127-bit */ mult_save[i].it = 0; mult_save[i].mult = mult; mult_save[i].imax = (SQUFOF_TYPE) (0.5 * mpz_get64(t)); if (mult_save[i].imax < 20) mult_save[i].imax = 20; } if (mults_racing == 1 || mult_save[i].imax > (rounds-rounds_done)) mult_save[i].imax = (rounds - rounds_done); f64 = squfof_unit(nn64, &mult_save[i], t); if (f64 > 1) { mpz_set64(t, f64); f64red = f64 / mpz_gcd_ui(t, t, mult); if (f64red > 1) { mpz_clear(t); mpz_clear(nn64); mpz_set64(f, f64red); return 1; } /* Found trivial factor. Quit working with this multiplier. */ mult_save[i].valid = 0; } if (mult_save[i].valid == 0) mults_racing--; rounds_done += mult_save[i].imax; /* Assume we did all rounds */ } } /* No factors found */ mpz_clear(t); mpz_clear(nn64); mpz_set(f, n); return 0; } Math-Prime-Util-GMP-0.52/squfof126.h0000644000175000017500000000022213663067455015247 0ustar danadana#ifndef MPU_SQUFOF126_H #define MPU_SQUFOF126_H #include #include "ptypes.h" extern int squfof126(mpz_t n, mpz_t f, UV rounds); #endif Math-Prime-Util-GMP-0.52/factor.c0000644000175000017500000013113413674026201014755 0ustar danadana#include #include "ptypes.h" #include "factor.h" #include "primality.h" #include "prime_iterator.h" #include "utility.h" #include "pbrent63.h" #include "squfof126.h" #include "ecm.h" #include "tinyqs.h" #include "simpqs.h" #define _GMP_ECM_FACTOR(n, f, b1, ncurves) \ _GMP_ecm_factor_projective(n, f, b1, 0, ncurves) #define NPRIMES_SMALL 2000 static unsigned short primes_small[NPRIMES_SMALL]; void _init_factor(void) { UV pn; PRIME_ITERATOR(iter); primes_small[0] = 0; primes_small[1] = 2; for (pn = 2; pn < NPRIMES_SMALL; pn++) { primes_small[pn] = prime_iterator_next(&iter); } prime_iterator_destroy(&iter); } /* Max number of factors on the unfactored stack, not the max total factors. * This is used when we split n into two or more composites. Since we work * on the smaller of the composites first, this rarely goes above 10 even * with thousands of non-trivial factors. */ #define MAX_FACTORS 128 static int add_factor(int nfactors, mpz_t f, mpz_t** pfactors, int** pexponents) { int i, j, cmp = 0; if (nfactors == 0) { /* First factor */ mpz_t *factors; int* exponents; New(0, factors, 10, mpz_t); New(0, exponents, 10, int); mpz_init_set(factors[0], f); exponents[0] = 1; *pfactors = factors; *pexponents = exponents; return 1; } else if (mpz_cmp((*pfactors)[nfactors-1],f) < 0) { /* New biggest factor */ if (!(nfactors % 10)) { Renew(*pfactors, nfactors+10, mpz_t); Renew(*pexponents, nfactors+10, int); } mpz_init_set((*pfactors)[nfactors], f); (*pexponents)[nfactors] = 1; return nfactors+1; } /* Insert in sorted order. Find out where we will put it. */ for (i = 0; i < nfactors; i++) if ((cmp = mpz_cmp((*pfactors)[i], f)) >= 0) break; if (cmp == 0) { /* Duplicate factor */ (*pexponents)[i]++; return nfactors; } /* factor[i] > f. Move everything from i to nfactors up. */ if (!(nfactors % 10)) { Renew(*pfactors, nfactors+10, mpz_t); Renew(*pexponents, nfactors+10, int); } mpz_init((*pfactors)[nfactors]); for (j = nfactors; j > i; j--) { mpz_set( (*pfactors)[j], (*pfactors)[j-1] ); (*pexponents)[j] = (*pexponents)[j-1]; } mpz_set((*pfactors)[i], f); (*pexponents)[i] = 1; return nfactors+1; } #define ADD_FACTOR_UI(f, t) \ do { \ mpz_set_ui(f, t); \ nfactors = add_factor(nfactors, f, &factors, &exponents); \ } while (0) #define ADD_FACTOR(f) \ do { nfactors = add_factor(nfactors, f, &factors, &exponents); } while (0) int factor(mpz_t input_n, mpz_t* pfactors[], int* pexponents[]) { mpz_t tofac_stack[MAX_FACTORS]; int ntofac = 0; mpz_t* factors = 0; int* exponents = 0; int nfactors = 0; mpz_t f, n; UV tf, tlim; mpz_init_set(n, input_n); mpz_init(f); if (mpz_cmp_ui(n, 4) < 0) { if (mpz_cmp_ui(n, 1) != 0) /* 1 should return no results */ ADD_FACTOR(n); goto DONE; } /* Trial factor to small limit */ while (mpz_even_p(n)) { ADD_FACTOR_UI(f, 2); mpz_divexact_ui(n, n, 2); } tlim = (mpz_sizeinbase(n,2) > 80) ? 4001 : 16001; { UV sp, p, un; un = (mpz_cmp_ui(n,2*tlim*tlim) >= 0) ? 2*tlim*tlim : mpz_get_ui(n); for (sp = 2, p = primes_small[sp]; p < tlim && p*p <= un; p = primes_small[++sp]) { while (mpz_divisible_ui_p(n, p)) { ADD_FACTOR_UI(f, p); mpz_divexact_ui(n, n, p); un = (mpz_cmp_ui(n,2*tlim*tlim) > 0) ? 2*tlim*tlim : mpz_get_ui(n); } } if (un < p*p) { if (un > 1) ADD_FACTOR(n); goto DONE; } } /* Power factor */ tf = power_factor(n, f); if (tf) { mpz_t* pow_factors; int* pow_exponents; int pow_nfactors, i, j; pow_nfactors = factor(f, &pow_factors, &pow_exponents); for (i = 0; i < pow_nfactors; i++) pow_exponents[i] *= tf; for (i = 0; i < pow_nfactors; i++) for (j = 0; j < pow_exponents[i]; j++) ADD_FACTOR(pow_factors[i]); clear_factors(pow_nfactors, &pow_factors, &pow_exponents); goto DONE; } do { /* loop over each remaining factor */ while ( mpz_cmp_ui(n, tlim*tlim) > 0 && !_GMP_is_prob_prime(n) ) { int success = 0; int o = get_verbose_level(); UV B1 = 5000; UV nbits = mpz_sizeinbase(n, 2); /* * This set of operations is meant to provide good performance for * "random" numbers as input. Hence we stack lots of effort up front * looking for small factors: prho and pbrent are ~ O(f^1/2) where * f is the smallest factor. SQUFOF is O(N^1/4), so arguable not * any better. p-1 and ECM are quite useful for pulling out small * factors (6-20 digits). * * Factoring a 778-digit number consisting of 101 8-digit factors * should complete in under 3 seconds. Factoring numbers consisting * of many 12-digit or 14-digit primes should take under 10 seconds. */ /* Handle small inputs here */ if (nbits <= 63) { if (!success) success = pbrent63(n, f, 400000); if (success&&o) {gmp_printf("UV Rho-Brent found factor %Zd\n", f);o=0;} } if (nbits >= 65 && nbits <= 126) { if (!success) success = _GMP_pminus1_factor(n, f, 5000, 5000); if (success&&o) {gmp_printf("p-1 (%dk) found factor %Zd\n",5000,f);o=0;} if (!success) success = tinyqs(n, f); if (success&&o) {gmp_printf("tinyqs found factor %Zd\n", f);o=0;} } /* It's possible the previous calls failed or weren't available */ if (nbits <= 53) { if (!success) success = squfof126(n, f, 400000); if (success&&o) {gmp_printf("UV SQUFOF126 found factor %Zd\n", f);o=0;} } else if (nbits <= 77) { int sb1 = (nbits < 58) ? 1 : (nbits < 63) ? 2 : (nbits < 72) ? 4 : 10; if (!success) success = _GMP_pminus1_factor(n, f, sb1*1000, sb1*10000); if (success&&o) {gmp_printf("p-1 (%dk) found factor %Zd\n",sb1,f);o=0;} if (!success) success = squfof126(n, f, 1000000); if (success&&o) {gmp_printf("SQUFOF126 found factor %Zd\n", f);o=0;} } /* Make sure it isn't a perfect power */ if (!success) success = (int)power_factor(n, f); if (success&&o) {gmp_printf("perfect power found factor %Zd\n", f);o=0;} if (!success) success = _GMP_pminus1_factor(n, f, 20000, 200000); if (success&&o) {gmp_printf("p-1 (20k) found factor %Zd\n", f);o=0;} /* Small ECM to find small factors */ if (!success) success = _GMP_ECM_FACTOR(n, f, 200, 4); if (success&&o) {gmp_printf("tiny ecm (200) found factor %Zd\n", f);o=0;} if (!success) success = _GMP_ECM_FACTOR(n, f, 600, 20); if (success&&o) {gmp_printf("tiny ecm (600) found factor %Zd\n", f);o=0;} if (!success) success = _GMP_ECM_FACTOR(n, f, 2000, 10); if (success&&o) {gmp_printf("tiny ecm (2000) found factor %Zd\n", f);o=0;} /* Small p-1 */ if (!success) { if (nbits < 100 || nbits >= 160) { success = _GMP_pminus1_factor(n, f, 200000, 3000000); if (success&&o) {gmp_printf("p-1 (200k) found factor %Zd\n", f);o=0;} } } /* Set ECM parameters that have a good chance of success */ if (!success) { UV curves; if (nbits < 100){ B1 = 5000; curves = 20; } else if (nbits < 128){ B1 = 10000; curves = 2; } /* go to QS */ else if (nbits < 160){ B1 = 20000; curves = 2; } /* go to QS */ else if (nbits < 192){ B1 = 30000; curves = 20; } else if (nbits < 224){ B1 = 40000; curves = 40; } else if (nbits < 256){ B1 = 80000; curves = 40; } else if (nbits < 512){ B1 = 160000; curves = 80; } else { B1 = 320000; curves = 160; } if (curves > 0) { success = _GMP_ECM_FACTOR(n, f, B1, curves); if (success&&o) {gmp_printf("small ecm (%luk,%lu) found factor %Zd\n", B1/1000, curves, f);o=0;} } } /* QS (30+ digits). Fantastic if it is a semiprime, but can be * slow and a memory hog if not (compared to ECM). Restrict to * reasonable size numbers (< 91 digits). Because of the way it * works, it will generate (possibly) multiple factors for the same * amount of work. Go to some trouble to use them. */ if (!success && mpz_sizeinbase(n,10) >= 30 && nbits < 300) { mpz_t farray[66]; int i, qs_nfactors; for (i = 0; i < 66; i++) mpz_init(farray[i]); qs_nfactors = _GMP_simpqs(n, farray); mpz_set(f, farray[0]); if (qs_nfactors > 2) { /* We found multiple factors */ for (i = 2; i < qs_nfactors; i++) { if (o){gmp_printf("SIMPQS found extra factor %Zd\n",farray[i]);} if (ntofac >= MAX_FACTORS-1) croak("Too many factors\n"); mpz_init_set(tofac_stack[ntofac], farray[i]); ntofac++; mpz_divexact(n, n, farray[i]); } /* f = farray[0], n = farray[1], farray[2..] pushed */ } for (i = 0; i < 66; i++) mpz_clear(farray[i]); success = qs_nfactors > 1; if (success&&o) {gmp_printf("SIMPQS found factor %Zd\n", f);o=0;} } if (!success) success = _GMP_ECM_FACTOR(n, f, 2*B1, 20); if (success&&o) {gmp_printf("ecm (%luk,20) found factor %Zd\n",2*B1/1000,f);o=0;} if (!success) success = _GMP_pbrent_factor(n, f, 1, 1*1024*1024); if (success&&o) {gmp_printf("pbrent (1,1M) found factor %Zd\n", f);o=0;} if (!success) success = _GMP_ECM_FACTOR(n, f, 4*B1, 20); if (success&&o) {gmp_printf("ecm (%luk,20) ecm found factor %Zd\n", 4*B1,f);o=0;} if (!success) success = _GMP_ECM_FACTOR(n, f, 8*B1, 20); if (success&&o) {gmp_printf("ecm (%luk,20) ecm found factor %Zd\n", 8*B1,f);o=0;} /* HOLF in case it's a near-ratio-of-perfect-square */ if (!success) success = _GMP_holf_factor(n, f, 1*1024*1024); if (success&&o) {gmp_printf("holf found factor %Zd\n", f);o=0;} /* Large p-1 with stage 2: B2 = 20*B1 */ if (!success) success = _GMP_pminus1_factor(n,f,5000000,5000000*20); if (success&&o) {gmp_printf("p-1 (5M) found factor %Zd\n", f);o=0;} if (!success) success = _GMP_ECM_FACTOR(n, f, 32*B1, 40); if (success&&o) {gmp_printf("ecm (%luk,40) ecm found factor %Zd\n", 32*B1,f);o=0;} /* if (!success) success = _GMP_pbrent_factor(n, f, 2, 512*1024*1024); if (success&&o) {gmp_printf("pbrent (2,512M) found factor %Zd\n", f);o=0;} */ /* Our method of last resort: ECM with high bmax and many curves*/ if (!success) { UV i; if (get_verbose_level()) gmp_printf("starting large ECM on %Zd\n",n); B1 *= 8; for (i = 0; i < 10; i++) { success = _GMP_ECM_FACTOR(n, f, B1, 100); if (success) break; B1 *= 2; } if (success&&o) {gmp_printf("ecm (%luk,100) ecm found factor %Zd\n", B1,f);o=0;} } if (success) { if (!mpz_divisible_p(n, f) || !mpz_cmp_ui(f, 1) || !mpz_cmp(f, n)) { gmp_printf("n = %Zd f = %Zd\n", n, f); croak("Incorrect factoring"); } } if (!success) { /* TODO: What to do with composites we can't factor? * Push them as "C#####" ? * For now, just push them as if we factored. */ if (get_verbose_level()) gmp_printf("gave up on %Zd\n", n); ADD_FACTOR(n); mpz_set_ui(n, 1); } else { int ndiv = mpz_remove(n, n, f); if (_GMP_is_prob_prime(f)) { /* prime factor */ while (ndiv-- > 0) ADD_FACTOR(f); } else if (ndiv > 1) { /* Repeated non-trivial composite factor */ mpz_t* pow_factors; int* pow_exponents; int pow_nfactors, i, j; pow_nfactors = factor(f, &pow_factors, &pow_exponents); for (i = 0; i < pow_nfactors; i++) pow_exponents[i] *= ndiv; for (i = 0; i < pow_nfactors; i++) for (j = 0; j < pow_exponents[i]; j++) ADD_FACTOR(pow_factors[i]); clear_factors(pow_nfactors, &pow_factors, &pow_exponents); } else { /* One non-trivial composite factor */ if (ntofac >= MAX_FACTORS-1) croak("Too many factors\n"); /* If f < n and both are composites, put n on stack and work on f */ if (mpz_cmp(f, n) < 0 && !_GMP_is_prob_prime(n)) { mpz_init_set(tofac_stack[ntofac++], n); mpz_set(n, f); } else { mpz_init_set(tofac_stack[ntofac++], f); } } } } /* n is now prime or 1 */ if (mpz_cmp_ui(n, 1) > 0) { ADD_FACTOR(n); mpz_set_ui(n, 1); } if (ntofac-- > 0) { mpz_set(n, tofac_stack[ntofac]); mpz_clear(tofac_stack[ntofac]); } } while (mpz_cmp_ui(n, 1) > 0); DONE: mpz_clear(f); mpz_clear(n); *pfactors = factors; *pexponents = exponents; return nfactors; } void clear_factors(int nfactors, mpz_t* pfactors[], int* pexponents[]) { while (nfactors > 0) mpz_clear((*pfactors)[--nfactors]); Safefree(*pfactors); Safefree(*pexponents); } /*****************************************************************************/ void sigma(mpz_t res, mpz_t n, UV k) { mpz_t* factors; mpz_t pk, pke, fmult; int* exponents; int i, j, nfactors; if (mpz_cmp_ui(n, 1) <= 0) { mpz_set_ui(res, (k == 0 && mpz_cmp_ui(n,1) < 0) ? 2 : 1); return; } if (_GMP_is_prob_prime(n)) { mpz_pow_ui(res, n, k); mpz_add_ui(res, res, 1); return; } nfactors = factor(n, &factors, &exponents); if (k == 0) { for (i = 0; i < nfactors; i++) { mpz_set_ui(factors[i], exponents[i]+1); } } else if (k == 1) { mpz_init(pke); mpz_init(fmult); for (i = 0; i < nfactors; i++) { mpz_set(pke, factors[i]); mpz_add_ui(fmult, factors[i], 1); for (j = 1; j < exponents[i]; j++) { mpz_mul(pke, pke, factors[i]); mpz_add(fmult, fmult, pke); } mpz_set(factors[i], fmult); } mpz_clear(fmult); mpz_clear(pke); } else { mpz_init(pk); mpz_init(pke); mpz_init(fmult); for (i = 0; i < nfactors; i++) { mpz_pow_ui(pk, factors[i], k); mpz_add_ui(fmult, pk, 1); mpz_set(pke, pk); for (j = 1; j < exponents[i]; j++) { mpz_mul(pke, pke, pk); mpz_add(fmult, fmult, pke); } mpz_set(factors[i], fmult); } mpz_clear(fmult); mpz_clear(pke); mpz_clear(pk); } mpz_product(factors, 0, nfactors-1); mpz_set(res, factors[0]); clear_factors(nfactors, &factors, &exponents); } static const unsigned long smalldiv[] = {4, 9, 25, 49, 121, 169, 289}; int moebius(mpz_t n) { mpz_t* factors; int* exponents; int i, nfactors, result; if (mpz_sgn(n) < 0) { mpz_neg(n,n); result = moebius(n); mpz_neg(n,n); return result; } if (mpz_sgn(n) == 0) return 0; if (mpz_cmp_ui(n, 1) == 0) return 1; for (i = 0; i < 7; i++) if (mpz_divisible_ui_p(n, smalldiv[i])) return 0; nfactors = factor(n, &factors, &exponents); result = (nfactors % 2) ? -1 : 1; for (i = 0; i < nfactors; i++) if (exponents[i] > 1) { result = 0; break; } clear_factors(nfactors, &factors, &exponents); return result; } int liouville(mpz_t n) { mpz_t* factors; int* exponents; int i, nfactors, result; nfactors = factor(n, &factors, &exponents); for (i = 0, result = 0; i < nfactors; i++) result += exponents[i]; result = (result & 1) ? -1 : 1; clear_factors(nfactors, &factors, &exponents); return result; } void totient(mpz_t tot, mpz_t n_input) { mpz_t t, n; mpz_t* factors; int* exponents; int i, j, nfactors; if (mpz_cmp_ui(n_input, 1) <= 0) { mpz_set(tot, n_input); return; } mpz_init_set(n, n_input); mpz_set_ui(tot, 1); /* Fast reduction of multiples of 2 */ i = mpz_scan1(n, 0); if (i > 0) { if (i > 1) mpz_mul_2exp(tot, tot, i-1); mpz_tdiv_q_2exp(n, n, i); } /* Now factor and calculate totient */ nfactors = factor(n, &factors, &exponents); mpz_init(t); for (i = 0; i < nfactors; i++) { mpz_sub_ui(t, factors[i], 1); for (j = 1; j < exponents[i]; j++) mpz_mul(t, t, factors[i]); mpz_mul(tot, tot, t); } mpz_clear(t); clear_factors(nfactors, &factors, &exponents); mpz_clear(n); } void jordan_totient(mpz_t tot, mpz_t n, unsigned long k) { if (k == 0) { mpz_set_ui(tot, (mpz_cmp_ui(n, 1) == 0) ? 1 : 0); } else if (k == 1) { totient(tot, n); } else if (mpz_cmp_ui(n, 1) <= 0) { mpz_set_ui(tot, (mpz_cmp_ui(n, 1) == 0) ? 1 : 0); } else { mpz_t t; mpz_t* factors; int* exponents; int i, j, nfactors; nfactors = factor(n, &factors, &exponents); mpz_init(t); mpz_set_ui(tot, 1); for (i = 0; i < nfactors; i++) { mpz_pow_ui(t, factors[i], k); mpz_sub_ui(t, t, 1); mpz_mul(tot, tot, t); mpz_add_ui(t, t, 1); for (j = 1; j < exponents[i]; j++) mpz_mul(tot, tot, t); } mpz_clear(t); clear_factors(nfactors, &factors, &exponents); } } void carmichael_lambda(mpz_t lambda, mpz_t n) { if (mpz_cmp_ui(n, 8) < 0) { totient(lambda, n); } else if (mpz_scan1(n, 0) == mpz_sizeinbase(n, 2)-1) { mpz_tdiv_q_2exp(lambda, n, 2); } else { mpz_t t; mpz_t* factors; int* exponents; int i, j, nfactors; nfactors = factor(n, &factors, &exponents); mpz_init(t); mpz_set_ui(lambda, 1); if (exponents[0] > 2 && mpz_cmp_ui(factors[0], 2) == 0) exponents[0]--; for (i = 0; i < nfactors; i++) { mpz_sub_ui(t, factors[i], 1); for (j = 1; j < exponents[i]; j++) mpz_mul(t, t, factors[i]); mpz_lcm(lambda, lambda, t); } mpz_clear(t); clear_factors(nfactors, &factors, &exponents); } } void znorder(mpz_t res, mpz_t a, mpz_t n) { mpz_t t; mpz_init(t); mpz_gcd(t, a, n); if (mpz_cmp_ui(n, 1) <= 0) { mpz_set(res, n); } else if (mpz_cmp_ui(a, 1) <= 0) { mpz_set(res, a); } else if (mpz_cmp_ui(t, 1) != 0) { mpz_set_ui(res, 0); } else { mpz_t order, phi; mpz_t* factors; int* exponents; int i, j, nfactors; mpz_init_set_ui(order, 1); mpz_init(phi); /* Abhijit Das, algorithm 1.7, applied to Carmichael Lambda */ carmichael_lambda(phi, n); nfactors = factor(phi, &factors, &exponents); for (i = 0; i < nfactors; i++) { mpz_divexact(t, phi, factors[i]); for (j = 1; j < exponents[i]; j++) mpz_divexact(t, t, factors[i]); mpz_powm(t, a, t, n); for (j = 0; mpz_cmp_ui(t, 1) != 0; mpz_powm(t, t, factors[i], n)) { if (j++ >= exponents[i]) { mpz_set_ui(order, 0); break; } mpz_mul(order, order, factors[i]); } if (j > exponents[i]) break; } mpz_set(res, order); mpz_clear(phi); mpz_clear(order); clear_factors(nfactors, &factors, &exponents); } mpz_clear(t); } void znprimroot(mpz_t root, mpz_t n) { mpz_t t, phi, a, on, r, *factors; int i, nfactors, *exponents, oddprime, k; mpz_set_ui(root, 0); if (mpz_cmp_ui(n, 4) <= 0) { if (mpz_sgn(n) > 0) mpz_sub_ui(root, n, 1); return; } if (mpz_divisible_ui_p(n, 4)) return; mpz_init(r); mpz_init_set(on, n); if (mpz_even_p(on)) mpz_tdiv_q_2exp(on, on, 1); if (!power_factor(on, r)) mpz_set(r, on); if (!_GMP_is_prob_prime(r)) { mpz_clear(on); mpz_clear(r); return; } mpz_init(phi); mpz_sub_ui(phi, r, 1); mpz_divexact(on, on, r); mpz_mul(phi, phi, on); mpz_sub_ui(r,n,1); oddprime = (mpz_cmp(r,phi) == 0); mpz_clear(on); mpz_clear(r); mpz_init(t); mpz_init(a); nfactors = factor(phi, &factors, &exponents); /* Replace each factor with phi/factor */ for (i = 0; i < nfactors; i++) mpz_divexact(factors[i], phi, factors[i]); for (mpz_set_ui(a,2); mpz_cmp(a,n) < 0; mpz_add_ui(a,a,1)) { if (!mpz_cmp_ui(a,4) || !mpz_cmp_ui(a,8) || !mpz_cmp_ui(a,9)) continue; k = mpz_kronecker(a, n); if ( (oddprime && k != -1) || (!oddprime && k == 0) ) continue; for (i = 0; i < nfactors; i++) { mpz_powm(t, a, factors[i], n); if (mpz_cmp_ui(t, 1) == 0) break; } if (i == nfactors) { mpz_set(root, a); break; } } clear_factors(nfactors, &factors, &exponents); mpz_clear(a); mpz_clear(t); mpz_clear(phi); } static const int32_t tau_table[] = { 0,1,-24,252,-1472,4830,-6048,-16744,84480,-113643,-115920,534612,-370944,-577738,401856,1217160,987136,-6905934,2727432,10661420,-7109760,-4219488,-12830688,18643272,21288960,-25499225,13865712,-73279080,24647168,128406630,-29211840,-52843168,-196706304,134722224,165742416,-80873520,167282496,-182213314,-255874080,-145589976,408038400,308120442,101267712,-17125708,-786948864,-548895690,-447438528 }; #define NTAU (sizeof(tau_table)/sizeof(tau_table[0])) void ramanujan_tau(mpz_t res, mpz_t n) { mpz_t t, t1, t2, t3, t4, *factors; int i, nfactors, *exponents; UV j, p2; if (mpz_cmp_ui(n, NTAU) < 0) { if (mpz_sgn(n) <= 0) mpz_set_si(res, 0); else mpz_set_si(res, tau_table[mpz_get_ui(n)]); return; } /* We are doing far too much work here for sigma5. We could do it just * for primes then use the multiplicative property. However that works * for prime *powers*, so it isn't quite so simple. This solution also * gets to be high memory use. */ /* Pari/GP does this using Hurwitz class numbers. That is a more * complicated but far more efficient solution. */ mpz_init(t); mpz_init(t1); mpz_init(t2); mpz_init(t3); mpz_init(t4); nfactors = factor(n, &factors, &exponents); for (i = 0; i < nfactors; i++) { /* t = tau(p) */ if (mpz_cmp_ui(factors[i], NTAU) < 0) { mpz_set_si(t, tau_table[mpz_get_ui(factors[i])]); } else { mpz_pow_ui(t, factors[i], 11); mpz_add_ui(t, t, 1); /* sigma(t,f,11) */ mpz_mul_ui(t1, t, 65); mpz_pow_ui(t, factors[i], 5); mpz_add_ui(t, t, 1); /* sigma(t,f, 5) */ mpz_mul_ui(t2, t, 691); mpz_add(t1, t1, t2); /* t1 in use. t2 accumulate. t3, t4, t free. */ mpz_sub_ui(t, factors[i], 1); mpz_tdiv_q_2exp(t, t, 1); p2 = mpz_get_ui(t); mpz_set_ui(t2, 0); for (j = 1; j <= p2; j++) { mpz_set_ui(t, j); sigma(t3, t, 5); mpz_sub_ui(t, factors[i], j); sigma(t, t, 5); mpz_mul(t4, t3, t); mpz_add(t2, t2, t4); } mpz_mul_ui(t2, t2, 2*691*252); mpz_sub(t, t1, t2); mpz_tdiv_q_ui(t, t, 756); } /* t holds tau(p), all other temps are free. */ if (exponents[i] > 1) { mpz_pow_ui(t1, t, exponents[i]); if (exponents[i] == 2) { mpz_pow_ui(t2, factors[i], 11); } else if (exponents[i] == 3) { mpz_pow_ui(t2, factors[i], 11); mpz_mul(t2, t2, t); mpz_mul_ui(t2, t2, 2); } else { /* t1 = t^e t2 = neg sum, t3 = prod, t4 = temp */ mpz_set_ui(t2, 0); for (j = 1; j <= (UV) (exponents[i]>>1); j++) { mpz_set_si(t3, (j&1) ? -1 : 1); mpz_pow_ui(t4, factors[i], 11*j); mpz_mul(t3, t3, t4); mpz_bin_uiui(t4, exponents[i]-j, exponents[i]-2*j); mpz_mul(t3, t3, t4); mpz_pow_ui(t4, t, exponents[i]-2*j); mpz_mul(t3, t3, t4); mpz_sub(t2, t2, t3); } } mpz_sub(t, t1, t2); } mpz_set(factors[i], t); } mpz_product(factors, 0, nfactors-1); mpz_set(res, factors[0]); clear_factors(nfactors, &factors, &exponents); mpz_clear(t4); mpz_clear(t3); mpz_clear(t2); mpz_clear(t1); mpz_clear(t); } int is_semiprime(mpz_t n) { int ret; UV div, lim = 6000; mpz_t t; if (mpz_cmp_ui(n,6) < 0) return (mpz_cmp_ui(n,4) == 0); mpz_init(t); div = _GMP_trial_factor(n, 2, lim); if (div > 0) { mpz_divexact_ui(t, n, div); ret = _GMP_is_prime(t); mpz_clear(t); return !!ret; } /* No small divisors */ if (_GMP_BPSW(n)) { mpz_clear(t); return 0; } if (mpz_ui_pow_ui(t,lim,3), mpz_cmp(n,t) < 0) { mpz_clear(t); return 1; } /* Number is composite, isn't tiny, and has no small divisors */ if ( 0 || _GMP_pbrent_factor(n, t, 1, 15000) || _GMP_pminus1_factor(n, t, 50000, 500000) || _GMP_ECM_FACTOR(n, t, 800, 10) || _GMP_ECM_FACTOR(n, t, 8000, 20) || _GMP_ECM_FACTOR(n, t, 80000, 40) || _GMP_ECM_FACTOR(n, t, 320000, 40) || _GMP_ECM_FACTOR(n, t, 1000000, 80) ) { ret = _GMP_BPSW(t); if (ret) { mpz_divexact(t, n, t); ret = _GMP_BPSW(t); } mpz_clear(t); return !!ret; } /* No luck finding a small factor. Do it the hard way. */ { mpz_t* factors; int* exponents; int nfactors, i, j; nfactors = factor(n, &factors, &exponents); for (i = 0, j = 0; i < nfactors; i++) j += exponents[i]; clear_factors(nfactors, &factors, &exponents); mpz_clear(t); return (j == 2); } } /*****************************************************************************/ UV _GMP_trial_factor(mpz_t n, UV from_n, UV to_n) { size_t log2n = mpz_sizeinbase(n, 2); UV p = 0; PRIME_ITERATOR(iter); if (mpz_cmp_ui(n, 6) < 0) { unsigned long un = mpz_get_ui(n); if (un == 1) p = 1; else if (un == 4 && from_n <= 2 && to_n >= 2) p = 2; prime_iterator_destroy(&iter); return p; } if (from_n <= 2 && to_n >= 2 && mpz_even_p(n)) p = 2; else if (from_n <= 3 && to_n >= 3 && mpz_divisible_ui_p(n, 3)) p = 3; else if (from_n <= 5 && to_n >= 5 && mpz_divisible_ui_p(n, 5)) p = 5; if (p != 0) { prime_iterator_destroy(&iter); return p; } if (from_n < 7) from_n = 7; if (from_n > to_n) { prime_iterator_destroy(&iter); return 0; } /* p will be the next prime >= from_n */ prime_iterator_setprime(&iter, from_n-1); p = prime_iterator_next(&iter); /* All native math if n fits in an unsigned long */ if (log2n <= sizeof(unsigned long)*8) { unsigned long un = mpz_get_ui(n); unsigned long sqrtn = (unsigned long) sqrt((double)un); /* Be extra careful here, as we are using unsigned long, which may not * match a UV. But GMP's ui is 'unsigned long' so that's what we have * to deal with. We want to make sure we get the correct integer sqrt, * but also watch out for overflow. */ while (sqrtn*sqrtn > un) sqrtn--; while ( (sqrtn+1)*(sqrtn+1) <= un && sqrtn < (1UL << 4*sizeof(unsigned long)) ) sqrtn++; if (to_n > sqrtn) to_n = sqrtn; while (p <= to_n) { if ((un % p) == 0) break; p = prime_iterator_next(&iter); } prime_iterator_destroy(&iter); return (p <= to_n) ? p : 0; } /* For "small" numbers, this simple method is best. */ { UV small_to = (log2n < 3000) ? to_n : 30000; while (p <= small_to) { if (mpz_divisible_ui_p(n, p)) break; p = prime_iterator_next(&iter); } if (p <= small_to || p > to_n) { prime_iterator_destroy(&iter); return (p <= small_to) ? p : 0; } } /* Simple treesieve. * This is much faster than simple divisibility for really big numbers. * Credit to Jens K Andersen for writing up the generic algorithm. * * This will search until the first group element is > to_n, which means * we will search a bit farther than to_n. */ { UV found = 0; unsigned long* xn; /* leaves */ mpz_t* xtree[16+1]; /* the tree (maxdepth = 16) */ mpz_t* xtemp; unsigned int i, j, d, depth, leafsize, nleaves; /* Decide on the tree depth (3-16) and number of leaves (10-31) */ { unsigned int dp = log2n >> 10; depth = 0; while (dp >>= 1) depth++; if (depth < 3) depth = 3; if (depth > 16) depth = 16; } leafsize = log2n / (1U << depth) / 68; nleaves = 1 << depth; /* printf("log2n %lu depth %u leafsize %u nleaves %u\n",log2n,depth,leafsize,nleaves); */ New(0, xn, nleaves * leafsize, unsigned long); for (d = 0; d <= depth; d++) { unsigned int nodes = 1 << (depth - d); New(0, xtree[d], nodes, mpz_t); for (j = 0; j < nodes; j++) mpz_init(xtree[d][j]); } xtemp = xtree[1]; /* implies mindepth = 3 */ while (!found && p <= to_n) { /* Create nleaves x[0] values, each the product of leafsize primes */ for (i = 0; i < nleaves; i++) { for (j = 0; j < 4; j++) /* Create 4 sub-products */ mpz_set_ui(xtemp[j], 1); for (j = 0; j < leafsize; j++) { xn[i*leafsize+j] = p; mpz_mul_ui(xtemp[j&3], xtemp[j&3], p); p = prime_iterator_next(&iter); } mpz_mul(xtemp[0], xtemp[0], xtemp[1]); /* Combine for final product*/ mpz_mul(xtemp[2], xtemp[2], xtemp[3]); mpz_mul(xtree[0][i], xtemp[0], xtemp[2]); } /* Multiply product tree, xtree[depth][0] has nleaves*leafsize product */ for (d = 1; d <= depth; d++) for (i = 0; i < (1U << (depth-d)); i++) mpz_mul(xtree[d][i], xtree[d-1][2*i], xtree[d-1][2*i+1]); /* Go backwards replacing the products with remainders */ mpz_tdiv_r(xtree[depth][0], n, xtree[depth][0]); for (d = 1; d <= depth; d++) for (i = 0; i < (1U << d); i++) mpz_tdiv_r(xtree[depth-d][i], xtree[depth-d+1][i>>1], xtree[depth-d][i]); /* Search each leaf for divisors */ for (i = 0; !found && i < nleaves; i++) for (j = 0; j < leafsize; j++) if (mpz_divisible_ui_p(xtree[0][i], xn[i*leafsize+j])) { found = xn[i*leafsize+j]; break; } } p = found; for (d = 0; d <= depth; d++) { unsigned int nodes = 1U << (depth - d); for (j = 0; j < nodes; j++) mpz_clear(xtree[d][j]); Safefree(xtree[d]); } Safefree(xn); if (p > 0 && !mpz_divisible_ui_p(n, p)) croak("incorrect trial factor\n"); } prime_iterator_destroy(&iter); return p; } #define TEST_FOR_2357(n, f) \ { \ if (mpz_divisible_ui_p(n, 2)) { mpz_set_ui(f, 2); return 1; } \ if (mpz_divisible_ui_p(n, 3)) { mpz_set_ui(f, 3); return 1; } \ if (mpz_divisible_ui_p(n, 5)) { mpz_set_ui(f, 5); return 1; } \ if (mpz_divisible_ui_p(n, 7)) { mpz_set_ui(f, 7); return 1; } \ if (mpz_cmp_ui(n, 121) < 0) { return 0; } \ } int _GMP_prho_factor(mpz_t n, mpz_t f, UV a, UV rounds) { mpz_t U, V, oldU, oldV, m; int i; const UV inner = 256; TEST_FOR_2357(n, f); rounds = (rounds + inner - 1) / inner; mpz_init_set_ui(U, 7); mpz_init_set_ui(V, 7); mpz_init(m); mpz_init(oldU); mpz_init(oldV); while (rounds-- > 0) { mpz_set_ui(m, 1); mpz_set(oldU, U); mpz_set(oldV, V); for (i = 0; i < (int)inner; i++) { mpz_mul(U, U, U); mpz_add_ui(U, U, a); mpz_tdiv_r(U, U, n); mpz_mul(V, V, V); mpz_add_ui(V, V, a); mpz_tdiv_r(V, V, n); mpz_mul(V, V, V); mpz_add_ui(V, V, a); mpz_tdiv_r(V, V, n); mpz_sub(f, U, V); mpz_mul(m, m, f); if ((i%4) == ((inner-1)%4)) mpz_tdiv_r(m, m, n); } mpz_gcd(f, m, n); if (!mpz_cmp_ui(f, 1)) continue; if (!mpz_cmp(f, n)) { /* f == n, so we have to back up to see what factor got found */ mpz_set(U, oldU); mpz_set(V, oldV); i = inner; do { mpz_mul(U, U, U); mpz_add_ui(U, U, a); mpz_tdiv_r(U, U, n); mpz_mul(V, V, V); mpz_add_ui(V, V, a); mpz_tdiv_r(V, V, n); mpz_mul(V, V, V); mpz_add_ui(V, V, a); mpz_tdiv_r(V, V, n); if (mpz_cmp(U, V) >= 0) mpz_sub(f, U, V); else mpz_sub(f, V, U); mpz_gcd(f, f, n); } while (!mpz_cmp_ui(f, 1) && i-- != 0); if ( (!mpz_cmp_ui(f, 1)) || (!mpz_cmp(f, n)) ) break; } mpz_clear(U); mpz_clear(V); mpz_clear(m); mpz_clear(oldU); mpz_clear(oldV); return 1; } mpz_clear(U); mpz_clear(V); mpz_clear(m); mpz_clear(oldU); mpz_clear(oldV); mpz_set(f, n); return 0; } int _GMP_pbrent_factor(mpz_t n, mpz_t f, UV a, UV rounds) { mpz_t Xi, Xm, saveXi, m, t; UV i, r; const UV inner = 256; TEST_FOR_2357(n, f); mpz_init_set_ui(Xi, 2); mpz_init_set_ui(Xm, 2); mpz_init(m); mpz_init(t); mpz_init(saveXi); r = 1; while (rounds > 0) { UV rleft = (r > rounds) ? rounds : r; while (rleft > 0) { /* Do rleft rounds, inner at a time */ UV dorounds = (rleft > inner) ? inner : rleft; mpz_set_ui(m, 1); mpz_set(saveXi, Xi); for (i = 0; i < dorounds; i++) { mpz_mul(t, Xi, Xi); mpz_add_ui(t, t, a); mpz_tdiv_r(Xi, t, n); mpz_sub(f, Xm, Xi); mpz_mul(m, m, f); if ((i%4) == ((dorounds-1)%4)) mpz_tdiv_r(m, m, n); } rleft -= dorounds; rounds -= dorounds; mpz_gcd(f, m, n); if (mpz_cmp_ui(f, 1) != 0) break; } if (!mpz_cmp_ui(f, 1)) { r *= 2; mpz_set(Xm, Xi); continue; } if (!mpz_cmp(f, n)) { /* f == n, so we have to back up to see what factor got found */ mpz_set(Xi, saveXi); do { mpz_mul(t, Xi, Xi); mpz_add_ui(t, t, a); mpz_tdiv_r(Xi, t, n); mpz_sub(f, Xm, Xi); if (mpz_sgn(f) < 0) mpz_add(f,f,n); mpz_gcd(f, f, n); } while (!mpz_cmp_ui(f, 1) && r-- != 0); } break; } mpz_clear(Xi); mpz_clear(Xm); mpz_clear(m); mpz_clear(saveXi); mpz_clear(t); if (!mpz_cmp_ui(f, 1) || !mpz_cmp(f, n)) { mpz_set(f, n); return 0; } return 1; } /* References for P-1: * Montgomery 1987: https://cr.yp.to/bib/1987/montgomery.pdf * Brent 1990: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.127.4316 * * The main advantage of this over ECM is that it is *much* lower overhead, * so very cheap to run with relatively small B1,B2 values. A disadvantage * is no continuation method, so subsequent calls with larger B1,B2 will * repeat all the previous work. ECM is much better for harder factorisations, * so we typically want to try a little p-1 then move to ECM (or QS). */ int _GMP_pminus1_factor(mpz_t n, mpz_t f, UV B1, UV B2) { mpz_t a, savea, t; UV q, saveq, j, sqrtB1; int _verbose = get_verbose_level(); PRIME_ITERATOR(iter); TEST_FOR_2357(n, f); if (B1 < 7) return 0; mpz_init(a); mpz_init(savea); mpz_init(t); if (_verbose>2) gmp_printf("# p-1 trying %Zd (B1=%"UVuf" B2=%"UVuf")\n", n, (unsigned long)B1, (unsigned long)B2); /* STAGE 1 * See Montgomery 1987 p249-250 or Brent 1990 p5. We can take E to be the * lcm of integers to B1, then gcd(a^E-1,n) may be a factor of n. While * we could actually calculate the LCM, it is quite inefficient to do so. * There are various ways to speed it up, but generally we prefer to do it * the way Brent indicates, which is one powmod for each prime p below B1, * a = a^(p^e) mod n, where e is the largest e such that p^e <= B1. * * One thing that can speed things up quite a bit is not running the GCD * on every step. However with small factors this means we can easily end * up with multiple factors between GCDs, so we allow backtracking. This * could also be added to stage 2, but it's far less likely to happen there. */ j = 15; mpz_set_ui(a, 2); mpz_set_ui(savea, 2); saveq = 2; /* We could wrap this in a loop trying a few different a values, in case * the current one ended up going to 0. */ q = 2; mpz_set_ui(t, 1); sqrtB1 = (UV) sqrt(B1); while (q <= B1) { UV k = q; if (q <= sqrtB1) { UV kmin = B1/q; while (k <= kmin) k *= q; } mpz_mul_ui(t, t, k); /* Accumulate powers for a */ if ( (j++ % 32) == 0) { mpz_powm(a, a, t, n); /* a=a^(k1*k2*k3*...) mod n */ if (mpz_sgn(a)) mpz_sub_ui(t, a, 1); else mpz_sub_ui(t, n, 1); mpz_gcd(f, t, n); /* f = gcd(a-1, n) */ mpz_set_ui(t, 1); if (mpz_cmp(f, n) == 0) break; if (mpz_cmp_ui(f, 1) != 0) goto end_success; saveq = q; mpz_set(savea, a); } q = prime_iterator_next(&iter); } mpz_powm(a, a, t, n); if (mpz_sgn(a)) mpz_sub_ui(t, a, 1); else mpz_sub_ui(t, n, 1); mpz_gcd(f, t, n); if (mpz_cmp(f, n) == 0) { /* We found multiple factors. Loop one at a time. */ prime_iterator_setprime(&iter, saveq); mpz_set(a, savea); for (q = saveq; q <= B1; q = prime_iterator_next(&iter)) { UV k = q; if (q <= sqrtB1) { UV kmin = B1/q; while (k <= kmin) k *= q; } mpz_powm_ui(a, a, k, n ); mpz_sub_ui(t, a, 1); mpz_gcd(f, t, n); if (mpz_cmp(f, n) == 0) goto end_fail; if (mpz_cmp_ui(f, 1) != 0) goto end_success; } } if ( (mpz_cmp_ui(f, 1) != 0) && (mpz_cmp(f, n) != 0) ) goto end_success; /* STAGE 2 * This is the standard continuation which replaces the powmods in stage 1 * with two mulmods, with a GCD every 64 primes (no backtracking). * This is quite a bit faster than stage 1. * See Montgomery 1987, p250-253 for possible optimizations. * We quickly precalculate a few of the prime gaps, and lazily cache others * up to a gap of 222. That's enough for a B2 value of 189 million. We * still work above that, we just won't cache the value for big gaps. */ if (B2 > B1) { mpz_t b, bm, bmdiff; mpz_t precomp_bm[111]; int is_precomp[111] = {0}; UV* primes = 0; UV sp = 1; mpz_init(bmdiff); mpz_init_set(bm, a); mpz_init_set_ui(b, 1); /* Set the first 20 differences */ mpz_powm_ui(bmdiff, bm, 2, n); mpz_init_set(precomp_bm[0], bmdiff); is_precomp[0] = 1; for (j = 1; j < 22; j++) { mpz_mul(bmdiff, bmdiff, bm); mpz_mul(bmdiff, bmdiff, bm); mpz_tdiv_r(bmdiff, bmdiff, n); mpz_init_set(precomp_bm[j], bmdiff); is_precomp[j] = 1; } mpz_powm_ui(a, a, q, n ); if (B2 < 10000000) { /* grab all the primes at once. Hack around non-perfect iterator. */ primes = sieve_to_n(B2+300, 0); for (sp = B1>>4; primes[sp] <= q; sp++) ; /* q is primes <= B1, primes[sp] is the next prime */ } j = 31; while (q <= B2) { UV lastq, qdiff; lastq = q; q = primes ? primes[sp++] : prime_iterator_next(&iter); qdiff = (q - lastq) / 2 - 1; if (qdiff < 111 && is_precomp[qdiff]) { mpz_mul(t, a, precomp_bm[qdiff]); } else if (qdiff < 111) { mpz_powm_ui(bmdiff, bm, q-lastq, n); mpz_init_set(precomp_bm[qdiff], bmdiff); is_precomp[qdiff] = 1; mpz_mul(t, a, bmdiff); } else { mpz_powm_ui(bmdiff, bm, q-lastq, n); /* Big gap */ mpz_mul(t, a, bmdiff); } mpz_tdiv_r(a, t, n); if (mpz_sgn(a)) mpz_sub_ui(t, a, 1); else mpz_sub_ui(t, n, 1); mpz_mul(b, b, t); if ((j % 2) == 0) /* put off mods a little */ mpz_tdiv_r(b, b, n); if ( (j++ % 64) == 0) { /* GCD every so often */ mpz_gcd(f, b, n); if ( (mpz_cmp_ui(f, 1) != 0) && (mpz_cmp(f, n) != 0) ) break; } } mpz_gcd(f, b, n); mpz_clear(b); mpz_clear(bm); mpz_clear(bmdiff); for (j = 0; j < 111; j++) { if (is_precomp[j]) mpz_clear(precomp_bm[j]); } if (primes != 0) Safefree(primes); if ( (mpz_cmp_ui(f, 1) != 0) && (mpz_cmp(f, n) != 0) ) goto end_success; } end_fail: mpz_set(f,n); end_success: prime_iterator_destroy(&iter); mpz_clear(a); mpz_clear(savea); mpz_clear(t); if ( (mpz_cmp_ui(f, 1) != 0) && (mpz_cmp(f, n) != 0) ) { if (_verbose>2) gmp_printf("# p-1: %Zd\n", f); return 1; } if (_verbose>2) gmp_printf("# p-1: no factor\n"); mpz_set(f, n); return 0; } static void pp1_pow(mpz_t X, mpz_t Y, unsigned long exp, mpz_t n) { mpz_t x0; unsigned long bit; { unsigned long v = exp; unsigned long b = 1; while (v >>= 1) b++; bit = 1UL << (b-2); } mpz_init_set(x0, X); mpz_mul(Y, X, X); mpz_sub_ui(Y, Y, 2); mpz_tdiv_r(Y, Y, n); while (bit) { if ( exp & bit ) { mpz_mul(X, X, Y); mpz_sub(X, X, x0); mpz_mul(Y, Y, Y); mpz_sub_ui(Y, Y, 2); } else { mpz_mul(Y, X, Y); mpz_sub(Y, Y, x0); mpz_mul(X, X, X); mpz_sub_ui(X, X, 2); } mpz_mod(X, X, n); mpz_mod(Y, Y, n); bit >>= 1; } mpz_clear(x0); } int _GMP_pplus1_factor(mpz_t n, mpz_t f, UV P0, UV B1, UV B2) { UV j, q, saveq, sqrtB1; mpz_t X, Y, saveX; PRIME_ITERATOR(iter); TEST_FOR_2357(n, f); if (B1 < 7) return 0; mpz_init_set_ui(X, P0); mpz_init(Y); mpz_init(saveX); /* Montgomery 1987 */ if (P0 == 0) { mpz_set_ui(X, 7); if (mpz_invert(X, X, n)) { mpz_mul_ui(X, X, 2); mpz_mod(X, X, n); } else P0 = 1; } if (P0 == 1) { mpz_set_ui(X, 5); if (mpz_invert(X, X, n)) { mpz_mul_ui(X, X, 6); mpz_mod(X, X, n); } else P0 = 2; } if (P0 == 2) { mpz_set_ui(X, 11); if (mpz_invert(X, X, n)) { mpz_mul_ui(X, X, 23); mpz_mod(X, X, n); } } sqrtB1 = (UV) sqrt(B1); j = 8; q = 2; saveq = q; mpz_set(saveX, X); while (q <= B1) { UV k = q; if (q <= sqrtB1) { UV kmin = B1/q; while (k <= kmin) k *= q; } pp1_pow(X, Y, k, n); if ( (j++ % 16) == 0) { mpz_sub_ui(f, X, 2); if (mpz_sgn(f) == 0) break; mpz_gcd(f, f, n); if (mpz_cmp(f, n) == 0) break; if (mpz_cmp_ui(f, 1) > 0) goto end_success; saveq = q; mpz_set(saveX, X); } q = prime_iterator_next(&iter); } mpz_sub_ui(f, X, 2); mpz_gcd(f, f, n); if (mpz_cmp_ui(X, 2) == 0 || mpz_cmp(f, n) == 0) { /* Backtrack */ prime_iterator_setprime(&iter, saveq); mpz_set(X, saveX); for (q = saveq; q <= B1; q = prime_iterator_next(&iter)) { UV k = q; if (q <= sqrtB1) { UV kmin = B1/q; while (k <= kmin) k *= q; } pp1_pow(X, Y, k, n); mpz_sub_ui(f, X, 2); if (mpz_sgn(f) == 0) goto end_fail; mpz_gcd(f, f, n); if (mpz_cmp(f, n) == 0) break; if (mpz_cmp_ui(f, 1) > 0) goto end_success; } } if ( (mpz_cmp_ui(f, 1) > 0) && (mpz_cmp(f, n) != 0) ) goto end_success; /* TODO: stage 2 */ end_fail: mpz_set(f,n); end_success: prime_iterator_destroy(&iter); mpz_clear(X); mpz_clear(Y); mpz_clear(saveX); return (mpz_cmp_ui(f, 1) != 0) && (mpz_cmp(f, n) != 0); } int _GMP_holf_factor(mpz_t n, mpz_t f, UV rounds) { mpz_t s, m; UV i; #define PREMULT 480 /* 1 2 6 12 480 151200 */ TEST_FOR_2357(n, f); if (mpz_perfect_square_p(n)) { mpz_sqrt(f, n); return 1; } mpz_mul_ui(n, n, PREMULT); mpz_init(s); mpz_init(m); for (i = 1; i <= rounds; i++) { mpz_mul_ui(f, n, i); /* f = n*i */ if (mpz_perfect_square_p(f)) { /* s^2 = n*i, so m = s^2 mod n = 0. Hence f = GCD(n, s) = GCD(n, n*i) */ mpz_divexact_ui(n, n, PREMULT); mpz_gcd(f, f, n); mpz_clear(s); mpz_clear(m); if (mpz_cmp(f, n) == 0) return 0; return 1; } mpz_sqrt(s, f); mpz_add_ui(s, s, 1); /* s = ceil(sqrt(n*i)) */ mpz_mul(m, s, s); mpz_sub(m, m, f); /* m = s^2 mod n = s^2 - n*i */ if (mpz_perfect_square_p(m)) { mpz_divexact_ui(n, n, PREMULT); mpz_sqrt(f, m); mpz_sub(s, s, f); mpz_gcd(f, s, n); mpz_clear(s); mpz_clear(m); return (mpz_cmp_ui(f, 1) > 0); } } mpz_divexact_ui(n, n, PREMULT); mpz_set(f, n); mpz_clear(s); mpz_clear(m); return 0; } /* See if n is a perfect power */ UV power_factor(mpz_t n, mpz_t f) { UV k = 1, b = 2; if (mpz_cmp_ui(n, 1) > 0 && mpz_perfect_power_p(n)) { mpz_t nf, tf; PRIME_ITERATOR(iter); mpz_init_set(nf, n); mpz_init(tf); while (1) { UV ok = k; while (mpz_root(tf, nf, b)) { mpz_set(f, tf); mpz_set(nf, tf); k *= b; } if (ok != k && !mpz_perfect_power_p(nf)) break; if (mpz_cmp_ui(tf, 1) <= 0) break; /* Exit if we can't find the power */ b = prime_iterator_next(&iter); } mpz_clear(tf); mpz_clear(nf); prime_iterator_destroy(&iter); } return (k == 1) ? 0 : k; } static int numcmp(const void *av, const void *bv) { return mpz_cmp(*(const mpz_t*)av, *(const mpz_t*)bv); } mpz_t * divisor_list(int *num_divisors, mpz_t n) { mpz_t *factors, *divs, mult; int nfactors, ndivisors, i, j, k, count, *exponents; nfactors = factor(n, &factors, &exponents); ndivisors = 1 + ((nfactors > 0) ? exponents[0] : 0); for (i = 1; i < nfactors; i++) ndivisors *= (exponents[i] + 1); mpz_init(mult); New(0, divs, ndivisors, mpz_t); mpz_init_set_ui(divs[0], 1); for (count = 1, k = 0; k < nfactors; k++) { int scount = count; mpz_set_ui(mult, 1); for (j = 0; j < exponents[k]; j++) { mpz_mul(mult, mult, factors[k]); for (i = 0; i < scount; i++) { mpz_init(divs[count]); mpz_mul(divs[count], divs[i], mult); count++; } } } mpz_clear(mult); clear_factors(nfactors, &factors, &exponents); qsort(divs, ndivisors, sizeof(mpz_t), numcmp); *num_divisors = ndivisors; return divs; } Math-Prime-Util-GMP-0.52/LICENSE0000644000175000017500000004367513054533725014362 0ustar danadanaThis software is Copyright (c) 2011-2017 by Dana Jacobsen. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Terms of the Perl programming language system itself a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" --- The GNU General Public License, Version 1, February 1989 --- This software is Copyright (c) 2011-2017 by Dana Jacobsen. This is free software, licensed under: The GNU General Public License, Version 1, February 1989 GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. 51 Franklin St, Suite 500, Boston, MA 02110-1335 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of a such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this General Public License. d) You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying the Program (or any work based on the Program) you indicate your acceptance of this license to do so, and all its terms and conditions. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. 7. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of the license which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the license, you may choose any version ever published by the Free Software Foundation. 8. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to humanity, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19xx name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice That's all there is to it! --- The Artistic License 1.0 --- This software is Copyright (c) 2011-2017 by Dana Jacobsen. This is free software, licensed under: The Artistic License 1.0 The Artistic License Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: - "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. - "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. - "Copyright Holder" is whoever is named in the copyright or copyrights for the package. - "You" is you, if you're thinking about copying or distributing this Package. - "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) - "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End Math-Prime-Util-GMP-0.52/real.h0000644000175000017500000000276213663067455014451 0ustar danadana#ifndef MPU_REAL_H #define MPU_REAL_H #include #include "ptypes.h" extern void bernfrac(mpz_t num, mpz_t den, mpz_t n); extern void harmfrac(mpz_t num, mpz_t den, mpz_t n); extern void li(mpf_t li, mpf_t x, unsigned long prec); extern void ei(mpf_t li, mpf_t x, unsigned long prec); extern void const_euler(mpf_t gamma, unsigned long prec); extern void const_pi(mpf_t pi, unsigned long prec); extern void const_log2(mpf_t logn, unsigned long prec); extern void free_float_constants(void); extern void free_borwein_zeta(void); extern char* bernreal(mpz_t zn, unsigned long prec); extern char* harmreal(mpz_t zn, unsigned long prec); extern char* zetareal(mpf_t r, unsigned long prec); extern char* eireal(mpf_t r, unsigned long prec); extern char* lireal(mpf_t r, unsigned long prec); extern char* riemannrreal(mpf_t r, unsigned long prec); extern char* lambertwreal(mpf_t r, unsigned long prec); extern char* logreal(mpf_t r, unsigned long prec); extern char* expreal(mpf_t r, unsigned long prec); extern char* powreal(mpf_t r, mpf_t x, unsigned long prec); extern char* rootreal(mpf_t r, mpf_t x, unsigned long prec); extern char* addreal(mpf_t r, mpf_t x, unsigned long prec); extern char* subreal(mpf_t r, mpf_t x, unsigned long prec); extern char* mulreal(mpf_t r, mpf_t x, unsigned long prec); extern char* divreal(mpf_t r, mpf_t x, unsigned long prec); extern char* agmreal(mpf_t a, mpf_t b, unsigned long prec); extern char* eulerconst(unsigned long n); extern char* piconst(unsigned long n); #endif Math-Prime-Util-GMP-0.52/tinyqs.c0000644000175000017500000015641313674067010015040 0ustar danadana#include #include #include #include "tinyqs.h" /******************************************************************************/ typedef signed char s8; typedef unsigned char u8; typedef signed short s16; typedef unsigned short u16; typedef signed int s32; typedef unsigned int u32; #ifdef _MSC_VER typedef signed __int64 s64; typedef unsigned __int64 u64; #else typedef long long s64; typedef unsigned long long u64; #endif /******************************************************************************/ #ifndef M_LN2 #define M_LN2 0.69314718055994530942 #endif #ifndef M_SQRT2 #define M_SQRT2 1.41421356237309504880 #endif /* High-throughput, low-overhead implementation of the self- initializing multiple polynomial quadratic sieve, optimized for small inputs (50-120 bits). Many of the ideas here are extensions of the remarkable MPQS code of F. Bahr, used in the lattice sievers by Jens Franke */ /* TODO: lots of static mpz_t is an issue for threading */ /* seeds for random numbers */ static u32 rand_seed1 = 11111111; static u32 rand_seed2 = 22222222; #define RAND_MULT 2131995753 static u32 get_rand(u32 *seed1, u32 *seed2) { /* A multiply-with-carry generator by George Marsaglia. The period is about 2^63. */ u64 temp = (u64)(*seed1) * (u64)RAND_MULT + (u64)(*seed2); *seed1 = (u32)temp; *seed2 = (u32)(temp >> 32); return (u32)temp; } /* masks for picking out individual bits of 64-bit words, used for the linear algebra */ #define B(x) ((u64)(1) << (x)) static const u64 bitmask[] = { B( 0), B( 1), B( 2), B( 3), B( 4), B( 5), B( 6), B( 7), B( 8), B( 9), B(10), B(11), B(12), B(13), B(14), B(15), B(16), B(17), B(18), B(19), B(20), B(21), B(22), B(23), B(24), B(25), B(26), B(27), B(28), B(29), B(30), B(31), B(32), B(33), B(34), B(35), B(36), B(37), B(38), B(39), B(40), B(41), B(42), B(43), B(44), B(45), B(46), B(47), B(48), B(49), B(50), B(51), B(52), B(53), B(54), B(55), B(56), B(57), B(58), B(59), B(60), B(61), B(62), B(63), }; /* maximum size pool of primes from which factor base is constructed */ #define NUM_PRIMES_TINY 1024 /* the number of dependencies the linear algebra will find */ #define NUM_EXTRA_RELATIONS_TINY 16 /* largest number of relations that can go into the linear algebra (includes relations combined from pairs of partial relations */ #define MAX_RELATIONS_TINY 512 /* the largest possible factor base */ #define MAX_FB_SIZE_TINY (MAX_RELATIONS_TINY - \ NUM_EXTRA_RELATIONS_TINY) /* offset of the first valid factor base prime */ #define MIN_FB_OFFSET_TINY 1 /* offset of the first factor base prime actually contributing to the sieving */ #define MIN_FB_OFFSET_TO_SIEVE_TINY 7 /* number of primes used when testing multipliers */ #define NUM_TEST_PRIMES_TINY 30 /* fudge factor to the target sieve value to account for not sieving with the smallest factor base primes */ #define SMALL_PRIME_FUDGE_TINY 10 /* maximum number of MPQS polynomials to be computed */ #define MAX_POLY_TINY 256 /* maximum number of FB primes that contribute to a single polynomial 'A' value */ #define MAX_POLY_FACTORS_TINY 5 /* the size of the sieve interval. Each polynomial will sieve over this many positive and negative values */ #define SIEVE_SIZE_TINY 16384 /* value of the sieve root used when sieving is not to be performed for a given FB prime. Since this is larger than SIEVE_SIZE_TINY no special-case code is needed in the core sieve code */ #define DO_NOT_SIEVE_TINY 65535 /* maximum number of factors a relation can have (the large prime is stored separately) */ #define MAX_FACTORS_TINY 20 /* partial relations are listed in the order in which they occur, and a hashtable matches up partial relations with the same large prime. */ #define LOG2_PARTIAL_TABLE_SIZE 10 #define LARGE_PRIME_HASH(x) (((u32)(x) * ((u32)40499 * 65543)) >> \ (32 - LOG2_PARTIAL_TABLE_SIZE)) /* number of collisions allowed in one hashtable entry */ #define LP_HASH_DEPTH_TINY 3 /* scale factor for all log values */ #define LOGPRIME_SCALE_TINY 2 /* maximum number of relations to be saved for resieving, used in place of trial factoring */ #define SIEVE_BATCH_SIZE_TINY 128 /* maximum size of the pool of FB primes that can appear in a polynomial 'A' value */ #define POLY_SELECT_BITS_TINY 12 #define POSITIVE 0 #define NEGATIVE 1 /* structure describing a single relation */ typedef struct { u32 large_prime; /* the large prime (may be 1) */ s16 sieve_offset; /* the sieve offset of the relation */ u8 poly_num; /* ID of the poly that produce the relation */ u8 num_factors; /* number of factors from the factor base (duplicates count) */ u16 fb_offsets[MAX_FACTORS_TINY]; /* offsets into FB of primes that divide this relation */ } tiny_relation; /* structure describing a factor base entry */ typedef struct { u16 prime; /* the factor base prime */ u16 modsqrt; /* x that solves x^2 = N mod p */ u32 recip; /* integer reciprocal of 'prime' */ u8 logprime; /* log value used in sieve */ u16 roots[2]; /* the two sieve roots for 'prime' */ } tiny_fb; /* structure describing one SIQS polynomial */ typedef struct { u16 a_fb_offsets[MAX_POLY_FACTORS_TINY]; /* factors of 'A' value */ mpz_t b; /* B value */ } tiny_poly; /* main structure controlling the factorization */ typedef struct { /* basic stuff */ mpz_t n; /* number to be factored */ u32 multiplier; /* small multiplier of n */ u16 multiplier_fb[2]; /* fb offsets of factors of multiplier */ /* polynomial selection stuff */ double target_a; /* the optimal size of poly A values */ s32 poly_num; /* ID of current polynomial */ s32 num_a_factors; /* # of factors in poly 'A' values */ s32 poly_select_idx; /* ID of the combination of primes that will make current A value */ u16 poly_select_offsets[POLY_SELECT_BITS_TINY]; /* pool of primes for A */ mpz_t poly_b_aux[MAX_POLY_FACTORS_TINY]; /* scratch values for com- puting poly B values */ tiny_poly poly_list[MAX_POLY_TINY]; /* list of SIQS polynomials */ /* sieve stuff */ double align_me; u8 sieve_block[SIEVE_SIZE_TINY]; /* the sieve interval (8-byte aligned) */ /* factor base stuff */ s32 fb_size; /* number of FB primes */ u16 prime_list[NUM_PRIMES_TINY]; /* complete list of primes from which factor base is generated */ float test_prime_contrib[NUM_TEST_PRIMES_TINY]; /* scratch space used in multiplier selection */ tiny_fb factor_base[MAX_FB_SIZE_TINY]; /* the factor base */ u16 root_aux[MAX_POLY_FACTORS_TINY * MAX_FB_SIZE_TINY]; /* scratch value for initializing sieve roots */ /* relation stuff */ s32 num_full_relations; /* where next full relation will go */ s32 partial_idx; /* where next partial relation will go */ s32 large_prime_max; /* max value of a large prime */ s32 error_bits; /* value used for trial factoring cutoff */ tiny_relation sieve_batch[SIEVE_BATCH_SIZE_TINY]; /* resieved relations */ /* all relations that survive sieving are put in relation_list. Full relations (and partial relations whose large prime has occurred more than once) are stored in a list that grows up from the beginning of the list, while partial relations that have not been matched up yet are stored in a list growing down from the end of relation_list. num_full_relations is the index of the first free space for full relations, and partial_idx does the same for unmatched partial relations. */ tiny_relation relation_list[4 * MAX_RELATIONS_TINY]; /* a hashtable is used to match up partial relations, using the large prime as a hash key. The hashtable stores the index in relation_list of the partial relation that connects up all the other partial relations with the same large prime (those other relations are treated as full relations) */ u16 partial_hash[1 << LOG2_PARTIAL_TABLE_SIZE][LP_HASH_DEPTH_TINY]; /* linear algebra stuff */ u16 null_vectors[MAX_RELATIONS_TINY]; u64 matrix[MAX_FB_SIZE_TINY][(MAX_RELATIONS_TINY+63) / 64]; } tiny_qs_params; /* the following is reused across factorizations */ static tiny_qs_params *g_params = NULL; /* The following utility routines are not really a performance bottleneck, but since they always deal with 16-bit data at most their input datatypes should really by u16's. This will make all the division and remainder operations a lot faster */ /***********************************/ static s32 legendre_16(s32 a, s32 p) /*********************************** Compute the Legendre symbol (a/p) ************************************/ { s32 tmp; s32 x = a; s32 y = p; s32 out = 1; while (x) { while ((x & 1) == 0) { x = x / 2; if ( (y & 7) == 3 || (y & 7) == 5 ) out = -out; } tmp = x; x = y; y = tmp; if ( (x & 3) == 3 && (y & 3) == 3 ) out = -out; x = x % y; } if (y == 1) return out; return 0; } /***********************************/ static s32 powm_16(s32 a, s32 b, s32 n) /*********************************** Compute a^b mod n ************************************/ { s32 res = 1; while (b) { if (b & 1) res = res * a % n; a = a * a % n; b = b >> 1; } return res; } /***********************************/ static s32 modinv_16(s32 a, s32 p) /*********************************** High-speed modular inverse of 'a' mod 'p' Thanks to the folks at www.mersenneforum.com for coming up with this ************************************/ { s32 ps1, ps2, parity, dividend, divisor, rem, q, t; q = 1; rem = a; dividend = p; divisor = a; ps1 = 1; ps2 = 0; parity = 0; while (divisor > 1) { rem = dividend - divisor; t = rem - divisor; if (t >= 0) { q += ps1; rem = t; t -= divisor; if (t >= 0) { q += ps1; rem = t; t -= divisor; if (t >= 0) { q += ps1; rem = t; t -= divisor; if (t >= 0) { q += ps1; rem = t; t -= divisor; if (t >= 0) { q += ps1; rem = t; t -= divisor; if (t >= 0) { q += ps1; rem = t; t -= divisor; if (t >= 0) { q += ps1; rem = t; t -= divisor; if (t >= 0) { q += ps1; rem = t; if (rem >= divisor) { q = dividend / divisor; rem = dividend % divisor; q *= ps1; } } } } } } } } } q += ps2; parity = ~parity; dividend = divisor; divisor = rem; ps2 = ps1; ps1 = q; } if (parity == 0) return ps1; else return p - ps1; } /***********************************/ static s32 sqrtModP_16(s32 a, s32 p) /*********************************** Compute the square root of 'a' mod 'p' This is Algorithm 2.3.8 from Crandall & Pomerance, "Prime Numbers: A Computational Perspective" ************************************/ { if ( (p & 7) == 3 || (p & 7) == 7 ) { return powm_16(a, (p+1)/4, p); } else if ( (p & 7) == 5 ) { #if 0 s32 x, y; x = powm_16(a, (p+3)/8, p); if ((x * x % p) == a) return x; y = powm_16(2, (p-1)/4, p); return (s32)x * y % p; #else #define mulm_16(a, b, n) (((a) * (b)) % (n)) u32 a2, alpha, beta, b; a2 = (a+a) % p; alpha = powm_16(a2, (p-5)>>3, p); beta = mulm_16(a2, mulm_16(alpha,alpha,p), p); b = mulm_16(alpha, mulm_16(a, (beta ? beta-1 : (u32)p-1), p), p); return b; } else if ( (p & 15) == 9 ) { s32 a2, alpha, beta, b, d = 1; a2 = (a+a) % p; alpha = powm_16(a2, (p-9)>>4, p); beta = mulm_16(a2, mulm_16(alpha,alpha,p), p); if (((beta*beta) % p) != p-1) { do { d += 2; } while (legendre_16(d,p) != -1 && d < p); alpha = mulm_16(alpha, powm_16(d, (p-9)>>3, p), p); beta = mulm_16(a2, mulm_16(mulm_16(d,d,p),mulm_16(alpha,p,p),p), p); } b = mulm_16(alpha, mulm_16(a, mulm_16(d, (beta ? beta-1 : p-1), p), p), p); return b; #endif } else { s32 i, d0, d1, a1, s, t, m; d0 = get_rand(&rand_seed1, &rand_seed2) % p; while (legendre_16(d0, p) != -1) d0 = get_rand(&rand_seed1, &rand_seed2) % p; t = p - 1; s = 0; while (!(t & 1)) { s++; t = t / 2; } a1 = powm_16(a, t, p); d1 = powm_16(d0, t, p); for (i = 0, m = 0; i < s; i++) { s32 ad = powm_16(d1, m, p); ad = ad * a1 % p; ad = powm_16(ad, (u16)(1) << (s-1-i), p); if (ad == (p - 1)) m += (1 << i); } a1 = powm_16(a, (t+1)/2, p); d1 = powm_16(d1, m/2, p); return a1 * d1 % p; } } /***********************************/ static void init_tinyqs(void) /***********************************/ { s32 i, j, k, rem; tiny_qs_params *p; if (g_params) return; /* allocate the main structure */ p = g_params = (tiny_qs_params *)malloc(sizeof(tiny_qs_params)); mpz_init(p->n); /* fill in the pool of primes */ p->prime_list[0] = 2; p->prime_list[1] = 3; for (i = 2, j = 5; i < NUM_PRIMES_TINY; j += 2) { for (k = 1, rem = 0; k < i; k++) { s32 prime = p->prime_list[k]; rem = j % prime; if (prime * prime > j || rem == 0) break; } if (rem != 0) p->prime_list[i++] = j; } /* init the scratch values for polynomial 'B' value computations */ for (i = 0; i < MAX_POLY_FACTORS_TINY; i++) { mpz_init(p->poly_b_aux[i]); } /* set up the list of sieve polynomials */ for (i = 0; i < MAX_POLY_TINY; i++) { mpz_init(p->poly_list[i].b); } /* see the next routine for an explanation of what these quantities are */ for (i = 1; i < NUM_TEST_PRIMES_TINY; i++) { p->test_prime_contrib[i] = 2 * log((double)p->prime_list[i]) / (p->prime_list[i] - 1) / M_LN2; } } /* Implementation of the modified Knuth-Schroeppel multiplier algorithm. This borrows ideas from at least four different sources, and seems to choose multipliers that are better on average than many of the other methods available. There are many misconceptions about what this algorithm is supposed to do. We want to multiply the input number n by a small odd squarefree constant k, chosen so that the factor base for k * n contains as many small primes as possible. Since small primes occur more often than big ones, this makes sieve values smaller on average and so more likely to be smooth. We quantify this by measuring the average contribution of the first NUM_TEST_PRIMES_TINY primes to sieve values. There are two constraints: first, larger multipliers mean a larger number to factor. Second, we can't spend all day testing multipliers, so the set of multipliers to test should be small. The list of available multipliers depends on the value of n mod 8, 3, and 5; each row of the table below gives the multipliers to try, pre-sorted by how well they approximately optimize sieving (the routine below computes a better approximation). Note that a multiplier of 1 (i.e. no multiplier) is always possible. Experiments show that 90% of the time the optimal multiplier is in one of the first four columns of the table */ #define MAX_MULTIPLIERS 13 /* for residue classes: */ static u8 mult_list[32][MAX_MULTIPLIERS] = { /* mod 8 mod 3 mod 5 */ { 1, 19, 61, 31, 21, 13, 7, 3, 73, 41, 5, 33, 37 }, /* 1 1 1 */ { 1, 13, 7, 3, 73, 33, 37, 17, 57, 43, 5, 19, 15 }, /* 1 1 2 */ { 1, 13, 7, 3, 73, 33, 37, 17, 57, 43, 5, 19, 15 }, /* 1 1 3 */ { 1, 19, 61, 31, 21, 13, 7, 3, 73, 41, 5, 33, 37 }, /* 1 1 4 */ { 1, 41, 5, 17, 11, 89, 29, 65, 21, 3, 59, 33, 35 }, /* 1 2 1 */ { 1, 17, 5, 3, 33, 65, 57, 23, 41, 53, 47, 11, 89 }, /* 1 2 2 */ { 1, 17, 5, 3, 33, 65, 57, 23, 41, 53, 47, 11, 89 }, /* 1 2 3 */ { 1, 41, 5, 17, 11, 89, 29, 65, 21, 3, 59, 33, 35 }, /* 1 2 4 */ { 1, 19, 3, 11, 31, 7, 51, 43, 15, 39, 61, 55, 21 }, /* 3 1 1 */ { 1, 3, 7, 43, 19, 13, 37, 15, 55, 11, 73, 31, 35 }, /* 3 1 2 */ { 1, 3, 7, 43, 19, 13, 37, 15, 55, 11, 73, 31, 35 }, /* 3 1 3 */ { 1, 19, 3, 11, 31, 7, 51, 43, 15, 39, 61, 55, 21 }, /* 3 1 4 */ { 1, 11, 3, 59, 35, 5, 51, 19, 29, 41, 15, 23, 39 }, /* 3 2 1 */ { 1, 3, 11, 35, 5, 23, 17, 47, 7, 59, 43, 15, 53 }, /* 3 2 2 */ { 1, 3, 11, 35, 5, 23, 17, 47, 7, 59, 43, 15, 53 }, /* 3 2 3 */ { 1, 11, 3, 59, 35, 5, 51, 19, 29, 41, 15, 23, 39 }, /* 3 2 4 */ { 1, 61, 21, 13, 5, 19, 37, 31, 29, 7, 3, 11, 15 }, /* 5 1 1 */ { 1, 13, 37, 7, 3, 5, 73, 61, 21, 43, 33, 53, 17 }, /* 5 1 2 */ { 1, 13, 37, 7, 3, 5, 73, 61, 21, 43, 33, 53, 17 }, /* 5 1 3 */ { 1, 61, 21, 13, 5, 19, 37, 31, 29, 7, 3, 11, 15 }, /* 5 1 4 */ { 1, 5, 29, 21, 11, 41, 53, 17, 89, 3, 59, 61, 65 }, /* 5 2 1 */ { 1, 5, 53, 17, 3, 13, 29, 23, 21, 37, 47, 33, 11 }, /* 5 2 2 */ { 1, 5, 53, 17, 3, 13, 29, 23, 21, 37, 47, 33, 11 }, /* 5 2 3 */ { 1, 5, 29, 21, 11, 41, 53, 17, 89, 3, 59, 61, 65 }, /* 5 2 4 */ { 1, 31, 7, 19, 15, 39, 55, 3, 11, 61, 21, 13, 51 }, /* 7 1 1 */ { 1, 7, 3, 15, 13, 55, 31, 43, 23, 37, 19, 47, 73 }, /* 7 1 2 */ { 1, 7, 3, 15, 13, 55, 31, 43, 23, 37, 19, 47, 73 }, /* 7 1 3 */ { 1, 31, 7, 19, 15, 39, 55, 3, 11, 61, 21, 13, 51 }, /* 7 1 4 */ { 1, 11, 5, 15, 23, 39, 3, 29, 47, 59, 31, 35, 7 }, /* 7 2 1 */ { 1, 23, 3, 47, 7, 5, 15, 17, 11, 35, 53, 39, 33 }, /* 7 2 2 */ { 1, 23, 3, 47, 7, 5, 15, 17, 11, 35, 53, 39, 33 }, /* 7 2 3 */ { 1, 11, 5, 15, 23, 39, 3, 29, 47, 59, 31, 35, 7 }, /* 7 2 4 */ }; /***********************************/ static void find_multiplier_tiny(void) /***********************************/ { tiny_qs_params *params = g_params; s32 i, j; u16 *prime_list = params->prime_list; u16 test_nmodp[NUM_TEST_PRIMES_TINY]; s32 best_mult = 1; s32 nmod8 = mpz_get_ui(params->n) % 8; float best_score; u8 *mult_row; s32 num_tests; /* precompute information that will be needed for all multipliers */ for (i = 1; i < NUM_TEST_PRIMES_TINY; i++) test_nmodp[i] = mpz_tdiv_ui(params->n, prime_list[i]); /* find the row of the table that is approriate for this value of n */ mult_row = mult_list[ test_nmodp[2] - 1 + 4*(test_nmodp[1] - 1) + 8*(nmod8 / 2) ]; /* test less than the whole row if n is small */ num_tests = mpz_sizeinbase(params->n, 2) / 10; if (num_tests > MAX_MULTIPLIERS) num_tests = MAX_MULTIPLIERS; best_score = 1000.0; for (i = 0; i < num_tests; i++) { s32 curr_mult = mult_row[i]; s32 knmod8 = (nmod8 * curr_mult) % 8; float score; /* measure the contribution of 2 as a factor of sieve values. The multiplier itself must also be taken into account in the score. 'score' is the correction that is implicitly applied to the size of sieve values; a negative score makes sieve values smaller, and so is better. */ if (knmod8 == 1) score = 0.5 * log((double)curr_mult) / M_LN2 - 2; else if (knmod8 == 5) score = 0.5 * log((double)curr_mult) / M_LN2 - 1; else score = 0.5 * log((double)curr_mult) / M_LN2 - 0.5; for (j = 1; j < NUM_TEST_PRIMES_TINY; j++) { s32 prime = prime_list[j]; s32 knmodp = (s32)test_nmodp[j] * curr_mult % prime; /* if prime j is actually in the factor base for k * n ... */ if (legendre_16(knmodp, prime) != -1) { /* ...add its contribution. A prime p con- tributes log(p) to 1 in p sieve values, plus log(p) to 1 in p^2 sieve values, etc. The average contribution of all multiples of p to a random sieve value is thus log(p) * (1/p + 1/p^2 + 1/p^3 + ...) = (log(p) / p) * 1 / (1 - (1/p)) = log(p) / (p-1) This contribution occurs once for each square root used for sieving. There are two roots for each factor base prime, unless the prime divides the multiplier. In that case there is only one root. The scores are premultiplied by 2.0, and logarithms are in base 2 (though any base will do) */ if (knmodp == 0) score -= 0.5 * params->test_prime_contrib[j]; else score -= params->test_prime_contrib[j]; } } if (score < best_score) { best_score = score; best_mult = curr_mult; } } /* from now on we will factor best_mult * n */ params->multiplier = best_mult; mpz_mul_ui(params->n, params->n, best_mult); } /***********************************/ static s32 init_fb_tiny(s32 fb_size) /***********************************/ { tiny_qs_params *params = g_params; u16 *prime_list = params->prime_list; s32 i, j, mult_idx; tiny_fb *factor_base = params->factor_base; i = MIN_FB_OFFSET_TINY; mult_idx = 0; factor_base[i].prime = 2; params->multiplier_fb[0] = 0; params->multiplier_fb[1] = 0; /* Keep setting up factor base primes until enough are found or the pool of primes runs out */ for (i++, j = 1; i < fb_size && j < NUM_PRIMES_TINY; j++) { tiny_fb *fbptr = factor_base + i; s32 prime = prime_list[j]; s32 nmodp = mpz_tdiv_ui(params->n, prime); if (legendre_16(nmodp, prime) != -1) { fbptr->prime = prime; fbptr->logprime = (u8)(LOGPRIME_SCALE_TINY * log((double)prime) / M_LN2 + 0.5); fbptr->recip = (u32)(B(32) / (u64)prime); /* if the prime divides n, it is part of n's multiplier and is treated separately */ if (nmodp != 0) { fbptr->modsqrt = (u16)sqrtModP_16(nmodp, prime); } else { fbptr->modsqrt = DO_NOT_SIEVE_TINY; params->multiplier_fb[mult_idx++] = i; } i++; } } params->fb_size = i; return i; } /***********************************/ static void fill_sieve_block_tiny(void) /*********************************** Core sieving routine ************************************/ { tiny_qs_params *params = g_params; s32 i; s32 fb_size = params->fb_size; u8 *sieve_block = params->sieve_block; tiny_fb *factor_base = params->factor_base; /* Note that since this code will only ever factor small inputs, the sieve interval will always be ridiculously small and does not need to be broken up into chunks. Further, the bottleneck with small inputs is the trial factoring of relations and not the sieving, so no crazy unrolling tricks are needed here either */ for (i = MIN_FB_OFFSET_TO_SIEVE_TINY; i < fb_size; i++) { tiny_fb *fbptr = factor_base + i; s32 prime = fbptr->prime; u8 logprime = fbptr->logprime; s32 root = fbptr->roots[0]; while (root < SIEVE_SIZE_TINY) { sieve_block[root] -= logprime; root += prime; } root = fbptr->roots[1]; while (root < SIEVE_SIZE_TINY) { sieve_block[root] -= logprime; root += prime; } } } #define PACKED_SIEVE_MASK ((u64)0x80808080 << 32 | 0x80808080) /***********************************/ static s32 mark_sieve_block_tiny(void) /*********************************** Walk through a filled-in sieve block and find the offsets correspodning to relations that are probably useful ************************************/ { tiny_qs_params *params = g_params; s32 i, j, k; u8 *sieve_block = params->sieve_block; u64 *packed_sieve_block = (u64 *)params->sieve_block; /* standard technique for testing sieve locations in parallel: initialize each byte to the target sieve value, and subtract logs of the factor base primes instead of adding them. Sieve offsets that accumulate enough log values become negative, and it's easy to simultaneously test for the top bit in several bytes being set */ for (i = j = 0; i < SIEVE_SIZE_TINY / 8; i += 4) { /* handle 32 bytes at a time */ u64 accum = packed_sieve_block[i] | packed_sieve_block[i+1] | packed_sieve_block[i+2] | packed_sieve_block[i+3]; if ((accum & PACKED_SIEVE_MASK) == (u64)(0)) continue; /* at least one byte is a hit; go back and search the list one at a time. We treat the sieve interval as a hashtable, and associate entry j in the list of relations to be resieved (params->sieve_batch[]) with a byte that is negative. The high-order bit of the byte is set to indicate that the low-order bits mean something */ for (k = 0; k < 32; k++) { u32 val = sieve_block[8 * i + k]; if (val & 0x80) { if (j < SIEVE_BATCH_SIZE_TINY) { tiny_relation *r = params->sieve_batch + j; r->sieve_offset = 8 * i + k; r->num_factors = 0; sieve_block[8 * i + k] = j | 0x80; j++; } else { sieve_block[8 * i + k] = 0; } } } } return j; } /***********************************/ static void resieve_tiny(void) /*********************************** Just like fill_sieve_block_tiny(), except sieving is used to avoid trial division on all the relations previously found ************************************/ { tiny_qs_params *params = g_params; s32 i; s32 fb_size = params->fb_size; u8 *sieve_block = params->sieve_block; tiny_fb *factor_base = params->factor_base; /* Note that even though this routine does only a little more work than fill_sieve_block_tiny(), it runs almost 3x slower */ for (i = MIN_FB_OFFSET_TO_SIEVE_TINY; i < fb_size; i++) { tiny_fb *fbptr = factor_base + i; s32 prime = fbptr->prime; s32 root = fbptr->roots[0]; while (root < SIEVE_SIZE_TINY) { s32 val = sieve_block[root]; if (val & 0x80) { tiny_relation *r = params->sieve_batch + (val & 0x7f); r->fb_offsets[r->num_factors++] = i; } root += prime; } root = fbptr->roots[1]; while (root < SIEVE_SIZE_TINY) { s32 val = sieve_block[root]; if (val & 0x80) { tiny_relation *r = params->sieve_batch + (val & 0x7f); r->fb_offsets[r->num_factors++] = i; } root += prime; } } } /***********************************/ static s32 check_sieve_val_tiny(mpz_t a, mpz_t b, mpz_t c, tiny_relation *r, s32 sign_of_index) /*********************************** Trial factor a relation that survived sieving ************************************/ { tiny_qs_params *params = g_params; s32 i, j; tiny_fb *factor_base = params->factor_base; s32 num_factors = 0; s32 sieve_offset = r->sieve_offset; tiny_relation *relation = params->relation_list + params->num_full_relations; u16 *fb_offsets = relation->fb_offsets; static u8 initialized = 0; static mpz_t res, res2; if (initialized == 0) { mpz_init(res); mpz_init(res2); initialized = 1; } /* form the polynomial value */ mpz_mul_ui(res, a, sieve_offset); if (sign_of_index == POSITIVE) mpz_add(res, res, b); else mpz_sub(res, res, b); mpz_mul_ui(res, res, sieve_offset); mpz_add(res, res, c); if (mpz_sgn(res) < 0) { mpz_abs(res, res); fb_offsets[num_factors++] = 0; } /* extract powers of two */ i = mpz_scan1(res, 0); if (i) { mpz_tdiv_q_2exp(res, res, i); do { if (num_factors >= MAX_FACTORS_TINY) return 0; fb_offsets[num_factors++] = MIN_FB_OFFSET_TINY; } while (--i); } /* divide out the unsieved factor base primes */ for (i = MIN_FB_OFFSET_TINY + 1; i < MIN_FB_OFFSET_TO_SIEVE_TINY; i++) { tiny_fb *fbptr = factor_base + i; s32 prime = fbptr->prime; s32 root1 = fbptr->roots[0]; s32 root2 = fbptr->roots[1]; u32 recip = fbptr->recip; if (root1 == DO_NOT_SIEVE_TINY) continue; j = (s32)(((u64)sieve_offset * (u64)recip) >> 32); j = sieve_offset - j * prime; if (j >= prime) j -= prime; if (j == root1 || j == root2) { while (mpz_tdiv_q_ui(res2, res, prime) == 0) { if (num_factors >= MAX_FACTORS_TINY) return 0; fb_offsets[num_factors++] = i; mpz_swap(res, res2); } } } /* divide out the factors of the multiplier, if any */ for (i = 0; i < 2; i++) { if (params->multiplier_fb[i]) { s32 prime; j = params->multiplier_fb[i]; prime = factor_base[j].prime; while (mpz_tdiv_q_ui(res2, res, prime) == 0) { if (num_factors >= MAX_FACTORS_TINY) return 0; fb_offsets[num_factors++] = j; mpz_swap(res, res2); } } } /* We should probably have been adding log values to the log of this relation in the previous loops, and testing that the complete log value now exceeds the trial factoring cutoff. However, resieving has already found the remaining factors, so we wouldn't save much time bailing out at this point */ for (i = 0; i < r->num_factors; i++) { s32 prime; j = r->fb_offsets[i]; prime = factor_base[j].prime; while (mpz_tdiv_q_ui(res2, res, prime) == 0) { if (num_factors >= MAX_FACTORS_TINY) return 0; fb_offsets[num_factors++] = j; mpz_swap(res, res2); } } /* start filling in the final relation */ if (sign_of_index == NEGATIVE) sieve_offset = -sieve_offset; relation->sieve_offset = sieve_offset; relation->num_factors = num_factors; relation->poly_num = params->poly_num; if (mpz_cmp_ui(res, 1) == 0) { /* full relation; we're done */ relation->large_prime = 1; params->num_full_relations++; } else if (mpz_cmp_ui(res, params->large_prime_max) < 0) { u32 lp = mpz_get_ui(res); u32 table_idx = LARGE_PRIME_HASH(lp); s32 partial_idx; /* partial relation; see if it has occurred already */ relation->large_prime = lp; for (i = 0; i < LP_HASH_DEPTH_TINY; i++) { partial_idx = params->partial_hash[table_idx][i]; if (partial_idx == 0xffff || lp == params->relation_list[partial_idx].large_prime) break; } if (i == LP_HASH_DEPTH_TINY) { /* not found, and no room to store it */ return 0; } else if (partial_idx == 0xffff) { /* not found, but the hashtable entry has room to keep it; transfer the relation to the partial list */ params->relation_list[params->partial_idx] = *relation; params->partial_hash[table_idx][i] = params->partial_idx--; } else { /* large prime has matched, new relation can stay */ params->num_full_relations++; } } /* make sure the 'heap' of full relations has not overflowed into the 'stack' of partial relations */ if (params->num_full_relations >= params->partial_idx) return -1; return 0; } /***********************************/ static void init_siqs_tiny(void) /*********************************** Initialize the subystem for forming SIQS sieve polynomials ************************************/ { tiny_qs_params *params = g_params; u32 i, j; u32 plus_idx, minus_idx; u32 fb_size = params->fb_size; u32 num_factors = params->num_a_factors; tiny_fb *factor_base = params->factor_base; /* compute the optimal size of the factors of the polynomial 'A' value. We know how many primes it should have, and know the optimal A value that will minimize sieving time. Assume further that all factors are the same size. First compute the factor size, then locate the factor base offset where it approximately occurs */ j = (u32)(exp(log(params->target_a) / num_factors) + 0.5); for (i = MIN_FB_OFFSET_TINY + 1; i < fb_size - 1; i++) { if (factor_base[i].prime > j) break; } if (i == MIN_FB_OFFSET_TINY + 1) i++; /* polynomial A values are built by selecting from a pool of primes. There are POLY_SELECT_BITS_TINY primes in the pool, evenly distributed above and below the optimal factor base offset */ memset(params->poly_select_offsets, 0, sizeof(params->poly_select_offsets)); plus_idx = i; minus_idx = i-1; i = 0; while (1) { if (plus_idx < fb_size && factor_base[plus_idx].modsqrt != DO_NOT_SIEVE_TINY) { params->poly_select_offsets[i] = plus_idx; if (++i == POLY_SELECT_BITS_TINY) break; } if (minus_idx > MIN_FB_OFFSET_TINY + 1 && factor_base[minus_idx].modsqrt != DO_NOT_SIEVE_TINY) { params->poly_select_offsets[i] = minus_idx; if (++i == POLY_SELECT_BITS_TINY) break; } if (minus_idx == 0) /* Something has gone wrong. Exit. */ break; plus_idx++; minus_idx--; } /* polynomial selection will begin at offset zero of the tables below */ params->poly_select_idx = 0; } /* A perpetual problem with SIQS is deciding which primes should make up the next polynomial A value. The selected set must multiply out to a value as close as possible to the optimal A value, but must be sufficiently different from previously selected sets that the odds of producing duplicate relations are low. And the set has to be computed quickly. Fortunately, we will only need a few polynomials so the sets to use can be precomputed. Each prime in the pool is assigned a bit in a bitfield. Consecutive bits in the bitfield refer to primes alternately above and below the optimal factor size. The low-order bits correspond to factors near the optimal value, and the more significant bits march away from the optimal value. Hence, setting the bitfield to an integer will select a unique set of primes, the number of which is the number of set bits in the integer. Small integer values of the bitfield will pick primes close to the optimal factor size, with later bitfield values selecting prime factors that march away from the optimal size. _popcount[] gives the number of set bits for each value of the bitfield, and a_choice[] lists the bitfields themselves. A given factorization only uses one of the population count sizes from the table; bitfields are arranged so that low-order bits are set first, then higher-order bits are set. Every bitfield is different by at least two bits from all other bitfields with the same weight, and there are enough bitfields to generate 256 polynomials, whether A values contain 3, 4, or 5 primes */ /* DAJ: Renamed because NetBSD is broken. */ static u8 _popcount[] = { 3, 4, 3, 5, 3, 4, 3, 4, 3, 3, 4, 4, 3, 4, 5, 4, 5, 4, 4, 4, 4, 5, 5, 4, 4, 5, 5, 4, 5, 5, 5, 5, 3, 5, 5, 5, 5, 5, 3, 4, 3, 4, 4, 4, 3, 3, 4, 4, 4, 4, 3, 4, 4, 4, 4, 3, 4, 4, 3, 4, 4, 4, 4, 3, 4, 3, }; static u16 a_choice[] = { 0x007, 0x00f, 0x019, 0x01f, 0x02a, 0x033, 0x034, 0x03c, 0x04c, 0x052, 0x055, 0x05a, 0x061, 0x066, 0x067, 0x069, 0x079, 0x096, 0x099, 0x0a5, 0x0aa, 0x0ab, 0x0b5, 0x0c3, 0x0cc, 0x0cd, 0x0d3, 0x0f0, 0x12d, 0x133, 0x14b, 0x155, 0x181, 0x187, 0x199, 0x1e1, 0x22e, 0x256, 0x282, 0x303, 0x304, 0x30c, 0x330, 0x3c0, 0x484, 0x502, 0x505, 0x50a, 0x550, 0x5a0, 0x601, 0x606, 0x609, 0x660, 0x690, 0x888, 0x906, 0x909, 0x910, 0x960, 0x990, 0xa05, 0xa0a, 0xa20, 0xa50, 0xc40, }; /***********************************/ static s32 find_poly_a(mpz_t a) /*********************************** Compute the next polynomial A value ************************************/ { tiny_qs_params *params = g_params; u32 i, j, mask; u32 num_a_factors = params->num_a_factors; tiny_fb *factor_base = params->factor_base; tiny_poly *poly = params->poly_list + params->poly_num; /* choose the next bitfield representing primes to use */ for (i = params->poly_select_idx; i < sizeof(_popcount); i++) { if (_popcount[i] == num_a_factors) break; } if (i >= sizeof(_popcount)) return -1; mask = a_choice[i]; params->poly_select_idx = i + 1; /* gather the chosen primes */ for (i = j = 0; i < POLY_SELECT_BITS_TINY; i++) { if (!(mask & (1 << i))) continue; if (params->poly_select_offsets[i] == 0) return -2; poly->a_fb_offsets[j] = params->poly_select_offsets[i]; if (++j == num_a_factors) break; } /* multiply them together */ mpz_set_ui(a, 1); for (i = 0; i < num_a_factors; i++) { j = poly->a_fb_offsets[i]; mpz_mul_ui(a, a, factor_base[j].prime); } return 0; } /***********************************/ static void find_first_poly_b(mpz_t a, mpz_t b, mpz_t c) /*********************************** Compute the first of a list of polynomial B values ************************************/ { tiny_qs_params *params = g_params; u32 i, j; u32 num_a_factors = params->num_a_factors; u32 fb_size = params->fb_size; tiny_fb *factor_base = params->factor_base; tiny_poly *poly = params->poly_list + params->poly_num; mpz_set_ui(b, 0); /* fill in the auxiliary quantities needed to compute future B values */ for (i = 0; i < num_a_factors; i++) { tiny_fb *fbptr = factor_base + poly->a_fb_offsets[i]; s32 g, prime = fbptr->prime; mpz_divexact_ui(params->poly_b_aux[i], a, prime); g = mpz_tdiv_ui(params->poly_b_aux[i], prime); g = modinv_16(g, prime); g = (s32)g * fbptr->modsqrt % prime; if (g > prime/2) g = prime - g; mpz_mul_ui(params->poly_b_aux[i], params->poly_b_aux[i], g); mpz_add(b, b, params->poly_b_aux[i]); mpz_add(params->poly_b_aux[i], params->poly_b_aux[i], params->poly_b_aux[i]); } /* This first B is the sum of the auxiliary quantities computed previously */ mpz_set(poly->b, b); /* Form C, a helper for computing the value of a polynomial before trial factoring */ mpz_mul(c, b, b); mpz_sub(c, c, params->n); mpz_divexact(c, c, a); /* initialize the factor base for sieving */ for (i = MIN_FB_OFFSET_TINY + 1; i < fb_size; i++) { tiny_fb *fbptr = factor_base + i; s32 prime = fbptr->prime; s32 modsqrt = fbptr->modsqrt; s32 amodp = mpz_tdiv_ui(a, prime); s32 bmodp = prime - mpz_tdiv_ui(b, prime); if (fbptr->modsqrt == DO_NOT_SIEVE_TINY) { /* factors of the multiplier never contribute to sieving */ fbptr->roots[0] = DO_NOT_SIEVE_TINY; fbptr->roots[1] = DO_NOT_SIEVE_TINY; continue; } else if (amodp == 0) { /* factor base primes that divide the A value get one sieve root and not two */ amodp = prime - mpz_tdiv_ui(c, prime); fbptr->roots[0] = amodp * modinv_16(2 * bmodp % prime, prime) % prime; fbptr->roots[1] = DO_NOT_SIEVE_TINY; } else { /* handle all the other FB primes, including the initialization that allows the next 2^(num_a_factors-1)-1 factor bases to initialize quickly */ amodp = modinv_16(amodp, prime); fbptr->roots[0] = amodp * (bmodp + modsqrt) % prime; fbptr->roots[1] = amodp * (bmodp + prime - modsqrt) % prime; for (j = 0; j < num_a_factors; j++) { bmodp = mpz_tdiv_ui(params->poly_b_aux[j], prime); params->root_aux[j * fb_size + i] = bmodp * amodp % prime; } } } } /***********************************/ static void find_next_poly_b(mpz_t a, mpz_t b, mpz_t c) /*********************************** Initialize B values beyond the first ************************************/ { tiny_qs_params *params = g_params; s32 i, j; s32 num_a_factors = params->num_a_factors; s32 fb_size = params->fb_size; tiny_fb *factor_base = params->factor_base; tiny_poly *poly = params->poly_list + params->poly_num; u32 mask = params->poly_num & ((1 << (num_a_factors-1)) - 1); u8 do_sub; u16 *row; /* current poly starts of with the previous poly */ mpz_set(b, poly[-1].b); for (i = 0; i < num_a_factors; i++) poly[0].a_fb_offsets[i] = poly[-1].a_fb_offsets[i]; /* determine the auxiliary B constant that comes next in Gray code order, and add to or subtract from the current B. This also determines which of the rows from the table of corrections are applied to the factor base */ i = 0; while ((mask & (1 << i)) == 0) i++; row = params->root_aux + fb_size * i; do_sub = 0; if (mask & (1 << (i+1))) { mpz_add(b, b, params->poly_b_aux[i]); do_sub = 1; } else { mpz_sub(b, b, params->poly_b_aux[i]); } /* form the C helper value */ mpz_mul(c, b, b); mpz_sub(c, c, params->n); mpz_divexact(c, c, a); /* set up the factor base for the next B */ for (j = MIN_FB_OFFSET_TINY + 1; j < fb_size; j++) { tiny_fb *fbptr = factor_base + j; s32 prime = fbptr->prime; s32 root1 = fbptr->roots[0]; s32 root2 = fbptr->roots[1]; /* apply the correction to each sieve root */ if (root2 != DO_NOT_SIEVE_TINY) { /* ordinary FB prime. Note that the pevious sieving operation negated the roots to use, so they have to be negated again before the correction is applied */ if (root1) root1 = prime - root1; if (root2) root2 = prime - root2; if (do_sub) { root1 -= row[j]; root2 -= row[j]; } else { root1 += row[j] - prime; root2 += row[j] - prime; } if (root1 < 0) root1 += prime; if (root2 < 0) root2 += prime; fbptr->roots[0] = root1; fbptr->roots[1] = root2; } else if (root1 != DO_NOT_SIEVE_TINY) { /* sieving with root1 but not root 2 only happens if the prime divides 'A'. Compute the new sieve root manually */ s32 cmodp = prime - mpz_tdiv_ui(c, prime); s32 bmodp = mpz_tdiv_ui(b, prime); if (mpz_sgn(b) > 0) bmodp = prime - bmodp; fbptr->roots[0] = cmodp * modinv_16(2 * bmodp % prime, prime) % prime; } } mpz_set(poly[0].b, b); } /***********************************/ static s32 sieve_next_poly_tiny(void) /*********************************** Do all the sieving for one polynomial ************************************/ { tiny_qs_params *params = g_params; s32 i; s32 fb_size = params->fb_size; u8 *sieve_block = params->sieve_block; tiny_fb *factor_base = params->factor_base; s32 cutoff1, num_surviving; s32 poly_num = params->poly_num; s32 target_relations = params->fb_size + NUM_EXTRA_RELATIONS_TINY; static u8 initialized = 0; static mpz_t a, b, c; if (initialized == 0) { mpz_init(a); mpz_init(b); mpz_init(c); initialized = 1; } /* generate the polynomial */ if (!(poly_num & ((1 << (params->num_a_factors-1))-1))) { i = find_poly_a(a); if (i) return i; find_first_poly_b(a, b, c); } else { find_next_poly_b(a, b, c); } /* compute the cutoff beyond which trial factoring will be used on sieve values. */ cutoff1 = LOGPRIME_SCALE_TINY * (mpz_sizeinbase(c, 2) - params->error_bits - SMALL_PRIME_FUDGE_TINY - 1); /* the trial factoring code wants 2*B and not B */ mpz_add(b, b, b); /* sieve over positive offsets, mark the most promising offsets, resieve to trial factor them all at once and then finish each in turn */ memset(sieve_block, cutoff1 - 1, SIEVE_SIZE_TINY); fill_sieve_block_tiny(); num_surviving = mark_sieve_block_tiny(); if (num_surviving) { resieve_tiny(); for (i = 0; i < num_surviving; i++) { if (check_sieve_val_tiny(a, b, c, params->sieve_batch + i, POSITIVE) != 0) { return -3; } if (params->num_full_relations >= target_relations) return 0; } } /* flip the sieve roots from positive to negative values */ for (i = MIN_FB_OFFSET_TINY + 1; i < fb_size; i++) { tiny_fb *fbptr = factor_base + i; s32 prime = fbptr->prime; s32 root1 = fbptr->roots[0]; s32 root2 = fbptr->roots[1]; if (root1 != DO_NOT_SIEVE_TINY && root1) fbptr->roots[0] = prime - root1; if (root2 != DO_NOT_SIEVE_TINY && root2) fbptr->roots[1] = prime - root2; } /* repeat the sieve procedure for negative sieve offsets */ memset(sieve_block, cutoff1 - 1, SIEVE_SIZE_TINY); fill_sieve_block_tiny(); num_surviving = mark_sieve_block_tiny(); if (num_surviving) { resieve_tiny(); for (i = 0; i < num_surviving; i++) { if (check_sieve_val_tiny(a, b, c, params->sieve_batch + i, NEGATIVE) != 0) { return -3; } if (params->num_full_relations >= target_relations) return 0; } } return 0; } /***********************************/ static void solve_linear_system_tiny(void) /*********************************** Find linear dependencies among a set of relations ************************************/ { tiny_qs_params *params = g_params; s32 i, j, k, start_row; s32 nrows = params->fb_size; s32 ncols = params->num_full_relations; s32 num_a_factors = params->num_a_factors; u16 rowperm[MAX_FB_SIZE_TINY]; u16 pivot[MAX_FB_SIZE_TINY]; s32 row = 0; memset(params->matrix, 0, sizeof(params->matrix)); /* build the matrix; relations become columns, and pairs of matched partial relations fuse into columns as well */ for (i = 0; i < ncols; i++) { tiny_relation *r; tiny_poly *poly; for (j = 0; j < 2; j++) { r = params->relation_list + i; if (j == 1) { s32 hash_idx = LARGE_PRIME_HASH(r->large_prime); s32 partial_idx; for (k = 0; k < LP_HASH_DEPTH_TINY; k++) { partial_idx = params->partial_hash[hash_idx][k]; if (params->relation_list[partial_idx].large_prime == r->large_prime) break; } r = params->relation_list + partial_idx; } poly = params->poly_list + r->poly_num; for (k = 0; k < r->num_factors; k++) { row = r->fb_offsets[k]; params->matrix[row][i / 64] ^= bitmask[i % 64]; } /* the factors in the polynomial A value figure into the matrix as well */ for (k = 0; k < num_a_factors; k++) { row = poly->a_fb_offsets[k]; params->matrix[row][i / 64] ^= bitmask[i % 64]; } if (r->large_prime == 1) break; } } for (i = 0; i < nrows; i++) rowperm[i] = i; /* begin with a random vector of dependencies */ for (i = 0; i < ncols; i++) params->null_vectors[i] = (u16)get_rand( &rand_seed1, &rand_seed2); /* perform the elimination */ for (i = start_row = 0; start_row < nrows && i < ncols; i++) { /* find the next pivot */ for (j = start_row; j < nrows; j++) { row = rowperm[j]; if (params->matrix[row][i / 64] & bitmask[i % 64]) break; } if (j == nrows) continue; rowperm[j] = rowperm[start_row]; rowperm[start_row] = row; pivot[start_row++] = i; /* eliminate it from the other rows */ for (j++; j < nrows; j++) { s32 row2 = rowperm[j]; if (params->matrix[row2][i / 64] & bitmask[i % 64]) { for (k = i / 64; k < (ncols + 63) / 64; k++) { params->matrix[row2][k] ^= params->matrix[row][k]; } } } } /* perform back substitution */ for (i = start_row - 1; i >= 0; i--) { u16 accum; row = rowperm[i]; for (j = pivot[i] + 1, accum = 0; j < ncols; j++) { if (params->matrix[row][j / 64] & bitmask[j & 63]) accum ^= params->null_vectors[j]; } params->null_vectors[pivot[i]] = accum; } } /***********************************/ static u32 find_factors_tiny(mpz_t factor1, mpz_t factor2) /*********************************** perform MPQS square root phase ************************************/ { tiny_qs_params *params = g_params; s32 i, j, k; u16 mask; u16 fb_counts[MAX_FB_SIZE_TINY]; tiny_fb *factor_base = params->factor_base; static mpz_t x, y, t0, t1; static u8 initialized = 0; if (initialized == 0) { mpz_init(x); mpz_init(y); mpz_init(t0); mpz_init(t1); initialized = 1; } /* for each dependency */ for (mask = 1; mask; mask <<= 1) { memset(fb_counts, 0, sizeof(fb_counts)); mpz_set_ui(x, 1); mpz_set_ui(y, 1); /* for each relation allowed in the dependency */ for (i = 0; i < params->num_full_relations; i++) { if (!(params->null_vectors[i] & mask)) continue; for (j = 0; j < 2; j++) { tiny_relation *r = params->relation_list + i; tiny_poly *poly; /* match up partials with the same large prime */ if (j == 1) { s32 hash_idx = LARGE_PRIME_HASH(r->large_prime); s32 partial_idx; for (k = 0; k < LP_HASH_DEPTH_TINY; k++) { partial_idx = params->partial_hash[hash_idx][k]; if (params->relation_list[partial_idx].large_prime == r->large_prime) break; } r = params->relation_list + partial_idx; mpz_mul_ui(t0, y, r->large_prime); mpz_mod(y, t0, params->n); } poly = params->poly_list + r->poly_num; /* add the factors of this relation to the table of factors. Include the factors of A as well */ for (k = 0; k < r->num_factors; k++) fb_counts[r->fb_offsets[k]]++; mpz_set_ui(t1, 1); for (k = 0; k < params->num_a_factors; k++) { s32 idx = poly->a_fb_offsets[k]; fb_counts[idx]++; mpz_mul_ui(t1, t1, factor_base[idx].prime); } /* multiply A * sieve_offset + B into the left side of the congruence */ if (r->sieve_offset < 0) { mpz_mul_ui(t1, t1, -(r->sieve_offset)); mpz_sub(t1, t1, poly->b); } else { mpz_mul_ui(t1, t1, r->sieve_offset); mpz_add(t1, t1, poly->b); } mpz_mul(t0, x, t1); mpz_mod(x, t0, params->n); if (r->large_prime == 1) break; } } /* Form the right side of the congruence; given its prime factorization, cut the exponent of each prime in half and perform a modular exponentiation */ for (i = MIN_FB_OFFSET_TINY; i < params->fb_size; i++) { u16 mask2 = 0x8000; u16 exponent = fb_counts[i] / 2; u32 prime = params->factor_base[i].prime; if (exponent == 0) continue; mpz_set_ui(t0, prime); while (!(exponent & mask2)) mask2 >>= 1; for (mask2 >>= 1; mask2; mask2 >>= 1) { mpz_mul(t1, t0, t0); mpz_mod(t0, t1, params->n); if (exponent & mask2) { mpz_mul_ui(t1, t0, prime); mpz_mod(t0, t1, params->n); } } mpz_mul(t1, t0, y); mpz_mod(y, t1, params->n); } /* For x and y the halves of the congruence, compute gcd(x+-y, n) */ for (i = 0; i < 2; i++) { if (i == 0) mpz_add(t0, x, y); else mpz_sub(t0, x, y); mpz_gcd(t1, t0, params->n); if (mpz_cmp_ui(t1, 1) && mpz_cmp(t1, params->n)) { /* we've possibly found a nontrivial factor of n. Divide any factors of the multiplier out from both factors */ u32 mult1 = 0; u32 mult2 = 0; if (params->multiplier_fb[0]) mult1 = params->factor_base[params->multiplier_fb[0]].prime; if (params->multiplier_fb[1]) mult2 = params->factor_base[params->multiplier_fb[1]].prime; mpz_divexact(t0, params->n, t1); if (mult1) { if (mpz_tdiv_ui(t0, mult1) == 0) mpz_divexact_ui(t0, t0, mult1); if (mpz_tdiv_ui(t1, mult1) == 0) mpz_divexact_ui(t1, t1, mult1); } if (mult2) { if (mpz_tdiv_ui(t0, mult2) == 0) mpz_divexact_ui(t0, t0, mult2); if (mpz_tdiv_ui(t1, mult2) == 0) mpz_divexact_ui(t1, t1, mult2); } /* If both remaining factors exceed unity, we've factored n and can stop */ if (mpz_cmp_ui(t0, 1) && mpz_cmp_ui(t1, 1)) { mpz_set(factor1, t0); mpz_set(factor2, t1); return 1; } } } /* otherwise try the next dependency */ } return 0; } typedef struct { s32 fb_size; s32 num_poly_factors; } tiny_qs_config; /* factor base sizes for 50 to 120-bit factorizations */ static tiny_qs_config static_config[] = { { 40, 3 }, { 50, 3 }, { 60, 3 }, { 70, 3 }, { 80, 3 }, { 90, 3 }, { 110, 3 }, { 120, 3 }, { 140, 3 }, { 140, 3 }, { 160, 3 }, { 180, 4 }, { 230, 4 }, { 280, 4 }, { 350, 4 }, { 420, 4 }, { 490, 5 }, }; /***********************************/ unsigned int tinyqs(mpz_t n, mpz_t factor) /*********************************** Main driver for MPQS factorization Returns 1 and sets factor if successful, returns 0 otherwise ************************************/ { tiny_qs_params *params; s32 bits, status = 0; s32 fb_size; s32 bound; s32 large_prime_mult; tiny_qs_config *config; mpz_t tmp; mpz_init(tmp); /* make sure the input isn't a perfect square. We may also want to add a test for a perfect cube, but that's so unlikely it's probably not worth worrying about */ if (mpz_root(tmp, n, 2) != 0) { mpz_set(factor, tmp); mpz_clear(tmp); return 1; } /* start the initialization */ init_tinyqs(); params = g_params; mpz_set(params->n, n); params->num_full_relations = 0; params->partial_idx = 4 * MAX_RELATIONS_TINY - 1; params->poly_num = 0; bits = mpz_sizeinbase(params->n, 2); find_multiplier_tiny(); /* determine the factor base size and the number of primes in a polynomial A value */ if (bits < 50) bits = 50; if (bits > 116) bits = 116; config = static_config + ((bits - 50) / 4); fb_size = config->fb_size; params->num_a_factors = config->num_poly_factors; /* build the factor base */ fb_size = init_fb_tiny(fb_size); /* compute the optimal A value */ mpz_sqrt(tmp, params->n); params->target_a = mpz_get_d(tmp) * M_SQRT2 / SIEVE_SIZE_TINY; init_siqs_tiny(); /* compute the large prime cutoff and the size of the fudge factor needed to account for it in the sieving cutoff */ large_prime_mult = 15; bound = params->factor_base[fb_size - 1].prime; bound *= large_prime_mult; params->large_prime_max = bound; params->error_bits = (u32)(log(bound) / M_LN2 + 1); /* empty out the hashtable for partial relations */ memset(params->partial_hash, 0xff, sizeof(params->partial_hash)); /* do the sieving! */ while (params->poly_num < MAX_POLY_TINY && params->num_full_relations < fb_size + NUM_EXTRA_RELATIONS_TINY) { if (sieve_next_poly_tiny() != 0) { mpz_clear(tmp); return 0; } params->poly_num++; } /* if enough relations were found, finish off the factorization */ if (params->num_full_relations >= fb_size + NUM_EXTRA_RELATIONS_TINY) { solve_linear_system_tiny(); status = find_factors_tiny(factor, tmp); /* Return smaller of two factors */ if (status && mpz_cmp(factor,tmp) > 0) mpz_swap(factor,tmp); } mpz_clear(tmp); return status; }