use rand::Rng;
use crate::{Felt, Word};
mod coin;
pub use coin::RandomCoin;
#[cfg(any(test, feature = "std"))]
pub mod test_utils;
pub trait Randomizable: Sized {
const VALUE_SIZE: usize;
fn from_random_bytes(source: &[u8]) -> Option<Self>;
}
impl Randomizable for u128 {
const VALUE_SIZE: usize = 16;
fn from_random_bytes(source: &[u8]) -> Option<Self> {
let bytes = source.get(..Self::VALUE_SIZE)?.try_into().ok()?;
Some(u128::from_le_bytes(bytes))
}
}
impl Randomizable for u64 {
const VALUE_SIZE: usize = 8;
fn from_random_bytes(source: &[u8]) -> Option<Self> {
let bytes = source.get(..Self::VALUE_SIZE)?.try_into().ok()?;
Some(u64::from_le_bytes(bytes))
}
}
impl Randomizable for u32 {
const VALUE_SIZE: usize = 4;
fn from_random_bytes(source: &[u8]) -> Option<Self> {
let bytes = source.get(..Self::VALUE_SIZE)?.try_into().ok()?;
Some(u32::from_le_bytes(bytes))
}
}
impl Randomizable for u16 {
const VALUE_SIZE: usize = 2;
fn from_random_bytes(source: &[u8]) -> Option<Self> {
let bytes = source.get(..Self::VALUE_SIZE)?.try_into().ok()?;
Some(u16::from_le_bytes(bytes))
}
}
impl Randomizable for u8 {
const VALUE_SIZE: usize = 1;
fn from_random_bytes(source: &[u8]) -> Option<Self> {
source.first().copied()
}
}
impl Randomizable for Felt {
const VALUE_SIZE: usize = 8;
fn from_random_bytes(source: &[u8]) -> Option<Self> {
let bytes = source.get(..Self::VALUE_SIZE)?.try_into().ok()?;
let value = u64::from_le_bytes(bytes);
if value < Felt::ORDER {
Some(Felt::new_unchecked(value))
} else {
None
}
}
}
impl Randomizable for Word {
const VALUE_SIZE: usize = Word::SERIALIZED_SIZE;
fn from_random_bytes(bytes: &[u8]) -> Option<Self> {
let bytes_array: [u8; 32] = bytes.get(..Self::VALUE_SIZE)?.try_into().ok()?;
Self::try_from(bytes_array).ok()
}
}
impl<const N: usize> Randomizable for [u8; N] {
const VALUE_SIZE: usize = N;
fn from_random_bytes(source: &[u8]) -> Option<Self> {
source.get(..N)?.try_into().ok()
}
}
pub trait FeltRng: Rng {
fn draw_element(&mut self) -> Felt;
fn draw_word(&mut self) -> Word;
}
#[cfg(feature = "std")]
pub fn random_felt() -> Felt {
use rand::RngExt;
let mut rng = rand::rng();
loop {
if let Ok(felt) = Felt::new(rng.random::<u64>()) {
return felt;
}
}
}
#[cfg(feature = "std")]
pub fn random_word() -> Word {
Word::new([random_felt(), random_felt(), random_felt(), random_felt()])
}
#[cfg(test)]
mod tests {
use super::Randomizable;
use crate::{Felt, Word};
#[test]
fn randomizable_short_inputs_return_none() {
assert!(u128::from_random_bytes(&[0; 15]).is_none());
assert!(u64::from_random_bytes(&[0; 7]).is_none());
assert!(u32::from_random_bytes(&[0; 3]).is_none());
assert!(u16::from_random_bytes(&[0; 1]).is_none());
assert!(u8::from_random_bytes(&[]).is_none());
assert!(Felt::from_random_bytes(&[0; 7]).is_none());
assert!(Word::from_random_bytes(&[0; 31]).is_none());
assert!(<[u8; 4]>::from_random_bytes(&[0; 3]).is_none());
}
}