Skip to main content

crypto_bigint/uint/boxed/
rand.rs

1//! Random number generator support.
2
3use super::BoxedUint;
4use crate::{
5    NonZero, RandomBits, RandomBitsError, RandomMod,
6    uint::rand::{random_bits_core, random_mod_vartime_core},
7};
8use rand_core::{Rng, TryRng};
9
10impl RandomBits for BoxedUint {
11    fn try_random_bits<R: TryRng + ?Sized>(
12        rng: &mut R,
13        bit_length: u32,
14    ) -> Result<Self, RandomBitsError<R::Error>> {
15        Self::try_random_bits_with_precision(rng, bit_length, bit_length)
16    }
17
18    fn try_random_bits_with_precision<R: TryRng + ?Sized>(
19        rng: &mut R,
20        bit_length: u32,
21        bits_precision: u32,
22    ) -> Result<Self, RandomBitsError<R::Error>> {
23        if bit_length > bits_precision {
24            return Err(RandomBitsError::BitLengthTooLarge {
25                bit_length,
26                bits_precision,
27            });
28        }
29
30        let mut ret = BoxedUint::zero_with_precision(bits_precision);
31        random_bits_core(rng, &mut ret, bit_length).map_err(RandomBitsError::RandCore)?;
32        Ok(ret)
33    }
34}
35
36impl RandomMod for BoxedUint {
37    fn random_mod_vartime<R: Rng + ?Sized>(rng: &mut R, modulus: &NonZero<Self>) -> Self {
38        let mut n = BoxedUint::zero_with_precision(modulus.bits_precision());
39        let Ok(()) = random_mod_vartime_core(rng, &mut n, modulus, modulus.bits());
40        n
41    }
42
43    fn try_random_mod_vartime<R: TryRng + ?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_vartime_core(rng, &mut n, modulus, modulus.bits())?;
49        Ok(n)
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use crate::{BoxedUint, NonZero, RandomBits, RandomMod};
56    use rand_core::SeedableRng;
57
58    #[test]
59    fn random() {
60        let mut rng = chacha20::ChaCha8Rng::seed_from_u64(1);
61
62        let r = BoxedUint::random_bits(&mut rng, 256);
63        assert!(r.bits_precision() == 256);
64
65        let r = BoxedUint::random_bits(&mut rng, 256 - 32 + 1);
66        assert!(r.bits_precision() == 256);
67        assert!(r < BoxedUint::one_with_precision(256) << (256 - 32 + 1));
68    }
69
70    #[test]
71    fn random_mod_vartime() {
72        let mut rng = chacha20::ChaCha8Rng::seed_from_u64(1);
73
74        // Ensure `random_mod_vartime` runs in a reasonable amount of time
75        let modulus = NonZero::new(BoxedUint::from(42u8)).unwrap();
76        let res = BoxedUint::random_mod_vartime(&mut rng, &modulus);
77
78        // Check that the value is in range
79        assert!(res < BoxedUint::from(42u8));
80
81        // Ensure `random_mod_vartime` runs in a reasonable amount of time
82        // when the modulus is larger than 1 limb
83        let modulus = NonZero::new(BoxedUint::from(0x10000000000000001u128)).unwrap();
84        let res = BoxedUint::random_mod_vartime(&mut rng, &modulus);
85
86        // Check that the value is in range
87        assert!(res < BoxedUint::from(0x10000000000000001u128));
88    }
89}