Skip to main content

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/// ```
56pub fn rand_value<T: Randomizable>() -> T {
57    rng_value(&mut rand::rng())
58}
59
60/// Generates a random array of type T with N elements.
61///
62/// # Examples
63/// ```
64/// # use miden_crypto::rand::test_utils::rand_array;
65/// let arr: [u64; 4] = rand_array();
66/// ```
67#[cfg(feature = "std")]
68pub fn rand_array<T: Randomizable, const N: usize>() -> [T; N] {
69    let mut rng = rand::rng();
70    core::array::from_fn(|_| rng_value(&mut rng))
71}
72
73/// Generates a random vector of type T with the specified length.
74///
75/// # Examples
76/// ```
77/// # use miden_crypto::rand::test_utils::rand_vector;
78/// let vec: Vec<u64> = rand_vector(100);
79/// ```
80#[cfg(feature = "std")]
81pub fn rand_vector<T: Randomizable>(length: usize) -> Vec<T> {
82    let mut rng = rand::rng();
83    (0..length).map(|_| rng_value(&mut rng)).collect()
84}
85
86/// Generates a deterministic value using a PRNG seeded with the provided seed.
87///
88/// This function uses ChaCha20 PRNG for deterministic random generation, which is
89/// useful for reproducible tests and benchmarks.
90///
91/// # Examples
92/// ```
93/// # use miden_crypto::rand::test_utils::prng_value;
94/// let seed = [0u8; 32];
95/// let val: u64 = prng_value(seed);
96/// ```
97pub fn prng_value<T: Randomizable>(seed: [u8; 32]) -> T {
98    rng_value(&mut seeded_rng(seed))
99}
100
101/// Generates a deterministic array using a PRNG seeded with the provided seed.
102///
103/// # Examples
104/// ```
105/// # use miden_crypto::rand::test_utils::prng_array;
106/// let seed = [0u8; 32];
107/// let arr: [u64; 4] = prng_array(seed);
108/// ```
109pub fn prng_array<T: Randomizable, const N: usize>(seed: [u8; 32]) -> [T; N] {
110    let mut rng = seeded_rng(seed);
111    core::array::from_fn(|_| rng_value(&mut rng))
112}
113
114/// Generates a deterministic vector using a PRNG seeded with the provided seed.
115///
116/// # Examples
117/// ```
118/// # use miden_crypto::rand::test_utils::prng_vector;
119/// let seed = [0u8; 32];
120/// let vec: Vec<u64> = prng_vector(seed, 100);
121/// ```
122pub fn prng_vector<T: Randomizable>(seed: [u8; 32], length: usize) -> Vec<T> {
123    let mut rng = seeded_rng(seed);
124    (0..length).map(|_| rng_value(&mut rng)).collect()
125}
126
127// CONTINUOUS RNG
128// ================================================================================================
129
130/// A continuous random number generator that works in `no-std` contexts.
131#[derive(Debug)]
132pub struct ContinuousRng {
133    rng: ChaCha20Rng,
134}
135impl ContinuousRng {
136    /// Creates a new instance of the random number generator from the seed.
137    pub fn new(seed: [u8; 32]) -> ContinuousRng {
138        ContinuousRng { rng: ChaCha20Rng::from_seed(seed) }
139    }
140
141    /// Generates a random value of the [`Randomizable`] type `T`.
142    pub fn value<T: Randomizable>(&mut self) -> T {
143        rng_value(&mut self.rng)
144    }
145}