use byteorder::{BigEndian, ByteOrder};
use integer::Integer;
use num_traits::{FromPrimitive, One, ToPrimitive, Zero};
use rand::rngs::StdRng;
use rand::SeedableRng;
use crate::algorithms::jacobi;
use crate::big_digit;
use crate::bigrand::RandBigInt;
use crate::Sign::Plus;
use crate::{BigInt, BigUint, IntoBigUint};
lazy_static! {
pub(crate) static ref BIG_1: BigUint = BigUint::one();
pub(crate) static ref BIG_2: BigUint = BigUint::from_u64(2).unwrap();
pub(crate) static ref BIG_3: BigUint = BigUint::from_u64(3).unwrap();
pub(crate) static ref BIG_64: BigUint = BigUint::from_u64(64).unwrap();
}
const PRIMES_A: u64 = 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 37;
const PRIMES_B: u64 = 29 * 31 * 41 * 43 * 47 * 53;
const PRIME_BIT_MASK: u64 = 1 << 2
| 1 << 3
| 1 << 5
| 1 << 7
| 1 << 11
| 1 << 13
| 1 << 17
| 1 << 19
| 1 << 23
| 1 << 29
| 1 << 31
| 1 << 37
| 1 << 41
| 1 << 43
| 1 << 47
| 1 << 53
| 1 << 59
| 1 << 61;
pub fn probably_prime(x: &BigUint, n: usize) -> bool {
if x.is_zero() {
return false;
}
if x < &*BIG_64 {
return (PRIME_BIT_MASK & (1 << x.to_u64().unwrap())) != 0;
}
if x.is_even() {
return false;
}
let r_a = &(x % PRIMES_A);
let r_b = &(x % PRIMES_B);
if (r_a % 3u32).is_zero()
|| (r_a % 5u32).is_zero()
|| (r_a % 7u32).is_zero()
|| (r_a % 11u32).is_zero()
|| (r_a % 13u32).is_zero()
|| (r_a % 17u32).is_zero()
|| (r_a % 19u32).is_zero()
|| (r_a % 23u32).is_zero()
|| (r_a % 37u32).is_zero()
|| (r_b % 29u32).is_zero()
|| (r_b % 31u32).is_zero()
|| (r_b % 41u32).is_zero()
|| (r_b % 43u32).is_zero()
|| (r_b % 47u32).is_zero()
|| (r_b % 53u32).is_zero()
{
return false;
}
probably_prime_miller_rabin(x, n + 1, true) && probably_prime_lucas(x)
}
const NUMBER_OF_PRIMES: usize = 127;
const PRIME_GAP: [u64; 167] = [
2, 2, 4, 2, 4, 2, 4, 6, 2, 6, 4, 2, 4, 6, 6, 2, 6, 4, 2, 6, 4, 6, 8, 4, 2, 4, 2, 4, 14, 4, 6,
2, 10, 2, 6, 6, 4, 6, 6, 2, 10, 2, 4, 2, 12, 12, 4, 2, 4, 6, 2, 10, 6, 6, 6, 2, 6, 4, 2, 10,
14, 4, 2, 4, 14, 6, 10, 2, 4, 6, 8, 6, 6, 4, 6, 8, 4, 8, 10, 2, 10, 2, 6, 4, 6, 8, 4, 2, 4, 12,
8, 4, 8, 4, 6, 12, 2, 18, 6, 10, 6, 6, 2, 6, 10, 6, 6, 2, 6, 6, 4, 2, 12, 10, 2, 4, 6, 6, 2,
12, 4, 6, 8, 10, 8, 10, 8, 6, 6, 4, 8, 6, 4, 8, 4, 14, 10, 12, 2, 10, 2, 4, 2, 10, 14, 4, 2, 4,
14, 4, 2, 4, 20, 4, 8, 10, 8, 4, 6, 6, 14, 4, 6, 6, 8, 6, 12,
];
const INCR_LIMIT: usize = 0x10000;
pub fn next_prime(n: &BigUint) -> BigUint {
if n < &*BIG_2 {
return 2u32.into_biguint().unwrap();
}
let mut res = n + &*BIG_1;
res |= &*BIG_1;
if let Some(val) = res.to_u64() {
if val < 7 {
return res;
}
}
let nbits = res.bits();
let prime_limit = if nbits / 2 >= NUMBER_OF_PRIMES {
NUMBER_OF_PRIMES - 1
} else {
nbits / 2
};
let mut moduli = vec![BigUint::zero(); prime_limit];
'outer: loop {
let mut prime = 3;
for i in 0..prime_limit {
moduli[i] = &res / prime;
prime += PRIME_GAP[i];
}
let mut difference: usize = 0;
for incr in (0..INCR_LIMIT as u64).step_by(2) {
let mut prime: u64 = 3;
let mut cancel = false;
for i in 0..prime_limit {
let r = (&moduli[i] + incr) % prime;
prime += PRIME_GAP[i];
if r.is_zero() {
cancel = true;
break;
}
}
if !cancel {
res += difference;
difference = 0;
if probably_prime(&res, 20) {
break 'outer;
}
}
difference += 2;
}
res += difference;
}
res
}
pub fn probably_prime_miller_rabin(n: &BigUint, reps: usize, force2: bool) -> bool {
let nm1 = n - &*BIG_1;
let k = nm1.trailing_zeros().unwrap() as usize;
let q = &nm1 >> k;
let nm3 = n - &*BIG_3;
let mut seed_vec = vec![0u8; 8];
BigEndian::write_uint(
seed_vec.as_mut_slice(),
n.get_limb(0) as u64,
big_digit::BITS / 8,
);
let mut seed = [0u8; 32];
seed[0..8].copy_from_slice(&seed_vec[..]);
let mut rng = StdRng::from_seed(seed);
'nextrandom: for i in 0..reps {
let x = if i == reps - 1 && force2 {
BIG_2.clone()
} else {
rng.gen_biguint_below(&nm3) + &*BIG_2
};
let mut y = x.modpow(&q, n);
if y.is_one() || y == nm1 {
continue;
}
for _ in 1..k {
y = y.modpow(&*BIG_2, n);
if y == nm1 {
break 'nextrandom;
}
if y.is_one() {
return false;
}
}
return false;
}
true
}
pub fn probably_prime_lucas(n: &BigUint) -> bool {
if n.is_zero() || n.is_one() {
return false;
}
if n.to_u64() == Some(2) {
return false;
}
let mut p = 3u64;
let n_int = BigInt::from_biguint(Plus, n.clone());
loop {
if p > 10000 {
panic!("internal error: cannot find (D/n) = -1 for {:?}", n)
}
let j = jacobi(&BigInt::from_u64(p * p - 4).unwrap(), &n_int);
if j == -1 {
break;
}
if j == 0 {
return n_int.to_i64() == Some(p as i64 + 2);
}
let t1 = &n_int * &n_int;
if p == 40 && t1.sqrt() == n_int {
return false;
}
p += 1;
}
let mut s = n + &*BIG_1;
let r = s.trailing_zeros().unwrap() as usize;
s = &s >> r;
let nm2 = n - &*BIG_2;
let mut vk = BIG_2.clone();
let mut vk1 = BigUint::from_u64(p).unwrap();
for i in (0..s.bits()).rev() {
if is_bit_set(&s, i) {
let t1 = (&vk * &vk1) + n - p;
vk = &t1 % n;
let t1 = (&vk1 * &vk1) + &nm2;
vk1 = &t1 % n;
} else {
let t1 = (&vk * &vk1) + n - p;
vk1 = &t1 % n;
let t1 = (&vk * &vk) + &nm2;
vk = &t1 % n;
}
}
if vk.to_u64() == Some(2) || vk == nm2 {
let mut t1 = &vk * p;
let mut t2 = &vk1 << 1;
if t1 < t2 {
::std::mem::swap(&mut t1, &mut t2);
}
t1 -= t2;
if (t1 % n).is_zero() {
return true;
}
}
for _ in 0..r - 1 {
if vk.is_zero() {
return true;
}
if vk.to_u64() == Some(2) {
return false;
}
let t1 = (&vk * &vk) - &*BIG_2;
vk = &t1 % n;
}
false
}
#[inline]
fn is_bit_set(x: &BigUint, i: usize) -> bool {
get_bit(x, i) == 1
}
#[inline]
fn get_bit(x: &BigUint, i: usize) -> u8 {
let j = i / big_digit::BITS;
if i >= x.bits() {
return 0;
}
(x.get_limb(j) >> (i % big_digit::BITS) & 1) as u8
}
#[cfg(test)]
mod tests {
use super::*;
use crate::biguint::ToBigUint;
lazy_static! {
static ref PRIMES: Vec<&'static str> = vec![
"2",
"3",
"5",
"7",
"11",
"13756265695458089029",
"13496181268022124907",
"10953742525620032441",
"17908251027575790097",
"18699199384836356663",
"98920366548084643601728869055592650835572950932266967461790948584315647051443",
"94560208308847015747498523884063394671606671904944666360068158221458669711639",
"449417999055441493994709297093108513015373787049558499205492347871729927573118262811508386655998299074566974373711472560655026288668094291699357843464363003144674940345912431129144354948751003607115263071543163",
"230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593",
"5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993",
"203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
"3618502788666131106986593281521497120414687020801267626233049500247285301239",
"57896044618658097711785492504343953926634992332820282019728792003956564819949",
"9850501549098619803069760025035903451269934817616361666987073351061430442874302652853566563721228910201656997576599",
"42307582002575910332922579714097346549017899709713998034217522897561970639123926132812109468141778230245837569601494931472367",
"6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151",
];
static ref COMPOSITES: Vec<&'static str> = vec![
"0",
"1",
"21284175091214687912771199898307297748211672914763848041968395774954376176754",
"6084766654921918907427900243509372380954290099172559290432744450051395395951",
"84594350493221918389213352992032324280367711247940675652888030554255915464401",
"82793403787388584738507275144194252681",
"1195068768795265792518361315725116351898245581",
"8038374574536394912570796143419421081388376882875581458374889175222974273765333652186502336163960045457915042023603208766569966760987284043965408232928738791850869166857328267761771029389697739470167082304286871099974399765441448453411558724506334092790222752962294149842306881685404326457534018329786111298960644845216191652872597534901",
"989",
"3239",
"5777",
"10877",
"27971",
"29681",
"30739",
"31631",
"39059",
"72389",
"73919",
"75077",
"100127",
"113573",
"125249",
"137549",
"137801",
"153931",
"155819",
"161027",
"162133",
"189419",
"218321",
"231703",
"249331",
"370229",
"429479",
"430127",
"459191",
"473891",
"480689",
"600059",
"621781",
"632249",
"635627",
"3673744903",
"3281593591",
"2385076987",
"2738053141",
"2009621503",
"1502682721",
"255866131",
"117987841",
"587861",
"6368689",
"8725753",
"80579735209",
"105919633",
];
}
#[test]
fn test_primes() {
for prime in PRIMES.iter() {
let p = BigUint::parse_bytes(prime.as_bytes(), 10).unwrap();
for i in [0, 1, 20].iter() {
assert!(
probably_prime(&p, *i as usize),
"{} is a prime ({})",
prime,
i,
);
}
}
}
#[test]
fn test_composites() {
for comp in COMPOSITES.iter() {
let p = BigUint::parse_bytes(comp.as_bytes(), 10).unwrap();
for i in [0, 1, 20].iter() {
assert!(
!probably_prime(&p, *i as usize),
"{} is a composite ({})",
comp,
i,
);
}
}
}
macro_rules! test_pseudo_primes {
($name:ident, $cond:expr, $want:expr) => {
#[test]
fn $name() {
let mut i = 3;
let mut want = $want;
while i < 100000 {
let n = BigUint::from_u64(i).unwrap();
let pseudo = $cond(&n);
if pseudo && (want.is_empty() || i != want[0]) {
panic!("cond({}) = true, want false", i);
} else if !pseudo && !want.is_empty() && i == want[0] {
panic!("cond({}) = false, want true", i);
}
if !want.is_empty() && i == want[0] {
want = want[1..].to_vec();
}
i += 2;
}
if !want.is_empty() {
panic!("forgot to test: {:?}", want);
}
}
};
}
test_pseudo_primes!(
test_probably_prime_miller_rabin,
|n| probably_prime_miller_rabin(n, 1, true) && !probably_prime_lucas(n),
vec![
2047, 3277, 4033, 4681, 8321, 15841, 29341, 42799, 49141, 52633, 65281, 74665, 80581,
85489, 88357, 90751,
]
);
test_pseudo_primes!(
test_probably_prime_lucas,
|n| probably_prime_lucas(n) && !probably_prime_miller_rabin(n, 1, true),
vec![989, 3239, 5777, 10877, 27971, 29681, 30739, 31631, 39059, 72389, 73919, 75077,]
);
#[test]
fn test_bit_set() {
let v = &vec![0b10101001];
let num = BigUint::from_slice(&v);
assert!(is_bit_set(&num, 0));
assert!(!is_bit_set(&num, 1));
assert!(!is_bit_set(&num, 2));
assert!(is_bit_set(&num, 3));
assert!(!is_bit_set(&num, 4));
assert!(is_bit_set(&num, 5));
assert!(!is_bit_set(&num, 6));
assert!(is_bit_set(&num, 7));
}
#[test]
fn test_next_prime() {
let primes1 = (0..2048u32)
.map(|i| next_prime(&i.to_biguint().unwrap()))
.collect::<Vec<_>>();
let primes2 = (0..2048u32)
.map(|i| {
let i = i.to_biguint().unwrap();
let p = next_prime(&i);
assert!(&p > &i);
p
})
.collect::<Vec<_>>();
for (p1, p2) in primes1.iter().zip(&primes2) {
assert_eq!(p1, p2);
assert!(probably_prime(p1, 25));
}
}
}