Math-Prime-Util-GMP-0.35/0000755000076400007640000000000012633466633013354 5ustar danadanaMath-Prime-Util-GMP-0.35/simpqs.h0000644000076400007640000000016612127325220015024 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.35/utility.c0000644000076400007640000007431412627512342015224 0ustar danadana/* * Utility functions, such as sqrt mod p, polynomial manipulation, etc. */ #include #include #include #include #include "ptypes.h" /* includes mpz_mulmod(r, a, b, n, temp) */ #include "utility.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; } void init_randstate(unsigned long seed) { #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); } void clear_randstate(void) { gmp_randclear(_randstate); } 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; } /* 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) { 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; } /* set x to sqrt(a) mod p. Returns 0 if a is not a square root mod p */ /* See Cohen section 1.5. * See http://www.math.vt.edu/people/brown/doc/sqrts.pdf */ int sqrtmod(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; /* 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_legendre(t, p) != -1) /* choose t "at random" */ mpz_add_ui(t, t, 1); 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(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(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 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 { mpz_ui_pow_ui(t2, base, 2); mpz_tdiv_q(t1, t1, t2); 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_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]); } } #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(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, gmp_randstate_t* p_randstate) { 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_urandomm(pxa[0], *p_randstate, 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, p_randstate); 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, p_randstate); } } else { polyz_div(pq, pt, pg, ph, &dq, &dt, dg, dh, NMOD); polyz_roots(roots, nroots, maxroots, pq, dq, NMOD, p_randstate); if (*nroots < maxroots) { polyz_roots(roots, nroots, maxroots, ph, dh, NMOD, p_randstate); } } } 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, gmp_randstate_t* p_randstate) { 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, p_randstate); /* 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" 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.35/ecpp.h0000644000076400007640000000062012350477427014451 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.35/META.json0000664000076400007640000000274212633466633015004 0ustar danadana{ "abstract" : "Utilities related to prime numbers, using GMP", "author" : [ "Dana A Jacobsen " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.1, CPAN::Meta::Converter version 2.150005", "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.52" }, "requires" : { "Carp" : "0", "Exporter" : "5.57", "XSLoader" : "0.01", "base" : "0", "perl" : "5.006002" } }, "test" : { "requires" : { "Test::More" : "0.45" } } }, "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.35", "x_serialization_backend" : "JSON::PP version 2.27300" } Math-Prime-Util-GMP-0.35/.travis.yml0000644000076400007640000000067412630616777015477 0ustar danadanalanguage: "perl" perl: - "5.16" - "5.14" - "5.12" - "5.10" before_install: - sudo apt-get install libgmp-dev - 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.35/gmp_main.c0000644000076400007640000032460412627512346015314 0ustar danadana #include #include #include #include #include #include #define FUNC_gcd_ui 1 #define FUNC_is_perfect_square 1 #include "ptypes.h" #include "gmp_main.h" #include "prime_iterator.h" #include "bls75.h" #include "ecpp.h" #include "utility.h" #include "factor.h" #define AKS_VARIANT_V6 1 /* The V6 paper with Lenstra impr */ #define AKS_VARIANT_BORNEMANN 2 /* Based on Folkmar Bornemann's impl */ #define AKS_VARIANT_BERNEXAMPLE 3 /* AKS-Bernstein-Morain */ #define AKS_VARIANT AKS_VARIANT_BORNEMANN 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) { /* We should not use this random number system for crypto, so * using this lousy seed is ok. We just would like something a * bit different every run. Using Perl_seed(aTHX) would be better. */ 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) { prime_iterator_global_shutdown(); clear_randstate(); mpz_clear(_bgcd); mpz_clear(_bgcd2); mpz_clear(_bgcd3); destroy_ecpp_gcds(); } 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 INLINE int _GMP_miller_rabin_ui(mpz_t n, UV base) { int rval; mpz_t a; mpz_init_set_ui(a, base); rval = _GMP_miller_rabin(n, a); mpz_clear(a); return rval; } int _GMP_miller_rabin_random(mpz_t n, UV numbases, char* seedstr) { gmp_randstate_t* p_randstate = get_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); mpz_init(base); mpz_init(t); if (seedstr != 0) { /* Set the RNG seed if they gave us a seed */ mpz_set_str(t, seedstr, 0); gmp_randseed(*p_randstate, t); } mpz_sub_ui(t, n, 3); for (i = 0; i < numbases; i++) { mpz_urandomm(base, *p_randstate, t); /* base = 0 .. (n-3)-1 */ mpz_add_ui(base, base, 2); /* base = 2 .. n-2 */ if (_GMP_miller_rabin(n, base) == 0) break; } mpz_clear(base); mpz_clear(t); return (i >= numbases); } int _GMP_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; } int is_miller_prime(mpz_t n, int assume_grh) { mpz_t nminus1, d, x; UV s, r, logn, 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 */ } mpz_init_set(nminus1, n); mpz_sub_ui(nminus1, nminus1, 1); mpz_init_set(d, nminus1); s = mpz_scan1(d, 0); mpz_tdiv_q_2exp(d, d, s); logn = mpz_sizeinbase(n, 2); if (mpz_cmp_ui(n, 1373653) < 0) { maxa = 3; } else if (assume_grh) { /* Rough computation of ln(n), slightly high */ logn = 1 + (0.69314718056 * ((double)logn)); if (logn > ((BITS_PER_WORD == 32) ? 46340UL : 3037000499UL)) croak("is_miller_prime: n is too large for GRH DMR"); maxa = 2*logn*logn; } else { /* Bober and Goldmakher 2015 (http://arxiv.org/abs/1311.7556) */ logn = 1 + ((1/6.59) * ((double)logn)); if (logn >= BITS_PER_WORD) croak("is_miller_prime: n is too large for unconditional DMR"); maxa = UVCONST(1) << logn; } 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(x); rval = 1; for (a = 2; rval && a <= maxa; a++) { rval = 0; mpz_set_ui(x, a); mpz_powm(x, x, d, n); 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); mpz_clear(d); 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; 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); 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; 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); } 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; } static 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(W); } mpz_clear(d); rval = 0; mpz_sub_ui(t, n, 2); 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); } } } mpz_clear(V); mpz_clear(t); return rval; } static void mat_mulmod_3x3(mpz_t* a, mpz_t* b, mpz_t n, mpz_t* t, mpz_t t2) { int i, row, col; for (row = 0; row < 3; row++) { for (col = 0; col < 3; col++) { mpz_mul(t[3*row+col], a[3*row+0], b[0+col]); mpz_mul(t2, a[3*row+1], b[3+col]); mpz_add(t[3*row+col], t[3*row+col], t2); mpz_mul(t2, a[3*row+2], b[6+col]); mpz_add(t[3*row+col], t[3*row+col], t2); } } for (i = 0; i < 9; i++) mpz_mod(a[i], t[i], n); } static void mat_powmod_3x3(mpz_t* m, mpz_t kin, mpz_t n) { mpz_t k, t2, t[9], res[9]; int i; mpz_init_set(k, kin); mpz_init(t2); for (i = 0; i < 9; i++) { mpz_init(t[i]); mpz_init(res[i]); } mpz_set_ui(res[0],1); mpz_set_ui(res[4],1); mpz_set_ui(res[8],1); while (mpz_sgn(k)) { if (mpz_odd_p(k)) mat_mulmod_3x3(res, m, n, t, t2); mpz_fdiv_q_2exp(k, k, 1); if (mpz_sgn(k)) mat_mulmod_3x3(m, m, n, t, t2); } for (i = 0; i < 9; i++) { mpz_set(m[i],res[i]); mpz_clear(res[i]); mpz_clear(t[i]); } mpz_clear(t2); mpz_clear(k); } int is_perrin_pseudoprime(mpz_t n) { int P[9] = {0,1,0, 0,0,1, 1,1,0}; mpz_t m[9]; int i, 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 */ } for (i = 0; i < 9; i++) mpz_init_set_ui(m[i], P[i]); mat_powmod_3x3(m, n, n); mpz_add(m[1], m[0], m[4]); mpz_add(m[2], m[1], m[8]); mpz_mod(m[0], m[2], n); rval = mpz_sgn(m[0]) ? 0 : 1; for (i = 0; i < 9; i++) mpz_clear(m[i]); 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) { gmp_randstate_t* p_randstate = get_randstate(); 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_urandomm(a, *p_randstate, t); mpz_add_ui(a, a, 1); mpz_urandomm(b, *p_randstate, 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); 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; } 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; } /* * 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 tests 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. * * What are these extra M-R tests getting us? The primary reference is * Damgård, Landrock, and Pomerance, 1993. From Rabin-Monier, with random * bases we have p <= 4^-t. So one extra test gives us p = 0.25, and four * tests gives us p = 0.00390625. But for larger k (bits in n) this is very * conservative. Since the value has passed BPSW, we are only interested in * k > 64. See the calculate-mr-probs.pl script in the xt/ directory. * For a 256-bit input, we get: * 1 test: p < 0.000244140625 * 2 tests: p < 0.00000000441533 * 3 tests: p < 0.0000000000062550875 * 4 tests: p < 0.000000000000028421709 * * It's even more extreme as k goes higher. Also recall that this is the * probability once we've somehow found a BPSW pseudoprime. */ int primality_pretest(mpz_t n) { /* If less than 1009, make trial factor handle it. */ if (mpz_cmp_ui(n, BGCD_NEXTPRIME) < 0) return _GMP_trial_factor(n, 2, BGCD_LASTPRIME) ? 0 : 2; /* 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; } int _GMP_BPSW(mpz_t n) { if (mpz_cmp_ui(n, 4) < 0) return (mpz_cmp_ui(n, 1) <= 0) ? 0 : 1; if (_GMP_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) */ static 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++) { mpz_set_ui(t, sprimes[i]); res = _GMP_miller_rabin(n, t); } if (res == 1) res = 2; } mpz_clear(t); } return res; } 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 _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 n-1 proof. */ if (prob_prime == 1) { if (is_proth_form(n)) prob_prime = _GMP_primality_bls_nm1(n, 2 /* effort */, 0 /* cert */); else if (nbits <= 200) prob_prime = _GMP_primality_bls_nm1(n, 1 /* effort */, 0 /* cert */); } /* 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 use enough bases to keep the probability below 1/595,000. */ if (prob_prime == 1) { UV ntests; if (nbits < 80) ntests = 5; /* p < .00000168 */ else if (nbits < 105) ntests = 4; /* p < .00000156 */ else if (nbits < 160) ntests = 3; /* p < .00000164 */ else if (nbits < 413) ntests = 2; /* p < .00000156 */ else ntests = 1; /* p < .00000159 */ prob_prime = _GMP_miller_rabin_random(n, ntests, 0); /* prob_prime = _GMP_is_frobenius_underwood_pseudoprime(n); */ /* prob_prime = _GMP_is_frobenius_khashin_pseudoprime(n); */ } /* Using Damgård, Landrock, and Pomerance, we get upper bounds: * k <= 64 p = 0 * k < 80 p < 7.53e-08 * k < 105 p < 3.97e-08 * k < 160 p < 1.68e-08 * k >= 160 p < 2.57e-09 * This (1) pretends the SPSP-2 is included in the random tests, (2) doesn't * take into account the trial division, (3) ignores the observed * SPSP-2 / Strong Lucas anti-correlation that makes the BPSW test so * useful. Hence these numbers are still extremely conservative. * * For an idea of how conservative we are being, we have now exceeded the * tests used in Mathematica, Maple, Pari, and SAGE. Note: Pari pre-2.3 * used just M-R tests. Pari 2.3+ uses BPSW with no extra M-R checks for * is_pseudoprime, but isprime uses APRCL which, being a proof, could only * output a pseudoprime through a coding error. */ 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 = _GMP_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); return prob_prime; } /*****************************************************************************/ /* AKS. This implementation is quite slow, but useful to have. */ 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); a %= r; 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_mod_ui(t, n, r); if (n_mod_r >= r) croak("n mod r >= 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_BORNEMANN static int is_primitive_root(mpz_t n, UV r) { mpz_t m, modr; UV p, rm1 = r-1; UV lim = (UV) (sqrt(rm1) + 0.00001); UV ret = 0; mpz_init(m); mpz_init_set_ui(modr, r); if ((rm1 % 2) == 0) { mpz_powm_ui(m, n, (rm1/2), modr); if (!mpz_cmp_ui(m,1)) goto END_PRIMROOT; } for (p = 3; p <= lim; p += 2) { if ((rm1 % p) == 0) { mpz_powm_ui(m, n, (rm1/p), modr); if (!mpz_cmp_ui(m,1)) goto END_PRIMROOT; } } ret = 1; END_PRIMROOT: mpz_clear(m); mpz_clear(modr); return ret; } 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 #if AKS_VARIANT == AKS_VARIANT_BERNEXAMPLE 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 int _GMP_is_aks_prime(mpz_t n) { mpz_t *px, *py; int retval; UV i, s, r, a; 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; PRIME_ITERATOR(iter); mpz_init(sqrtn); mpz_sqrt(sqrtn, n); /* limit should be floor( log2(n) ** 2 ). The simple GMP solution is * to get ceil(log2(n)) via mpz_sizeinbase(n,2) and square, but that * overcalculates by a fair amount. We'll calculate float log2n as: * ceil(log2(n**k)) / k [mpz_sizeinbase(n,2) <=> ceil(log2(n))] * which gives us a value that slightly overestimates log2(n). */ mpz_init(t); mpz_pow_ui(t, n, 32); log2n = ((double) mpz_sizeinbase(t, 2) + 0.000001) / 32.0; limit = (UV) floor( log2n * log2n ); mpz_clear(t); 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; 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 (mpz_order_ui(r, n, limit) > limit) { retval = 2; break; } } prime_iterator_destroy(&iter); mpz_clear(sqrtn); if (retval != 2) return retval; /* Bernstein 2002 suggests we could use: * s = (UV) floor( ceil(sqrt(((double)(r-1))/3.0)) * log2n ); * here, by Minkowski's theorem. r-1 is really phi(r). */ 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(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_BERNEXAMPLE { double slim, scmp, x; mpz_t t, t2; PRIME_ITERATOR(iter); mpz_init(t); mpz_init(t2); r = 0; s = 0; while (1) { UV q, tmp; /* todo: Check r|n and r >= sqrt(n) */ 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; slim = 40 * (r-1); scmp = 2 * floor(sqrt(r)) * log(mpz_get_d(n))/log(2); for (s = 2; s < slim; s++) { mpz_bin_uiui(t, q+s-1, s); if (log(mpz_get_d(t))/log(2) > 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; } #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 = 1; a <= s; a++) { if (! test_anr(a, n, r, px, py) ) { retval = 0; 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; } /*****************************************************************************/ /* Controls how many numbers to sieve. Little time impact. */ #define NPS_MERIT 30.0 /* Controls how many primes to use. Big time impact. */ #define NPS_DEPTH (log2n > 200000 ? 4200000000UL : log2n * (log2n/10)) static void next_prime_with_sieve(mpz_t n) { uint32_t* comp; mpz_t t, base; UV i; UV log2n = mpz_sizeinbase(n, 2); UV width = (UV) (NPS_MERIT/1.4427 * (double)log2n + 0.5); UV depth = NPS_DEPTH; 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) { uint32_t* comp; mpz_t t, base; UV i, j; UV log2n = mpz_sizeinbase(n, 2); UV width = (UV) (NPS_MERIT/1.4427 * (double)log2n + 0.5); UV depth = NPS_DEPTH; 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) ); } } #define LAST_DOUBLE_PROD \ ((BITS_PER_WORD == 32) ? UVCONST(65521) : UVCONST(4294967291)) void _GMP_pn_primorial(mpz_t prim, UV n) { UV p = 2; PRIME_ITERATOR(iter); if (n < 800) { /* Don't go above 6500 to prevent overflow below */ /* Simple linear multiplication, two at a time */ 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); } } else { /* Shallow product tree, ~10x faster for large values */ mpz_t t[16]; UV i; for (i = 0; i < 16; i++) mpz_init_set_ui(t[i], 1); i = 0; while (n-- > 0) { if (p <= LAST_DOUBLE_PROD && n > 0) { p *= prime_iterator_next(&iter); n--; } mpz_mul_ui(t[i&15], t[i&15], p); p = prime_iterator_next(&iter); i++; } mpz_product(t, 0, 16-1); mpz_set(prim, t[0]); for (i = 0; i < 16; i++) mpz_clear(t[i]); } 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 UV p = 2; PRIME_ITERATOR(iter); if (n < 1000) { /* Simple linear multiplication, one at a time */ mpz_set_ui(prim, 1); while (p <= n) { mpz_mul_ui(prim, prim, p); p = prime_iterator_next(&iter); } } else { /* Shallow product tree, ~10x faster for large values */ mpz_t t[16]; UV i; for (i = 0; i < 16; i++) mpz_init_set_ui(t[i], 1); i = 0; while (p <= n) { mpz_mul_ui(t[i&15], t[i&15], p); p = prime_iterator_next(&iter); i++; } mpz_product(t, 0, 16-1); mpz_set(prim, t[0]); for (i = 0; i < 16; i++) mpz_clear(t[i]); } prime_iterator_destroy(&iter); #endif } /* Luschny's version of the "Brent-Harvey" method */ void bernfrac(mpz_t num, mpz_t den, mpz_t zn) { UV k, j, n = mpz_get_ui(zn); mpz_t* T; mpz_t t; if (n == 0) { mpz_set_ui(num, 1); mpz_set_ui(den, 1); return; } else if (n == 1) { mpz_set_ui(num, 1); mpz_set_ui(den, 2); return; } else if (n & 1) { mpz_set_ui(num, 0); mpz_set_ui(den, 1); return; } n >>= 1; New(0, T, n+1, mpz_t); for (k = 1; k <= n; k++) mpz_init(T[k]); mpz_set_ui(T[1], 1); mpz_init(t); 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); } } mpz_mul_ui(num, T[n], n); mpz_mul_si(num, num, (n & 1) ? 2 : -2); mpz_set_ui(t, 1); mpz_mul_2exp(den, t, 2*n); /* den = U = 1 << 2n */ mpz_sub_ui(t, den, 1); /* t = U-1 */ mpz_mul(den, den, t); /* den = U*(U-1) */ mpz_gcd(t, num, den); mpz_divexact(num, num, t); mpz_divexact(den, den, t); mpz_clear(t); for (k = 1; k <= n; k++) mpz_clear(T[k]); Safefree(T); } 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); } char* harmreal(mpz_t zn, unsigned long prec) { char* out; mpz_t num, den; mpf_t fnum, fden, res; unsigned long numsize, densize; mpz_init(num); mpz_init(den); harmfrac(num, den, zn); numsize = mpz_sizeinbase(num, 10); densize = mpz_sizeinbase(den, 10); mpf_init2(fnum, 1 + mpz_sizeinbase(num,2)); mpf_init2(fden, 1 + mpz_sizeinbase(den,2)); mpf_set_z(fnum, num); mpf_set_z(fden, den); mpz_clear(den); mpz_clear(num); mpf_init2(res, (unsigned long) (8+prec*3.4) ); mpf_div(res, fnum, fden); mpf_clear(fnum); mpf_clear(fden); New(0, out, (10+numsize-densize)+prec, char); gmp_sprintf(out, "%.*Ff", (int)(prec), res); mpf_clear(res); return out; } 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) { mpz_bin_uiui(t, n-1, m-1); mpz_fac_ui(t2, n); mpz_mul(r, t, t2); mpz_fac_ui(t2, m); mpz_divexact(r, r, t2); } else if (type == 2) { for (j = 1; j <= m; j++) { mpz_bin_uiui(t, m, j); mpz_ui_pow_ui(t2, j, n); mpz_mul(t, t, t2); if ((m-j) & 1) mpz_sub(r, r, t); else mpz_add(r, r, t); } mpz_fac_ui(t, m); mpz_divexact(r, r, t); } else { for (j = 1; j <= n-m; j++) { mpz_bin_uiui(t, n+j-1, n+j-m); mpz_bin_uiui(t2, n+n-m, n-j-m); mpz_mul(t, t, t2); stirling(t2, n+j-m, j, 2); mpz_mul(t, t, t2); if (j & 1) mpz_sub(r, r, t); else mpz_add(r, r, t); } } 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); } #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); if (mpz_cmp(U, V) >= 0) mpz_sub(f, U, V); else mpz_sub(f, V, U); mpz_mul(m, m, f); 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); if (mpz_cmp(Xi, Xm) >= 0) mpz_sub(f, Xi, Xm); else mpz_sub(f, Xm, Xi); mpz_mul(t, m, f); mpz_tdiv_r(m, t, 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); if (mpz_cmp(Xi, Xm) >= 0) mpz_sub(f, Xi, Xm); else mpz_sub(f, Xm, Xi); mpz_gcd(f, f, n); } while (!mpz_cmp_ui(f, 1) && r-- != 0); if ( (!mpz_cmp_ui(f, 1)) || (!mpz_cmp(f, n)) ) break; } mpz_clear(Xi); mpz_clear(Xm); mpz_clear(m); mpz_clear(saveXi); mpz_clear(t); return 1; } mpz_clear(Xi); mpz_clear(Xm); mpz_clear(m); mpz_clear(saveXi); mpz_clear(t); mpz_set(f, n); return 0; } void _GMP_lcm_of_consecutive_integers(UV B, mpz_t m) { 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); } 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 * Montgomery 1987 p249-250 and Brent 1990 p5 both indicate we can calculate * a^m mod n where m is the lcm of the integers to B1. This can be done * using either * m = calc_lcm(B), b = a^m mod n * or * calculate_b_lcm(b, B1, a, n); * * The first means raising a to a huge power then doing the mod, which is * inefficient and can be _very_ slow on some machines. The latter does * one powmod for each prime power, which works pretty well. Yet another * way to handle this is to loop over each prime p below B1, calculating * a = a^(p^e) mod n, where e is the largest e such that p^e <= B1. * My experience with GMP is that this last method is faster with large B1, * sometimes a lot faster. * * 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; } /*---------------------------------------------------------------------- * GMP version of Ben Buhrow's public domain 9/24/09 implementation. * It uses ideas and code from Jason Papadopoulos, Scott Contini, and * Tom St. Denis. Also see the papers of Stephen McMath, Daniel Shanks, * and Jason Gower. Gower and Wagstaff is particularly useful: * http://homes.cerias.purdue.edu/~ssw/squfof.pdf *--------------------------------------------------------------------*/ static int shanks_mult(mpz_t n, mpz_t f) { /* * use shanks SQUFOF to factor N. * * return 0 if no factor found, 1 if found with factor in f1. * * Input should have gone through trial division to 5. */ int result = 0; unsigned long j=0; mpz_t b0, bn, imax, tmp, Q0, Qn, P, i, t1, t2, S, Ro, So, bbn; if (mpz_cmp_ui(n, 3) <= 0) return 0; if (mpz_perfect_square_p(n)) { mpz_sqrt(f, n); return 1; } mpz_init(b0); mpz_init(bn); mpz_init(imax); mpz_init(tmp); mpz_init(Q0); mpz_init(Qn); mpz_init(P); mpz_init(i); mpz_init(t1); mpz_init(t2); mpz_init(S); mpz_init(Ro); mpz_init(So); mpz_init(bbn); mpz_mod_ui(t1, n, 4); if (mpz_cmp_ui(t1, 3)) croak("Incorrect call to shanks\n"); mpz_sqrt(b0, n); mpz_sqrt(tmp, b0); mpz_mul_ui(imax, tmp, 3); /* set up recurrence */ mpz_set_ui(Q0, 1); mpz_set(P, b0); mpz_mul(tmp, b0, b0); mpz_sub(Qn, n, tmp); mpz_add(tmp, b0, P); mpz_tdiv_q(bn, tmp, Qn); mpz_set_ui(i, 0); while (1) { j=0; while (1) { mpz_set(t1, P); /* hold Pn for this iteration */ mpz_mul(tmp, bn, Qn); mpz_sub(P, tmp, P); mpz_set(t2, Qn); /* hold Qn for this iteration */ mpz_sub(tmp, t1, P); mpz_mul(tmp, tmp, bn); mpz_add(Qn, Q0, tmp); mpz_set(Q0, t2); /* remember last Q */ mpz_add(tmp, b0, P); mpz_tdiv_q(bn, tmp, Qn); if (mpz_even_p(i)) { if (mpz_perfect_square_p(Qn)) { mpz_add_ui(i, i, 1); break; } } mpz_add_ui(i, i, 1); if (mpz_cmp(i, imax) >= 0) { result = 0; goto end; } } /* reduce to G0 */ mpz_sqrt(S, Qn); mpz_sub(tmp, b0, P); mpz_tdiv_q(tmp, tmp, S); mpz_mul(tmp, S, tmp); mpz_add(Ro, P, tmp); mpz_mul(tmp, Ro, Ro); mpz_sub(tmp, n, tmp); mpz_tdiv_q(So, tmp, S); mpz_add(tmp, b0, Ro); mpz_tdiv_q(bbn, tmp, So); /* search for symmetry point */ while (1) { mpz_set(t1, Ro); /* hold Ro for this iteration */ mpz_mul(tmp, bbn, So); mpz_sub(Ro, tmp, Ro); mpz_set(t2, So); /* hold So for this iteration */ mpz_sub(tmp, t1, Ro); mpz_mul(tmp, bbn, tmp); mpz_add(So, S, tmp); mpz_set(S, t2); /* remember last S */ mpz_add(tmp, b0, Ro); mpz_tdiv_q(bbn, tmp, So); /* check for symmetry point */ if (mpz_cmp(Ro, t1) == 0) break; /* this gets stuck very rarely, but it does happen. */ if (++j > 1000000000) { result = -1; goto end; } } mpz_gcd(t1, Ro, n); if (mpz_cmp_ui(t1, 1) > 0) { mpz_set(f, t1); /* gmp_printf("GMP SQUFOF found factor after %Zd/%lu rounds: %Zd\n", i, j, f); */ result = 1; goto end; } } end: mpz_clear(b0); mpz_clear(bn); mpz_clear(imax); mpz_clear(tmp); mpz_clear(Q0); mpz_clear(Qn); mpz_clear(P); mpz_clear(i); mpz_clear(t1); mpz_clear(t2); mpz_clear(S); mpz_clear(Ro); mpz_clear(So); mpz_clear(bbn); return result; } int _GMP_squfof_factor(mpz_t n, mpz_t f, UV rounds) { const UV multipliers[] = { 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 }; const size_t sz_mul = sizeof(multipliers)/sizeof(multipliers[0]); size_t i; int result; UV nmod4; mpz_t nm, t; TEST_FOR_2357(n, f); mpz_init(nm); mpz_init(t); mpz_set_ui(f, 1); nmod4 = mpz_tdiv_r_ui(nm, n, 4); for (i = 0; i < sz_mul; i++) { UV mult = multipliers[i]; /* Only use multipliers where n*m = 3 mod 4 */ if (nmod4 == (mult % 4)) continue; /* Only run when 64*m^3 < n */ mpz_set_ui(t, mult); mpz_pow_ui(t, t, 3); mpz_mul_ui(t, t, 64); if (mpz_cmp(t, n) >= 0) continue; /* Run with this multiplier */ mpz_mul_ui(nm, n, mult); result = shanks_mult(nm, f); if (result == -1) break; if ( (result == 1) && (mpz_cmp_ui(f, mult) != 0) ) { unsigned long gcdf = mpz_gcd_ui(NULL, f, mult); mpz_divexact_ui(f, f, gcdf); if (mpz_cmp_ui(f, 1) > 0) break; } } mpz_clear(t); mpz_clear(nm); return (mpz_cmp_ui(f, 1) > 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; } /* 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) 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; } } void exp_mangoldt(mpz_t res, mpz_t n) { UV k; mpz_set_ui(res, 1); if (mpz_cmp_ui(n, 1) <= 0) return; k = mpz_scan1(n, 0); if (k > 0) { if (k+1 == mpz_sizeinbase(n, 2)) mpz_set_ui(res, 2); return; } if (_GMP_is_prob_prime(n)) { mpz_set(res, n); return; } k = power_factor(n, res); if (k > 1 && _GMP_is_prob_prime(res)) return; mpz_set_ui(res, 1); } 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(uint32_t* comp, mpz_t start, UV p, UV len) { UV pos = p - mpz_fdiv_ui(start,p); /* First multiple of p after start */ if (!(pos & 1)) pos += p; /* Make sure it is odd. */ for ( ; pos < len; pos += 2*p ) SETAVAL(comp, pos); } uint32_t* partial_sieve(mpz_t start, UV length, UV maxprime) { uint32_t* comp; UV p, wlen, pwlen; 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++; /* 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); 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 */ for ( ; p <= maxprime; p = prime_iterator_next(&iter)) sievep(comp, start, p, length); prime_iterator_destroy(&iter); return comp; } char* pidigits(UV n) { char* out; New(0, out, n+4, char); out[0] = '3'; out[1] = '\0'; if (n <= 1) return out; #if 0 /* Spigot method. * ~40x slower than the Machin formulas, 2x slower than spigot in plain C */ { mpz_t t1, t2, acc, den, num; UV i, k, d, d2; mpz_init(t1); mpz_init(t2); mpz_init_set_ui(acc, 0); mpz_init_set_ui(den, 1); mpz_init_set_ui(num, 1); n++; /* rounding */ for (i = k = 0; i < n; ) { { UV k2 = ++k * 2 + 1; mpz_mul_2exp(t1, num, 1); mpz_add(acc, acc, t1); mpz_mul_ui(acc, acc, k2); mpz_mul_ui(den, den, k2); mpz_mul_ui(num, num, k); } if (mpz_cmp(num, acc) > 0) continue; { mpz_mul_ui(t1, num, 3); mpz_add(t2, t1, acc); mpz_tdiv_q(t1, t2, den); d = mpz_get_ui(t1); } { mpz_mul_ui(t1, num, 4); mpz_add(t2, t1, acc); mpz_tdiv_q(t1, t2, den); d2 = mpz_get_ui(t1); } if (d != d2) continue; out[++i] = '0' + d; { mpz_submul_ui(acc, den, d); mpz_mul_ui(acc, acc, 10); mpz_mul_ui(num, num, 10); } } mpz_clear(num); mpz_clear(den); mpz_clear(acc); mpz_clear(t2);mpz_clear(t1); if (out[n] >= '5') out[n-1]++; /* Round */ for (i = n-1; out[i] == '9'+1; i--) /* Keep rounding */ { out[i] = '0'; out[i-1]++; } n--; /* Undo the extra digit we used for rounding */ out[1] = '.'; out[n+1] = '\0'; } #elif 0 /* https://en.wikipedia.org/wiki/Machin-like_formula * Thanks to Ledrug from RosettaCode for the simple code for base 10. * Pretty fast, but growth is a lot slower than AGM. */ { mpz_t t1, t2, term1, term2, pows; UV i, k; mpz_init(t1); mpz_init(t2); mpz_init(term1); mpz_init(term2); mpz_init(pows); n++; /* rounding */ mpz_ui_pow_ui(pows, 10, n+20); #if 0 /* Machin 1706 */ mpz_arctan(term1, 5, pows, t1, t2); mpz_mul_ui(term1, term1, 4); mpz_arctan(term2, 239, pows, t1, t2); mpz_sub(term1, term1, term2); #elif 0 /* Störmer 1896 */ mpz_arctan(term1, 57, pows, t1, t2); mpz_mul_ui(term1, term1, 44); mpz_arctan(term2, 239, pows, t1, t2); mpz_mul_ui(term2, term2, 7); mpz_add(term1, term1, term2); mpz_arctan(term2, 682, pows, t1, t2); mpz_mul_ui(term2, term2, 12); mpz_sub(term1, term1, term2); mpz_arctan(term2, 12943, pows, t1, t2); mpz_mul_ui(term2, term2, 24); mpz_add(term1, term1, term2); #else /* Chien-Lih 1997 */ mpz_arctan(term1, 239, pows, t1, t2); mpz_mul_ui(term1, term1, 183); mpz_arctan(term2, 1023, pows, t1, t2); mpz_mul_ui(term2, term2, 32); mpz_add(term1, term1, term2); mpz_arctan(term2, 5832, pows, t1, t2); mpz_mul_ui(term2, term2, 68); mpz_sub(term1, term1, term2); mpz_arctan(term2, 110443, pows, t1, t2); mpz_mul_ui(term2, term2, 12); mpz_add(term1, term1, term2); mpz_arctan(term2, 4841182, pows, t1, t2); mpz_mul_ui(term2, term2, 12); mpz_sub(term1, term1, term2); mpz_arctan(term2, 6826318, pows, t1, t2); mpz_mul_ui(term2, term2, 100); mpz_sub(term1, term1, term2); #endif mpz_mul_ui(term1, term1, 4); mpz_ui_pow_ui(pows, 10, 20); mpz_tdiv_q(term1, term1, pows); mpz_clear(t1); mpz_clear(t2); mpz_clear(term2); mpz_clear(pows); k = mpz_sizeinbase(term1, 10); /* Copy result to out string */ while (k > n+1) { /* making sure we don't overflow */ mpz_tdiv_q_ui(term1, term1, 10); k = mpz_sizeinbase(term1, 10); } (void) mpz_get_str(out+1, 10, term1); mpz_clear(term1); if (out[n] >= '5') out[n-1]++; /* Round */ for (i = n-1; out[i] == '9'+1; i--) /* Keep rounding */ { out[i] = '0'; out[i-1]++; } n--; /* Undo the extra digit we used for rounding */ out[1] = '.'; out[n+1] = '\0'; } #else /* AGM using GMP's floating point. Fast and very good growth. */ { mpf_t t, an, bn, tn, prev_an; UV k = 0; unsigned long oldprec = mpf_get_default_prec(); mpf_set_default_prec(10 + n * 3.322); mpf_init(t); mpf_init(prev_an); mpf_init_set_d(an, 1); mpf_init_set_d(bn, 0.5); mpf_init_set_d(tn, 0.25); mpf_sqrt(bn, bn); while ((n >> k) > 0) { mpf_set(prev_an, an); mpf_add(t, an, bn); mpf_div_ui(an, t, 2); mpf_mul(t, bn, prev_an); mpf_sqrt(bn, t); 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); k++; } mpf_add(t, an, bn); mpf_mul(an, t, t); mpf_mul_2exp(t, tn, 2); mpf_div(bn, an, t); gmp_sprintf(out, "%.*Ff", (int)(n-1), bn); mpf_clear(tn); mpf_clear(bn); mpf_clear(an); mpf_clear(prev_an); mpf_clear(t); mpf_set_default_prec(oldprec); } #endif return out; } 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; int k_primality = 0; uint32_t* comp; vlist retlist; if (k < 2) { test_primality = 1; k = 5000 * mpz_sizeinbase(high,2); } 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_sqrt(t, high); /* No need for k to be > sqrt(high) */ if (mpz_cmp_ui(t, k) < 0) k = mpz_get_ui(t); if (mpz_cmp_ui(t, k) <= 0) { 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; } 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)) { mpz_add_ui(t, low, i); if (_GMP_BPSW(t)) { mpz_add_ui(t, t, twin); if (_GMP_BPSW(t)) { 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, nprps = 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) > 260) 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 */ for (c = 0; c < nc; c++) if (! (mpz_add_ui(t, low, i+cl[c]), nprps++, _GMP_BPSW(t)) ) 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" BPSW tests (pretests %s)\n", nprps, 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; } Math-Prime-Util-GMP-0.35/TODO0000644000076400007640000000645612627512342014047 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. - Add Riemann R function - 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. - New version of Pi code using Chudnovsky. See Pari. - tests for sieve_primes. speed up range sieving. time mpu 'use bigint; my $n = 10**20; say join "\n",Math::Prime::Util::GMP::sieve_primes($n,$n+8e9,0);' >foo takes ~35 minutes. NewPGen can do it in less than 4. At 10^22 it is closer. - More efficient version of ramanujan_tau? - 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. Math-Prime-Util-GMP-0.35/simpqs.c0000644000076400007640000014403012543164113015022 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(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.35/factor.h0000644000076400007640000000124512563375205015001 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 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); #endif Math-Prime-Util-GMP-0.35/small_factor.c0000644000076400007640000001240412627512342016157 0ustar danadana /* Racing SQUFOF, based in part on Ben Buhrow's code. */ #include #include "ptypes.h" #include "small_factor.h" #define FUNC_gcd_ui 1 #define FUNC_isqrt 1 #define FUNC_is_perfect_square 1 #include "utility.h" typedef struct { int valid; UV P; UV bn; UV Qn; UV Q0; UV b0; UV it; UV imax; } mult_t; /* N < 2^63 (or 2^31). Returns 0 or a factor */ static UV squfof_unit(UV n, mult_t* mult_save) { UV imax,i,Q0,b0,Qn,bn,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) { int j = 0; 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 for square: Qn = S*S */ if (is_perfect_square(Qn, &S)) break; /* Odd iteration. */ SQUARE_SEARCH_ITERATION; } /* printf("found square %lu after %lu iterations with mult %d\n", Qn, i, mult_save->mult); */ /* Reduce to G0 */ Ro = P + S*((b0 - P)/S); t1 = Ro; So = (n - t1*t1)/S; bbn = (b0+Ro)/So; /* Search for symmetry point */ #define SYMMETRY_POINT_ITERATION \ t1 = Ro; \ Ro = bbn*So - Ro; \ t2 = So; \ So = S + bbn*(t1-Ro); \ S = t2; \ bbn = (b0+Ro)/So; \ if (Ro == t1) break; j = 0; while (1) { SYMMETRY_POINT_ITERATION; SYMMETRY_POINT_ITERATION; SYMMETRY_POINT_ITERATION; SYMMETRY_POINT_ITERATION; if (j++ > 2000000) { mult_save->valid = 0; return 0; } } t1 = gcd_ui(Ro, n); 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 UV squfof_multipliers[] = /* { 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 }; */ { 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 }; #define NSQUFOF_MULT (sizeof(squfof_multipliers)/sizeof(squfof_multipliers[0])) int racing_squfof_factor(UV n, UV *factors, UV rounds) { const UV big2 = UV_MAX; mult_t mult_save[NSQUFOF_MULT]; int still_racing; UV i, nn64, mult, f64; UV rounds_done = 0; /* Caller should have handled these trivial cases */ MPUassert( (n >= 3) && ((n%2) != 0) , "bad n in squfof_factor"); /* Too big */ if (n > big2) { factors[0] = n; return 1; } for (i = 0; i < NSQUFOF_MULT; i++) mult_save[i].valid = -1; /* Process the multipliers a little at a time: 0.33*(n*mult)^1/4: 20-20k */ do { still_racing = 0; for (i = 0; i < NSQUFOF_MULT; i++) { if (mult_save[i].valid == 0) continue; mult = squfof_multipliers[i]; nn64 = n * mult; if (mult_save[i].valid == -1) { if ((big2 / mult) < n) { mult_save[i].valid = 0; /* This multiplier would overflow 64-bit */ continue; } mult_save[i].valid = 1; mult_save[i].b0 = isqrt(nn64); mult_save[i].imax = (UV) (sqrt(mult_save[i].b0) / 16); if (mult_save[i].imax < 20) mult_save[i].imax = 20; if (mult_save[i].imax > rounds) mult_save[i].imax = rounds; mult_save[i].Q0 = 1; mult_save[i].P = mult_save[i].b0; mult_save[i].Qn = nn64 - (mult_save[i].b0 * mult_save[i].b0); if (mult_save[i].Qn == 0) { factors[0] = mult_save[i].b0; factors[1] = n / mult_save[i].b0; MPUassert( factors[0] * factors[1] == n , "incorrect factoring"); return 2; } mult_save[i].bn = (mult_save[i].b0 + mult_save[i].P) / mult_save[i].Qn; mult_save[i].it = 0; } f64 = squfof_unit(nn64, &mult_save[i]); if (f64 > 1) { if (f64 != mult) { f64 /= gcd_ui(f64, mult); if (f64 != 1) { factors[0] = f64; factors[1] = n / f64; MPUassert( factors[0] * factors[1] == n , "incorrect factoring"); return 2; } } /* Found trivial factor. Quit working with this multiplier. */ mult_save[i].valid = 0; } if (mult_save[i].valid == 1) still_racing = 1; rounds_done += mult_save[i].imax; if (rounds_done >= rounds) break; } } while (still_racing && rounds_done < rounds); /* No factors found */ factors[0] = n; return 1; } Math-Prime-Util-GMP-0.35/ecm.h0000644000076400007640000000063312237244573014270 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.35/utility.h0000644000076400007640000001130512627512342015220 0ustar danadana#ifndef MPU_UTILITY_H #define MPU_UTILITY_H #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); /* 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, mpz_t t, mpz_t t2, mpz_t b, mpz_t g); /* 4 temp 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_product(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, gmp_randstate_t* p_randstate); /* 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); /* 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); #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 #endif Math-Prime-Util-GMP-0.35/LICENSE0000644000076400007640000004367512537562254014377 0ustar danadanaThis software is Copyright (c) 2011-2015 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-2015 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-2015 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.35/README0000644000076400007640000000511212633466232014226 0ustar danadanaMath::Prime::Util::GMP version 0.35 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-2015 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.35/t/0000755000076400007640000000000012633466633013617 5ustar danadanaMath-Prime-Util-GMP-0.35/t/24-bernfrac.t0000644000076400007640000002014212465451513016002 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/bernfrac 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/], ); 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(@stirling2) + scalar(@stirling1) + 2 + 2+6; { 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 (@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(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,5), "2.28333", "harmreal(5,5)" ); is( harmreal(15,2), "3.32", "harmreal(15,2)" ); is( harmreal(15,24), "3.318228993228993228993229", "harmreal(15,24)" ); is( harmreal(1500,84), "7.890769348288132237024982466533383516587334672793034866299830645277849644355893942483", "harmreal(1500,84)" ); is( harmreal(2502,763), "8.4022611827442616317889358234638600819223549876775756009040579007028304622396704717826054849631311959827336370652350363210214348075460454127806820991887787301726524318112301788039510819911216154119126624804602690267244260972035688366573000214774520753765479437246871327307674220381391918202939677188395567028236867891536047084719881902222764381394522556877103822410093096790602691889769666625414585123756378881628875119610391914967976757016187471943182230789317973147668458937306028722119815966094143929327181951971889166127652438346064969183176053197768023014774945977838767778096364258279792884478027384432419591251420003615953125404288714656235208556151078286913808883501164776686214636296222092373622320260770103224594844688053478029558802715467037435761134100", "harmreal(2502,763)" ); is( harmreal(2502,764), "8.40226118274426163178893582346386008192235498767757560090405790070283046223967047178260548496313119598273363706523503632102143480754604541278068209918877873017265243181123017880395108199112161541191266248046026902672442609720356883665730002147745207537654794372468713273076742203813919182029396771883955670282368678915360470847198819022227643813945225568771038224100930967906026918897696666254145851237563788816288751196103919149679767570161874719431822307893179731476684589373060287221198159660941439293271819519718891661276524383460649691831760531977680230147749459778387677780963642582797928844780273844324195912514200036159531254042887146562352085561510782869138088835011647766862146362962220923736223202607701032245948446880534780295588027154670374357611340997", "harmreal(2502,764)" ); Math-Prime-Util-GMP-0.35/t/16-provableprime.t0000644000076400007640000001517412627512342017077 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_nminus1_prime is_ecpp_prime is_miller_prime/; plan tests => 0 + 6 + 38 + 43 + 34 + 2 + 7 # _with_cert + 5 # 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 = < '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 gcd lcm kronecker invmod von pseudoprime pseudoprimes semiprime semiprimes coprime k-tuples precalculated premultiplier PSP-2 pp/); all_pod_files_spelling_ok(); Math-Prime-Util-GMP-0.35/t/02-can.t0000644000076400007640000000434612537403473014767 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_ecpp_prime is_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 miller_rabin_random lucas_sequence lucasu lucasv primes sieve_primes next_prime prev_prime trial_factor prho_factor pbrent_factor pminus1_factor pplus1_factor holf_factor squfof_factor ecm_factor qs_factor factor moebius prime_count primorial pn_primorial factorial consecutive_integer_lcm partitions bernfrac harmfrac harmreal stirling gcd lcm kronecker valuation invmod binomial gcdext vecsum vecprod exp_mangoldt liouville totient jordan_totient carmichael_lambda is_power znorder znprimroot Pi ); can_ok( 'Math::Prime::Util::GMP', @functions); Math-Prime-Util-GMP-0.35/t/25-pi.t0000644000076400007640000000263712410103725014627 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.35/t/11-primes.t0000644000076400007640000001470112627512342015515 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/; plan tests => 12 + 12 + 1 + 19 + 1 + 1 + 13*1 + 1 + 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/], "partial sieve a 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.35/t/12-nextprime.t0000644000076400007640000001060412054572125016227 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/next_prime prev_prime/; plan tests => 2 + 3*2 + 6 + 1 + 148 + 148 + 1 + 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 = (0, @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), 0, "Previous prime of 2 returns 0" ); # Turns out the testing of prev/next from 0-3572 still misses some cases. foreach my $n (2010733 .. 2010880) { is(next_prime($n), 2010881, "next_prime($n) == 2010881"); } foreach my $n (2010734 .. 2010881) { is(prev_prime($n), 2010733, "prev_prime($n) == 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"); Math-Prime-Util-GMP-0.35/t/21-conseq-lcm.t0000644000076400007640000000664612044131766016271 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.35/t/91-release-pod-syntax.t0000644000076400007640000000062311776462767017773 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.35/t/26-mersenne.t0000644000076400007640000000106512435526314016040 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.35/t/20-primorial.t0000644000076400007640000000572012407213521016206 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/primorial pn_primorial factorial/; 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 + 2 # primorial and pn_primorial + 2; # extra primorial tests { my @fact = map { factorial($_) } 0 .. $#factorials; is_deeply( \@fact, \@factorials, "factorial 0 .. $#factorials" ); } { 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)" ); Math-Prime-Util-GMP-0.35/t/90-release-perlcritic.t0000644000076400007640000000106211776462767020022 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.35/t/23-gcd.t0000644000076400007640000002171412627512342014760 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/gcd lcm kronecker is_power valuation invmod 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 @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], ); 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) + scalar(@invmods) + 2 + scalar(@binomials) + scalar(@gcdexts) + scalar(@vecsums) + scalar(@vecprods) + 3 + 3 + 1 + 5; 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" ); } foreach my $r (@invmods) { my($a, $n, $exp) = @$r; is( invmod($a,$n), $exp, "invmod($a,$n) = ".((defined $exp)?$exp:"") ); } 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" ); Math-Prime-Util-GMP-0.35/t/17-pseudoprime.t0000644000076400007640000005635612627512342016574 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/ is_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/ ], 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 + scalar @small_lucas_trials + scalar(keys %lucas_sequences) + 7 # lucasu lucasv # + $num_large_pseudoprime_tests + 18*$extra # Large Carmichael numbers + 2 # M-R-random + 4 * scalar(@primes128) # strong probable prime tests + 4 * scalar(@comp128) # strong probable prime tests + 15 # Check Frobenius for small primes + 0; eval { is_strong_pseudoprime(2047); }; like($@, qr/no base/i, "is_strong_pseudoprime with no base fails"); eval { is_strong_pseudoprime(2047, undef); }; like($@, qr/defined/i, "is_strong_pseudoprime with base undef fails"); eval { is_strong_pseudoprime(2047, ''); }; like($@, qr/positive/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 { is_strong_pseudoprime(undef, 2); }; like($@, qr/defined/i, "is_strong_pseudoprime(undef,2) is invalid"); eval { is_strong_pseudoprime('', 2); }; like($@, qr/positive/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 =~ /^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 '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)"); # 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_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_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" ); } Math-Prime-Util-GMP-0.35/t/19-moebius.t0000644000076400007640000002605612566522704015704 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 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" ], ); 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 + 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" ); ###### 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.35/t/50-factoring.t0000644000076400007640000002715112566522704016205 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/factor is_prime sigma/; 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) + 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) ], [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)" ); 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), 1, "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)" ); } Math-Prime-Util-GMP-0.35/t/13-primecount.t0000644000076400007640000001211512047266577016416 0ustar danadana#!/usr/bin/env perl use strict; use warnings; use Test::More; use Math::Prime::Util::GMP qw/prime_count/; 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], ); plan tests => 4 + scalar (keys %pivals) + scalar @tests; # 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]" ); } Math-Prime-Util-GMP-0.35/t/15-probprime.t0000644000076400007640000000471712237244573016234 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.35/t/92-release-pod-coverage.t0000644000076400007640000000105212435526452020217 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.35/t/22-partitions.t0000644000076400007640000000270312237244573016420 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.35/t/27-clusters.t0000644000076400007640000001003312627512342016063 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) { use bigint; # For 32-bit Perls my($n,$name,$cl) = @$test; my @res = sieve_prime_cluster($n-1e6, $n+1e6, @$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.35/t/01-load.t0000644000076400007640000000016111776462767015152 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.35/t/10-isprime.t0000644000076400007640000002117212627512342015665 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.35/XS.xs0000644000076400007640000006151012630616765014265 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 "small_factor.h" #include "ecm.h" #include "simpqs.h" #include "bls75.h" #include "ecpp.h" #include "utility.h" #include "factor.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(const char* f, const char* s) { const char* p; if (s == 0) croak("%s: null string pointer as input", f); if (*s == 0) croak("%s: empty string as input", f); p = s; while (*p != 0) { if (!isdigit(*p)) croak("%s: input '%s' must be a positive integer", f, s); p++; } } #define VALIDATE_AND_SET(func, var, str) \ validate_string_number(func " (" #var ")", str); \ mpz_init_set_str(var, str, 10); MODULE = Math::Prime::Util::GMP PACKAGE = Math::Prime::Util::GMP PROTOTYPES: ENABLE void _GMP_set_verbose(IN int v) PPCODE: set_verbose_level(v); void _GMP_init() void _GMP_destroy() int _GMP_miller_rabin(IN char* strn, ...) ALIAS: is_pseudoprime = 1 PREINIT: mpz_t n, a; char* strbase; CODE: validate_string_number("GMP_miller_rabin (n)", strn); strbase = (items == 1) ? "2" : SvPV_nolen(ST(1)); /* default base = 2 */ validate_string_number("GMP_miller_rabin (base)", strbase); 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 */ } } mpz_init_set_str(n, strn, 10); mpz_init_set_str(a, strbase, 10); if (ix == 0) { RETVAL = _GMP_miller_rabin(n, a); } else { mpz_t nm1; mpz_init(nm1); mpz_sub_ui(nm1, n, 1); mpz_powm(a, a, nm1, n); mpz_clear(nm1); RETVAL = !mpz_cmp_ui(a,1); } mpz_clear(a); mpz_clear(n); OUTPUT: RETVAL int miller_rabin_random(IN char* strn, IN UV nbases, IN char* seedstr = 0) PREINIT: mpz_t n; CODE: VALIDATE_AND_SET("miller_rabin_random", n, strn); RETVAL = _GMP_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(name " (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_perrin_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_perrin_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_ecpp_prime = 6 is_bpsw_prime = 7 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 = _GMP_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); break; case 6: ret = _GMP_ecpp(n, 0); break; case 7: 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 PREINIT: int result; mpz_t n; PPCODE: PRIMALITY_START("is_provable_prime", 2, 1); if (ix == 1) { result = is_miller_prime(n, wantproof); /* Assume GRH or not */ 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("_validate_ecpp_curve", a, stra); VALIDATE_AND_SET("_validate_ecpp_curve", b, strb); /* Unused */ VALIDATE_AND_SET("_validate_ecpp_curve", n, strn); VALIDATE_AND_SET("_validate_ecpp_curve", px, strpx); VALIDATE_AND_SET("_validate_ecpp_curve", py, strpy); VALIDATE_AND_SET("_validate_ecpp_curve", m, strm); VALIDATE_AND_SET("_validate_ecpp_curve", 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 = (strn[0] == '-'); if (isneg) strn++; validate_string_number("is_power (n)", strn); RETVAL = 0; if (!isneg || (a == 0 || a & 1)) { mpz_init_set_str(n, strn, 10); RETVAL = is_power(n, a); mpz_clear(n); } if (isneg && a == 0 && RETVAL != 0) { UV r = RETVAL; while (!(r & 1)) r >>= 1; RETVAL = (r == 1) ? 0 : r; } 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 PREINIT: mpz_t n; PPCODE: VALIDATE_AND_SET("next_prime", n, strn); if (ix == 0) _GMP_next_prime(n); else _GMP_prev_prime(n); XPUSH_MPZ(n); mpz_clear(n); void prime_count(IN char* strlow, IN char* strhigh) PREINIT: mpz_t low, high, count; PPCODE: VALIDATE_AND_SET("prime_count", low, strlow); VALIDATE_AND_SET("prime_count", high, strhigh); mpz_init_set_ui(count, 0); if (mpz_cmp(low, high) <= 0) { mpz_t curprime; mpz_init_set(curprime, low); if (mpz_cmp_ui(curprime, 2) >= 0) mpz_sub_ui(curprime, curprime, 1); /* Make sure low gets included */ _GMP_next_prime(curprime); while (mpz_cmp(curprime, high) <= 0) { mpz_add_ui(count, count, 1); _GMP_next_prime(curprime); } mpz_clear(curprime); } XPUSH_MPZ(count); mpz_clear(count); mpz_clear(high); mpz_clear(low); void primorial(IN char* strn) ALIAS: pn_primorial = 1 consecutive_integer_lcm = 2 exp_mangoldt = 3 totient = 4 carmichael_lambda = 5 factorial = 6 bernfrac = 7 harmfrac = 8 znprimroot = 9 ramanujan_tau = 10 PREINIT: mpz_t res, n; UV un; PPCODE: if (strn != 0 && strn[0] == '-') { /* If input is negative... */ if (ix == 3) XSRETURN_IV(1); /* exp_mangoldt return 1 */ if (ix == 9) strn++; /* znprimroot flip sign */ } VALIDATE_AND_SET("primorial", n, strn); un = mpz_get_ui(n); mpz_init(res); switch (ix) { case 0: _GMP_primorial(res, un); break; case 1: _GMP_pn_primorial(res, un); break; case 2: _GMP_lcm_of_consecutive_integers(un, res); break; case 3: exp_mangoldt(res, n); break; case 4: totient(res, n); break; case 5: carmichael_lambda(res, n); break; case 6: mpz_fac_ui(res, un); break; /* swing impl in 5.1+, so fast */ case 7: bernfrac(n, res, n); XPUSH_MPZ(n); break; case 8: harmfrac(n, res, n); XPUSH_MPZ(n); break; case 9: znprimroot(res, n); break; case 10: default: ramanujan_tau(res, n); break; } if (ix == 9 && !mpz_sgn(res) && mpz_cmp_ui(n,1) != 0) { mpz_clear(n); mpz_clear(res); XSRETURN_UNDEF; } XPUSH_MPZ(res); mpz_clear(n); mpz_clear(res); void harmreal(IN char* strn, IN UV prec = 40) PREINIT: mpz_t n; char* res; PPCODE: VALIDATE_AND_SET("harmreal", n, strn); res = harmreal(n, prec); XPUSHs(sv_2mortal(newSVpv(res, 0))); Safefree(res); mpz_clear(n); 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 == 3) { mpz_t* list; New(0, list, items, mpz_t); for (i = 0; i < items; i++) { char* strn = SvPV_nolen(ST(i)); validate_string_number("vecprod", (strn[0]=='-') ? strn+1 : strn); mpz_init_set_str(list[i], strn, 10); } 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(n); mpz_init_set_ui(ret, (ix == 1 || ix == 3) ? 1 : 0); for (i = 0; i < items; i++) { char* strn = SvPV_nolen(ST(i)); validate_string_number("gcd/lcm", (strn[0]=='-') ? strn+1 : strn); if (ix <= 1 && strn != 0 && strn[0] == '-') strn++; mpz_set_str(n, strn, 10); 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; } } XPUSH_MPZ(ret); mpz_clear(n); mpz_clear(ret); int kronecker(IN char* stra, IN char* strb) ALIAS: valuation = 1 PREINIT: mpz_t a, b; CODE: validate_string_number("kronecker", (stra[0]=='-') ? stra+1 : stra); validate_string_number("kronecker", (strb[0]=='-') ? strb+1 : strb); mpz_init_set_str(a, stra, 10); mpz_init_set_str(b, strb, 10); if (ix == 0) { RETVAL = mpz_kronecker(a, b); } else { 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); } } 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("moebius", n, strn); if (stro == 0) { int result = moebius(n); mpz_clear(n); XSRETURN_IV(result); } else { /* Ranged result */ mpz_t nhi; VALIDATE_AND_SET("moebius high value", nhi, stro); 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("lucasu/lucasv", 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) PREINIT: mpz_t n; CODE: VALIDATE_AND_SET("liouville", n, strn); RETVAL = liouville(n); mpz_clear(n); OUTPUT: RETVAL void invmod(IN char* stra, IN char* strb) ALIAS: binomial = 1 gcdext = 2 jordan_totient = 3 znorder = 4 PREINIT: mpz_t a, b, t; int retundef; PPCODE: validate_string_number("invmod", (stra[0]=='-') ? stra+1 : stra); validate_string_number("invmod", (strb[0]=='-') ? strb+1 : strb); mpz_init_set_str(a, stra, 10); mpz_init_set_str(b, strb, 10); retundef = 0; if (ix == 0) { /* undef if a|b is zero, 0 if b is 1, otherwise result of mpz_invert */ 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); } else if (ix == 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); } } else if (ix == 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); } else if (ix == 3) { jordan_totient(a, b, mpz_get_ui(a)); } else { znorder(a, a, b); if (!mpz_sgn(a)) retundef = 1; } if (!retundef) XPUSH_MPZ(a); mpz_clear(b); mpz_clear(a); if (retundef) XSRETURN_UNDEF; void partitions(IN UV n) ALIAS: Pi = 1 is_mersenne_prime = 2 PREINIT: UV i, j, k; PPCODE: if (ix == 2) { XSRETURN_IV(lucas_lehmer(n)); } else if (ix == 1) { if (n == 1) XSRETURN_IV(3); else if (n > 0) { char* pi = pidigits(n); XPUSHs(sv_2mortal(newSVpvn(pi, n+1))); Safefree(pi); } } else if (n == 0) { XPUSHs(sv_2mortal(newSVuv( 1 ))); } else if (n <= 3) { XPUSHs(sv_2mortal(newSVuv( n ))); } else { mpz_t psum; mpz_t* part; UV* pent; UV d = (UV) sqrt(n+1); 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_clear(psum); XPUSH_MPZ( part[n] ); for (i = 0; i <= n; i++) mpz_clear(part[i]); Safefree(part); Safefree(pent); } 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; 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_string_number("chinese", (strn[0]=='-') ? strn+1 : strn); mpz_init_set_str(an[i+0], strn, 10); strn = SvPV_nolen(*psvn); validate_string_number("chinese", (strn[0]=='-') ? strn+1 : strn); mpz_init_set_str(an[i+items], strn, 10); } mpz_init(lcm); i = chinese(ret, lcm, an, an+items, items); if (i) 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 (!i) XSRETURN_UNDEF; 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("sieve_primes", low, strlow); VALIDATE_AND_SET("sieve_primes", 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 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("lucas_sequence", n, strn); VALIDATE_AND_SET("lucas_sequence", 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(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,16000000,0, 0 }; /* Trial,Rho, Brent, P-1, P+1, HOLF, SQUFOF, ECM,QS */ PPCODE: VALIDATE_AND_SET(" specific factor", 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 = _GMP_squfof_factor(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) { XPUSH_MPZ(f); mpz_divexact(n, n, f); } mpz_clear(f); } if (mpz_cmp_ui(n,1) > 0) XPUSH_MPZ(n); mpz_clear(n); void _GMP_factor(IN char* strn) PREINIT: mpz_t n; mpz_t* factors; int* exponents; int nfactors, i, j; PPCODE: VALIDATE_AND_SET("factor", n, strn); nfactors = factor(n, &factors, &exponents); for (i = 0; i < nfactors; i++) { for (j = 0; j < exponents[i]; j++) { XPUSH_MPZ(factors[i]); } } clear_factors(nfactors, &factors, &exponents); mpz_clear(n); void sigma(IN char* strn, IN UV k = 1) PREINIT: mpz_t n; PPCODE: VALIDATE_AND_SET("sigma", n, strn); sigma(n, n, k); XPUSH_MPZ(n); mpz_clear(n); Math-Prime-Util-GMP-0.35/lib/0000755000076400007640000000000012633466633014122 5ustar danadanaMath-Prime-Util-GMP-0.35/lib/Math/0000755000076400007640000000000012633466633015013 5ustar danadanaMath-Prime-Util-GMP-0.35/lib/Math/Prime/0000755000076400007640000000000012633466633016067 5ustar danadanaMath-Prime-Util-GMP-0.35/lib/Math/Prime/Util/0000755000076400007640000000000012633466633017004 5ustar danadanaMath-Prime-Util-GMP-0.35/lib/Math/Prime/Util/GMP.pm0000644000076400007640000017545412633466240017777 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.35'; } # 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_ecpp_prime is_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 next_prime prev_prime trial_factor prho_factor pbrent_factor pminus1_factor pplus1_factor holf_factor squfof_factor ecm_factor qs_factor factor sigma chinese moebius prime_count primorial pn_primorial factorial consecutive_integer_lcm partitions bernfrac harmfrac harmreal stirling gcd lcm kronecker valuation invmod binomial gcdext vecsum vecprod exp_mangoldt liouville totient jordan_totient carmichael_lambda is_power znorder znprimroot ramanujan_tau Pi ); # Should add: # nth_prime our %EXPORT_TAGS = (all => [ @EXPORT_OK ]); BEGIN { eval { require XSLoader; XSLoader::load(__PACKAGE__, $Math::Prime::Util::GMP::VERSION); _GMP_init(); 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_strong_pseudoprime { my($n, @bases) = @_; _validate_positive_integer($n); croak "No bases given to is_strong_pseudoprime" unless @bases; foreach my $base (@bases) { _validate_positive_integer($base); return 0 unless _GMP_miller_rabin("$n", "$base"); } 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 factor { my ($n) = @_; my @factors = ($n < 4) ? ($n) : sort {$a<=>$b} _GMP_factor($n); return @factors; } 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 gcdext vecsum vecprod moebius totient liouville znorder znprimroot bernfrac harmfrac harmreal stirling lucasu lucasv OpenPFGW gmpy2 nonresidue chinese tuplets =head1 NAME Math::Prime::Util::GMP - Utilities related to prime numbers and factoring, using GMP =head1 VERSION Version 0.34 =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, especially if performance is critical for 65- to 200-bit inputs, 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", a small number of Miller-Rabin tests with random bases are 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 a base C as input, and returns 1 if C is a probable prime to base C. This is the simple Fermat primality 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 as input and one or more bases. Returns 1 if the input is a prime or a strong pseudoprime to all of the bases, and 0 if not. The base must be a positive integer. 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_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 This is not a commonly used test, as it runs 5 to 10 times slower than most of the other probable prime tests and offers little benefit, especially over combined tests like L and 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 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. =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. In theory, AKS is extremely important. In practice, it is essentially useless. Estimated run time for a 150 digit input is about 9 years, making the case that while the algorithmic complexity I is polynomial, the constants are ludicrously high. There are some ideas of Bernstein that can reduce this a little, but it would still take years for numbers that ECPP or APR-CL can prove in seconds. 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 C then this is a Mersenne number and the Lucas-Lehmer test is used. If the number is not of this form, or if C= 2^n>, then C<-1> will be returned as the test does not apply. 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 number 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_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. Typically you should use L and let it decide the method. =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 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. =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 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 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 out 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 > 0> are undefined. =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 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>. =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 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 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. =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 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 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. It is very fast and uses an extremely memory efficient iterator. It is not, however, practical for producing the partition I for values over 100 or so. =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 AGM and is only slightly slower than MPFR (which has tighter bounds on the intermediate bits and exit conditions). =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 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 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. =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 little 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. =item L. An open source ECPP primality proving program. Slower than this module's ECPP for all inputs when the large polynomial set from github is used. Extremely slow once past 300 or so digits. There are now better alternatives. =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 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 William Hart wrote the SIMPQS code 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 SQUFOF work 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 papers by Brent and Montgomery. =head1 COPYRIGHT Copyright 2011-2015 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.35/prime_iterator.h0000644000076400007640000000117612413200300016524 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.35/META.yml0000664000076400007640000000154512633466633014634 0ustar danadana--- abstract: 'Utilities related to prime numbers, using GMP' author: - 'Dana A Jacobsen ' build_requires: ExtUtils::MakeMaker: '0' Test::More: '0.45' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.1, CPAN::Meta::Converter version 2.150005' 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 recommends: Math::Prime::Util: '0.52' requires: Carp: '0' Exporter: '5.57' 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.35' x_serialization_backend: 'CPAN::Meta::YAML version 0.017' Math-Prime-Util-GMP-0.35/ecpp.c0000644000076400007640000011145512627512342014446 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" /* is_prob_prime, pminus1_factor, miller_rabin_random */ #include "ecm.h" #include "utility.h" #include "prime_iterator.h" #include "bls75.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); } 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; gmp_randstate_t* p_randstate = get_randstate(); 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)) return 0; dT = degree; polyz_mod(T, T, &dT, N); polyz_roots_modp(roots, &nroots, maxroots, T, dT, N, p_randstate); 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 roots to Hilbert roots */ if (poly_type == 2) for (i = 0; i < nroots; i++) weber_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; gmp_randstate_t* p_randstate = get_randstate(); 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_urandomb(x, *p_randstate, 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(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 && _GMP_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_type == 1) ? "Hilbert" : "Weber", 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_type == 1) ? "Hilbert" : "Weber", 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; if (np1lq < 2) croak("Error in BLS15 proof: LQ < 2\n"); proofptr += gmp_sprintf(proofptr, "Type BLS15\nN %Zd\nQ %Zd\n", Ni,q); proofptr += sprintf(proofptr, "LP %"IVdf"\nLQ %"IVdf"\n", np1lp, 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)\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" int main(int argc, char **argv) { mpz_t n; int isprime, i, do_printcert; int do_nminus1 = 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], "-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_aks) { isprime = 2 * _GMP_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.35/examples/0000755000076400007640000000000012633466633015172 5ustar danadanaMath-Prime-Util-GMP-0.35/examples/bench-mp-psrp.pl0000755000076400007640000000176012350477427020210 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.35/examples/vcert.c0000644000076400007640000014705312373552774016476 0ustar danadana/* * Verify Cert * version 0.95 * * Copyright (c) 2013 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 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_MPU 2 #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, 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(_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(_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); //gmp_printf("x is %Zd z is %Zd k is %Zd\n", x, z, k); 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; } 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, Q; 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); //gmp_printf("PX: %Zd PY: %Zd\n", PX, PY); mpz_divexact(T1, M, Q); pec_mult(PA, PB, T1, N, PX, PY); //gmp_printf("PX: %Zd PY: %Zd\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); //gmp_printf("PX: %Zd PY: %Zd\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"); 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 */ 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) { /* TODO: The latest primo.html doesn't require A,B to meet these conditions */ 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_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 { 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); } /* 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; while (items_found < 3) { get_line(0); if (sscanf(_line, "TestCount=%d", &_testcount) == 1) items_found++; if (strcmp(_line, "[Candidate]") == 0) items_found++; 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 { 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.9. 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.35/examples/verify_primegap.pl0000644000076400007640000000727712270516217020723 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.35/examples/verify-cert.pl0000755000076400007640000004577612237244573020011 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.35/examples/convert-primo-cert.pl0000755000076400007640000000452712237244573021276 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.35/examples/convert-gmpecpp-cert.pl0000755000076400007640000000265012237244573021576 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.35/MANIFEST0000644000076400007640000000221512633466633014505 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 prime_iterator.h prime_iterator.c small_factor.h small_factor.c factor.h factor.c ecm.h ecm.c class_poly_data.h bls75.h bls75.c ecpp.h ecpp.c simpqs.h simpqs.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-pi.t t/26-mersenne.t t/27-clusters.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/create-standalone.sh xt/calculate-mr-probs.pl xt/proof-text-format.txt xt/expr-impl.h xt/expr.c xt/expr.h 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.35/class_poly_data.h0000644000076400007640000041056212607507332016667 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 */ 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, 1, 1, "\x01\x20" }, { 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, 1, 2, "\x82\x14\x00\x04\x07\x08\x00\x00" }, { 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, 1, 3, "\x03\x0b\x00\x00\x86\x80\x11\x40\x00\x00\x00\x05\x07\x07\xec\x00\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, 1, 3, "\x03\x7d\x00\x00\x87\x93\x66\xfc\x40\x00\x00\x00\x06\x02\x72\xc2\x32\x00\x00" }, { 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, 1, 3, "\x04\x04\x26\x80\x00\x88\x5d\xe0\x69\xf9\x40\x00\x00\x00\x06\x76\x09\x86\x47\x80\x00" }, { 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, 1, 5, "\x05\x0c\x38\x00\x00\x00\x8c\xc3\x04\x38\xbc\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x58\xad\xa4\xf2\xb9\xa0\x00\x00\x00\x00\x00\x89\x24\x62\x74\x24\x41\x40\x00\x00\x00\x07\x0e\xac\xa7\xaa\x63\x80\x00" }, { 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, 1, 4, "\x05\x07\xc9\xc0\x00\x00\x0c\x41\xe7\x62\x49\xbb\x10\x00\x00\x00\x00\x00\x00\x8a\x09\x6b\x26\x75\x0c\x46\xc0\x00\x00\x00\x08\x01\x58\x47\x13\xf0\x5b\x00\x00" }, { 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, 1, 5, "\x06\x03\xbc\xa8\x00\x00\x00\x8f\x04\x82\x24\xc7\x5d\x7b\xf8\x90\x00\x00\x00\x00\x00\x00\x00\x0d\x21\xbb\x85\xc7\xd6\xe9\xfa\xc0\x00\x00\x00\x00\x00\x8b\x01\xd1\xed\x0d\x19\xa9\xf0\x00\x00\x00\x00\x08\x18\xe9\xcf\xef\x3e\xf9\x00\x00" }, { 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, 1, 4, "\x05\x49\xda\x40\x00\x00\x0e\x0c\x5b\x72\x23\x61\xbc\xf4\x40\x00\x00\x00\x00\x00\x00\x8b\x44\xb3\x36\xe7\xbd\x25\x71\x40\x00\x00\x00\x09\x01\x7d\xac\x30\x8d\x07\xc4\x00\x00" }, { 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, 1, 5, "\x06\x0f\xa3\xe8\x00\x00\x00\x90\x01\x96\x96\x29\xdf\x46\x91\xda\x70\x00\x00\x00\x00\x00\x00\x00\x0f\x03\x82\xad\x62\x96\xb9\x49\x55\xbc\x00\x00\x00\x00\x00\x00\x8c\x08\x47\x81\xd9\x27\x8c\x8d\x66\x80\x00\x00\x00\x09\x13\x85\x27\x6f\x9b\x5c\xb0\x00\x00" }, { 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, 1, 7, "\x08\x01\xba\xe8\x90\x00\x00\x00\x00\x95\x01\x39\xe0\x17\xbb\xe0\x49\xc7\xf9\xc4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x12\xa8\xf4\xe3\x6a\x21\xaf\xc1\xd0\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x17\x69\x5e\x4b\xf1\x63\xf5\xb4\x46\x30\x00\x00\x00\x00\x00\x00\x00\x0f\xcc\x89\x14\x96\x16\x99\x12\x8e\x96\x00\x00\x00\x00\x00\x00\x8c\xd5\xea\xd1\x90\x75\xb6\x2b\x7c\xc0\x00\x00\x00\x09\xdf\xcd\xb3\x40\xa5\x7a\xbe\x00\x00" }, { 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" }, { 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, 1, 8, "\x89\x01\x6d\x89\x4c\x00\x00\x00\x00\x00\x18\x01\xde\x26\x04\xd0\x9a\x59\xc8\x02\xd0\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\x33\x56\x89\x7d\x4a\x31\x14\x4e\xfa\x1e\x34\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15\x04\x64\x0a\x91\x26\x2f\x6e\x8a\xe5\x36\x50\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x93\x08\x5d\x75\x20\xc4\x2e\x76\x09\x7c\xce\x40\x50\x00\x00\x00\x00\x00\x00\x00\x11\x06\x27\x64\x66\xe5\x20\xf3\x12\x53\x54\xa6\x00\x00\x00\x00\x00\x00\x8e\x01\x69\x6d\x95\x2c\xb6\x69\xba\x25\xab\xc0\x00\x00\x00\x0a\x52\xd0\xd4\xf9\x3e\x14\x9c\x4c\x00\x00" }, { 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, 1, 4, "\x87\x01\xc3\x0c\x71\xe0\x00\x00\x11\xd8\xe4\x61\x9e\xec\x56\x22\x92\x7b\x92\xd7\xa0\x00\x00\x00\x00\x00\x8e\x18\x65\xd5\xe6\x06\xa2\x65\x5b\x4e\xc3\x40\x00\x00\x00\x0b\x02\xbe\x90\x72\xf9\xd5\xd0\x4e\x13\x80\x00" }, { 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, 1, 5, "\x07\x14\x3d\x80\xd8\x00\x00\x00\x93\x03\x72\x56\xa0\x8f\x25\x81\xfc\x3d\x65\x18\x50\x00\x00\x00\x00\x00\x00\x00\x12\x1a\x3f\xc3\xb2\xf4\x0b\x6e\xd3\x3d\x75\x98\x1c\x40\x00\x00\x00\x00\x00\x8f\x01\x7c\x65\x84\x0a\x49\xfb\x46\x03\x81\x79\x00\x00\x00\x00\x0b\x15\x88\x97\x25\x3a\xd8\x8d\xe0\x83\x00\x00" }, { 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, 1, 8, "\x09\x65\x13\x2f\x14\x00\x00\x00\x00\x00\x9a\x05\xdf\x6e\x7f\x25\x86\xf3\x9a\x47\x2d\x28\x9a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x01\x44\x70\x71\xe6\x2f\x59\xe6\x04\x3c\x6b\x89\x7f\x7c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\x15\x9d\x44\x67\xda\x1b\x95\xeb\x4e\x8a\xb5\xcc\x2b\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15\x04\xe8\x4e\x62\xce\x68\x2e\x11\x26\x83\x40\xf1\xd0\x30\x00\x00\x00\x00\x00\x00\x00\x13\x02\xd3\x73\x97\xcc\x3e\xf4\x51\x8b\x5d\x64\xe3\x1f\x00\x00\x00\x00\x00\x00\x8f\x15\x18\xc2\xe5\xa6\x6b\x7e\x9a\xa6\xa9\x08\xc0\x00\x00\x00\x0b\x9d\x85\xf8\x6b\x47\x0e\x7e\x43\xca\x00\x00" }, { 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, 1, 8, "\x09\xe5\x77\x3f\x7c\x00\x00\x00\x00\x00\x9a\x28\xcb\x7e\x6a\x3d\x6b\xdc\x09\xea\xfc\x84\x35\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x01\x7b\x62\x81\xa8\x0f\x82\xbe\x6d\x03\x9c\x1c\x0c\xe4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\x11\xde\x2c\x7f\x7e\x40\x3e\x57\x51\x84\x00\xca\x0b\x50\x00\x00\x00\x00\x00\x00\x00\x00\x00\x16\x01\x1f\x0c\x1d\xee\xf9\x12\x2d\xe4\x28\x37\x87\xbc\xd8\xf0\x00\x00\x00\x00\x00\x00\x00\x13\x46\x16\xac\x74\xd5\x0d\x05\xef\x8f\xad\xe5\x82\x57\x80\x00\x00\x00\x00\x00\x90\x01\x13\x4a\x9e\xb8\x75\xfe\xe3\xb1\x3c\xa4\x1a\x40\x00\x00\x00\x0c\x04\x39\x8b\x2e\x6d\x6e\xbc\x57\x0d\xed\x00\x00" }, { 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" }, { 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, 1, 5, "\x08\x10\x2a\x3a\x59\x46\x00\x00\x00\x96\x01\xb9\xca\x61\xd0\xf2\x41\xb5\x53\xc7\xdf\xb1\x04\x6c\xf0\x00\x00\x00\x00\x00\x00\x00\x14\x7f\x48\xc2\xe0\x9a\x21\x3d\x07\xf1\x29\x79\x5c\x09\xa5\x40\x00\x00\x00\x00\x00\x90\x92\x60\x13\x41\x24\xe4\xd6\x49\xfe\x4a\xbd\x80\x80\x00\x00\x00\x0c\xa8\x54\x63\xe7\x67\x22\x45\xcf\x64\x75\x80\x00" }, { 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, 1, 7, "\x09\xa2\xe3\xd1\xbb\x78\x00\x00\x00\x00\x9a\x0c\xc5\xf1\xf1\x70\x06\xd9\x5c\x11\x78\xcf\xb0\x38\x2c\xd4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\xb6\xd0\xb2\xfa\xd8\x85\x4e\xe1\xeb\x8d\x0d\x72\x06\xab\x78\x00\x00\x00\x00\x00\x00\x00\x00\x00\x97\x02\x04\xe4\x20\xb1\x71\x89\xa1\xf6\x91\x9d\x62\xb9\x44\x2f\x50\x00\x00\x00\x00\x00\x00\x00\x15\x09\x75\xd7\x41\xa2\x59\xd8\x97\xd6\x12\xea\x12\x91\x4e\xea\xa0\x00\x00\x00\x00\x00\x91\x06\x09\x20\xfe\x71\x0a\xa8\x74\xde\xda\x41\x18\xb5\xc0\x00\x00\x00\x0d\x03\xd9\xc9\x4a\x90\x0f\x17\x41\xd4\xf5\x76\x80\x00" }, { 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" }, { 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, 1, 6, "\x09\xbf\xa9\xd0\x26\xf4\x00\x00\x00\x00\x9a\x01\xee\xfd\xf4\x80\x26\xfd\x3a\x87\xe0\x19\x2f\xbf\x01\x77\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\xff\x4a\xbd\x57\x7c\xa8\xb9\x8e\x01\x39\x7d\x52\xa1\x85\x2c\xec\x70\x00\x00\x00\x00\x00\x00\x00\x16\x0a\xbf\x5a\x9a\xef\x85\xd0\xac\x61\xb0\x50\x60\x24\xd8\x5a\x5a\xc0\x00\x00\x00\x00\x00\x92\x02\x34\x74\xf2\x76\xbc\xf2\x96\xc5\x70\x69\xd9\xa8\x24\x00\x00\x00\x00\x0d\x73\xcf\x70\xcc\x5f\xe3\x2d\xfd\x3b\xad\x19\x00\x00" }, { 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" }, { 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" }, { 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, 1, 7, "\x0a\xc0\x4a\x1a\xd0\xbb\x80\x00\x00\x00\x00\x9c\xb9\x63\xce\x00\xe5\xca\xcd\x28\x95\x20\xd4\xd5\x6a\x93\x47\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\x56\x48\xbb\x7e\x9f\xb2\x31\x0f\xf8\x90\x40\xfa\x0d\x9c\xcf\x96\xf1\x28\x00\x00\x00\x00\x00\x00\x00\x00\x00\x99\xbe\x90\x83\x93\x69\xac\xa8\xc4\x87\x08\x58\xff\x70\x6d\x0c\xab\xcd\x70\x00\x00\x00\x00\x00\x00\x00\x17\x81\x8b\xfd\x3a\x36\x43\x7b\xd3\x2e\x99\x86\x0c\x96\x48\x41\xe3\xaf\xc0\x00\x00\x00\x00\x00\x93\x05\x54\x39\x32\x64\xb0\x61\x3f\x5a\x2d\x56\x7b\x10\x40\x1a\x80\x00\x00\x00\x0e\x38\x1e\x43\x2e\xb7\x4d\x16\x34\x22\x79\xc8\x0e\x80\x00" }, { 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" }, { 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" }, { 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" }, { 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, 1, 5, "\x0a\x06\x49\x62\xa2\xf3\x71\xf0\x00\x00\x00\x9b\x0c\x37\x2a\x8a\xbf\x9b\xb9\x97\x67\x52\x80\x01\xa6\x58\xdc\xf7\xea\x7c\x6c\xf0\x00\x00\x00\x00\x00\x00\x00\x19\x2a\xb5\xf8\x29\x03\xf2\x7b\x46\x0f\xa6\x79\x0f\xe6\xd6\xa7\x9e\x20\x33\xec\x00\x00\x00\x00\x00\x00\x94\x3d\x1a\xef\xa4\x54\x4d\xf6\x54\xdf\x91\x6c\x72\x2a\x18\x68\x4c\x80\x00\x00\x00\x0f\x57\x6b\xed\x78\x3f\x9e\xd7\x87\x6a\x98\x9f\xc1\xd0\x00\x00" }, { 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, 1, 6, "\x0b\x02\xf4\xd0\x99\xfc\x9d\x59\x00\x00\x00\x00\x1e\x01\x00\x0f\x73\x7a\x90\x86\x0c\x0d\x86\x76\x83\x20\x27\x30\x35\xf5\xe4\x42\xf5\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x04\x98\x84\xc8\x9b\x09\x3b\x79\x13\xac\x25\x14\x41\x26\xa3\xf7\x9b\x20\x18\x22\x70\x00\x00\x00\x00\x00\x00\x00\x1a\x01\xcf\x13\x30\x73\xcc\x98\x20\x6b\x24\xe2\x2c\xd7\x0f\xf9\xfa\x9a\x91\x8b\xc1\x40\x00\x00\x00\x00\x00\x95\x01\x9b\x4f\x4c\xa6\x52\x22\xa0\x62\x7f\xd7\x9b\xcd\x10\x99\xcd\x44\x00\x00\x00\x00\x10\x01\x6d\x54\xcb\x77\xb3\xa6\x36\x61\x64\x5d\x10\x16\xf7\x00\x00" }, { 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" }, { 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" }, { 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" }, { 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" }, { 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, 1, 7, "\x0c\x04\x5a\x72\x6d\xd2\xfd\x7b\x20\x00\x00\x00\x00\xa1\x09\x4a\xea\xff\xfa\x87\xc5\x32\x2a\xdf\xc8\x37\x37\x2f\x8b\xa7\x3b\x24\x2d\x7c\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x78\x54\x85\xce\x3a\x4a\xd4\x12\xc1\xb9\xdf\x11\x0f\x0d\x4f\xf1\x16\xb0\xf0\x8d\xa2\x58\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9e\x01\xd3\x6d\x9b\x21\xbb\x9e\xab\x20\x65\x82\xf9\xc8\xb2\x42\xfe\x2a\x66\xac\x17\x2b\x06\x70\x00\x00\x00\x00\x00\x00\x00\x1c\x02\x59\xc4\x06\x31\x9d\x00\xa5\xfd\x39\x31\x0d\x20\xb1\xee\x21\x99\x00\x01\x1c\xbb\xdd\x40\x00\x00\x00\x00\x00\x96\x37\x31\xbb\x6b\x04\x22\xb6\xa3\xaf\x18\x36\xa0\xd1\xf1\x3d\x3b\xfd\xd2\x80\x00\x00\x00\x11\x05\x0f\xfc\x84\xc4\x39\x02\x9c\x7b\xcf\x24\x48\x1c\xf4\xed\x80\x00" }, { 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" }, { 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" }, { 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" }, { 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" }, { 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, 1, 5, "\x0b\xe1\x46\xc7\xea\xb9\x74\x63\x3e\x00\x00\x00\x1f\x4e\x53\xbd\x6a\x2b\x32\xf4\x3a\x7b\x4c\x9d\xd0\xd1\xfb\x22\xb7\x12\x86\x72\x29\x0e\x78\x2b\x90\x00\x00\x00\x00\x00\x00\x00\x1e\x01\x60\x20\xbe\x1c\x78\x90\x05\xa6\x90\x47\xe9\x12\x99\xb8\xc6\x2c\x40\x07\x2c\xf9\x3a\x45\x0d\x40\x00\x00\x00\x00\x00\x98\x03\xe9\x83\x2d\x7c\x45\xa5\x59\x24\xa6\x36\x77\xfe\x01\x5e\x3a\x7e\x33\xb9\x4a\x80\x00\x00\x00\x12\x0b\x20\x79\x4d\x6c\x75\x64\x9a\x42\x58\x12\xbd\xc1\xc5\x91\x33\x80\x00" }, { 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" }, { 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" }, { 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.35/bls75.h0000644000076400007640000000212112237244573014452 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); #endif Math-Prime-Util-GMP-0.35/prime_iterator.c0000644000076400007640000005157212627512342016547 0ustar danadana#include #include #include #include #include "ptypes.h" #include "prime_iterator.h" #if 0 /* 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}; #endif /* 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}; #define FIND_COMPOSITE_POS(i,j) \ { \ UV dlast = d; \ do { \ d += dinc; \ m += minc; \ if (m >= 30) { d++; m -= 30; } \ } while ( masktab30[m] == 0 ); \ wdinc[i] = d - dlast; \ wmask[j] = masktab30[m]; \ } #define FIND_COMPOSITE_POSITIONS(p) \ do { \ FIND_COMPOSITE_POS(0,1) \ FIND_COMPOSITE_POS(1,2) \ FIND_COMPOSITE_POS(2,3) \ FIND_COMPOSITE_POS(3,4) \ FIND_COMPOSITE_POS(4,5) \ FIND_COMPOSITE_POS(5,6) \ FIND_COMPOSITE_POS(6,7) \ FIND_COMPOSITE_POS(7,0) \ d -= p; \ } while (0) 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; } } /* Wheel 30 sieve. Ideas from Terje Mathisen and Quesada / Van Pelt. */ static unsigned char* sieve_erat30(UV end) { unsigned char* mem; UV max_buf, limit; UV 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 ); if (mem == 0) { croak("allocation failure in sieve_erat30: could not alloc %"UVuf" bytes", max_buf); return 0; } /* Fill buffer with marked 7, 11, and 13 */ sieve_prefill(mem, 0, max_buf-1); limit = (UV) sqrt((double) end); /* prime*prime can overflow */ for (prime = 17; prime <= limit; prime = next_prime_in_sieve(mem,prime)) { UV d = (prime*prime)/30; UV m = (prime*prime) - d*30; UV dinc = (2*prime)/30; UV minc = (2*prime) - dinc*30; UV wdinc[8]; unsigned char wmask[8]; /* Find the positions of the next composites we will mark */ FIND_COMPOSITE_POSITIONS(prime); /* Mark the composites (unrolled) */ while (1) { mem[d] |= wmask[0]; d += wdinc[0]; if (d >= max_buf) break; mem[d] |= wmask[1]; d += wdinc[1]; if (d >= max_buf) break; mem[d] |= wmask[2]; d += wdinc[2]; if (d >= max_buf) break; mem[d] |= wmask[3]; d += wdinc[3]; if (d >= max_buf) break; mem[d] |= wmask[4]; d += wdinc[4]; if (d >= max_buf) break; mem[d] |= wmask[5]; d += wdinc[5]; if (d >= max_buf) break; mem[d] |= wmask[6]; d += wdinc[6]; if (d >= max_buf) break; mem[d] |= wmask[7]; d += wdinc[7]; if (d >= max_buf) break; } } return mem; } 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 = (UV) sqrt((double) endp); if (limit*limit < endp) limit++; /* ceil(sqrt(endp)) */ /* printf("segment sieve from %"UVuf" to %"UVuf" (aux sieve to %"UVuf")\n", startp, endp, limit); */ if ( (prim_sieve != 0) && (limit <= prim_limit) ) { sieve = prim_sieve; } else { sieve = sieve_erat30(limit); } MPUassert( sieve != 0, "Could not generate base sieve" ); for (p = 17; p <= limit; p = next_prime_in_sieve(sieve,p)) { /* p increments from 17 to at least sqrt(endp) */ UV p2 = p*p; /* TODO: overflow */ if (p2 > endp) break; /* Find first multiple of p greater than p*p and larger than startp */ if (p2 < startp) { p2 = (startp / p) * p; if (p2 < startp) p2 += p; } /* Bump to next multiple that isn't divisible by 2, 3, or 5 */ while (masktab30[p2%30] == 0) { p2 += p; } /* It is possible we've overflowed p2, so check for that */ if ( (p2 <= endp) && (p2 >= startp) ) { /* Sieve from startd to endd starting at p2, stepping p */ UV d = (p2)/30; UV m = (p2) - d*30; UV dinc = (2*p)/30; UV minc = (2*p) - dinc*30; UV wdinc[8]; unsigned char wmask[8]; UV offset_endd = endd - startd; /* Find the positions of the next composites we will mark */ FIND_COMPOSITE_POSITIONS(p); d -= startd; /* Mark composites (unrolled) */ while ( (d+p) <= offset_endd ) { mem[d] |= wmask[0]; d += wdinc[0]; mem[d] |= wmask[1]; d += wdinc[1]; mem[d] |= wmask[2]; d += wdinc[2]; mem[d] |= wmask[3]; d += wdinc[3]; mem[d] |= wmask[4]; d += wdinc[4]; mem[d] |= wmask[5]; d += wdinc[5]; mem[d] |= wmask[6]; d += wdinc[6]; mem[d] |= wmask[7]; d += wdinc[7]; } while (1) { mem[d] |= wmask[0]; d += wdinc[0]; if (d > offset_endd) break; mem[d] |= wmask[1]; d += wdinc[1]; if (d > offset_endd) break; mem[d] |= wmask[2]; d += wdinc[2]; if (d > offset_endd) break; mem[d] |= wmask[3]; d += wdinc[3]; if (d > offset_endd) break; mem[d] |= wmask[4]; d += wdinc[4]; if (d > offset_endd) break; mem[d] |= wmask[5]; d += wdinc[5]; if (d > offset_endd) break; mem[d] |= wmask[6]; d += wdinc[6]; if (d > offset_endd) break; mem[d] |= wmask[7]; d += wdinc[7]; if (d > offset_endd) break; } } } 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.35/bls75.c0000644000076400007640000005632612543164057014463 0ustar danadana #include #include #include #include #include #include "ptypes.h" #include "gmp_main.h" #include "prime_iterator.h" #include "small_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 try_factor(mpz_t f, mpz_t n, int effort) { int success = 0; UV log2n = mpz_sizeinbase(n, 2); if (!success && mpz_cmp_ui(n, (unsigned long)(UV_MAX>>5)) < 0) { UV ui_n = mpz_get_ui(n); UV ui_factors[2]; if (!mpz_cmp_ui(n, ui_n)) { success = racing_squfof_factor(ui_n, ui_factors, 200000)-1; if (success) mpz_set_ui(f, ui_factors[0]); } } if (effort >= 1) { if (!success) success = _GMP_pminus1_factor(n, f, 1000, 10000); } if (!success) success = (int)power_factor(n, f); if (!success && effort == 2) { UV brent_rounds = (log2n <= 64) ? 100000 : 100000 / (log2n-63); int final_B2 = 1000 * (150-(int)log2n); if (log2n < 70) brent_rounds *= 3; if (!success && 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 > 10000) success = _GMP_pminus1_factor(n, f, 10000, final_B2); } if (!success && effort >= 3) { if (!success) success = _GMP_pminus1_factor(n, f, 10000, 200000); if (!success) success = _GMP_ECM_FACTOR(n, f, 500, 30); if (!success) success = _GMP_ECM_FACTOR(n, f, 2000, 20); } if (!success && effort >= 5 && log2n > 170) { UV B1 = (log2n > 2500) ? 10000000 : 4000 * log2n; if (!success) success = _GMP_pminus1_factor(n, f, B1, 20*B1); /* To head off expensive QS, do these early */ if (!success && log2n > 210) success = _GMP_ECM_FACTOR(n, f, 20000, 10); if (!success && log2n > 240) success = _GMP_ECM_FACTOR(n, f, 40000, 10); if (!success && log2n > 240) success = _GMP_ECM_FACTOR(n, f, 80000, 5); if (!success && log2n > 270) success = _GMP_ECM_FACTOR(n, f,160000, 20); } return success; } static int try_factor2(mpz_t f, mpz_t n, int effort) { int success = 0; if (!success && effort >= 4) { if (!success) success = _GMP_pminus1_factor(n, f, 200000, 4000000); if (!success) success = _GMP_ECM_FACTOR(n, f, 10000, 10); } if (!success && effort >= 5) { UV i; UV ecm_B1 = 10000; UV curves = 10; if (_GMP_is_prob_prime(n)) croak("Internal error in BLS75\n"); for (i = 1; i < 18 && !success; i++) { if ((4+i) > (UV)effort) break; ecm_B1 *= 2; success = _GMP_ECM_FACTOR(n, f, ecm_B1, curves); } } 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); } /* FIXME: * (1) too much repetitious overhead code in these * (2) way too much copy/paste between Pocklington and BLS * (3) Pocklington has code rotted, so fix before using */ #define ADD_TO_STACK(val, stack, cur, max) \ if (cur == max) \ Renew(stack, max += 10, mpz_t); \ mpz_init_set( stack[cur++], val ); #define ADD_TO_STACK_UI(val, stack, cur, max) \ if (cur == max) \ Renew(stack, max += 10, mpz_t); \ mpz_init_set_ui( stack[cur++], val ); #define primality_handle_factor(f, primality_func, factor_prob) \ { \ int f_prob_prime = _GMP_is_prob_prime(f); \ if ( (f_prob_prime == 1) && (primality_func(f, effort, prooftextptr) == 2) ) \ f_prob_prime = 2; \ if (f_prob_prime == 2) { \ ADD_TO_STACK( f, fstack, fsp, fsmax ); \ while (mpz_divisible_p(B, f)) { \ mpz_mul(A, A, f); \ mpz_divexact(B, B, f); \ } \ } else if ( (f_prob_prime == 0) || (factor_prob) ) { \ ADD_TO_STACK( f, mstack, msp, msmax ); \ } \ } #define INNER_QS_FACTOR(qn, primality_func) \ { \ mpz_t farray[66]; \ int i, nfactors; \ for (i = 0; i < 66; i++) mpz_init(farray[i]); \ nfactors = _GMP_simpqs(qn, farray); \ /* Insert all found factors */ \ if (nfactors > 1) { \ success = 1; \ for (i = 0; i < nfactors; i++) \ primality_handle_factor(farray[i], primality_func, 0); \ } \ for (i = 0; i < 66; i++) mpz_clear(farray[i]); \ if (success) \ continue; \ } #if 0 int _GMP_primality_pocklington(mpz_t n, int do_quick) { mpz_t nm1, A, B, sqrtn, t, m, f; mpz_t mstack[PRIM_STACK_SIZE]; mpz_t fstack[PRIM_STACK_SIZE]; int msp = 0; int fsp = 0; int success = 1; mpz_init(nm1); mpz_sub_ui(nm1, n, 1); mpz_init_set_ui(A, 1); mpz_init_set(B, nm1); mpz_init(sqrtn); mpz_sqrt(sqrtn, n); mpz_init(m); mpz_init(f); mpz_init(t); { /* Pull small factors out */ UV tf = 2; while ( (tf = _GMP_trial_factor(B, tf, 1000)) != 0 ) { if (fsp >= PRIM_STACK_SIZE) { success = 0; break; } mpz_init_set_ui(fstack[fsp++], tf); while (mpz_divisible_ui_p(B, tf)) { mpz_mul_ui(A, A, tf); mpz_divexact_ui(B, B, tf); } tf++; } } if (success) { mpz_set(f, B); primality_handle_factor(f, _GMP_primality_pocklington, 1); } while (success) { mpz_gcd(t, A, B); if ( (mpz_cmp(A, sqrtn) > 0) && (mpz_cmp_ui(t, 1) == 0) ) break; success = 0; /* If the stack is empty, we have failed. */ if (msp == 0) break; /* pop a component off the stack */ mpz_set(m, mstack[--msp]); mpz_clear(mstack[msp]); /* Try to factor it without trying too hard */ if (!success) success = (int)power_factor(m, f); if (do_quick) { UV log2m = mpz_sizeinbase(m, 2); UV rounds = (log2m <= 64) ? 300000 : 300000 / (log2m-63); if (!success) success = _GMP_pbrent_factor(m, f, 3, rounds); } else { if (!success) success = _GMP_pbrent_factor(m, f, 3, 64*1024); if (!success) success = _GMP_pbrent_factor(m, f, 5, 64*1024); if (!success) success = _GMP_pbrent_factor(m, f, 7, 64*1024); if (!success) success = _GMP_pbrent_factor(m, f,11, 64*1024); if (!success) success = _GMP_pbrent_factor(m, f,13, 64*1024); if (!success) success = _GMP_pbrent_factor(m, f, 1, 16*1024*1024); if (!success) success = _GMP_ECM_FACTOR (m, f, 12500, 4); if (!success) success = _GMP_ECM_FACTOR (m, f, 3125000, 10); if (!success) success = _GMP_pbrent_factor(m, f, 3, 256*1024*1024); if (!success) success = _GMP_ECM_FACTOR (m, f, 400000000, 200); } /* If we couldn't factor m and the stack is empty, we've failed. */ if ( (!success) && (msp == 0) ) break; /* Put the two factors f and m/f into the stacks */ primality_handle_factor(f, _GMP_primality_pocklington, 0); mpz_divexact(f, m, f); primality_handle_factor(f, _GMP_primality_pocklington, 0); } if (success) { int pcount, a; int const alimit = do_quick ? 200 : 10000; mpz_t p, ap; mpz_init(p); mpz_init(ap); for (pcount = 0; success && pcount < fsp; pcount++) { mpz_set(p, fstack[pcount]); success = 0; for (a = 2; !success && a <= alimit; a = next_small_prime(a)) { mpz_set_ui(ap, a); /* Does a^(n-1) % n = 1 ? */ mpz_powm(t, ap, nm1, n); if (mpz_cmp_ui(t, 1) != 0) continue; /* Does gcd(a^((n-1)/f)-1,n) = 1 ? */ mpz_divexact(B, nm1, p); mpz_powm(t, ap, B, 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 */ } } mpz_clear(p); mpz_clear(ap); } while (msp-- > 0) { mpz_clear(mstack[msp]); } while (fsp-- > 0) { mpz_clear(fstack[fsp]); } mpz_clear(nm1); mpz_clear(A); mpz_clear(B); mpz_clear(sqrtn); mpz_clear(m); mpz_clear(f); mpz_clear(t); return success; } #endif static int bls_theorem5_limit(mpz_t n, mpz_t A, mpz_t B, 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; } int _GMP_primality_bls_nm1(mpz_t n, int effort, char** prooftextptr) { mpz_t nm1, A, B, t, m, f, r, s; mpz_t* fstack; mpz_t* mstack; int fsp = 0, fsmax = 10; int msp = 0, msmax = 10; int success = 1; UV B1 = (mpz_sizeinbase(n,10) > 1000) ? 100000 : 2000; /* 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); New(0, fstack, fsmax, mpz_t); New(0, mstack, msmax, mpz_t); { /* 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; if (mpz_divisible_ui_p(B, tf)) { ADD_TO_STACK_UI( tf, fstack, fsp, fsmax ); do { mpz_mul_ui(A, A, tf); mpz_divexact_ui(B, B, tf); } while (mpz_divisible_ui_p(B, tf)); } } prime_iterator_destroy(&iter); } if (success) { mpz_set(f, B); primality_handle_factor(f, _GMP_primality_bls_nm1, 1); } while (success) { if (bls_theorem5_limit(n, A, B, t, m, r, s)) break; success = 0; /* If the stack is empty, we have failed. */ if (msp == 0) break; /* pop a component off the stack */ mpz_set(m, mstack[--msp]); mpz_clear(mstack[msp]); success = try_factor(f, m, effort); /* QS. Uses lots of memory, but finds multiple factors quickly */ if (!success && effort >= 5 && mpz_sizeinbase(m,10) >= 30 && mpz_sizeinbase(m,10) <= 90) { if (effort > 5 || (effort == 5 && mpz_sizeinbase(m,10) < 55) ) { INNER_QS_FACTOR(m, _GMP_primality_bls_nm1); } } if (!success) success = try_factor2(f, m, effort); /* If we couldn't factor m and the stack is empty, we've failed. */ if ( (!success) && (msp == 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); primality_handle_factor(f, _GMP_primality_bls_nm1, 0); primality_handle_factor(m, _GMP_primality_bls_nm1, 0); } /* clear mstack since we don't care about it. Use to hold a values. */ while (msp-- > 0) mpz_clear(mstack[msp]); msp = 0; /* Sort factors found from largest to smallest, but 2 must be at start. */ { 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--; } } /* Shrink to smallest set and verify conditions. */ if (success > 0) { int i; mpz_set_ui(A, 1); mpz_set(B, nm1); for (i = 0; i < fsp; i++) { if (bls_theorem5_limit(n, A, B, t, m, r, s)) break; do { mpz_mul(A, A, fstack[i]); mpz_divexact(B, B, fstack[i]); } while (mpz_divisible_p(B, fstack[i])); } /* Delete any extra factors */ while (i < fsp) mpz_clear(fstack[--fsp]); /* Verify Q[0] = 2 */ if (mpz_cmp_ui(fstack[0], 2) != 0) croak("BLS75 internal error: 2 not at start of fstack"); /* Verify conditions */ success = 0; if (bls_theorem5_limit(n, A, B, 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 < fsp; pcount++) { PRIME_ITERATOR(iter); mpz_set(p, fstack[pcount]); success = 0; for (a = 2; !success && a <= alimit; a = prime_iterator_next(&iter)) { mpz_set_ui(ap, a); /* Does a^(n-1) % n = 1 ? */ if (afermat[a] == -1) { mpz_powm(t, ap, nm1, n); afermat[a] = (mpz_cmp_ui(t, 1) == 0); } if (afermat[a] == 0) continue; /* Does gcd(a^((n-1)/f)-1,n) = 1 ? */ mpz_divexact(B, nm1, p); mpz_powm(t, ap, B, 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 */ ADD_TO_STACK( ap, mstack, msp, msmax ); } prime_iterator_destroy(&iter); } /* 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" :) */ mpz_clear(p); mpz_clear(ap); } if (success > 0 && prooftextptr != 0) { int i; char *proofstr, *proofptr; int curprooflen = (*prooftextptr == 0) ? 0 : strlen(*prooftextptr); 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[i]); /* A[i] only printed if not 2 */ for (i = 0; i < msp; i++) if (mpz_cmp_ui(mstack[i], 2) != 0) proofptr += gmp_sprintf(proofptr, "A[%d] %Zd\n", i, mstack[i]); proofptr += gmp_sprintf(proofptr, "----\n"); /* Set or prepend */ if (*prooftextptr) { proofptr += gmp_sprintf(proofptr, "\n"); strcat(proofptr, *prooftextptr); Safefree(*prooftextptr); } *prooftextptr = proofstr; } while (fsp-- > 0) mpz_clear(fstack[fsp]); Safefree(fstack); while (msp-- > 0) mpz_clear(mstack[msp]); Safefree(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; } /* 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)) { 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 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; } success = try_factor(f, q, effort); if (!success) success = try_factor2(f, q, effort); 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 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; } success = try_factor(f, p, effort); if (!success) success = try_factor2(f, p, effort); 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.35/small_factor.h0000644000076400007640000000022412420642023016150 0ustar danadana#ifndef MPU_SMALL_FACTOR_H #define MPU_SMALL_FACTOR_H #include "ptypes.h" extern int racing_squfof_factor(UV n, UV *factors, UV rounds); #endif Math-Prime-Util-GMP-0.35/inc/0000755000076400007640000000000012633466633014125 5ustar danadanaMath-Prime-Util-GMP-0.35/inc/Devel/0000755000076400007640000000000012633466633015164 5ustar danadanaMath-Prime-Util-GMP-0.35/inc/Devel/CheckLib.pm0000644000076400007640000003544112237244573017172 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.35/Makefile.PL0000644000076400007640000000601412566522704015324 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 ' . 'small_factor.o ' . 'utility.o ' . 'factor.o ' . 'ecm.o ' . 'bls75.o ' . 'ecpp.o ' . 'simpqs.o ' . 'gmp_main.o ' . 'XS.o', LIBS => ['-lgmp -lm'], TEST_REQUIRES=> { 'Test::More' => '0.45', }, PREREQ_PM => { 'Exporter' => '5.57', 'XSLoader' => '0.01', '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.52, }, }, }, }, 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.35/ecm.c0000644000076400007640000004733212543164057014270 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; gmp_randstate_t* p_randstate = get_randstate(); 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_urandomm(a, *p_randstate, 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; gmp_randstate_t* p_randstate = get_randstate(); 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_urandomm(sigma, *p_randstate, 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.35/gmp_main.h0000644000076400007640000000534212627512342015310 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 int _GMP_miller_rabin(mpz_t n, mpz_t a); 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); extern int is_frobenius_pseudoprime(mpz_t n, IV P, IV Q); extern int is_frobenius_cp_pseudoprime(mpz_t n, UV ntests); extern int _GMP_miller_rabin_random(mpz_t n, UV numbases, char* seedstr); 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 UV _GMP_trial_factor(mpz_t n, UV from_n, UV to_n); extern int primality_pretest(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); extern int _GMP_is_aks_prime(mpz_t n); extern int is_miller_prime(mpz_t n, int assume_grh); extern int _GMP_BPSW(mpz_t n); extern void _GMP_next_prime(mpz_t n); extern void _GMP_prev_prime(mpz_t 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 void _GMP_pn_primorial(mpz_t prim, UV n); extern void _GMP_primorial(mpz_t prim, UV n); extern void _GMP_lcm_of_consecutive_integers(UV B, mpz_t m); 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 stirling(mpz_t r, unsigned long n, unsigned long m, UV type); extern void binomial(mpz_t r, UV n, UV k); extern UV power_factor(mpz_t n, mpz_t f); extern UV is_power(mpz_t n, UV a); extern void exp_mangoldt(mpz_t res, mpz_t n); extern uint32_t* partial_sieve(mpz_t start, UV length, UV maxprime); extern char* pidigits(UV n); extern char* harmreal(mpz_t zn, unsigned long prec); 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); #endif Math-Prime-Util-GMP-0.35/ptypes.h0000644000076400007640000000556512627512342015054 0ustar danadana#ifndef MPU_PTYPES_H #define MPU_PTYPES_H #ifndef _MSC_VER #define __STDC_LIMIT_MACROS #include #else typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; #endif #ifdef STANDALONE #include #include #include typedef unsigned long UV; typedef signed long IV; #define UV_MAX ULONG_MAX #define UVCONST(x) ((unsigned long)x##UL) #define UVuf "lu" #define IVdf "ld" #define croak(fmt,...) { printf(fmt,##__VA_ARGS__); exit(3); } #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 /* Try to determine if we have 64-bit available via uint64_t */ #define HAVE_STD_U64 0 #if defined(UINT64_MAX) && defined(__UINT64_C) #if (UINT64_MAX >= __UINT64_C(18446744073709551615)) #undef HAVE_STD_U64 #define HAVE_STD_U64 1 #endif #endif #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.35/xt/0000755000076400007640000000000012633466633014007 5ustar danadanaMath-Prime-Util-GMP-0.35/xt/expr.c0000644000076400007640000010740312372057102015121 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.35/xt/expr.h0000644000076400007640000001212312314312303015111 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.35/xt/proof-text-format.txt0000644000076400007640000002055112237244573020145 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.35/xt/calculate-mr-probs.pl0000755000076400007640000000216312237244573020042 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.35/xt/create-standalone.sh0000755000076400007640000002416512537562312017741 0ustar danadana#!/bin/bash if [ ! -d standalone ] then mkdir standalone fi cp -p ptypes.h standalone/ cp -p ecpp.[ch] bls75.[ch] ecm.[ch] prime_iterator.[ch] standalone/ cp -p gmp_main.[ch] factor.[ch] small_factor.[ch] utility.[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 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 ecm.o prime_iterator.o gmp_main.o \ small_factor.o factor.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-2015, 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.35/xt/expr-impl.h0000644000076400007640000001052212314312303016051 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.35/Changes0000644000076400007640000004402012633466277014653 0ustar danadanaRevision history for Perl module Math::Prime::Util::GMP 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.35/factor.c0000644000076400007640000005507412627512342015001 0ustar danadana#include "factor.h" #include "gmp_main.h" #include "prime_iterator.h" #include "utility.h" #include "small_factor.h" #include "ecm.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 nbits, B1 = 5000; /* * 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. */ if (mpz_cmp_ui(n, (unsigned long)(UV_MAX>>4)) < 0) { UV ui_n = mpz_get_ui(n); UV ui_factors[2]; if (!mpz_cmp_ui(n, ui_n)) { success = racing_squfof_factor(ui_n, ui_factors, 200000)-1; if (success) { mpz_set_ui(f, ui_factors[0]); } else { if (o > 2) {gmp_printf("UV SQUFOF failed %Zd\n", n);} } } if (success&&o) {gmp_printf("UV SQUFOF 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, 15000, 150000); if (success&&o) {gmp_printf("p-1 (15k) 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) { nbits = mpz_sizeinbase(n, 2); 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;} if (!success) success = _GMP_squfof_factor(n, f, 256*1024*1024); if (success&&o) {gmp_printf("squfof 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) 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) { if (mpz_cmp_ui(n, 4) <= 0) { if (mpz_sgn(n) <= 0) mpz_set_ui(root, 0); else mpz_sub_ui(root, n, 1); } else if (mpz_divisible_ui_p(n, 4)) { mpz_set_ui(root, 0); } else { mpz_t* factors; int* exponents; int i, nfactors; mpz_t t, phi, a; mpz_init(phi); mpz_init(t); nfactors = 1; mpz_sub_ui(phi, n, 1); if (!_GMP_is_prob_prime(n)) { if (mpz_even_p(n)) mpz_tdiv_q_2exp(t, n, 1); else mpz_set(t, n); nfactors = factor(t, &factors, &exponents); mpz_sub_ui(phi, factors[0], 1); for (i = 1; i < exponents[0]; i++) mpz_mul(phi, phi, factors[0]); clear_factors(nfactors, &factors, &exponents); } if (nfactors != 1) { mpz_set_ui(root, 0); } else { nfactors = factor(phi, &factors, &exponents); i = 0; for (mpz_init_set_ui(a,2); mpz_cmp(a, n) < 0; mpz_add_ui(a, a, 1)) { if (mpz_kronecker(a, n) == 0) continue; for (i = 0; i < nfactors; i++) { mpz_divexact(t, phi, factors[i]); mpz_powm(t, a, t, n); if (mpz_cmp_ui(t, 1) == 0) break; } if (i == nfactors) break; } if (i == nfactors) mpz_set(root, a); else mpz_set_ui(root, 0); mpz_clear(a); clear_factors(nfactors, &factors, &exponents); } 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(t1); mpz_clear(t2); mpz_clear(t3); mpz_init(t4); mpz_clear(t); }