mpir/mpz/likely_prime_p.c

922 lines
20 KiB
C

/*
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 n_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
}
double n_precompute_inverse(mp_limb_t n)
{
return (double) 1 / (double) n;
}
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;
}
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};
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};
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};
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 = n_sqrt(x);
return (x == sq*sq);
}
mp_limb_t n_preinvert_limb(mp_limb_t n)
{
mp_limb_t norm, ninv;
count_leading_zeros(norm, n);
invert_limb(ninv, n<<norm);
return ninv;
}
mp_limb_t n_addmod(mp_limb_t x, mp_limb_t y, mp_limb_t n)
{
if (n - y > 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;
}
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, n<<norm, ninv);
return (r>>norm);
}
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) + r_shift(a_lo, GMP_LIMB_BITS-norm), a_lo<<norm, n<<norm, ninv);
return (r>>norm);
}
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;
}
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);
}
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;
}
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;
}
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);
}
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);
}
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;
}
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;
}
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)) // we are only interested in values mod 8,
s = -s; //so overflows don't matter here
if ((((a - 1)*(b - 1))/4)%2 == CNST_LIMB(1)) // we are only interested in 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)) // we are only interested in values mod 8,
s = -s; //so overflows don't matter here
if ((((a - 1)*(b - 1))/4)%2 == CNST_LIMB(1)) // we are only interested in values mod 4,
s = -s; //so overflows don't matter here
}
return s;
}
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));
}
}
}
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);
}
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);
}
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;
}
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;
}
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; // cannot 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));
}
}
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;
}
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;
}
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 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
// ie for factoring , for RSA
// or to state that we have already done trial div
// could call it mpz_likely_composite_p then when true we could return more info about it , ie a factor
int
mpz_likely_prime_p (mpz_srcptr N, gmp_randstate_t STATE, unsigned long 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 dont 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 is_likely_prime_BPSW(PTR(n)[0]);
}
#endif
// for factoring purposes
// we assume we know nothing about N ie 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 then n is not a single limb so cant be true anyway
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);
// so 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); // so 2^t divides nm1
ASSERT (t > 0);
mpz_tdiv_q_2exp (e, nm1, t); // so 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;
}