miden_crypto/rand/test_utils.rs
1//! Test and benchmark utilities for generating random data.
2//!
3//! This module provides helper functions for tests and benchmarks that need
4//! random data generation. These functions replace the functionality previously
5//! provided by winter-rand-utils.
6//!
7//! # no_std Compatibility
8//!
9//! This module provides both `std`-dependent and `no_std`-compatible functions:
10//!
11//! - **`std` required**: [`rand_value`], [`rand_array`], [`rand_vector`] use the thread-local RNG
12//! and require the `std` feature.
13//! - **`no_std` compatible**: [`seeded_rng`], [`prng_array`], [`prng_vector`] use deterministic
14//! seeded PRNGs and work in `no_std` environments.
15//!
16//! For tests that should run in `no_std` mode, prefer using [`seeded_rng`] to obtain
17//! a deterministic RNG instead of `rand::rng()`.
18
19use alloc::{vec, vec::Vec};
20
21use rand::{Rng, SeedableRng};
22use rand_chacha::ChaCha20Rng;
23
24use crate::rand::Randomizable;
25
26/// Creates a deterministic seeded RNG suitable for tests.
27///
28/// This function returns a ChaCha20 PRNG seeded with the provided seed, providing
29/// deterministic random number generation that works in `no_std` environments.
30///
31/// # Examples
32/// ```
33/// # use miden_crypto::rand::test_utils::seeded_rng;
34/// let mut rng = seeded_rng([0u8; 32]);
35/// // Use rng with any function that accepts impl RngCore
36/// ```
37pub fn seeded_rng(seed: [u8; 32]) -> ChaCha20Rng {
38 ChaCha20Rng::from_seed(seed)
39}
40
41/// Generates a random value of type T from an RNG.
42fn rng_value<T: Randomizable>(rng: &mut impl Rng) -> T {
43 let mut bytes = vec![0u8; T::VALUE_SIZE];
44 rng.fill(&mut bytes[..]);
45 T::from_random_bytes(&bytes).expect("failed to generate random value")
46}
47
48/// Generates a random value of type T using the thread-local random number generator.
49///
50/// # Examples
51/// ```
52/// # use miden_crypto::rand::test_utils::rand_value;
53/// let x: u64 = rand_value();
54/// let y: u128 = rand_value();
55/// ```
56#[cfg(feature = "std")]
57pub fn rand_value<T: Randomizable>() -> T {
58 rng_value(&mut rand::rng())
59}
60
61/// Generates a deterministic value of type `T` in `no_std` builds.
62///
63/// This keeps tests and feature-matrix checks buildable without relying on
64/// thread-local RNG support.
65#[cfg(not(feature = "std"))]
66pub fn rand_value<T: Randomizable>() -> T {
67 prng_value([0u8; 32])
68}
69
70/// Generates a random array of type T with N elements.
71///
72/// # Examples
73/// ```
74/// # use miden_crypto::rand::test_utils::rand_array;
75/// let arr: [u64; 4] = rand_array();
76/// ```
77#[cfg(feature = "std")]
78pub fn rand_array<T: Randomizable, const N: usize>() -> [T; N] {
79 let mut rng = rand::rng();
80 core::array::from_fn(|_| rng_value(&mut rng))
81}
82
83/// Generates a random vector of type T with the specified length.
84///
85/// # Examples
86/// ```
87/// # use miden_crypto::rand::test_utils::rand_vector;
88/// let vec: Vec<u64> = rand_vector(100);
89/// ```
90#[cfg(feature = "std")]
91pub fn rand_vector<T: Randomizable>(length: usize) -> Vec<T> {
92 let mut rng = rand::rng();
93 (0..length).map(|_| rng_value(&mut rng)).collect()
94}
95
96/// Generates a deterministic value using a PRNG seeded with the provided seed.
97///
98/// This function uses ChaCha20 PRNG for deterministic random generation, which is
99/// useful for reproducible tests and benchmarks.
100///
101/// # Examples
102/// ```
103/// # use miden_crypto::rand::test_utils::prng_value;
104/// let seed = [0u8; 32];
105/// let val: u64 = prng_value(seed);
106/// ```
107pub fn prng_value<T: Randomizable>(seed: [u8; 32]) -> T {
108 rng_value(&mut seeded_rng(seed))
109}
110
111/// Generates a deterministic array using a PRNG seeded with the provided seed.
112///
113/// # Examples
114/// ```
115/// # use miden_crypto::rand::test_utils::prng_array;
116/// let seed = [0u8; 32];
117/// let arr: [u64; 4] = prng_array(seed);
118/// ```
119pub fn prng_array<T: Randomizable, const N: usize>(seed: [u8; 32]) -> [T; N] {
120 let mut rng = seeded_rng(seed);
121 core::array::from_fn(|_| rng_value(&mut rng))
122}
123
124/// Generates a deterministic vector using a PRNG seeded with the provided seed.
125///
126/// # Examples
127/// ```
128/// # use miden_crypto::rand::test_utils::prng_vector;
129/// let seed = [0u8; 32];
130/// let vec: Vec<u64> = prng_vector(seed, 100);
131/// ```
132pub fn prng_vector<T: Randomizable>(seed: [u8; 32], length: usize) -> Vec<T> {
133 let mut rng = seeded_rng(seed);
134 (0..length).map(|_| rng_value(&mut rng)).collect()
135}
136
137// CONTINUOUS RNG
138// ================================================================================================
139
140/// A continuous random number generator that works in `no-std` contexts.
141#[derive(Debug)]
142pub struct ContinuousRng {
143 rng: ChaCha20Rng,
144}
145impl ContinuousRng {
146 /// Creates a new instance of the random number generator from the seed.
147 pub fn new(seed: [u8; 32]) -> ContinuousRng {
148 ContinuousRng { rng: ChaCha20Rng::from_seed(seed) }
149 }
150
151 /// Generates a random value of the [`Randomizable`] type `T`.
152 pub fn value<T: Randomizable>(&mut self) -> T {
153 rng_value(&mut self.rng)
154 }
155}