Skip to main content

miden_crypto/rand/
mod.rs

1//! Pseudo-random element generation.
2
3use rand::RngCore;
4
5use crate::{Felt, Word};
6
7mod coin;
8pub use coin::RandomCoin;
9
10// Test utilities for generating random data (used in tests and benchmarks)
11#[cfg(any(test, feature = "std"))]
12pub mod test_utils;
13
14// RANDOMNESS (ported from Winterfell's winter-utils)
15// ================================================================================================
16
17/// Defines how `Self` can be read from a sequence of random bytes.
18pub trait Randomizable: Sized {
19    /// Size of `Self` in bytes.
20    ///
21    /// This is used to determine how many bytes should be passed to the
22    /// [from_random_bytes()](Self::from_random_bytes) function.
23    const VALUE_SIZE: usize;
24
25    /// Returns `Self` if the set of bytes forms a valid value, otherwise returns None.
26    fn from_random_bytes(source: &[u8]) -> Option<Self>;
27}
28
29impl Randomizable for u128 {
30    const VALUE_SIZE: usize = 16;
31
32    fn from_random_bytes(source: &[u8]) -> Option<Self> {
33        if let Ok(bytes) = source[..Self::VALUE_SIZE].try_into() {
34            Some(u128::from_le_bytes(bytes))
35        } else {
36            None
37        }
38    }
39}
40
41impl Randomizable for u64 {
42    const VALUE_SIZE: usize = 8;
43
44    fn from_random_bytes(source: &[u8]) -> Option<Self> {
45        if let Ok(bytes) = source[..Self::VALUE_SIZE].try_into() {
46            Some(u64::from_le_bytes(bytes))
47        } else {
48            None
49        }
50    }
51}
52
53impl Randomizable for u32 {
54    const VALUE_SIZE: usize = 4;
55
56    fn from_random_bytes(source: &[u8]) -> Option<Self> {
57        if let Ok(bytes) = source[..Self::VALUE_SIZE].try_into() {
58            Some(u32::from_le_bytes(bytes))
59        } else {
60            None
61        }
62    }
63}
64
65impl Randomizable for u16 {
66    const VALUE_SIZE: usize = 2;
67
68    fn from_random_bytes(source: &[u8]) -> Option<Self> {
69        if let Ok(bytes) = source[..Self::VALUE_SIZE].try_into() {
70            Some(u16::from_le_bytes(bytes))
71        } else {
72            None
73        }
74    }
75}
76
77impl Randomizable for u8 {
78    const VALUE_SIZE: usize = 1;
79
80    fn from_random_bytes(source: &[u8]) -> Option<Self> {
81        Some(source[0])
82    }
83}
84
85impl Randomizable for Felt {
86    const VALUE_SIZE: usize = 8;
87
88    fn from_random_bytes(source: &[u8]) -> Option<Self> {
89        if let Ok(bytes) = source[..Self::VALUE_SIZE].try_into() {
90            let value = u64::from_le_bytes(bytes);
91            // Ensure the value is within the field modulus
92            if value < Felt::ORDER {
93                Some(Felt::new_unchecked(value))
94            } else {
95                None
96            }
97        } else {
98            None
99        }
100    }
101}
102
103impl Randomizable for Word {
104    const VALUE_SIZE: usize = Word::SERIALIZED_SIZE;
105
106    fn from_random_bytes(bytes: &[u8]) -> Option<Self> {
107        let bytes_array: Option<[u8; 32]> = bytes.try_into().ok();
108        if let Some(bytes_array) = bytes_array {
109            Self::try_from(bytes_array).ok()
110        } else {
111            None
112        }
113    }
114}
115
116impl<const N: usize> Randomizable for [u8; N] {
117    const VALUE_SIZE: usize = N;
118
119    fn from_random_bytes(source: &[u8]) -> Option<Self> {
120        let mut result = [Default::default(); N];
121        result.copy_from_slice(source);
122
123        Some(result)
124    }
125}
126
127/// Pseudo-random element generator.
128///
129/// An instance can be used to draw, uniformly at random, base field elements as well as [Word]s.
130pub trait FeltRng: RngCore {
131    /// Draw, uniformly at random, a base field element.
132    fn draw_element(&mut self) -> Felt;
133
134    /// Draw, uniformly at random, a [Word].
135    fn draw_word(&mut self) -> Word;
136}
137
138// RANDOM VALUE GENERATION FOR TESTING
139// ================================================================================================
140
141/// Generates a random field element for testing purposes.
142///
143/// This function is only available with the `std` feature.
144#[cfg(feature = "std")]
145pub fn random_felt() -> Felt {
146    use rand::Rng;
147    let mut rng = rand::rng();
148    // We use the `Felt::new` constructor to do rejection sampling here. It should effectively
149    // never repeat, but nevertheless gives us the correct distribution.
150    loop {
151        if let Ok(felt) = Felt::new(rng.random::<u64>()) {
152            return felt;
153        }
154    }
155}
156
157/// Generates a random word (4 field elements) for testing purposes.
158///
159/// This function is only available with the `std` feature.
160#[cfg(feature = "std")]
161pub fn random_word() -> Word {
162    Word::new([random_felt(), random_felt(), random_felt(), random_felt()])
163}