Skip to main content

miden_crypto/rand/
mod.rs

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