/* Copyright 2009 Jason Moxham Copyright (C) 2008 Peter Shrimpton Copyright (C) 2008, 2009 William Hart This file is part of the MPIR Library. The MPIR Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The MPIR 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the MPIR Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "mpir.h" #include "gmp-impl.h" #include "longlong.h" #if GMP_LIMB_BITS == 32 || GMP_LIMB_BITS == 64 #if GMP_LIMB_BITS == 32 #define D_BITS 31 #else #define D_BITS 53 #endif typedef struct pair_s { mp_limb_t x, y; } n_pair_t; #define r_shift(in, shift) \ ((shift == GMP_LIMB_BITS) ? CNST_LIMB(0) : ((in)>>(shift))) mp_limb_t mpir_sqrt(mp_limb_t r) { mp_limb_t res, is; #if GMP_LIMB_BITS == 32 float x, z; union { float f; mp_limb_t l; } temp; mp_limb_t bits32 = (r & GMP_LIMB_HIGHBIT); mp_limb_t r2; /* algorithm can't handle 32 bits */ if (bits32) { r2 = r; r >>= 2; } temp.f = (float) r; temp.l = (CNST_LIMB(0xbe6ec85e) - temp.l)>>1; // estimate of 1/sqrt(y) x = temp.f; z = (float) r*0.5; x = (1.5*x) - (x*x)*(x*z); x = (1.5*x) - (x*x)*(x*z); x = (1.5*x) - (x*x)*(x*z); x = (1.5*x) - (x*x)*(x*z); is = (mp_limb_t) (x*(double) r); res = is + ((is+1)*(is+1) <= r); if (!bits32) return res - (res*res > r); else { mp_limb_t sq; res = res - (res*res > r); res <<= 1; sq = res*res; res = res - ((sq > r2) || ((sq ^ r2) & GMP_LIMB_HIGHBIT)); sq = (res + 1)*(res + 1); res = res + ((sq <= r2) && !((sq ^ r2) & GMP_LIMB_HIGHBIT)); return res; } #else double x, z; union { double f; mp_limb_t l; } temp; mp_limb_t bits64 = (r & GMP_LIMB_HIGHBIT); mp_limb_t r2; /* algorithm can't handle 64 bits */ if (bits64) { r2 = r; r >>= 2; } temp.f = (double) r; temp.l = (CNST_LIMB(0xbfcdd90a00000000) - temp.l)>>1; /* estimate of 1/sqrt(y) */ x = temp.f; z = (double) r*0.5; x = (1.5*x) - (x*x)*(x*z); x = (1.5*x) - (x*x)*(x*z); x = (1.5*x) - (x*x)*(x*z); x = (1.5*x) - (x*x)*(x*z); x = (1.5*x) - (x*x)*(x*z); is = (mp_limb_t) (x*(double) r); res = is + ((is+1)*(is+1) <= r); if (!bits64) return res - (res*res > r); else { mp_limb_t sq; res = res - (res*res > r); res <<= 1; sq = res*res; res = res - ((sq > r2) || ((sq ^ r2) & GMP_LIMB_HIGHBIT)); sq = (res + 1)*(res + 1); res = res + ((sq <= r2) && !((sq ^ r2) & GMP_LIMB_HIGHBIT)); return res; } #endif } static double n_precompute_inverse(mp_limb_t n) { return (double) 1 / (double) n; } static unsigned int BIT_COUNT(mp_limb_t x) { unsigned int zeros = GMP_LIMB_BITS; if (x) count_leading_zeros(zeros, x); return GMP_LIMB_BITS - zeros; } static int mod64[64] = {1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0, 0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1, 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0}; static int mod65[65] = {1,1,0,0,1,0,0,0,0,1,1,0,0,0,1,0,1,0,0,0,0,0, 0,0,0,1,1,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0, 0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,0,0,1,0,0,1}; static int mod63[63] = {1,1,0,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,1,0,0, 0,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0, 0,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0}; static int n_is_square(mp_limb_t x) { mp_limb_t sq; if (!mod64[x%CNST_LIMB(64)]) return 0; if (!mod63[x%CNST_LIMB(63)]) return 0; if (!mod65[x%CNST_LIMB(65)]) return 0; sq = mpir_sqrt(x); return (x == sq*sq); } static mp_limb_t n_preinvert_limb(mp_limb_t n) { mp_limb_t norm, ninv; count_leading_zeros(norm, n); invert_limb(ninv, n< x) return x + y; else return x + y - n; } static inline mp_limb_t n_submod(mp_limb_t x, mp_limb_t y, mp_limb_t n) { if (y > x) return x - y + n; else return x - y; } static mp_limb_t n_mod2_preinv(mp_limb_t a, mp_limb_t n, mp_limb_t ninv) { unsigned int norm; mp_limb_t q, r; count_leading_zeros(norm, n); udiv_qrnnd_preinv(q, r, r_shift(a, GMP_LIMB_BITS-norm), a<>norm); } static mp_limb_t n_ll_mod_preinv(mp_limb_t a_hi, mp_limb_t a_lo, mp_limb_t n, mp_limb_t ninv) { mp_limb_t q, r, norm; if (a_hi > n) a_hi = n_mod2_preinv(a_hi, n, ninv); count_leading_zeros(norm, n); udiv_qrnnd_preinv(q, r, (a_hi<>norm); } static mp_limb_t n_mulmod_precomp(mp_limb_t a, mp_limb_t b, mp_limb_t n, double npre) { mp_limb_t quot = (mp_limb_t) ((double) a * (double) b * npre); mp_limb_signed_t rem = a*b - quot*n; if (rem < 0) { rem += n; if (rem < 0) return rem + n; } else if (rem >= n) return rem - n; return rem; } static mp_limb_t n_mulmod2_preinv(mp_limb_t a, mp_limb_t b, mp_limb_t n, mp_limb_t ninv) { mp_limb_t p1, p2; umul_ppmm(p1, p2, a, b); return n_ll_mod_preinv(p1, p2, n, ninv); } static mp_limb_t n_powmod_precomp(mp_limb_t a, mp_limb_t exp, mp_limb_t n, double npre) { mp_limb_t x, y; mp_limb_t e; if (n == CNST_LIMB(1)) return 0L; e = exp; x = CNST_LIMB(1); y = a; while (e) { if (e & 1L) x = n_mulmod_precomp(x, y, n, npre); e >>= 1; if (e) y = n_mulmod_precomp(y, y, n, npre); } return x; } static mp_limb_t n_powmod2_preinv(mp_limb_t a, mp_limb_t exp, mp_limb_t n, mp_limb_t ninv) { mp_limb_t x, y; mp_limb_t e; if (n == CNST_LIMB(1)) return CNST_LIMB(0); e = exp; x = CNST_LIMB(1); y = a; while (e) { if (e & 1) x = n_mulmod2_preinv(x, y, n, ninv); e = e >> 1; if (e) y = n_mulmod2_preinv(y, y, n, ninv); } return x; } static mp_limb_t n_powmod(mp_limb_t a, mp_limb_signed_t exp, mp_limb_t n) { double npre = n_precompute_inverse(n); return n_powmod_precomp(a, exp, n, npre); } static mp_limb_t n_powmod2(mp_limb_t a, mp_limb_signed_t exp, mp_limb_t n) { mp_limb_t ninv = n_preinvert_limb(n); return n_powmod2_preinv(a, exp, n, ninv); } static mp_limb_t n_gcd(mp_limb_t x, mp_limb_t y) { mp_limb_t u3, v3; mp_limb_t quot, rem; u3 = x; v3 = y; if ((mp_limb_signed_t) (x & y) < 0L) /* x and y both have top bit set */ { quot=u3-v3; u3 = v3; v3 = quot; } while ((mp_limb_signed_t) (v3<<1) < 0L) /* second value has second msb set */ { quot=u3-v3; if (quot < v3) { u3 = v3; v3 = quot; } else if (quot < (v3<<1)) { u3 = v3; v3 = quot-u3; } else { u3 = v3; v3 = quot-(u3<<1); } } while (v3) { quot=u3-v3; if (u3 < (v3<<2)) /* overflow not possible due to top 2 bits of v3 not being set */ { if (quot < v3) { u3 = v3; v3 = quot; } else if (quot < (v3<<1)) { u3 = v3; v3 = quot-u3; } else { u3 = v3; v3 = quot-(u3<<1); } } else { quot=u3/v3; rem = u3 - v3*quot; u3 = v3; v3 = rem; } } return u3; } static mp_limb_t n_invmod(mp_limb_t x, mp_limb_t y) { mp_limb_signed_t v1 = CNST_LIMB(0); mp_limb_signed_t v2 = CNST_LIMB(1); mp_limb_signed_t t2; mp_limb_t u3, v3; mp_limb_t quot, rem; u3 = y, v3 = x; if (v3 > u3) { rem = u3; u3 = v3; t2 = v2; v2 = v1; v1 = t2; v3 = rem; } if ((mp_limb_signed_t) (y & x) < 0L) /* y and x both have top bit set */ { quot=u3-v3; t2 = v2; u3 = v3; v2 = v1 - v2; v1 = t2; v3 = quot; } while ((mp_limb_signed_t) (v3<<1) < 0L) /* second value has second msb set */ { quot=u3-v3; if (quot < v3) { t2 = v2; u3 = v3; v2 = v1 - v2; v1 = t2; v3 = quot; } else if (quot < (v3<<1)) { u3 = v3; t2 = v2; v2 = v1 - (v2<<1); v1 = t2; v3 = quot-u3; } else { u3 = v3; t2 = v2; v2 = v1 - 3*v2; v1 = t2; v3 = quot-(u3<<1); } } while (v3) { quot=u3-v3; if (u3 < (v3<<2)) /* overflow not possible due to top 2 bits of v3 not being set */ { if (quot < v3) { t2 = v2; u3 = v3; v2 = v1 - v2; v1 = t2; v3 = quot; } else if (quot < (v3<<1)) { u3 = v3; t2 = v2; v2 = v1 - (v2<<1); v1 = t2; v3 = quot-u3; } else { u3 = v3; t2 = v2; v2 = v1 - 3*v2; v1 = t2; v3 = quot-(u3<<1); } } else { quot=u3/v3; rem = u3 - v3*quot; u3 = v3; t2 = v2; v2 = v1 - quot*v2; v1 = t2; v3 = rem; } } if (v1 < 0L) v1 += y; return v1; } static int n_jacobi(mp_limb_signed_t x, mp_limb_t y) { mp_limb_t a, b, temp; int s, exp; a = x; b = y; s = 1; if (x < 0L) { if (((b - 1)/2)%2 == CNST_LIMB(1)) s = -s; a = -x; } if ((a < b) && (b != CNST_LIMB(1))) { if (a == CNST_LIMB(0)) return 0; temp = a; a = b; b = temp; count_trailing_zeros(exp, b); b>>=exp; if (((exp*(a*a - 1))/8)%2 == CNST_LIMB(1)) /* only want values mod 8, */ s = -s; /* so overflows don't matter here */ if ((((a - 1)*(b - 1))/4)%2 == CNST_LIMB(1)) /* only want values mod 4, */ s = -s; /* so overflows don't matter here */ } while (b != CNST_LIMB(1)) { if ((a>>2) < b) { temp = a - b; a = b; if (temp < b) b = temp; else if (temp < (b<<1)) b = temp - a; else b = temp - (a<<1); } else { temp = (a%b); a = b; b = temp; } if (b == CNST_LIMB(0)) return 0; count_trailing_zeros(exp, b); b>>=exp; if (((exp*(a*a - 1))/8)%2 == CNST_LIMB(1)) /* only want values mod 8, */ s = -s; /* so overflows don't matter here */ if ((((a - 1)*(b - 1))/4)%2 == CNST_LIMB(1)) /* only want values mod 4, */ s = -s; /* so overflows don't matter here */ } return s; } static int n_is_pseudoprime_fermat(mp_limb_t n, mp_limb_t i) { if (BIT_COUNT(n) <= D_BITS) return (n_powmod(i, n - 1, n) == CNST_LIMB(1)); else { if ((mp_limb_signed_t) (n - 1) < 0L) { mp_limb_t temp = n_powmod2(i, (n - 1)/2, n); return (n_powmod2(temp, 2, n) == CNST_LIMB(1)); } else { return (n_powmod2(i, n - 1, n) == CNST_LIMB(1)); } } } static int n_is_strong_pseudoprime_precomp(mp_limb_t n, double npre, mp_limb_t a, mp_limb_t d) { mp_limb_t t = d; mp_limb_t y; y = n_powmod_precomp(a, t, n, npre); if (y == CNST_LIMB(1)) return 1; t <<= 1; while ((t != n - 1) && (y != n - 1)) { y = n_mulmod_precomp(y, y, n, npre); t <<= 1; } return (y == n - 1); } static int n_is_strong_pseudoprime2_preinv(mp_limb_t n, mp_limb_t ninv, mp_limb_t a, mp_limb_t d) { mp_limb_t t = d; mp_limb_t y; y = n_powmod2_preinv(a, t, n, ninv); if (y == CNST_LIMB(1)) return 1; t <<= 1; while ((t != n - 1) && (y != n - 1)) { y = n_mulmod2_preinv(y, y, n, ninv); t <<= 1; } return (y == n - 1); } static n_pair_t fchain_precomp(mp_limb_t m, mp_limb_t n, double npre) { n_pair_t current, old; int length; mp_limb_t power, xy, xx, yy; old.x = CNST_LIMB(2); old.y = n - CNST_LIMB(3); length = BIT_COUNT(m); power = (CNST_LIMB(1)<<(length-1)); for ( ; length > 0; length--) { xy = n_mulmod_precomp(old.x, old.y, n, npre); xy = n_addmod(xy, CNST_LIMB(3), n); if (m & power) { current.y = n_submod(n_mulmod_precomp(old.y, old.y, n, npre), CNST_LIMB(2), n); current.x = xy; } else { current.x = n_submod(n_mulmod_precomp(old.x, old.x, n, npre), CNST_LIMB(2), n); current.y = xy; } power >>= 1; old = current; } return current; } static n_pair_t fchain2_preinv(mp_limb_t m, mp_limb_t n, mp_limb_t ninv) { n_pair_t current, old; int length; mp_limb_t power, xy, xx, yy; old.x = CNST_LIMB(2); old.y = n - CNST_LIMB(3); length = BIT_COUNT(m); power = (CNST_LIMB(1)<<(length-1)); for ( ; length > 0; length--) { xy = n_mulmod2_preinv(old.x, old.y, n, ninv); xy = n_addmod(xy, CNST_LIMB(3), n); if (m & power) { current.y = n_submod(n_mulmod2_preinv(old.y, old.y, n, ninv), CNST_LIMB(2), n); current.x = xy; } else { current.x = n_submod(n_mulmod2_preinv(old.x, old.x, n, ninv), CNST_LIMB(2), n); current.y = xy; } power >>= 1; old = current; } return current; } static int n_is_pseudoprime_fibonacci(mp_limb_t n) { mp_limb_t m, left, right; n_pair_t V; if (ABS((mp_limb_signed_t) n) <= CNST_LIMB(3)) { if (n >= CNST_LIMB(2)) return 1; return 0; } m = (n - n_jacobi(CNST_LIMB(5), n))/2; /* no overflow as (5/n) = 0 for n = 2^64 - 1 */ if (BIT_COUNT(n) <= D_BITS) { double npre = n_precompute_inverse(n); V = fchain_precomp(m, n, npre); return (n_mulmod_precomp(n - CNST_LIMB(3), V.x, n, npre) == n_mulmod_precomp(CNST_LIMB(2), V.y, n, npre)); } else { mp_limb_t ninv = n_preinvert_limb(n); V = fchain2_preinv(m, n, ninv); return (n_mulmod2_preinv(n - CNST_LIMB(3), V.x, n, ninv) == n_mulmod2_preinv(CNST_LIMB(2), V.y, n, ninv)); } } static n_pair_t lchain_precomp(mp_limb_t m, mp_limb_t a, mp_limb_t n, double npre) { n_pair_t current, old; int length, i; mp_limb_t power, xy, xx, yy; old.x = CNST_LIMB(2); old.y = a; length = BIT_COUNT(m); power = (CNST_LIMB(1)<<(length - 1)); for (i = 0; i < length; i++) { xy = n_submod(n_mulmod_precomp(old.x, old.y, n, npre), a, n); if (m & power) { yy = n_submod(n_mulmod_precomp(old.y, old.y, n, npre), CNST_LIMB(2), n); current.x = xy; current.y = yy; } else { xx = n_submod(n_mulmod_precomp(old.x, old.x, n, npre), CNST_LIMB(2), n); current.x = xx; current.y = xy; } power >>= 1; old = current; } return current; } static n_pair_t lchain2_preinv(mp_limb_t m, mp_limb_t a, mp_limb_t n, mp_limb_t ninv) { n_pair_t current, old; int length, i; mp_limb_t power, xy, xx, yy; old.x = CNST_LIMB(2); old.y = a; length = BIT_COUNT(m); power = (CNST_LIMB(1)<<(length - 1)); for (i = 0; i < length; i++) { xy = n_submod(n_mulmod2_preinv(old.x, old.y, n, ninv), a, n); if (m & power) { yy = n_submod(n_mulmod2_preinv(old.y, old.y, n, ninv), CNST_LIMB(2), n); current.x = xy; current.y = yy; } else { xx = n_submod(n_mulmod2_preinv(old.x, old.x, n, ninv), CNST_LIMB(2), n); current.x = xx; current.y = xy; } power >>= 1; old = current; } return current; } static int n_is_pseudoprime_lucas(mp_limb_t n) { int i, D, Q; mp_limb_t A; mp_limb_t left, right; n_pair_t V; D = 0; Q = 0; if (((n % 2) == 0) || (ABS((mp_limb_signed_t) n) <= 2)) { if (n == CNST_LIMB(2)) return 1; else return 0; } for (i = 0; i < 100; i++) { D = 5 + 2*i; if (n_gcd(D, n%D) != CNST_LIMB(1)) { if (n == D) continue; else return 0; } if (i % 2 == 1) D = -D; if (n_jacobi(D, n) == -1) break; } if (i == 100) { if (n_is_square(n)) return -1; else return 1; } Q = (1 - D)/4; if (Q < 0) { if (n < CNST_LIMB(52)) { while (Q < 0) Q += n; A = n_submod(n_invmod(Q, n), CNST_LIMB(2), n); } else A = n_submod(n_invmod(Q + n, n), CNST_LIMB(2), n); } else { if (n < CNST_LIMB(52)) { while (Q >= n) Q -= n; A = n_submod(n_invmod(Q, n), CNST_LIMB(2), n); } else A = n_submod(n_invmod(Q, n), CNST_LIMB(2), n); } if (BIT_COUNT(n) <= D_BITS) { double npre = n_precompute_inverse(n); V = lchain_precomp(n + 1, A, n, npre); left = n_mulmod_precomp(A, V.x, n, npre); right = n_mulmod_precomp(2, V.y, n, npre); } else { mp_limb_t ninv = n_preinvert_limb(n); V = lchain2_preinv(n + 1, A, n, ninv); left = n_mulmod_precomp(A, V.x, n, ninv); right = n_mulmod_precomp(2, V.y, n, ninv); } return (left == right); } int mpir_is_likely_prime_BPSW(mp_limb_t n) { if (n <= CNST_LIMB(1)) return 0; if ((n & CNST_LIMB(1)) == CNST_LIMB(0)) { if (n == CNST_LIMB(2)) return 1; return 0; } if (((n % CNST_LIMB(10)) == CNST_LIMB(3)) || ((n % CNST_LIMB(10)) == CNST_LIMB(7))) { if (n_is_pseudoprime_fermat(n, 2) == 0) return 0; return n_is_pseudoprime_fibonacci(n); } else { mp_limb_t d; d = n - CNST_LIMB(1); while ((d & CNST_LIMB(1)) == CNST_LIMB(0)) d >>= 1; if (BIT_COUNT(n) <= D_BITS) { double npre = n_precompute_inverse(n); if (n_is_strong_pseudoprime_precomp(n, npre, 2L, d) == 0) return 0; } else { mp_limb_t ninv = n_preinvert_limb(n); if (n_is_strong_pseudoprime2_preinv(n, ninv, 2L, d) == 0) return 0; } return (n_is_pseudoprime_lucas(n) == 1); } } #endif /* GMP_LIMB_BITS */ /* Could have another parameter to specify what "likely" means i.e. for factoring, for RSA or to state that we have already done trial div */ /* could call it mpz_likely_composite_p then when true return more info, i.e. a factor */ int mpz_likely_prime_p (mpz_srcptr N, gmp_randstate_t STATE, mpir_ui td) { int d, t, r; unsigned long tdlim, i; mpz_t base, nm1, x, e, n; ALLOC (n) = ALLOC(N); SIZ (n) = ABSIZ(N); PTR (n) = PTR(N); /* fake up an absolute value that we don't have de-allocate */ /* algorithm does not handle small values, get rid of them here */ if (mpz_cmp_ui (n, 2) == 0 || mpz_cmp_ui (n, 3) == 0) return 1; if (mpz_cmp_ui (n, 5) < 0 || mpz_even_p (n)) return 0; #if GMP_LIMB_BITS == 64 || GMP_LIMB_BITS == 32 if (SIZ(n) == 1) { return mpir_is_likely_prime_BPSW(PTR(n)[0]); } #endif /* For factoring purposes we assume we know nothing about N i.e. it is a random integer. Therefore it has a good chance of factoring by small divisiors. So try trial division as its fast and it checks small divisors. Checking for other divisors is not worth it even if the test is fast as we have random integer so only small divisors are common enough. Remember this is not exact so it doesn't matter if we miss a few divisors */ tdlim = mpz_sizeinbase(n, 2); tdlim = MAX(1000, tdlim); d = mpz_trial_division(n, 3, tdlim); if (d != 0) { if (mpz_cmp_ui(n, d) == 0) return 1; return 0; } if (mpz_cmp_ui (n, tdlim * tdlim) < 0) return 1; /* if tdlim*tdlim overflows, n is not a single limb so can't be true */ ASSERT (mpz_odd_p(n)); ASSERT (mpz_cmp_ui (n, 5) >= 0); /* so we can choose a base */ /* now do strong pseudoprime test */ /* get random base, for now choose any size, later choose a small one */ mpz_init (base); mpz_init_set (nm1, n); mpz_sub_ui (nm1, nm1, 1); mpz_init (e); mpz_init (x); r = 1; for (i = 0; i < 10; i++) /* try LP_ITERS random bases */ { do { mpz_urandomm(base, STATE, nm1); } while (mpz_cmp_ui(base, 1) <= 0); /* Base is 2 to n - 2 which implies n >= 4. Only really want a small base, and ignore the rare base = n - 1 condition etc. */ t = mpz_scan1(nm1, 0); /* 2^t divides nm1 */ ASSERT(t > 0); mpz_tdiv_q_2exp(e, nm1, t); /* e = nm1/2^t */ mpz_powm(x, base, e, n); /* x = base^e mod n */ if (mpz_cmp_ui(x, 1) == 0) continue; if (mpz_cmp(x, nm1) == 0) continue; for (r = 0, t = t - 1; t > 0; t--) { mpz_mul(x, x, x); mpz_mod(x, x, n); if (mpz_cmp(x, nm1) == 0) { r = 1; break; } if (mpz_cmp_ui (x, 1) == 0) break; } if (r == 1) continue; break; } mpz_clear (e); mpz_clear (base); mpz_clear (nm1); mpz_clear (x); return r; }