use crate::montgomery::Montgomery;
pub const fn is_prime(p: u64) -> bool {
if p == 1 || p & 1 == 0 {
return p == 2;
}
let mont = Montgomery::<u64>::new(p);
let s = (p - 1).trailing_zeros();
let t = (p - 1) >> s;
let mut i = 0;
const WIT: [u64; 7] = [2, 325, 9375, 28178, 450775, 9780504, 1795265022];
while i < WIT.len() {
let a = WIT[i] % p;
if a != 0 {
let a = mont.convert(a);
let mut at = mont.pow(a, t);
let mut found = at == mont.r || at == p - mont.r;
let mut j = 1;
while j < s && !found {
at = mont.multiply(at, at);
found |= at == p - mont.r;
j += 1;
}
if !found {
return false;
}
}
i += 1;
}
true
}
#[cfg(test)]
mod tests {
use super::*;
#[rustfmt::skip]
const PRIME: &[u64] = &[
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 47, 53, 59, 61, 67, 73, 79, 83, 89, 97,
998244353, 1000000007, 67280421310721, 999999999999999989
];
const NO_PRIME: &[u64] = &[
1,
57,
5329,
49141,
4759123141,
1122004669633,
21652684502221,
31858317218647,
47636622961201,
55245642489451,
3071837692357849,
3770579582154547,
7999252175582851,
585226005592931977,
];
#[rustfmt::skip]
const CARMICHAEL: &[u64] = &[
561, 1105, 1729, 2465, 2821, 6601, 8911, 10585, 15841, 29341, 41041, 46657, 52633, 62745,
63973, 75361, 101101, 115921, 126217, 162401, 172081, 188461, 252601, 278545, 294409,
314821, 334153, 340561, 399001, 410041, 449065, 488881, 512461,
];
#[test]
fn primality_test() {
for &p in PRIME {
assert!(is_prime(p))
}
}
#[test]
fn non_primality_test() {
for &p in NO_PRIME {
assert!(!is_prime(p));
}
for &p in CARMICHAEL {
assert!(!is_prime(p));
}
}
}