diff --git a/.github/workflows/crypto-primes.yml b/.github/workflows/crypto-primes.yml index 00c5cbf..8d1a667 100644 --- a/.github/workflows/crypto-primes.yml +++ b/.github/workflows/crypto-primes.yml @@ -17,7 +17,7 @@ jobs: strategy: matrix: rust: - - 1.65.0 # MSRV + - 1.73.0 # MSRV - stable target: - wasm32-unknown-unknown @@ -134,6 +134,6 @@ jobs: - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: - toolchain: 1.65.0 + toolchain: 1.73.0 profile: minimal - run: cargo build --all-features --benches diff --git a/Cargo.toml b/Cargo.toml index 96fcd7b..f09b783 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,10 +7,10 @@ description = "Random prime number generation and primality checking library" repository = "https://github.com/entropyxyz/crypto-primes" readme = "README.md" categories = ["cryptography", "no-std"] -rust-version = "1.65" +rust-version = "1.73" [dependencies] -crypto-bigint = { version = "0.5.4", default-features = false, features = ["rand_core"] } +crypto-bigint = { version = "0.6.0-pre.5", default-features = false, features = ["rand_core"] } rand_core = { version = "0.6.4", default-features = false } openssl = { version = "0.10.39", optional = true, features = ["vendored"] } rug = { version = "1.18", default-features = false, features = ["integer"], optional = true } diff --git a/benches/bench.rs b/benches/bench.rs index 7c469ed..8992b5e 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,5 +1,5 @@ use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; -use crypto_bigint::{nlimbs, Uint, U1024}; +use crypto_bigint::{nlimbs, Odd, Uint, U1024}; use rand_chacha::ChaCha8Rng; use rand_core::{CryptoRngCore, OsRng, SeedableRng}; @@ -23,13 +23,13 @@ fn make_rng() -> ChaCha8Rng { } fn make_sieve(rng: &mut impl CryptoRngCore) -> Sieve { - let start: Uint = random_odd_uint(rng, Uint::::BITS); + let start = random_odd_uint::(rng, Uint::::BITS); Sieve::new(&start, Uint::::BITS, false) } -fn make_presieved_num(rng: &mut impl CryptoRngCore) -> Uint { +fn make_presieved_num(rng: &mut impl CryptoRngCore) -> Odd> { let mut sieve = make_sieve(rng); - sieve.next().unwrap() + Odd::new(sieve.next().unwrap()).unwrap() } fn bench_sieve(c: &mut Criterion) { @@ -85,14 +85,14 @@ fn bench_miller_rabin(c: &mut Criterion) { group.bench_function("(U128) creation", |b| { b.iter_batched( || random_odd_uint::<{ nlimbs!(128) }>(&mut OsRng, 128), - |start| MillerRabin::new(&start), + MillerRabin::new, BatchSize::SmallInput, ) }); group.bench_function("(U128) random base test (pre-sieved)", |b| { b.iter_batched( - || MillerRabin::new(&make_presieved_num::<{ nlimbs!(128) }>(&mut OsRng)), + || MillerRabin::new(make_presieved_num::<{ nlimbs!(128) }>(&mut OsRng)), |mr| mr.test_random_base(&mut OsRng), BatchSize::SmallInput, ) @@ -101,14 +101,14 @@ fn bench_miller_rabin(c: &mut Criterion) { group.bench_function("(U1024) creation", |b| { b.iter_batched( || random_odd_uint::<{ nlimbs!(1024) }>(&mut OsRng, 1024), - |start| MillerRabin::new(&start), + MillerRabin::new, BatchSize::SmallInput, ) }); group.bench_function("(U1024) random base test (pre-sieved)", |b| { b.iter_batched( - || MillerRabin::new(&make_presieved_num::<{ nlimbs!(1024) }>(&mut OsRng)), + || MillerRabin::new(make_presieved_num::<{ nlimbs!(1024) }>(&mut OsRng)), |mr| mr.test_random_base(&mut OsRng), BatchSize::SmallInput, ) @@ -257,7 +257,7 @@ fn bench_gmp(c: &mut Criterion) { let mut group = c.benchmark_group("GMP"); fn random(rng: &mut impl CryptoRngCore) -> Integer { - let num: Uint = random_odd_uint(rng, Uint::::BITS); + let num = random_odd_uint::(rng, Uint::::BITS); Integer::from_digits(num.as_words(), Order::Lsf) } diff --git a/src/hazmat/gcd.rs b/src/hazmat/gcd.rs index 0b3d6bf..cb74393 100644 --- a/src/hazmat/gcd.rs +++ b/src/hazmat/gcd.rs @@ -16,7 +16,7 @@ pub(crate) fn gcd(n: &Uint, m: u32) -> u32 { } // Normalize input: the resulting (a, b) are both small, a >= b, and b != 0. - let (mut a, mut b): (u32, u32) = if n.bits() > (u32::BITS as usize) { + let (mut a, mut b): (u32, u32) = if n.bits() > u32::BITS { // `m` is non-zero, so we can unwrap. let (_quo, n) = n.div_rem_limb(NonZero::new(Limb::from(m)).unwrap()); // `n` is a remainder of a division by `u32`, so it can be safely cast to `u32`. @@ -47,7 +47,7 @@ pub(crate) fn gcd(n: &Uint, m: u32) -> u32 { #[cfg(test)] mod tests { - use crypto_bigint::{Encoding, U128}; + use crypto_bigint::U128; use num_bigint::BigUint; use num_integer::Integer; use proptest::prelude::*; diff --git a/src/hazmat/jacobi.rs b/src/hazmat/jacobi.rs index 8f2bc04..b8bc3c3 100644 --- a/src/hazmat/jacobi.rs +++ b/src/hazmat/jacobi.rs @@ -151,7 +151,7 @@ mod tests { use alloc::format; - use crypto_bigint::{Encoding, U128}; + use crypto_bigint::U128; use num_bigint::{BigInt, Sign}; use num_modular::ModularSymbols; use proptest::prelude::*; diff --git a/src/hazmat/lucas.rs b/src/hazmat/lucas.rs index 69f0039..2fc4979 100644 --- a/src/hazmat/lucas.rs +++ b/src/hazmat/lucas.rs @@ -1,7 +1,7 @@ //! Lucas primality test. use crypto_bigint::{ - modular::runtime_mod::{DynResidue, DynResidueParams}, - CheckedAdd, Integer, Limb, Uint, Word, + modular::{MontyForm, MontyParams}, + CheckedAdd, Integer, Limb, Odd, Uint, Word, }; use super::{ @@ -172,17 +172,24 @@ impl LucasBase for BruteForceBase { } /// For the given odd `n`, finds `s` and odd `d` such that `n + 1 == 2^s * d`. -fn decompose(n: &Uint) -> (usize, Uint) { +fn decompose(n: &Odd>) -> (u32, Odd>) { debug_assert!(bool::from(n.is_odd())); // Need to be careful here since `n + 1` can overflow. // Instead of adding 1 and counting trailing 0s, we count trailing ones on the original `n`. let s = n.trailing_ones(); - // This won't overflow since the original `n` was odd, so we right-shifted at least once. - let d = Option::from((n >> s).checked_add(&Uint::::ONE)).expect("Integer overflow"); + let d = if s < n.bits_precision() { + // This won't overflow since the original `n` was odd, so we right-shifted at least once. + n.as_ref() + .wrapping_shr(s) + .checked_add(&Uint::ONE) + .expect("Integer overflow") + } else { + Uint::ONE + }; - (s, d) + (s, Odd::new(d).expect("ensured to be odd")) } /// The checks to perform in the Lucas test. @@ -279,10 +286,15 @@ pub fn lucas_test( // R. Crandall, C. Pomerance, "Prime numbers: a computational perspective", // 2nd ed., Springer (2005) (ISBN: 0-387-25282-7, 978-0387-25282-7) - if candidate.is_even().into() { - return Primality::Composite; + if candidate == &Uint::::from(2u32) { + return Primality::Prime; } + let odd_candidate = match Odd::new(*candidate).into() { + Some(x) => x, + None => return Primality::Composite, + }; + // Find the base for the Lucas sequence. let (p, q) = match base.generate(candidate) { Ok((p, q)) => (p, q), @@ -311,14 +323,14 @@ pub fn lucas_test( // Find `d` and `s`, such that `d` is odd and `d * 2^s = n - (D/n)`. // Since `(D/n) == -1` by construction, we're looking for `d * 2^s = n + 1`. - let (s, d) = decompose(candidate); + let (s, d) = decompose(&odd_candidate); // Some constants in Montgomery form - let params = DynResidueParams::::new(candidate); + let params = MontyParams::::new(odd_candidate); - let zero = DynResidue::::zero(params); - let one = DynResidue::::one(params); + let zero = MontyForm::::zero(params); + let one = MontyForm::::one(params); let two = one + one; let minus_two = -two; @@ -327,7 +339,7 @@ pub fn lucas_test( let q = if q_is_one { one } else { - let abs_q = DynResidue::::new(&Uint::::from(q.abs_diff(0)), params); + let abs_q = MontyForm::::new(&Uint::::from(q.abs_diff(0)), params); if q < 0 { -abs_q } else { @@ -340,7 +352,7 @@ pub fn lucas_test( let p = if p_is_one { one } else { - DynResidue::::new(&Uint::::from(p), params) + MontyForm::::new(&Uint::::from(p), params) }; // Compute d-th element of Lucas sequence (U_d(P, Q), V_d(P, Q)), where: @@ -359,11 +371,11 @@ pub fn lucas_test( // Starting with k = 0 let mut vk = two; // keeps V_k - let mut uk = DynResidue::::zero(params); // keeps U_k + let mut uk = MontyForm::::zero(params); // keeps U_k let mut qk = one; // keeps Q^k // D in Montgomery representation - note that it can be negative. - let abs_d = DynResidue::::new(&Uint::::from(discriminant.abs_diff(0)), params); + let abs_d = MontyForm::::new(&Uint::::from(discriminant.abs_diff(0)), params); let d_m = if discriminant < 0 { -abs_d } else { abs_d }; for i in (0..d.bits_vartime()).rev() { @@ -472,7 +484,7 @@ mod tests { use alloc::format; - use crypto_bigint::{Uint, U128, U64}; + use crypto_bigint::{Odd, Uint, U128, U64}; #[cfg(feature = "tests-exhaustive")] use num_prime::nt_funcs::is_prime64; @@ -547,9 +559,18 @@ mod tests { #[test] fn decomposition() { - assert_eq!(decompose(&U128::MAX), (128, U128::ONE)); - assert_eq!(decompose(&U128::ONE), (1, U128::ONE)); - assert_eq!(decompose(&U128::from(7766015u32)), (15, U128::from(237u32))); + assert_eq!( + decompose(&Odd::new(U128::MAX).unwrap()), + (128, Odd::new(U128::ONE).unwrap()) + ); + assert_eq!( + decompose(&Odd::new(U128::ONE).unwrap()), + (1, Odd::new(U128::ONE).unwrap()) + ); + assert_eq!( + decompose(&Odd::new(U128::from(7766015u32)).unwrap()), + (15, Odd::new(U128::from(237u32)).unwrap()) + ); } fn is_slpsp(num: u32) -> bool { diff --git a/src/hazmat/miller_rabin.rs b/src/hazmat/miller_rabin.rs index 29c401a..c773053 100644 --- a/src/hazmat/miller_rabin.rs +++ b/src/hazmat/miller_rabin.rs @@ -3,8 +3,8 @@ use rand_core::CryptoRngCore; use crypto_bigint::{ - modular::runtime_mod::{DynResidue, DynResidueParams}, - CheckedAdd, Integer, NonZero, RandomMod, Uint, + modular::{MontyForm, MontyParams}, + CheckedAdd, NonZero, Odd, RandomMod, Uint, }; use super::Primality; @@ -20,11 +20,11 @@ use super::Primality; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct MillerRabin { candidate: Uint, - bit_length: usize, - montgomery_params: DynResidueParams, - one: DynResidue, - minus_one: DynResidue, - s: usize, + bit_length: u32, + montgomery_params: MontyParams, + one: MontyForm, + minus_one: MontyForm, + s: u32, d: Uint, } @@ -32,19 +32,20 @@ impl MillerRabin { /// Initializes a Miller-Rabin test for `candidate`. /// /// Panics if `candidate` is even. - pub fn new(candidate: &Uint) -> Self { - if candidate.is_even().into() { - panic!("`candidate` must be odd."); - } - - let params = DynResidueParams::::new(candidate); - let one = DynResidue::::one(params); + pub fn new(candidate: Odd>) -> Self { + let params = MontyParams::::new(candidate); + let one = MontyForm::::one(params); let minus_one = -one; // Find `s` and odd `d` such that `candidate - 1 == 2^s * d`. - let candidate_minus_one = candidate.wrapping_sub(&Uint::::ONE); - let s = candidate_minus_one.trailing_zeros(); - let d = candidate_minus_one >> s; + let (s, d) = if candidate.as_ref() == &Uint::ONE { + (0, Uint::ONE) + } else { + let candidate_minus_one = candidate.wrapping_sub(&Uint::ONE); + let s = candidate_minus_one.trailing_zeros(); + let d = candidate_minus_one.shr(s); + (s, d) + }; Self { candidate: *candidate, @@ -62,7 +63,7 @@ impl MillerRabin { // TODO: it may be faster to first check that gcd(base, candidate) == 1, // otherwise we can return `Composite` right away. - let base = DynResidue::::new(base, self.montgomery_params); + let base = MontyForm::::new(base, self.montgomery_params); // Implementation detail: bounded exp gets faster every time we decrease the bound // by the window length it uses, which is currently 4 bits. @@ -119,7 +120,7 @@ mod tests { use alloc::format; - use crypto_bigint::{Uint, U1024, U128, U1536, U64}; + use crypto_bigint::{Odd, Uint, U1024, U128, U1536, U64}; use rand_chacha::ChaCha8Rng; use rand_core::{CryptoRngCore, OsRng, SeedableRng}; @@ -131,23 +132,17 @@ mod tests { #[test] fn miller_rabin_derived_traits() { - let mr = MillerRabin::new(&U64::ONE); + let mr = MillerRabin::new(Odd::new(U64::ONE).unwrap()); assert!(format!("{mr:?}").starts_with("MillerRabin")); assert_eq!(mr.clone(), mr); } - #[test] - #[should_panic(expected = "`candidate` must be odd.")] - fn parity_check() { - let _mr = MillerRabin::new(&U64::from(10u32)); - } - #[test] #[should_panic( expected = "No suitable random base possible when `candidate == 3`; use the base 2 test." )] fn random_base_range_check() { - let mr = MillerRabin::new(&U64::from(3u32)); + let mr = MillerRabin::new(Odd::new(U64::from(3u32)).unwrap()); mr.test_random_base(&mut OsRng); } @@ -179,7 +174,7 @@ mod tests { // with about 1/4 probability. So we're expecting less than // 35 out of 100 false positives, seems to work. - let mr = MillerRabin::new(&U64::from(*num)); + let mr = MillerRabin::new(Odd::new(U64::from(*num)).unwrap()); assert_eq!( mr.test_base_two().is_probably_prime(), actual_expected_result @@ -195,9 +190,9 @@ mod tests { #[test] fn trivial() { let mut rng = ChaCha8Rng::from_seed(*b"01234567890123456789012345678901"); - let start: U1024 = random_odd_uint(&mut rng, 1024); + let start: Odd = random_odd_uint(&mut rng, 1024); for num in Sieve::new(&start, 1024, false).take(10) { - let mr = MillerRabin::new(&num); + let mr = MillerRabin::new(Odd::new(num).unwrap()); // Trivial tests, must always be true. assert!(mr.test(&1u32.into()).is_probably_prime()); @@ -212,7 +207,7 @@ mod tests { // Mersenne prime 2^127-1 let num = U128::from_be_hex("7fffffffffffffffffffffffffffffff"); - let mr = MillerRabin::new(&num); + let mr = MillerRabin::new(Odd::new(num).unwrap()); assert!(mr.test_base_two().is_probably_prime()); for _ in 0..10 { assert!(mr.test_random_base(&mut rng).is_probably_prime()); @@ -224,7 +219,7 @@ mod tests { let mut rng = ChaCha8Rng::from_seed(*b"01234567890123456789012345678901"); for num in pseudoprimes::STRONG_FIBONACCI.iter() { - let mr = MillerRabin::new(num); + let mr = MillerRabin::new(Odd::new(*num).unwrap()); assert!(!mr.test_base_two().is_probably_prime()); for _ in 0..1000 { assert!(!mr.test_random_base(&mut rng).is_probably_prime()); @@ -252,7 +247,7 @@ mod tests { #[test] fn large_carmichael_number() { - let mr = MillerRabin::new(&pseudoprimes::LARGE_CARMICHAEL_NUMBER); + let mr = MillerRabin::new(Odd::new(pseudoprimes::LARGE_CARMICHAEL_NUMBER).unwrap()); // It is known to pass MR tests for all prime bases <307 assert!(mr.test_base_two().is_probably_prime()); @@ -265,7 +260,7 @@ mod tests { fn test_large_primes(nums: &[Uint]) { let mut rng = ChaCha8Rng::from_seed(*b"01234567890123456789012345678901"); for num in nums { - let mr = MillerRabin::new(num); + let mr = MillerRabin::new(Odd::new(*num).unwrap()); assert!(mr.test_base_two().is_probably_prime()); for _ in 0..10 { assert!(mr.test_random_base(&mut rng).is_probably_prime()); @@ -292,7 +287,7 @@ mod tests { let spsp = is_spsp(num); - let mr = MillerRabin::new(&U64::from(num)); + let mr = MillerRabin::new(Odd::new(U64::from(num)).unwrap()); let res = mr.test_base_two().is_probably_prime(); let expected = spsp || res_ref; assert_eq!( diff --git a/src/hazmat/precomputed.rs b/src/hazmat/precomputed.rs index bdd363e..0f52f7f 100644 --- a/src/hazmat/precomputed.rs +++ b/src/hazmat/precomputed.rs @@ -151,7 +151,11 @@ const fn create_reciprocals() -> [Reciprocal; SMALL_PRIMES_SIZE] { let mut arr = [Reciprocal::default(); SMALL_PRIMES_SIZE]; let mut i = 0; while i < SMALL_PRIMES_SIZE { - arr[i] = Reciprocal::ct_new(Limb(SMALL_PRIMES[i] as Word)).0; + arr[i] = Reciprocal::new( + Limb(SMALL_PRIMES[i] as Word) + .to_nz() + .expect("ensured to be non-zero"), + ); i += 1; } arr diff --git a/src/hazmat/sieve.rs b/src/hazmat/sieve.rs index 7b29625..7a0fa80 100644 --- a/src/hazmat/sieve.rs +++ b/src/hazmat/sieve.rs @@ -3,7 +3,7 @@ use alloc::{vec, vec::Vec}; -use crypto_bigint::{CheckedAdd, Random, Uint}; +use crypto_bigint::{CheckedAdd, Odd, Random, Uint}; use rand_core::CryptoRngCore; use crate::hazmat::precomputed::{SmallPrime, RECIPROCALS, SMALL_PRIMES}; @@ -12,7 +12,10 @@ use crate::hazmat::precomputed::{SmallPrime, RECIPROCALS, SMALL_PRIMES}; /// (that is, with both `0` and `bit_length-1` bits set). /// /// Panics if `bit_length` is 0 or is greater than the bit size of the target `Uint`. -pub fn random_odd_uint(rng: &mut impl CryptoRngCore, bit_length: usize) -> Uint { +pub fn random_odd_uint( + rng: &mut impl CryptoRngCore, + bit_length: u32, +) -> Odd> { if bit_length == 0 { panic!("Bit length must be non-zero"); } @@ -36,7 +39,7 @@ pub fn random_odd_uint(rng: &mut impl CryptoRngCore, bit_length: // Make sure it's the correct bit size random |= Uint::::ONE << (bit_length - 1); - random + Odd::new(random).expect("ensured to be odd") } // The type we use to calculate incremental residues. @@ -59,7 +62,7 @@ pub struct Sieve { incr_limit: Residue, safe_primes: bool, residues: Vec, - max_bit_length: usize, + max_bit_length: u32, produces_nothing: bool, starts_from_exception: bool, last_round: bool, @@ -78,7 +81,7 @@ impl Sieve { /// Panics if `max_bit_length` is zero or greater than the size of the target `Uint`. /// /// If `safe_primes` is `true`, both the returned `n` and `n/2` are sieved. - pub fn new(start: &Uint, max_bit_length: usize, safe_primes: bool) -> Self { + pub fn new(start: &Uint, max_bit_length: u32, safe_primes: bool) -> Self { if max_bit_length == 0 { panic!("The requested bit length cannot be zero"); } @@ -162,14 +165,17 @@ impl Sieve { // Re-calculate residues. for (i, rec) in RECIPROCALS.iter().enumerate().take(self.residues.len()) { - let (_quo, rem) = self.base.ct_div_rem_limb_with_reciprocal(rec); + let (_quo, rem) = self.base.div_rem_limb_with_reciprocal(rec); self.residues[i] = rem.0 as SmallPrime; } // Find the increment limit. - let max_value = (Uint::::ONE << self.max_bit_length).wrapping_sub(&Uint::::ONE); + let max_value = Uint::::ONE + .overflowing_shl(self.max_bit_length) + .unwrap_or(Uint::ZERO) + .wrapping_sub(&Uint::::ONE); let incr_limit = max_value.wrapping_sub(&self.base); - self.incr_limit = if incr_limit > INCR_LIMIT.into() { + self.incr_limit = if incr_limit > Uint::::from(INCR_LIMIT) { INCR_LIMIT } else { // We are close to `2^max_bit_length - 1`. @@ -267,7 +273,7 @@ mod tests { use alloc::format; use alloc::vec::Vec; - use crypto_bigint::U64; + use crypto_bigint::{Odd, U64}; use num_prime::nt_funcs::factorize64; use rand_chacha::ChaCha8Rng; use rand_core::{OsRng, SeedableRng}; @@ -280,7 +286,7 @@ mod tests { let max_prime = SMALL_PRIMES[SMALL_PRIMES.len() - 1]; let mut rng = ChaCha8Rng::from_seed(*b"01234567890123456789012345678901"); - let start: U64 = random_odd_uint(&mut rng, 32); + let start: Odd = random_odd_uint(&mut rng, 32); for num in Sieve::new(&start, 32, false).take(100) { let num_u64: u64 = num.into(); assert!(num_u64.leading_zeros() == 32); @@ -292,7 +298,7 @@ mod tests { } } - fn check_sieve(start: u32, bit_length: usize, safe_prime: bool, reference: &[u32]) { + fn check_sieve(start: u32, bit_length: u32, safe_prime: bool, reference: &[u32]) { let test = Sieve::new(&U64::from(start), bit_length, safe_prime).collect::>(); assert_eq!(test.len(), reference.len()); for (x, y) in test.iter().zip(reference.iter()) { @@ -360,7 +366,7 @@ mod tests { #[test] fn random_below_max_length() { for _ in 0..10 { - let r: U64 = random_odd_uint(&mut OsRng, 50); + let r: Odd = random_odd_uint(&mut OsRng, 50); assert_eq!(r.bits(), 50); } } @@ -368,13 +374,13 @@ mod tests { #[test] #[should_panic(expected = "Bit length must be non-zero")] fn random_odd_uint_0bits() { - let _p: U64 = random_odd_uint(&mut OsRng, 0); + let _p: Odd = random_odd_uint(&mut OsRng, 0); } #[test] #[should_panic(expected = "The requested bit length (65) is larger than the chosen Uint size")] fn random_odd_uint_too_many_bits() { - let _p: U64 = random_odd_uint(&mut OsRng, 65); + let _p: Odd = random_odd_uint(&mut OsRng, 65); } #[test] diff --git a/src/presets.rs b/src/presets.rs index 50eada1..f624695 100644 --- a/src/presets.rs +++ b/src/presets.rs @@ -1,4 +1,4 @@ -use crypto_bigint::{Integer, Uint}; +use crypto_bigint::{Integer, Odd, Uint}; use rand_core::CryptoRngCore; #[cfg(feature = "default-rng")] @@ -13,7 +13,7 @@ use crate::hazmat::{ /// /// See [`is_prime_with_rng`] for details about the performed checks. #[cfg(feature = "default-rng")] -pub fn generate_prime(bit_length: Option) -> Uint { +pub fn generate_prime(bit_length: Option) -> Uint { generate_prime_with_rng(&mut OsRng, bit_length) } @@ -23,7 +23,7 @@ pub fn generate_prime(bit_length: Option) -> Uint { /// /// See [`is_prime_with_rng`] for details about the performed checks. #[cfg(feature = "default-rng")] -pub fn generate_safe_prime(bit_length: Option) -> Uint { +pub fn generate_safe_prime(bit_length: Option) -> Uint { generate_safe_prime_with_rng(&mut OsRng, bit_length) } @@ -53,14 +53,14 @@ pub fn is_safe_prime(num: &Uint) -> bool { /// See [`is_prime_with_rng`] for details about the performed checks. pub fn generate_prime_with_rng( rng: &mut impl CryptoRngCore, - bit_length: Option, + bit_length: Option, ) -> Uint { let bit_length = bit_length.unwrap_or(Uint::::BITS); if bit_length < 2 { panic!("`bit_length` must be 2 or greater."); } loop { - let start: Uint = random_odd_uint(rng, bit_length); + let start = random_odd_uint::(rng, bit_length); let sieve = Sieve::new(&start, bit_length, false); for num in sieve { if is_prime_with_rng(rng, &num) { @@ -79,14 +79,14 @@ pub fn generate_prime_with_rng( /// See [`is_prime_with_rng`] for details about the performed checks. pub fn generate_safe_prime_with_rng( rng: &mut impl CryptoRngCore, - bit_length: Option, + bit_length: Option, ) -> Uint { let bit_length = bit_length.unwrap_or(Uint::::BITS); if bit_length < 3 { panic!("`bit_length` must be 3 or greater."); } loop { - let start: Uint = random_odd_uint(rng, bit_length); + let start = random_odd_uint::(rng, bit_length); let sieve = Sieve::new(&start, bit_length, true); for num in sieve { if is_safe_prime_with_rng(rng, &num) { @@ -152,7 +152,7 @@ pub fn is_safe_prime_with_rng(rng: &mut impl CryptoRngCore, num: /// Checks for primality assuming that `num` is odd. fn _is_prime_with_rng(rng: &mut impl CryptoRngCore, num: &Uint) -> bool { debug_assert!(bool::from(num.is_odd())); - let mr = MillerRabin::new(num); + let mr = MillerRabin::new(Odd::new(*num).unwrap()); if !mr.test_base_two().is_probably_prime() { return false; @@ -232,7 +232,11 @@ mod tests { assert!(is_safe_prime(&next)); } - next = (next << 1).checked_add(&Uint::::ONE).unwrap(); + next = next + .overflowing_shl_vartime(1) + .unwrap() + .checked_add(&Uint::::ONE) + .unwrap(); } // The chain ended. @@ -321,7 +325,7 @@ mod tests { #[test] fn corner_cases_generate_prime() { - for bits in 2usize..5 { + for bits in 2..5 { for _ in 0..100 { let p: U64 = generate_prime(Some(bits)); let p_word = p.as_words()[0]; @@ -332,7 +336,7 @@ mod tests { #[test] fn corner_cases_generate_safe_prime() { - for bits in 3usize..5 { + for bits in 3..5 { for _ in 0..100 { let p: U64 = generate_safe_prime(Some(bits)); let p_word = p.as_words()[0]; @@ -347,7 +351,7 @@ mod tests { mod tests_openssl { use alloc::format; - use crypto_bigint::U128; + use crypto_bigint::{Odd, U128}; use openssl::bn::{BigNum, BigNumContext}; use rand_core::OsRng; @@ -390,7 +394,7 @@ mod tests_openssl { // Generate random numbers, check if our test agrees with OpenSSL for _ in 0..100 { - let p: U128 = random_odd_uint(&mut OsRng, 128); + let p: Odd = random_odd_uint(&mut OsRng, 128); let actual = is_prime(&p); let p_bn = to_openssl(&p); let expected = openssl_is_prime(&p_bn, &mut ctx); @@ -405,7 +409,7 @@ mod tests_openssl { #[cfg(test)] #[cfg(feature = "tests-gmp")] mod tests_gmp { - use crypto_bigint::U128; + use crypto_bigint::{Odd, U128}; use rand_core::OsRng; use rug::{ integer::{IsPrime, Order}, @@ -438,7 +442,7 @@ mod tests_gmp { // Generate primes with GMP, check them for _ in 0..100 { - let start: U128 = random_odd_uint(&mut OsRng, 128); + let start: Odd = random_odd_uint(&mut OsRng, 128); let start_bn = to_gmp(&start); let p_bn = start_bn.next_prime(); let p = from_gmp(&p_bn); @@ -447,7 +451,7 @@ mod tests_gmp { // Generate random numbers, check if our test agrees with GMP for _ in 0..100 { - let p: U128 = random_odd_uint(&mut OsRng, 128); + let p: Odd = random_odd_uint(&mut OsRng, 128); let actual = is_prime(&p); let p_bn = to_gmp(&p); let expected = gmp_is_prime(&p_bn); diff --git a/src/traits.rs b/src/traits.rs index c36c11d..bb72242 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -15,7 +15,7 @@ pub trait RandomPrimeWithRng { /// Panics if `bit_length` is less than 2, or greater than the bit size of the target `Uint`. /// /// See [`is_prime_with_rng`] for details about the performed checks. - fn generate_prime_with_rng(rng: &mut impl CryptoRngCore, bit_length: Option) -> Self; + fn generate_prime_with_rng(rng: &mut impl CryptoRngCore, bit_length: Option) -> Self; /// Returns a random safe prime (that is, such that `(n - 1) / 2` is also prime) /// of size `bit_length` using the provided RNG. @@ -24,10 +24,7 @@ pub trait RandomPrimeWithRng { /// Panics if `bit_length` is less than 3, or greater than the bit size of the target `Uint`. /// /// See [`is_prime_with_rng`] for details about the performed checks. - fn generate_safe_prime_with_rng( - rng: &mut impl CryptoRngCore, - bit_length: Option, - ) -> Self; + fn generate_safe_prime_with_rng(rng: &mut impl CryptoRngCore, bit_length: Option) -> Self; /// Checks probabilistically if the given number is prime using the provided RNG. /// @@ -41,13 +38,10 @@ pub trait RandomPrimeWithRng { } impl RandomPrimeWithRng for Uint { - fn generate_prime_with_rng(rng: &mut impl CryptoRngCore, bit_length: Option) -> Self { + fn generate_prime_with_rng(rng: &mut impl CryptoRngCore, bit_length: Option) -> Self { generate_prime_with_rng(rng, bit_length) } - fn generate_safe_prime_with_rng( - rng: &mut impl CryptoRngCore, - bit_length: Option, - ) -> Self { + fn generate_safe_prime_with_rng(rng: &mut impl CryptoRngCore, bit_length: Option) -> Self { generate_safe_prime_with_rng(rng, bit_length) } fn is_prime_with_rng(&self, rng: &mut impl CryptoRngCore) -> bool {