mod constfn;
mod montgomery;
mod sieve;
pub use constfn::is_prime;
use montgomery::Montgomery;
pub use sieve::LinearSieve;
const SMALL_PRIMES_MEMO: LinearSieve<255> = LinearSieve::new();
pub trait IsPrime {
fn is_prime(&self) -> bool;
}
macro_rules! impl_is_prime {
( $t:ty, $witness_ty:ty, [ $( $witness:expr ),* ] ) => {
impl IsPrime for $t {
fn is_prime(&self) -> bool {
let p = *self as $witness_ty;
if p == 1 || p & 1 == 0 {
return p == 2;
}
if <$witness_ty>::BITS == 64 && (p as u64) < 1795265022 {
return (p as u32).is_prime();
}
if p < SMALL_PRIMES_MEMO.len() as $witness_ty {
return SMALL_PRIMES_MEMO.is_prime(p as usize);
}
let mont = Montgomery::<$witness_ty>::new(p);
let s = (p - 1).trailing_zeros();
let t = (p - 1) >> s;
[$( $witness ),*]
.iter()
.all(|&a| {
let a = mont.convert(a);
let at = mont.pow(a, t);
if at == mont.r || at == p - mont.r {
return true;
}
(1..s)
.scan(at, |at, _| {
*at = mont.multiply(*at, *at);
Some(*at)
})
.any(|at| at == p - mont.r)
})
}
}
};
}
impl_is_prime!(u8, u8, [2, 7, 61]);
impl_is_prime!(u16, u16, [2, 7, 61]);
impl_is_prime!(u32, u32, [2, 7, 61]);
impl_is_prime!(u64, u64, [2, 325, 9375, 28178, 450775, 9780504, 1795265022]);
#[cfg(target_pointer_width = "64")]
impl_is_prime!(
usize,
u64,
[2, 325, 9375, 28178, 450775, 9780504, 1795265022]
);
#[cfg(target_pointer_width = "32")]
impl_is_prime!(usize, u32, [2, 7, 61]);
#[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 {
if p <= u8::MAX as u64 {
assert!((p as u8).is_prime());
}
if p <= u16::MAX as u64 {
assert!((p as u16).is_prime());
}
if p <= u32::MAX as u64 {
assert!((p as u32).is_prime());
}
assert!(p.is_prime());
}
}
#[test]
fn non_primality_test() {
for &p in NO_PRIME {
if p <= u8::MAX as u64 {
assert!(!(p as u8).is_prime());
}
if p <= u16::MAX as u64 {
assert!(!(p as u16).is_prime());
}
if p <= u32::MAX as u64 {
assert!(!(p as u32).is_prime());
}
assert!(!p.is_prime());
}
for &p in CARMICHAEL {
if p <= u8::MAX as u64 {
assert!(!(p as u8).is_prime());
}
if p <= u16::MAX as u64 {
assert!(!(p as u16).is_prime());
}
if p <= u32::MAX as u64 {
assert!(!(p as u32).is_prime());
}
assert!(!p.is_prime());
}
}
}