Skip to main content

primitives/random/
mod.rs

1pub mod prf;
2pub mod prg;
3pub mod rng;
4
5use std::sync::Arc;
6
7pub use rand_chacha::rand_core::CryptoRngCore;
8#[cfg(any(test, feature = "dev"))]
9pub use rng::test_rng;
10pub use rng::{BaseRng, Seed, SeedableRng};
11use subtle::Choice;
12use typenum::Unsigned;
13
14use crate::{
15    algebra::field::FieldExtension,
16    constants::Lambda,
17    errors::PrimitiveError,
18    types::{HeapArray, Positive},
19    utils::IntoExactSizeIterator,
20};
21
22/// A trait for getting a random value for a type. Will be replaced by the `random` feature
23/// once it is included in std (https://github.com/rust-lang/rust/issues/130703).
24pub trait Random: Sized {
25    // Generates a random value.
26    fn random(rng: impl CryptoRngCore) -> Self;
27
28    // Generates a container with `size` random elements.
29    fn random_n<Container: FromIterator<Self>>(
30        mut rng: impl CryptoRngCore,
31        size: usize,
32    ) -> Container {
33        (0..size).map(|_| Self::random(&mut rng)).collect()
34    }
35
36    // Generates an array with `M` random elements, known at compile time.
37    fn random_array<M: Positive>(rng: impl CryptoRngCore) -> HeapArray<Self, M> {
38        HeapArray::random(rng)
39    }
40}
41
42impl Random for Seed {
43    #[inline]
44    fn random(mut rng: impl CryptoRngCore) -> Self {
45        let mut seed = [0u8; 32];
46        rng.fill_bytes(&mut seed);
47        seed
48    }
49}
50
51impl<T: Random> Random for Arc<T> {
52    #[inline]
53    fn random(mut source: impl CryptoRngCore) -> Self {
54        Arc::new(T::random(&mut source))
55    }
56}
57
58impl<T1: Random, T2: Random> Random for (T1, T2) {
59    #[inline]
60    fn random(mut source: impl CryptoRngCore) -> Self {
61        (T1::random(&mut source), T2::random(&mut source))
62    }
63}
64
65impl<T: Random> RandomWith<usize> for Vec<T> {
66    #[inline]
67    fn random_with(mut source: impl CryptoRngCore, n_elements: usize) -> Self {
68        (0..n_elements).map(|_| T::random(&mut source)).collect()
69    }
70}
71
72/// A trait for getting a random instance of a type alongside some data.
73pub trait RandomWith<D: Clone>: Sized {
74    // Generates a random value given additional data.
75    fn random_with(rng: impl CryptoRngCore, data: D) -> Self;
76
77    // Generates a container with `size` random elements and some available data.
78    fn random_n_with<Container: FromIterator<Self>>(
79        mut rng: impl CryptoRngCore,
80        size: usize,
81        data: D,
82    ) -> Container {
83        (0..size)
84            .map(|_| Self::random_with(&mut rng, data.clone()))
85            .collect()
86    }
87
88    // Generates a container with `[data.len()]` random elements and some available data.
89    fn random_n_with_each<Container: FromIterator<Self>>(
90        mut rng: impl CryptoRngCore,
91        all_data: impl IntoExactSizeIterator<Item = D>,
92    ) -> Container {
93        all_data
94            .into_iter()
95            .map(|data| Self::random_with(&mut rng, data))
96            .collect()
97    }
98}
99
100impl<D: Clone, T: RandomWith<D>> RandomWith<Vec<D>> for Vec<T> {
101    /// Generates a container with an element of T for each element in `data`,
102    /// yielding a container of `[data.len()]` length.
103    #[inline]
104    fn random_with(mut source: impl CryptoRngCore, data: Vec<D>) -> Self {
105        T::random_n_with_each(&mut source, data)
106    }
107
108    /// Generates `size` instances of T for each element in `data.len()`,
109    /// yielding a container of `[data.len()][size]` dimensions.
110    #[inline]
111    fn random_n_with<Container: FromIterator<Self>>(
112        mut rng: impl CryptoRngCore,
113        size: usize,
114        data: Vec<D>,
115    ) -> Container {
116        let mut res = (0..data.len())
117            .map(|_| Vec::<T>::with_capacity(size))
118            .collect::<Vec<_>>();
119        for _ in 0..size {
120            let row: Vec<_> = T::random_n_with_each(&mut rng, data.clone());
121            for (res_row, item) in res.iter_mut().zip(row) {
122                res_row.push(item);
123            }
124        }
125        res.into_iter().collect()
126    }
127}
128
129/// Generate random non-zero values.
130pub trait RandomNonZero: Sized {
131    // Generates a non-zero element.
132    fn random_non_zero(rng: impl CryptoRngCore) -> Result<Self, PrimitiveError>;
133
134    // Generates a container with `size` random non-zero elements.
135    fn random_n_non_zero<Container: FromIterator<Self>>(
136        mut rng: impl CryptoRngCore,
137        size: usize,
138    ) -> Result<Container, PrimitiveError> {
139        (0..size).map(|_| Self::random_non_zero(&mut rng)).collect()
140    }
141}
142
143impl<T: FieldExtension> RandomNonZero for T {
144    /// Generates a random non-zero value.
145    ///
146    /// May error out if it cannot find a non-zero value after a certain number
147    /// of tries, defined so that:
148    ///
149    /// > `Prob(out == 0) <= 2^-(λ)` as long as `Prob(random()==0) <= 2^-(size_of::<Self>)`
150    ///
151    /// The default implementation repetitively calls `random()` (rejection sampling).
152    /// As such, it is not constant-time, but the side channel leakage should not impact security
153    /// as long as the rng is evaluated in constant time and produces uniformly random values.
154    ///
155    /// If needed, override with a constant-time implementation using `ConditionallySelectable` and
156    /// always running for a fixed number of iterations, potentially returning a zero value
157    /// (with overwhelmingly low probability).
158    #[inline]
159    fn random_non_zero(mut rng: impl CryptoRngCore) -> Result<Self, PrimitiveError> {
160        let n_tries = (Lambda::USIZE).div_ceil(std::mem::size_of::<Self>()) + 1;
161        for _ in 0..n_tries {
162            let value = <Self as ff::Field>::random(&mut rng);
163            if !<Choice as Into<bool>>::into(value.is_zero()) {
164                return Ok(value);
165            }
166        }
167        Err(PrimitiveError::ZeroValueSampled(
168            std::any::type_name::<Self>().into(),
169        ))
170    }
171}
172
173impl Random for u8 {
174    #[inline]
175    fn random(mut rng: impl CryptoRngCore) -> Self {
176        let mut buf = [0u8; 1];
177        rng.fill_bytes(&mut buf);
178        buf[0]
179    }
180
181    fn random_n<Container: FromIterator<Self>>(
182        mut rng: impl CryptoRngCore,
183        size: usize,
184    ) -> Container {
185        let mut buf = vec![0u8; size];
186        rng.fill_bytes(&mut buf);
187        buf.into_iter().collect()
188    }
189}
190
191impl Random for usize {
192    #[inline]
193    fn random(mut rng: impl CryptoRngCore) -> Self {
194        let mut buf = [0u8; std::mem::size_of::<usize>()];
195        rng.fill_bytes(&mut buf);
196        usize::from_le_bytes(buf)
197    }
198
199    fn random_n<Container: FromIterator<Self>>(
200        mut rng: impl CryptoRngCore,
201        size: usize,
202    ) -> Container {
203        let mut buf = vec![0u8; size * std::mem::size_of::<usize>()];
204        rng.fill_bytes(&mut buf);
205        buf.chunks_exact(std::mem::size_of::<usize>())
206            .map(|chunk| usize::from_le_bytes(chunk.try_into().unwrap()))
207            .collect()
208    }
209}