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        let mut result = Vec::with_capacity(n);
48        let seed = rand::rng().random::<[u8; 32]>();
49        let mut g = StdRng::from_seed(seed);
50        for _ in 0..1000 * n {
51            let bytes = g.random::<[u8; 32]>();
52            if let Some(element) = R::from_random_bytes(&bytes[..R::VALUE_SIZE]) {
53                result.push(element);
54                if result.len() == n {
55                    return result;
56                }
57            }
58        }
59
60        panic!("failed to generate enough random field elements");
61    }
62
63    /// Returns an array of random value of the specified type and the specified length.
64    ///
65    /// # Panics
66    /// Panics if:
67    /// * A valid value requires at over 32 bytes.
68    /// * A valid value could not be generated after 1000 tries.
69    pub fn rand_array<R: Randomizable + Debug, const N: usize>() -> [R; N] {
70        let elements = rand_vector(N);
71        elements.try_into().expect("failed to convert vector to array")
72    }
73
74    /// Returns a vector of value of the specified type and the specified length generated
75    /// pseudo-randomly from the specified `seed`.
76    ///
77    /// # Panics
78    /// Panics if:
79    /// * A valid value requires at over 32 bytes.
80    /// * A valid value could not be generated after 1000 tries.
81    pub fn prng_vector<R: Randomizable>(seed: [u8; 32], n: usize) -> Vec<R> {
82        let mut result = Vec::with_capacity(n);
83        let mut g = StdRng::from_seed(seed);
84        for _ in 0..1000 * n {
85            let bytes = g.random::<[u8; 32]>();
86            if let Some(element) = R::from_random_bytes(&bytes[..R::VALUE_SIZE]) {
87                result.push(element);
88                if result.len() == n {
89                    return result;
90                }
91            }
92        }
93
94        panic!("failed to generate enough random field elements");
95    }
96
97    /// Returns an array of value of the specified type and the specified length generated
98    /// pseudo-randomly from the specified `seed`.
99    ///
100    /// # Panics
101    /// Panics if:
102    /// * A valid value requires at over 32 bytes.
103    /// * A valid value could not be generated after 1000 tries.
104    pub fn prng_array<R: Randomizable + Debug, const N: usize>(seed: [u8; 32]) -> [R; N] {
105        let elements = prng_vector(seed, N);
106        elements.try_into().expect("failed to convert vector to array")
107    }
108
109    // SHUFFLING
110    // ============================================================================================
111
112    /// Randomly shuffles slice elements.
113    pub fn shuffle<T>(values: &mut [T]) {
114        values.shuffle(&mut rand::rng());
115    }
116}
117
118#[cfg(target_family = "wasm")]
119mod internal {}
120
121// TESTS
122// ================================================================================================
123
124#[cfg(test)]
125mod tests {
126    use super::{rand_array, rand_value};
127
128    #[test]
129    fn rand_primitives() {
130        let a = rand_value::<u16>();
131        let b = rand_value::<u16>();
132        assert_ne!(a, b);
133
134        let a = rand_value::<u32>();
135        let b = rand_value::<u32>();
136        assert_ne!(a, b);
137
138        let a = rand_value::<u64>();
139        let b = rand_value::<u64>();
140        assert_ne!(a, b);
141
142        let a = rand_value::<u128>();
143        let b = rand_value::<u128>();
144        assert_ne!(a, b);
145    }
146
147    #[test]
148    fn rand_byte_array() {
149        let a = rand_array::<u8, 30>();
150        let b = rand_array::<u8, 30>();
151        assert_ne!(a, b);
152
153        let a = rand_array::<u8, 32>();
154        let b = rand_array::<u8, 32>();
155        assert_ne!(a, b);
156
157        let a = rand_array::<u8, 34>();
158        let b = rand_array::<u8, 34>();
159        assert_ne!(a, b);
160    }
161}