#![cfg(feature = "primality")]
use puremp::Int;
use puremp::primality::{Bound, Primality, prove_prime};
fn n(s: &str) -> Int {
s.parse().expect("valid integer literal")
}
fn mersenne(k: u32) -> Int {
Int::from(2).pow(k).sub(&Int::ONE)
}
#[track_caller]
fn assert_proved_prime(x: &Int) -> Primality {
let outcome = prove_prime(x);
match &outcome {
Primality::Prime(cert) => {
assert!(cert.verify(x), "certificate failed to verify for {x}");
assert_eq!(cert.n(), x, "certificate is about the wrong number");
}
other => panic!("expected Prime for {x}, got {other:?}"),
}
outcome
}
#[test]
fn small_primes_are_proved() {
for p in [2u64, 3, 5, 7, 11, 13, 97, 101, 7919, 104729] {
assert_proved_prime(&Int::from(p));
}
}
#[test]
fn small_composites_are_rejected() {
for c in [
0u64, 1, 4, 6, 8, 9, 15, 100, 561, 1105, 1729, 41041, 63973, 104728,
] {
assert!(
matches!(prove_prime(&Int::from(c)), Primality::Composite),
"{c} should be Composite"
);
}
}
#[test]
fn negatives_are_not_prime() {
assert!(matches!(prove_prime(&Int::from(-7)), Primality::Composite));
assert!(matches!(prove_prime(&Int::from(-1)), Primality::Composite));
}
#[test]
fn mersenne_prime_2p89_pocklington() {
let m = mersenne(89);
assert!(m.is_prime_bpsw());
let outcome = assert_proved_prime(&m);
if let Primality::Prime(cert) = outcome {
assert_eq!(cert.bound(), Some(Bound::Sqrt));
}
}
#[test]
fn mersenne_prime_2p127_bls() {
let m = mersenne(127);
assert!(m.is_prime_bpsw());
let outcome = assert_proved_prime(&m);
if let Primality::Prime(cert) = outcome {
assert_eq!(cert.bound(), Some(Bound::Cbrt));
}
}
#[test]
fn large_proth_primes_are_proved() {
let p80 = Int::from(102).mul(&Int::from(2).pow(256)).add(&Int::ONE);
assert_eq!(p80.to_string().len(), 80);
assert!(p80.is_prime_bpsw());
assert_proved_prime(&p80);
let p93 = Int::from(267).mul(&Int::from(2).pow(300)).add(&Int::ONE);
assert_eq!(p93.to_string().len(), 93);
assert!(p93.is_prime_bpsw());
assert_proved_prime(&p93);
}
#[test]
fn hundred_digit_prime_is_proved() {
let p = Int::from(135).mul(&Int::from(2).pow(330)).add(&Int::ONE);
assert_eq!(p.to_string().len(), 102);
assert!(p.is_prime_bpsw());
assert_proved_prime(&p);
}
#[test]
fn product_of_two_large_primes_is_composite() {
let semiprime = mersenne(61).mul(&mersenne(89));
assert!(matches!(prove_prime(&semiprime), Primality::Composite));
let p = Int::from(10).pow(40).next_prime();
let q = Int::from(7).mul(&Int::from(10).pow(39)).next_prime();
assert!(p != q && p.is_prime_bpsw() && q.is_prime_bpsw());
assert!(matches!(prove_prime(&p.mul(&q)), Primality::Composite));
}
#[test]
fn certificate_bound_to_wrong_number_fails() {
let m = mersenne(89);
let cert = match prove_prime(&m) {
Primality::Prime(c) => c,
other => panic!("expected Prime, got {other:?}"),
};
assert!(cert.verify(&m));
assert!(!cert.verify(&mersenne(127)));
assert!(!cert.verify(&m.add(&Int::from(2))));
}
#[test]
fn unprovable_when_n_minus_1_is_hard() {
let p = Int::from(10).pow(40).next_prime();
let q = Int::from(3).mul(&Int::from(10).pow(40)).next_prime();
let n = Int::from(112).mul(&p).mul(&q).add(&Int::ONE);
assert!(
n.is_prime_bpsw(),
"constructed n must be a (probable) prime"
);
assert!(
matches!(prove_prime(&n), Primality::Unproven),
"n − 1 cannot be factored past n^{{1/3}}, so the proof is Unproven"
);
}
#[test]
fn agrees_with_bpsw_over_a_range() {
for k in 0u64..1500 {
let x = Int::from(k);
let bpsw = x.is_prime_bpsw();
match prove_prime(&x) {
Primality::Prime(cert) => {
assert!(bpsw, "{k}: proved prime but bpsw says composite");
assert!(cert.verify(&x));
}
Primality::Composite => assert!(!bpsw, "{k}: said composite but bpsw says prime"),
Primality::Unproven => panic!("{k}: small values should never be Unproven"),
}
}
}
#[test]
fn agrees_with_bpsw_on_larger_samples() {
let samples = [
n("18446744073709551557"), n("18446744073709551615"), n("18446744073709551629"), n("340282366920938463463374607431768211297"), n("340282366920938463463374607431768211455"), ];
for x in samples {
let bpsw = x.is_prime_bpsw();
match prove_prime(&x) {
Primality::Prime(cert) => {
assert!(bpsw, "{x}: proved prime but bpsw disagrees");
assert!(cert.verify(&x));
}
Primality::Composite => assert!(!bpsw, "{x}: composite but bpsw says prime"),
Primality::Unproven => assert!(bpsw, "{x}: only probable primes may be Unproven"),
}
}
}