1use crate::traits::PrimalityTest;
2use num_bigint::{BigUint, RandBigInt};
3use num_traits::{One, Zero};
45/// The Miller-Rabin primality test.
6///
7/// This is a probabilistic test, but can be configured to have a cryptographically small error
8/// margin.
9pub struct MillerRabin {
10pub error_bits: usize,
11}
1213impl PrimalityTest for MillerRabin {
14fn is_prime(&self, n: &BigUint) -> bool {
15if n.is_zero() || n.is_one() {
16return false;
17 }
1819let one = BigUint::one();
20let two = BigUint::from(2u8);
21let mut rng = rand::thread_rng();
2223// Decompose n - 1 into 2^s d by splitting off factors of two.
24let n_minus_1 = n - &one;
25let s = n_minus_1.trailing_zeros().unwrap();
26let d = &n_minus_1 >> s;
2728let num_bases = (self.error_bits + 1) / 2;
29'base_search: for _ in 0..num_bases {
30let base = rng.gen_biguint_range(&one, &n);
3132// Let x = 2^d mod n.
33let x = base.modpow(&d, &n);
34if x.is_one() {
35continue; // pass
36}
3738// Use iterative squaring to check if x^(2^r) == n - 1 for some r < s.
39let mut square = x;
40if square == n_minus_1 {
41continue; // pass with r = 0
42}
43for _r in 1..s {
44 square = square.modpow(&two, &n);
45if square == n_minus_1 {
46continue 'base_search; // pass
47}
48 }
49return false; // failed; composite detected
50}
51true
52}
53}