primitives/random/
mod.rs

1pub mod derive_rng;
2pub mod prf;
3pub mod prg;
4pub mod test_rng;
5
6use num_traits::Zero;
7pub use prg::{new_prg, prg, Prng};
8use rand::{distributions::Standard, prelude::Distribution};
9pub use rand_chacha::rand_core::CryptoRngCore;
10pub use test_rng::{test_rng, TestRng};
11use typenum::Unsigned;
12
13use crate::{
14    constants::{CollisionResistanceBytes, Lambda},
15    errors::PrimitiveError,
16    random::derive_rng::DeriveRng,
17    utils::IntoExactSizeIterator,
18};
19
20/// The generic type for all seeds across our protocols.
21pub type Seed = [u8; CollisionResistanceBytes::USIZE];
22
23impl DeriveRng for Seed {}
24
25/// A trait for getting a random value for a type. Will be replaced by the `random` feature
26/// once it is included in std (https://github.com/rust-lang/rust/issues/130703).
27pub trait Random: Sized {
28    // Generates a random value.
29    fn random(rng: impl CryptoRngCore) -> Self;
30
31    // Generates a container with `size` random elements.
32    fn random_n<Container: FromIterator<Self>>(
33        mut rng: impl CryptoRngCore,
34        size: usize,
35    ) -> Container {
36        (0..size).map(|_| Self::random(&mut rng)).collect()
37    }
38}
39
40/// Generalise so that `rand::random()` can be used for any type that implements `Random`.
41impl<T> Random for T
42where
43    Standard: Distribution<T>,
44{
45    #[inline]
46    fn random(mut source: impl CryptoRngCore) -> Self {
47        Standard.sample(&mut source)
48    }
49}
50
51/// A trait for getting a random value for a type alongside some data.
52pub trait RandomWith<D: Clone>: Sized {
53    // Generates a random value given additional data.
54    fn random_with(rng: impl CryptoRngCore, data: D) -> Self;
55
56    // Generates a container with `size` random elements and some available data.
57    fn random_n_with<Container: FromIterator<Self>>(
58        mut rng: impl CryptoRngCore,
59        size: usize,
60        data: D,
61    ) -> Container {
62        (0..size)
63            .map(|_| Self::random_with(&mut rng, data.clone()))
64            .collect()
65    }
66
67    // Generates a container with `size` random elements and some available data.
68    fn random_n_with_each<Container: FromIterator<Self>>(
69        mut rng: impl CryptoRngCore,
70        all_data: impl IntoExactSizeIterator<Item = D>,
71    ) -> Container {
72        all_data
73            .into_iter()
74            .map(|data| Self::random_with(&mut rng, data))
75            .collect()
76    }
77}
78
79/// Generate random non-zero values.
80pub trait RandomNonZero: Sized + Zero + Random {
81    /// Generates a random non-zero value.
82    ///
83    /// May error out if it cannot find a non-zero value after a certain number
84    /// of tries, defined so that:
85    ///
86    /// > `Prob(out == 0) <= 2^-(λ)` as long as `Prob(random()==0) <= 2^-(size_of::<Self>)`
87    ///
88    /// The default implementation repetitively calls `random()` (rejection sampling).
89    /// As such, it is not constant-time, but the side channel leakage should not impact security
90    /// as long as the rng is evaluated in constant time and produces uniformly random values.
91    ///
92    /// If needed, override with a constant-time implementation using `ConditionallySelectable` and
93    /// always running for a fixed number of iterations, potentially returning a zero value
94    /// (with overwhelmingly low probability).
95    #[inline]
96    fn random_non_zero(mut rng: impl CryptoRngCore) -> Result<Self, PrimitiveError> {
97        let n_tries = (Lambda::USIZE).div_ceil(std::mem::size_of::<Self>());
98        for _ in 0..n_tries {
99            let value = Self::random(&mut rng);
100            if !value.is_zero() {
101                return Ok(value);
102            }
103        }
104        Err(PrimitiveError::ZeroValueSampled(
105            std::any::type_name::<Self>().into(),
106        ))
107    }
108
109    // Generates a container with `size` random non-zero elements.
110    fn random_n_non_zero<Container: FromIterator<Self>>(
111        mut rng: impl CryptoRngCore,
112        size: usize,
113    ) -> Result<Container, PrimitiveError> {
114        (0..size).map(|_| Self::random_non_zero(&mut rng)).collect()
115    }
116}