winter_rand_utils/
lib.rs

1// Copyright (c) Facebook, Inc. and its affiliates.
2//
3// This source code is licensed under the MIT license found in the
4// LICENSE file in the root directory of this source tree.
5
6//! This crates contains functions for generating random values.
7//!
8//! These functions are intended to be used in tests, benchmarks, and examples. When compiled to
9//! WebAssembly target, all of the functions are omitted.
10
11pub use internal::*;
12
13#[cfg(not(target_family = "wasm"))]
14mod internal {
15    use core::fmt::Debug;
16
17    use rand::prelude::*;
18    use utils::Randomizable;
19
20    // RANDOM VALUE GENERATION
21    // ============================================================================================
22
23    /// Returns a single random value of the specified type.
24    ///
25    /// # Panics
26    /// Panics if:
27    /// * A valid value requires over 32 bytes.
28    /// * A valid value could not be generated after 1000 tries.
29    pub fn rand_value<R: Randomizable>() -> R {
30        for _ in 0..1000 {
31            let bytes = rand::rng().random::<[u8; 32]>();
32            if let Some(value) = R::from_random_bytes(&bytes[..R::VALUE_SIZE]) {
33                return value;
34            }
35        }
36
37        panic!("failed generate a random field element");
38    }
39
40    /// Returns a vector of random value of the specified type and the specified length.
41    ///
42    /// # Panics
43    /// Panics if:
44    /// * A valid value requires at over 32 bytes.
45    /// * A valid value could not be generated after 1000 tries.
46    pub fn rand_vector<R: Randomizable>(n: usize) -> Vec<R> {
47        if n == 0 {
48            return Vec::new();
49        }
50        let mut result = Vec::with_capacity(n);
51        let seed = rand::rng().random::<[u8; 32]>();
52        let mut g = StdRng::from_seed(seed);
53        for _ in 0..1000 * n {
54            let bytes = g.random::<[u8; 32]>();
55            if let Some(element) = R::from_random_bytes(&bytes[..R::VALUE_SIZE]) {
56                result.push(element);
57                if result.len() == n {
58                    return result;
59                }
60            }
61        }
62
63        panic!("failed to generate enough random field elements");
64    }
65
66    /// Returns an array of random value of the specified type and the specified length.
67    ///
68    /// # Panics
69    /// Panics if:
70    /// * A valid value requires at over 32 bytes.
71    /// * A valid value could not be generated after 1000 tries.
72    pub fn rand_array<R: Randomizable + Debug, const N: usize>() -> [R; N] {
73        let elements = rand_vector(N);
74        elements.try_into().expect("failed to convert vector to array")
75    }
76
77    /// Returns a vector of value of the specified type and the specified length generated
78    /// pseudo-randomly from the specified `seed`.
79    ///
80    /// # Panics
81    /// Panics if:
82    /// * A valid value requires at over 32 bytes.
83    /// * A valid value could not be generated after 1000 tries.
84    pub fn prng_vector<R: Randomizable>(seed: [u8; 32], n: usize) -> Vec<R> {
85        let mut result = Vec::with_capacity(n);
86        let mut g = StdRng::from_seed(seed);
87        for _ in 0..1000 * n {
88            let bytes = g.random::<[u8; 32]>();
89            if let Some(element) = R::from_random_bytes(&bytes[..R::VALUE_SIZE]) {
90                result.push(element);
91                if result.len() == n {
92                    return result;
93                }
94            }
95        }
96
97        panic!("failed to generate enough random field elements");
98    }
99
100    /// Returns an array of value of the specified type and the specified length generated
101    /// pseudo-randomly from the specified `seed`.
102    ///
103    /// # Panics
104    /// Panics if:
105    /// * A valid value requires at over 32 bytes.
106    /// * A valid value could not be generated after 1000 tries.
107    pub fn prng_array<R: Randomizable + Debug, const N: usize>(seed: [u8; 32]) -> [R; N] {
108        let elements = prng_vector(seed, N);
109        elements.try_into().expect("failed to convert vector to array")
110    }
111
112    // SHUFFLING
113    // ============================================================================================
114
115    /// Randomly shuffles slice elements.
116    pub fn shuffle<T>(values: &mut [T]) {
117        values.shuffle(&mut rand::rng());
118    }
119}
120
121#[cfg(target_family = "wasm")]
122mod internal {}
123
124// TESTS
125// ================================================================================================
126
127#[cfg(test)]
128mod tests {
129    use super::{rand_array, rand_value};
130
131    #[test]
132    fn rand_primitives() {
133        let a = rand_value::<u16>();
134        let b = rand_value::<u16>();
135        assert_ne!(a, b);
136
137        let a = rand_value::<u32>();
138        let b = rand_value::<u32>();
139        assert_ne!(a, b);
140
141        let a = rand_value::<u64>();
142        let b = rand_value::<u64>();
143        assert_ne!(a, b);
144
145        let a = rand_value::<u128>();
146        let b = rand_value::<u128>();
147        assert_ne!(a, b);
148    }
149
150    #[test]
151    fn rand_byte_array() {
152        let a = rand_array::<u8, 30>();
153        let b = rand_array::<u8, 30>();
154        assert_ne!(a, b);
155
156        let a = rand_array::<u8, 32>();
157        let b = rand_array::<u8, 32>();
158        assert_ne!(a, b);
159
160        let a = rand_array::<u8, 34>();
161        let b = rand_array::<u8, 34>();
162        assert_ne!(a, b);
163    }
164}