Skip to content

Commit d668d41

Browse files
authored
Provide RandomMod::try_random_mod and Random::try_random methods (#770)
1 parent ad2eab7 commit d668d41

File tree

11 files changed

+96
-47
lines changed

11 files changed

+96
-47
lines changed

Cargo.lock

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ subtle = { version = "2.6", default-features = false }
2323
der = { version = "0.8.0-rc.1", optional = true, default-features = false }
2424
hybrid-array = { version = "0.3", optional = true }
2525
num-traits = { version = "0.2.19", default-features = false }
26-
rand_core = { version = "0.9", optional = true, default-features = false }
26+
rand_core = { version = "0.9.2", optional = true, default-features = false }
2727
rlp = { version = "0.6", optional = true, default-features = false }
2828
serdect = { version = "0.3", optional = true, default-features = false }
2929
zeroize = { version = "1", optional = true, default-features = false }

src/int/rand.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
//! Random number generator support
22
3-
use rand_core::{RngCore, TryRngCore};
3+
use rand_core::TryRngCore;
44

55
use crate::{Int, Random, RandomBits, RandomBitsError};
66

77
use super::Uint;
88

99
impl<const LIMBS: usize> Random for Int<LIMBS> {
1010
/// Generate a cryptographically secure random [`Int`].
11-
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
12-
Self(Uint::random(rng))
11+
fn try_random<R: TryRngCore + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
12+
Ok(Self(Uint::try_random(rng)?))
1313
}
1414
}
1515

src/limb/rand.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,38 @@
22
33
use super::Limb;
44
use crate::{Encoding, NonZero, Random, RandomMod};
5-
use rand_core::RngCore;
5+
use rand_core::TryRngCore;
66
use subtle::ConstantTimeLess;
77

88
impl Random for Limb {
9-
#[cfg(target_pointer_width = "32")]
10-
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
11-
Self(rng.next_u32())
12-
}
9+
fn try_random<R: TryRngCore + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
10+
#[cfg(target_pointer_width = "32")]
11+
let val = rng.try_next_u32()?;
12+
#[cfg(target_pointer_width = "64")]
13+
let val = rng.try_next_u64()?;
1314

14-
#[cfg(target_pointer_width = "64")]
15-
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
16-
Self(rng.next_u64())
15+
Ok(Self(val))
1716
}
1817
}
1918

2019
impl RandomMod for Limb {
21-
fn random_mod<R: RngCore + ?Sized>(rng: &mut R, modulus: &NonZero<Self>) -> Self {
20+
fn try_random_mod<R: TryRngCore + ?Sized>(
21+
rng: &mut R,
22+
modulus: &NonZero<Self>,
23+
) -> Result<Self, R::Error> {
2224
let mut bytes = <Self as Encoding>::Repr::default();
2325

2426
let n_bits = modulus.bits() as usize;
2527
let n_bytes = (n_bits + 7) / 8;
2628
let mask = 0xffu8 >> (8 * n_bytes - n_bits);
2729

2830
loop {
29-
rng.fill_bytes(&mut bytes[..n_bytes]);
31+
rng.try_fill_bytes(&mut bytes[..n_bytes])?;
3032
bytes[n_bytes - 1] &= mask;
3133

3234
let n = Limb::from_le_bytes(bytes);
3335
if n.ct_lt(modulus).into() {
34-
return n;
36+
return Ok(n);
3537
}
3638
}
3739
}

src/modular/const_monty_form.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use core::{fmt::Debug, marker::PhantomData};
1515
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
1616

1717
#[cfg(feature = "rand_core")]
18-
use crate::{Random, RandomMod, rand_core::RngCore};
18+
use crate::{Random, RandomMod, rand_core::TryRngCore};
1919

2020
#[cfg(feature = "serde")]
2121
use {
@@ -204,8 +204,11 @@ where
204204
MOD: ConstMontyParams<LIMBS>,
205205
{
206206
#[inline]
207-
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
208-
Self::new(&Uint::random_mod(rng, MOD::MODULUS.as_nz_ref()))
207+
fn try_random<R: TryRngCore + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
208+
Ok(Self::new(&Uint::try_random_mod(
209+
rng,
210+
MOD::MODULUS.as_nz_ref(),
211+
)?))
209212
}
210213
}
211214

src/non_zero.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
1212
use crate::{ArrayEncoding, ByteArray};
1313

1414
#[cfg(feature = "rand_core")]
15-
use {crate::Random, rand_core::RngCore};
15+
use {crate::Random, rand_core::TryRngCore};
1616

1717
#[cfg(feature = "serde")]
1818
use serdect::serde::{
@@ -246,10 +246,10 @@ where
246246
/// As a result, it runs in variable time. If the generator `rng` is
247247
/// cryptographically secure (for example, it implements `CryptoRng`),
248248
/// then this is guaranteed not to leak anything about the output value.
249-
fn random<R: RngCore + ?Sized>(mut rng: &mut R) -> Self {
249+
fn try_random<R: TryRngCore + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
250250
loop {
251-
if let Some(result) = Self::new(T::random(&mut rng)).into() {
252-
break result;
251+
if let Some(result) = Self::new(T::try_random(rng)?).into() {
252+
break Ok(result);
253253
}
254254
}
255255
}

src/odd.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
88
use crate::BoxedUint;
99

1010
#[cfg(feature = "rand_core")]
11-
use {crate::Random, rand_core::RngCore};
11+
use crate::{Random, rand_core::TryRngCore};
1212

1313
#[cfg(all(feature = "alloc", feature = "rand_core"))]
14-
use {crate::RandomBits, rand_core::TryRngCore};
14+
use crate::RandomBits;
1515

1616
#[cfg(feature = "serde")]
1717
use crate::Zero;
@@ -153,10 +153,10 @@ impl PartialOrd<Odd<BoxedUint>> for BoxedUint {
153153
#[cfg(feature = "rand_core")]
154154
impl<const LIMBS: usize> Random for Odd<Uint<LIMBS>> {
155155
/// Generate a random `Odd<Uint<T>>`.
156-
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
157-
let mut ret = Uint::random(rng);
156+
fn try_random<R: TryRngCore + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
157+
let mut ret = Uint::try_random(rng)?;
158158
ret.limbs[0] |= Limb::ONE;
159-
Odd(ret)
159+
Ok(Odd(ret))
160160
}
161161
}
162162

src/traits.rs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,15 @@ pub trait Random: Sized {
299299
/// Generate a random value.
300300
///
301301
/// If `rng` is a CSRNG, the generation is cryptographically secure as well.
302-
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self;
302+
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
303+
let Ok(out) = Self::try_random(rng);
304+
out
305+
}
306+
307+
/// Generate a random value.
308+
///
309+
/// If `rng` is a CSRNG, the generation is cryptographically secure as well.
310+
fn try_random<R: TryRngCore + ?Sized>(rng: &mut R) -> Result<Self, R::Error>;
303311
}
304312

305313
/// Possible errors of the methods in [`RandomBits`] trait.
@@ -419,7 +427,24 @@ pub trait RandomMod: Sized + Zero {
419427
/// example, it implements `CryptoRng`), then this is guaranteed not to
420428
/// leak anything about the output value aside from it being less than
421429
/// `modulus`.
422-
fn random_mod<R: RngCore + ?Sized>(rng: &mut R, modulus: &NonZero<Self>) -> Self;
430+
fn random_mod<R: RngCore + ?Sized>(rng: &mut R, modulus: &NonZero<Self>) -> Self {
431+
let Ok(out) = Self::try_random_mod(rng, modulus);
432+
out
433+
}
434+
435+
/// Generate a random number which is less than a given `modulus`.
436+
///
437+
/// This uses rejection sampling.
438+
///
439+
/// As a result, it runs in variable time that depends in part on
440+
/// `modulus`. If the generator `rng` is cryptographically secure (for
441+
/// example, it implements `CryptoRng`), then this is guaranteed not to
442+
/// leak anything about the output value aside from it being less than
443+
/// `modulus`.
444+
fn try_random_mod<R: TryRngCore + ?Sized>(
445+
rng: &mut R,
446+
modulus: &NonZero<Self>,
447+
) -> Result<Self, R::Error>;
423448
}
424449

425450
/// Compute `self + rhs mod p`.

src/uint/boxed/rand.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,18 @@ impl RandomBits for BoxedUint {
3636
impl RandomMod for BoxedUint {
3737
fn random_mod<R: RngCore + ?Sized>(rng: &mut R, modulus: &NonZero<Self>) -> Self {
3838
let mut n = BoxedUint::zero_with_precision(modulus.bits_precision());
39-
random_mod_core(rng, &mut n, modulus, modulus.bits());
39+
let Ok(()) = random_mod_core(rng, &mut n, modulus, modulus.bits());
4040
n
4141
}
42+
43+
fn try_random_mod<R: TryRngCore + ?Sized>(
44+
rng: &mut R,
45+
modulus: &NonZero<Self>,
46+
) -> Result<Self, R::Error> {
47+
let mut n = BoxedUint::zero_with_precision(modulus.bits_precision());
48+
random_mod_core(rng, &mut n, modulus, modulus.bits())?;
49+
Ok(n)
50+
}
4251
}
4352

4453
#[cfg(test)]

src/uint/rand.rs

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ use rand_core::{RngCore, TryRngCore};
66
use subtle::ConstantTimeLess;
77

88
impl<const LIMBS: usize> Random for Uint<LIMBS> {
9-
fn random<R: RngCore + ?Sized>(mut rng: &mut R) -> Self {
9+
fn try_random<R: TryRngCore + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
1010
let mut limbs = [Limb::ZERO; LIMBS];
1111

1212
for limb in &mut limbs {
13-
*limb = Limb::random(&mut rng)
13+
*limb = Limb::try_random(rng)?
1414
}
1515

16-
limbs.into()
16+
Ok(limbs.into())
1717
}
1818
}
1919

@@ -83,35 +83,45 @@ impl<const LIMBS: usize> RandomBits for Uint<LIMBS> {
8383
impl<const LIMBS: usize> RandomMod for Uint<LIMBS> {
8484
fn random_mod<R: RngCore + ?Sized>(rng: &mut R, modulus: &NonZero<Self>) -> Self {
8585
let mut n = Self::ZERO;
86-
random_mod_core(rng, &mut n, modulus, modulus.bits_vartime());
86+
let Ok(()) = random_mod_core(rng, &mut n, modulus, modulus.bits_vartime());
8787
n
8888
}
89+
90+
fn try_random_mod<R: TryRngCore + ?Sized>(
91+
rng: &mut R,
92+
modulus: &NonZero<Self>,
93+
) -> Result<Self, R::Error> {
94+
let mut n = Self::ZERO;
95+
random_mod_core(rng, &mut n, modulus, modulus.bits_vartime())?;
96+
Ok(n)
97+
}
8998
}
9099

91100
/// Generic implementation of `random_mod` which can be shared with `BoxedUint`.
92101
// TODO(tarcieri): obtain `n_bits` via a trait like `Integer`
93-
pub(super) fn random_mod_core<T, R: RngCore + ?Sized>(
102+
pub(super) fn random_mod_core<T, R: TryRngCore + ?Sized>(
94103
rng: &mut R,
95104
n: &mut T,
96105
modulus: &NonZero<T>,
97106
n_bits: u32,
98-
) where
107+
) -> Result<(), R::Error>
108+
where
99109
T: AsMut<[Limb]> + AsRef<[Limb]> + ConstantTimeLess + Zero,
100110
{
101111
#[cfg(target_pointer_width = "64")]
102-
let mut next_word = || rng.next_u64();
112+
let mut next_word = || rng.try_next_u64();
103113
#[cfg(target_pointer_width = "32")]
104-
let mut next_word = || rng.next_u32();
114+
let mut next_word = || rng.try_next_u32();
105115

106116
let n_limbs = n_bits.div_ceil(Limb::BITS) as usize;
107117

108118
let hi_word_modulus = modulus.as_ref().as_ref()[n_limbs - 1].0;
109119
let mask = !0 >> hi_word_modulus.leading_zeros();
110-
let mut hi_word = next_word() & mask;
120+
let mut hi_word = next_word()? & mask;
111121

112122
loop {
113123
while hi_word > hi_word_modulus {
114-
hi_word = next_word() & mask;
124+
hi_word = next_word()? & mask;
115125
}
116126
// Set high limb
117127
n.as_mut()[n_limbs - 1] = Limb::from_le_bytes(hi_word.to_le_bytes());
@@ -120,15 +130,16 @@ pub(super) fn random_mod_core<T, R: RngCore + ?Sized>(
120130
// Need to deserialize from little-endian to make sure that two 32-bit limbs
121131
// deserialized sequentially are equal to one 64-bit limb produced from the same
122132
// byte stream.
123-
n.as_mut()[i] = Limb::from_le_bytes(next_word().to_le_bytes());
133+
n.as_mut()[i] = Limb::from_le_bytes(next_word()?.to_le_bytes());
124134
}
125135
// If the high limb is equal to the modulus' high limb, it's still possible
126136
// that the full uint is too big so we check and repeat if it is.
127137
if n.ct_lt(modulus).into() {
128138
break;
129139
}
130-
hi_word = next_word() & mask;
140+
hi_word = next_word()? & mask;
131141
}
142+
Ok(())
132143
}
133144

134145
#[cfg(test)]

0 commit comments

Comments
 (0)