use core::ops::Range;
use num_traits::{Bounded, PrimInt, Unsigned};
use rand_core::{CryptoRng, RngCore};
#[inline]
pub fn rand_bytes(out: &mut [u8]) {
unsafe {
ledger_secure_sdk_sys::cx_rng_no_throw(out.as_mut_ptr(), out.len());
}
}
pub trait Random
where
Self: PrimInt + Unsigned + Bounded,
{
fn random() -> Self;
fn random_from_range(range: Range<Self>) -> Self {
assert!(range.end > range.start, "Invalid range");
let width = range.end - range.start;
if width & (width - Self::one()) == Self::zero() {
range.start + Self::random() % width
} else {
let chunk_size = Self::max_value() / width;
let last_chunk_value = chunk_size * width;
let mut r = Self::random();
while r >= last_chunk_value {
r = Self::random();
}
range.start + r / chunk_size
}
}
}
impl Random for u8 {
fn random() -> Self {
let mut r = [0u8; 1];
rand_bytes(&mut r);
r[0]
}
}
impl Random for u32 {
fn random() -> Self {
let mut r = [0u8; 4];
rand_bytes(&mut r);
u32::from_be_bytes(r)
}
}
#[derive(Copy, Clone, Debug)]
pub struct LedgerRng;
impl RngCore for LedgerRng {
#[inline]
fn next_u32(&mut self) -> u32 {
let mut b = [0u8; 4];
rand_bytes(&mut b);
u32::from_be_bytes(b)
}
#[inline]
fn next_u64(&mut self) -> u64 {
let mut b = [0u8; 8];
rand_bytes(&mut b);
u64::from_be_bytes(b)
}
#[inline]
fn fill_bytes(&mut self, dest: &mut [u8]) {
rand_bytes(dest);
}
#[inline]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
self.fill_bytes(dest);
Ok(())
}
}
impl CryptoRng for LedgerRng {}
#[cfg(test)]
mod tests {
use super::*;
use crate::assert_eq_err as assert_eq;
use crate::testing::TestType;
use testmacro::test_item as test;
#[test]
fn rng() {
let r: [u8; 16] = core::array::from_fn(|_| u8::random());
assert_eq!(u128::from_be_bytes(r) != 0, true);
}
}