1use core::num::NonZero;
2
3use rand::CryptoRng;
4
5use crypto_bigint::{Unsigned, UnsignedWithMontyForm, RandomMod};
6
7fn next_prime_candidates<U: Unsigned>(seed: U) -> impl Iterator<Item = U> {
13 let max_bit_length = NonZero::new(seed.bits_precision()).unwrap();
14 match crypto_primes::hazmat::SmallFactorsSieve::new(seed, max_bit_length, false) {
15 Ok(iter) => iter,
16 Err(crypto_primes::Error::BitLengthTooLarge { .. }) => {
18 unreachable!("`max_bit_length = bits_precision`")
19 }
20 Err(crypto_primes::Error::BitLengthTooSmall { .. }) => unreachable!(),
22 }
23}
24
25#[derive(Debug)]
26pub(super) enum Error {
27 NoMillerRabin,
28 Capacity,
29}
30
31pub(super) fn next_prime<U: UnsignedWithMontyForm + RandomMod>(
38 mut rng: impl CryptoRng,
39 seed: U,
40 bits_of_security: u32,
41) -> Result<U, Error> {
42 let candidates = next_prime_candidates(seed);
43 for candidate in candidates {
44 let options =
45 crypto_primes::fips::FipsOptions::with_error_bound(candidate.bits(), bits_of_security)
46 .ok_or(Error::NoMillerRabin)?
47 .with_lucas_test();
48 if crypto_primes::fips::is_prime(&mut rng, crypto_primes::Flavor::Any, &candidate, options) {
49 return Ok(candidate);
50 }
51 }
52 Err(Error::Capacity)
53}