1use rand::Rng;
4
5use crate::{Felt, Word};
6
7mod coin;
8pub use coin::RandomCoin;
9
10mod eidos_coin;
11pub use eidos_coin::EidosRandomCoin;
12
13#[cfg(any(test, feature = "std"))]
15pub mod test_utils;
16
17pub trait Randomizable: Sized {
22 const VALUE_SIZE: usize;
27
28 fn from_random_bytes(source: &[u8]) -> Option<Self>;
30}
31
32impl Randomizable for u128 {
33 const VALUE_SIZE: usize = 16;
34
35 fn from_random_bytes(source: &[u8]) -> Option<Self> {
36 let bytes = source.get(..Self::VALUE_SIZE)?.try_into().ok()?;
37 Some(u128::from_le_bytes(bytes))
38 }
39}
40
41impl Randomizable for u64 {
42 const VALUE_SIZE: usize = 8;
43
44 fn from_random_bytes(source: &[u8]) -> Option<Self> {
45 let bytes = source.get(..Self::VALUE_SIZE)?.try_into().ok()?;
46 Some(u64::from_le_bytes(bytes))
47 }
48}
49
50impl Randomizable for u32 {
51 const VALUE_SIZE: usize = 4;
52
53 fn from_random_bytes(source: &[u8]) -> Option<Self> {
54 let bytes = source.get(..Self::VALUE_SIZE)?.try_into().ok()?;
55 Some(u32::from_le_bytes(bytes))
56 }
57}
58
59impl Randomizable for u16 {
60 const VALUE_SIZE: usize = 2;
61
62 fn from_random_bytes(source: &[u8]) -> Option<Self> {
63 let bytes = source.get(..Self::VALUE_SIZE)?.try_into().ok()?;
64 Some(u16::from_le_bytes(bytes))
65 }
66}
67
68impl Randomizable for u8 {
69 const VALUE_SIZE: usize = 1;
70
71 fn from_random_bytes(source: &[u8]) -> Option<Self> {
72 source.first().copied()
73 }
74}
75
76impl Randomizable for Felt {
77 const VALUE_SIZE: usize = 8;
78
79 fn from_random_bytes(source: &[u8]) -> Option<Self> {
80 let bytes = source.get(..Self::VALUE_SIZE)?.try_into().ok()?;
81 let value = u64::from_le_bytes(bytes);
82 if value < Felt::ORDER {
84 Some(Felt::new_unchecked(value))
85 } else {
86 None
87 }
88 }
89}
90
91impl Randomizable for Word {
92 const VALUE_SIZE: usize = Word::SERIALIZED_SIZE;
93
94 fn from_random_bytes(bytes: &[u8]) -> Option<Self> {
95 let bytes_array: [u8; 32] = bytes.get(..Self::VALUE_SIZE)?.try_into().ok()?;
96 Self::try_from(bytes_array).ok()
97 }
98}
99
100impl<const N: usize> Randomizable for [u8; N] {
101 const VALUE_SIZE: usize = N;
102
103 fn from_random_bytes(source: &[u8]) -> Option<Self> {
104 source.get(..N)?.try_into().ok()
105 }
106}
107
108pub trait FeltRng: Rng {
112 fn draw_element(&mut self) -> Felt;
114
115 fn draw_word(&mut self) -> Word;
117}
118
119#[cfg(feature = "std")]
126pub fn random_felt() -> Felt {
127 use rand::RngExt;
128 let mut rng = rand::rng();
129 loop {
132 if let Ok(felt) = Felt::new(rng.random::<u64>()) {
133 return felt;
134 }
135 }
136}
137
138#[cfg(feature = "std")]
142pub fn random_word() -> Word {
143 Word::new([random_felt(), random_felt(), random_felt(), random_felt()])
144}
145
146#[cfg(test)]
147mod tests {
148 use super::Randomizable;
149 use crate::{Felt, Word};
150
151 #[test]
152 fn randomizable_short_inputs_return_none() {
153 assert!(u128::from_random_bytes(&[0; 15]).is_none());
154 assert!(u64::from_random_bytes(&[0; 7]).is_none());
155 assert!(u32::from_random_bytes(&[0; 3]).is_none());
156 assert!(u16::from_random_bytes(&[0; 1]).is_none());
157 assert!(u8::from_random_bytes(&[]).is_none());
158 assert!(Felt::from_random_bytes(&[0; 7]).is_none());
159 assert!(Word::from_random_bytes(&[0; 31]).is_none());
160 assert!(<[u8; 4]>::from_random_bytes(&[0; 3]).is_none());
161 }
162}