Skip to content

Commit

Permalink
Merge pull request entropyxyz#76 from fjarri/dyn-rng
Browse files Browse the repository at this point in the history
Relax `CryptoRngCore` bound to allow non-sized args
  • Loading branch information
fjarri authored Feb 17, 2025
2 parents 7524e59 + e53a457 commit 44e4901
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 31 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## [0.6.1] - in development

### Added

- Relaxed `CryptoRngCore` bounds to allow `?Sized`. ([#76])


[#76]: https://github.com/entropyxyz/crypto-primes/pull/76


## [0.6.0] - 2025-01-29

### Changed
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "crypto-primes"
version = "0.6.0"
version = "0.6.1-dev"
edition = "2021"
license = "Apache-2.0 OR MIT"
description = "Random prime number generation and primality checking library"
Expand All @@ -21,7 +21,7 @@ rayon = { version = "1", optional = true }

[dev-dependencies]
# need `crypto-bigint` with `alloc` to test `BoxedUint`
crypto-bigint = { version = "0.6", default-features = false, features = ["alloc"] }
crypto-bigint = { version = "0.6.1", default-features = false, features = ["alloc"] }
rand_chacha = "0.3"
criterion = { version = "0.5", features = ["html_reports"] }
num-modular = { version = "0.5", features = ["num-bigint"] }
Expand Down
12 changes: 6 additions & 6 deletions benches/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@ fn make_random_rng() -> ChaCha8Rng {
ChaCha8Rng::from_seed(seed)
}

fn random_odd_uint<T: RandomBits + Integer>(rng: &mut impl CryptoRngCore, bit_length: u32) -> Odd<T> {
fn random_odd_uint<T: RandomBits + Integer>(rng: &mut (impl CryptoRngCore + ?Sized), bit_length: u32) -> Odd<T> {
random_odd_integer::<T>(rng, NonZero::new(bit_length).unwrap(), SetBits::Msb).unwrap()
}

fn make_sieve<const L: usize>(rng: &mut impl CryptoRngCore) -> SmallPrimesSieve<Uint<L>> {
fn make_sieve<const L: usize>(rng: &mut (impl CryptoRngCore + ?Sized)) -> SmallPrimesSieve<Uint<L>> {
let start = random_odd_uint::<Uint<L>>(rng, Uint::<L>::BITS);
SmallPrimesSieve::new(start.get(), NonZero::new(Uint::<L>::BITS).unwrap(), false)
}

fn make_presieved_num<const L: usize>(rng: &mut impl CryptoRngCore) -> Odd<Uint<L>> {
fn make_presieved_num<const L: usize>(rng: &mut (impl CryptoRngCore + ?Sized)) -> Odd<Uint<L>> {
let mut sieve = make_sieve(rng);
Odd::new(sieve.next().unwrap()).unwrap()
}
Expand Down Expand Up @@ -352,7 +352,7 @@ fn bench_multicore_presets(_c: &mut Criterion) {}
fn bench_gmp(c: &mut Criterion) {
let mut group = c.benchmark_group("GMP");

fn random<const L: usize>(rng: &mut impl CryptoRngCore) -> GmpInteger {
fn random<const L: usize>(rng: &mut (impl CryptoRngCore + ?Sized)) -> GmpInteger {
let num = random_odd_uint::<Uint<L>>(rng, Uint::<L>::BITS).get();
GmpInteger::from_digits(num.as_words(), Order::Lsf)
}
Expand Down Expand Up @@ -447,7 +447,7 @@ fn bench_glass_pumpkin(c: &mut Criterion) {
}

// Mimics the sequence of checks `glass-pumpkin` does to find a prime.
fn prime_like_gp(bit_length: u32, rng: &mut impl CryptoRngCore) -> BoxedUint {
fn prime_like_gp(bit_length: u32, rng: &mut (impl CryptoRngCore + ?Sized)) -> BoxedUint {
loop {
let start = random_odd_integer::<BoxedUint>(rng, NonZero::new(bit_length).unwrap(), SetBits::Msb)
.unwrap()
Expand All @@ -473,7 +473,7 @@ fn bench_glass_pumpkin(c: &mut Criterion) {
}

// Mimics the sequence of checks `glass-pumpkin` does to find a safe prime.
fn safe_prime_like_gp(bit_length: u32, rng: &mut impl CryptoRngCore) -> BoxedUint {
fn safe_prime_like_gp(bit_length: u32, rng: &mut (impl CryptoRngCore + ?Sized)) -> BoxedUint {
loop {
let start = random_odd_integer::<BoxedUint>(rng, NonZero::new(bit_length).unwrap(), SetBits::Msb)
.unwrap()
Expand Down
8 changes: 4 additions & 4 deletions src/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub fn sieve_and_find<R, S>(
) -> Option<S::Item>
where
S: SieveFactory,
R: CryptoRngCore,
R: CryptoRngCore + ?Sized,
{
// We could use `SieveIterator` here, but it requires cloning the `rng`.
// Unlike the parallel version, it is avoidable here.
Expand Down Expand Up @@ -67,13 +67,13 @@ where
/// A structure that chains the creation of sieves, returning the results from one until it is exhausted,
/// and then creating a new one.
#[derive(Debug)]
pub struct SieveIterator<'a, R: CryptoRngCore, S: SieveFactory> {
pub struct SieveIterator<'a, R: CryptoRngCore + ?Sized, S: SieveFactory> {
sieve_factory: S,
sieve: S::Sieve,
rng: &'a mut R,
}

impl<'a, R: CryptoRngCore, S: SieveFactory> SieveIterator<'a, R, S> {
impl<'a, R: CryptoRngCore + ?Sized, S: SieveFactory> SieveIterator<'a, R, S> {
/// Creates a new chained iterator producing results from sieves returned from `sieve_factory`.
pub fn new(rng: &'a mut R, sieve_factory: S) -> Option<Self> {
let mut sieve_factory = sieve_factory;
Expand Down Expand Up @@ -123,7 +123,7 @@ mod tests {

fn make_sieve(
&mut self,
_rng: &mut impl CryptoRngCore,
_rng: &mut (impl CryptoRngCore + ?Sized),
previous_sieve: Option<&Self::Sieve>,
) -> Option<Self::Sieve> {
self.count += 1;
Expand Down
8 changes: 6 additions & 2 deletions src/hazmat/miller_rabin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ impl<T: Integer + RandomMod> MillerRabin<T> {
/// drawn using the provided RNG.
///
/// Note: panics if `candidate == 3` (so the range above is empty).
pub fn test_random_base(&self, rng: &mut impl CryptoRngCore) -> Primality {
pub fn test_random_base(&self, rng: &mut (impl CryptoRngCore + ?Sized)) -> Primality {
// We sample a random base from the range `[3, candidate-2]`:
// - we have a separate method for base 2;
// - the test holds trivially for bases 1 or `candidate-1`.
Expand Down Expand Up @@ -167,7 +167,11 @@ mod tests {
pseudoprimes::STRONG_BASE_2.iter().any(|x| *x == num)
}

fn random_checks<T: Integer + RandomMod>(rng: &mut impl CryptoRngCore, mr: &MillerRabin<T>, count: usize) -> usize {
fn random_checks<T: Integer + RandomMod>(
rng: &mut (impl CryptoRngCore + ?Sized),
mr: &MillerRabin<T>,
count: usize,
) -> usize {
(0..count)
.map(|_| -> usize { mr.test_random_base(rng).is_probably_prime().into() })
.sum()
Expand Down
4 changes: 2 additions & 2 deletions src/hazmat/sieve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub enum SetBits {
/// Returns an error variant if `bit_length` is greater than the maximum allowed for `T`
/// (applies to fixed-length types).
pub fn random_odd_integer<T: Integer + RandomBits>(
rng: &mut impl CryptoRngCore,
rng: &mut (impl CryptoRngCore + ?Sized),
bit_length: NonZeroU32,
set_bits: SetBits,
) -> Result<Odd<T>, RandomBitsError> {
Expand Down Expand Up @@ -325,7 +325,7 @@ impl<T: Integer + RandomBits> SieveFactory for SmallPrimesSieveFactory<T> {
type Sieve = SmallPrimesSieve<T>;
fn make_sieve(
&mut self,
rng: &mut impl CryptoRngCore,
rng: &mut (impl CryptoRngCore + ?Sized),
_previous_sieve: Option<&Self::Sieve>,
) -> Option<Self::Sieve> {
let start =
Expand Down
10 changes: 5 additions & 5 deletions src/presets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub fn is_safe_prime<T: Integer + RandomMod>(num: &T) -> bool {
///
/// See [`is_prime_with_rng`] for details about the performed checks.
pub fn generate_prime_with_rng<T: Integer + RandomBits + RandomMod>(
rng: &mut impl CryptoRngCore,
rng: &mut (impl CryptoRngCore + ?Sized),
bit_length: u32,
) -> T {
sieve_and_find(
Expand All @@ -99,7 +99,7 @@ pub fn generate_prime_with_rng<T: Integer + RandomBits + RandomMod>(
///
/// See [`is_prime_with_rng`] for details about the performed checks.
pub fn generate_safe_prime_with_rng<T: Integer + RandomBits + RandomMod>(
rng: &mut impl CryptoRngCore,
rng: &mut (impl CryptoRngCore + ?Sized),
bit_length: u32,
) -> T {
sieve_and_find(
Expand Down Expand Up @@ -187,7 +187,7 @@ where
/// "Strengthening the Baillie-PSW primality test",
/// Math. Comp. 90 1931-1955 (2021),
/// DOI: [10.1090/mcom/3616](https://doi.org/10.1090/mcom/3616)
pub fn is_prime_with_rng<T: Integer + RandomMod>(rng: &mut impl CryptoRngCore, num: &T) -> bool {
pub fn is_prime_with_rng<T: Integer + RandomMod>(rng: &mut (impl CryptoRngCore + ?Sized), num: &T) -> bool {
if num == &T::from_limb_like(Limb::from(2u32), num) {
return true;
}
Expand All @@ -201,7 +201,7 @@ pub fn is_prime_with_rng<T: Integer + RandomMod>(rng: &mut impl CryptoRngCore, n
/// Probabilistically checks if the given number is a safe prime using the provided RNG.
///
/// See [`is_prime_with_rng`] for details about the performed checks.
pub fn is_safe_prime_with_rng<T: Integer + RandomMod>(rng: &mut impl CryptoRngCore, num: &T) -> bool {
pub fn is_safe_prime_with_rng<T: Integer + RandomMod>(rng: &mut (impl CryptoRngCore + ?Sized), num: &T) -> bool {
// Since, by the definition of safe prime, `(num - 1) / 2` must also be prime,
// and therefore odd, `num` has to be equal to 3 modulo 4.
// 5 is the only exception, so we check for it.
Expand All @@ -228,7 +228,7 @@ pub fn is_safe_prime_with_rng<T: Integer + RandomMod>(rng: &mut impl CryptoRngCo
/// If the outcome of M-R is "probably prime", then run a Lucas test
/// If the Lucas test is inconclusive, run a Miller-Rabin with random base and unless this second
/// M-R test finds it's composite, then conclude that it's prime.
fn _is_prime_with_rng<T: Integer + RandomMod>(rng: &mut impl CryptoRngCore, candidate: Odd<T>) -> bool {
fn _is_prime_with_rng<T: Integer + RandomMod>(rng: &mut (impl CryptoRngCore + ?Sized), candidate: Odd<T>) -> bool {
let mr = MillerRabin::new(candidate.clone());

if !mr.test_base_two().is_probably_prime() {
Expand Down
23 changes: 13 additions & 10 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ pub trait SieveFactory {
/// Makes a sieve given an RNG and the previous exhausted sieve (if any).
///
/// Returning `None` signals that the prime generation should stop.
fn make_sieve(&mut self, rng: &mut impl CryptoRngCore, previous_sieve: Option<&Self::Sieve>)
-> Option<Self::Sieve>;
fn make_sieve(
&mut self,
rng: &mut (impl CryptoRngCore + ?Sized),
previous_sieve: Option<&Self::Sieve>,
) -> Option<Self::Sieve>;
}

/// Provides a generic way to access methods for random prime number generation
Expand All @@ -26,41 +29,41 @@ 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: u32) -> Self;
fn generate_prime_with_rng(rng: &mut (impl CryptoRngCore + ?Sized), bit_length: u32) -> Self;

/// Returns a random safe prime (that is, such that `(n - 1) / 2` is also prime)
/// of size `bit_length` using the provided RNG.
///
/// 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: u32) -> Self;
fn generate_safe_prime_with_rng(rng: &mut (impl CryptoRngCore + ?Sized), bit_length: u32) -> Self;

/// Probabilistically checks if the given number is prime using the provided RNG.
///
/// See [`is_prime_with_rng`] for details about the performed checks.
fn is_prime_with_rng(&self, rng: &mut impl CryptoRngCore) -> bool;
fn is_prime_with_rng(&self, rng: &mut (impl CryptoRngCore + ?Sized)) -> bool;

/// Probabilistically checks if the given number is a safe prime using the provided RNG.
///
/// See [`is_prime_with_rng`] for details about the performed checks.
fn is_safe_prime_with_rng(&self, rng: &mut impl CryptoRngCore) -> bool;
fn is_safe_prime_with_rng(&self, rng: &mut (impl CryptoRngCore + ?Sized)) -> bool;
}

impl<T> RandomPrimeWithRng for T
where
T: Integer + RandomBits + RandomMod,
{
fn generate_prime_with_rng(rng: &mut impl CryptoRngCore, bit_length: u32) -> Self {
fn generate_prime_with_rng(rng: &mut (impl CryptoRngCore + ?Sized), bit_length: u32) -> Self {
generate_prime_with_rng(rng, bit_length)
}
fn generate_safe_prime_with_rng(rng: &mut impl CryptoRngCore, bit_length: u32) -> Self {
fn generate_safe_prime_with_rng(rng: &mut (impl CryptoRngCore + ?Sized), bit_length: u32) -> Self {
generate_safe_prime_with_rng(rng, bit_length)
}
fn is_prime_with_rng(&self, rng: &mut impl CryptoRngCore) -> bool {
fn is_prime_with_rng(&self, rng: &mut (impl CryptoRngCore + ?Sized)) -> bool {
is_prime_with_rng(rng, self)
}
fn is_safe_prime_with_rng(&self, rng: &mut impl CryptoRngCore) -> bool {
fn is_safe_prime_with_rng(&self, rng: &mut (impl CryptoRngCore + ?Sized)) -> bool {
is_safe_prime_with_rng(rng, self)
}
}
Expand Down

0 comments on commit 44e4901

Please # to comment.