use num_bigint::{BigUint, RandBigInt};
use num_traits::{FromPrimitive, One, Zero};
use rayon::prelude::*;
use std::sync::Arc;
fn decompose(n: &BigUint) -> (BigUint, u128) {
let mut d = n - BigUint::one();
let mut s = 0;
while &d & BigUint::one() == BigUint::zero() {
d >>= 1;
s += 1;
}
(d, s)
}
fn is_witness(a: BigUint, d: &BigUint, s: u128, n: &BigUint) -> bool {
let mut x = a.modpow(d, n);
let two: BigUint = BigUint::from_u8(2).unwrap();
if x == BigUint::one() || x == n - BigUint::one() {
return false;
}
for _ in 0..s - 1 {
x = x.modpow(&two, n);
if x == n - BigUint::one() {
return false;
}
}
true
}
pub fn is_likely_big_prime(candidate: &BigUint, num_checks: u32) -> bool {
let (d, s) = decompose(candidate);
let candidate_arc = Arc::new(candidate.clone());
let d_arc = Arc::new(d);
let two: BigUint = BigUint::from_u8(2).unwrap();
!(0..num_checks).into_par_iter().any(|_| {
let mut rng = rand::thread_rng();
let candidate = Arc::clone(&candidate_arc);
let d = Arc::clone(&d_arc);
let a = rng.gen_biguint_range(&two, &(candidate.as_ref() - &two));
is_witness(a, d.as_ref(), s, candidate.as_ref())
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_decompose() {
assert_eq!(decompose(&BigUint::from(13u8)), (BigUint::from(3u8), 2)); assert_eq!(decompose(&BigUint::from(9u8)), (BigUint::from(1u8), 3)); assert_eq!(decompose(&BigUint::from(17u8)), (BigUint::from(1u8), 4)); assert_eq!(decompose(&BigUint::from(7u8)), (BigUint::from(3u8), 1)); }
#[test]
fn test_probabilistic_primes() {
assert!(is_likely_big_prime(&BigUint::from(7919u32), 10)); assert!(!is_likely_big_prime(&BigUint::from(7921u32), 10));
assert!(is_likely_big_prime(
&BigUint::from(0xFFFFFFFFFFFFFFC5u128),
10
));
}
#[test]
fn test_large_numbers() {
let mersenne61 = BigUint::from((1u128 << 61) - 1);
assert!(is_likely_big_prime(&mersenne61, 5));
let large_composite = &mersenne61 * &mersenne61;
assert!(!is_likely_big_prime(&large_composite, 5));
}
}