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