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}