use core::num::NonZero;
use rand::CryptoRng;
use crypto_bigint::{Unsigned, UnsignedWithMontyForm, RandomMod};
fn next_prime_candidates<U: Unsigned>(seed: U) -> impl Iterator<Item = U> {
let max_bit_length = NonZero::new(seed.bits_precision()).unwrap();
match crypto_primes::hazmat::SmallFactorsSieve::new(seed, max_bit_length, false) {
Ok(iter) => iter,
Err(crypto_primes::Error::BitLengthTooLarge { .. }) => {
unreachable!("`max_bit_length = bits_precision`")
}
Err(crypto_primes::Error::BitLengthTooSmall { .. }) => unreachable!(),
}
}
#[derive(Debug)]
pub(super) enum Error {
NoMillerRabin,
Capacity,
}
pub(super) fn next_prime<U: UnsignedWithMontyForm + RandomMod>(
mut rng: impl CryptoRng,
seed: U,
bits_of_security: u32,
) -> Result<U, Error> {
let candidates = next_prime_candidates(seed);
for candidate in candidates {
let options =
crypto_primes::fips::FipsOptions::with_error_bound(candidate.bits(), bits_of_security)
.ok_or(Error::NoMillerRabin)?
.with_lucas_test();
if crypto_primes::fips::is_prime(&mut rng, crypto_primes::Flavor::Any, &candidate, options) {
return Ok(candidate);
}
}
Err(Error::Capacity)
}