Skip to content

Commit

Permalink
crypto-bigint: add rand feature (#508)
Browse files Browse the repository at this point in the history
Adds initial support for random number generation, for both `UInt` and
`Limb`.

Also adds a `UInt::random_mod` function which generates a random number
within the range of a provided modulus using rejection sampling.
  • Loading branch information
tarcieri committed Jun 27, 2021
1 parent a93ddb6 commit 950e62c
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions crypto-bigint/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,18 @@ readme = "README.md"
[dependencies]
generic-array = { version = "0.14", optional = true }
subtle = { version = "2.4", default-features = false }

# optional dependencies
rand_core = { version = "0.6", optional = true }
zeroize = { version = "1", optional = true, default-features = false }

[dev-dependencies]
hex-literal = "0.3"

[features]
default = ["rand"]
alloc = []
rand = ["rand_core"]

[package.metadata.docs.rs]
all-features = true
Expand Down
3 changes: 3 additions & 0 deletions crypto-bigint/src/limb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ mod from;
mod mul;
mod sub;

#[cfg(feature = "rand")]
mod rand;

use core::fmt;
use subtle::{Choice, ConditionallySelectable};

Expand Down
20 changes: 20 additions & 0 deletions crypto-bigint/src/limb/rand.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//! Random number generator support

use super::Limb;
use rand_core::{CryptoRng, RngCore};

impl Limb {
/// Generate a random limb
#[cfg(target_pointer_width = "32")]
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
pub fn random(mut rng: impl CryptoRng + RngCore) -> Self {
Self(rng.next_u32())
}

/// Generate a random limb
#[cfg(target_pointer_width = "64")]
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
pub fn random(mut rng: impl CryptoRng + RngCore) -> Self {
Self(rng.next_u64())
}
}
3 changes: 3 additions & 0 deletions crypto-bigint/src/uint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ mod sub;
#[cfg(feature = "generic-array")]
mod array;

#[cfg(feature = "rand")]
mod rand;

use crate::{Concat, Encoding, Limb, Split};
use core::fmt;
use subtle::{Choice, ConditionallySelectable};
Expand Down
41 changes: 41 additions & 0 deletions crypto-bigint/src/uint/rand.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//! Random number generator support

use super::UInt;
use crate::Limb;
use rand_core::{CryptoRng, RngCore};
use subtle::ConstantTimeLess;

#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
impl<const LIMBS: usize> UInt<LIMBS> {
/// Generate a cryptographically secure random [`UInt`].
pub fn random(mut rng: impl CryptoRng + RngCore) -> Self {
let mut limbs = [Limb::default(); LIMBS];

for limb in &mut limbs {
*limb = Limb::random(&mut rng)
}

limbs.into()
}

/// Generate a cryptographically secure random [`UInt`] which is less than
/// a given `modulus`.
///
/// This function uses rejection sampling, a method which produces an
/// unbiased distribution of in-range values provided the underlying
/// [`CryptoRng`] is unbiased, but runs in variable-time.
///
/// The variable-time nature of the algorithm should not pose a security
/// issue so long as the underlying random number generator is truly a
/// [`CryptoRng`], where previous outputs are unrelated to subsequent
/// outputs and do not reveal information about the RNG's internal state.
pub fn random_mod(mut rng: impl CryptoRng + RngCore, modulus: &Self) -> Self {
loop {
let n = Self::random(&mut rng);

if n.ct_lt(&modulus).into() {
return n;
}
}
}
}

0 comments on commit 950e62c

Please sign in to comment.