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