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}