use crate::int::Int;
use crate::nat::Nat;
pub trait RandomSource {
fn fill_bytes(&mut self, dest: &mut [u8]);
}
#[cfg(feature = "rand")]
impl<R: rand_core::RngCore> RandomSource for R {
#[inline]
fn fill_bytes(&mut self, dest: &mut [u8]) {
rand_core::RngCore::fill_bytes(self, dest);
}
}
impl Nat {
pub fn random_bits(bits: u64, src: &mut impl RandomSource) -> Nat {
if bits == 0 {
return Nat::zero();
}
let nbytes = bits.div_ceil(8) as usize;
let mut buf = alloc::vec![0u8; nbytes];
src.fill_bytes(&mut buf);
let rem = (bits % 8) as u32;
if rem != 0 {
buf[nbytes - 1] &= (1u8 << rem) - 1;
}
Nat::from_bytes_le(&buf)
}
pub fn random_below(bound: &Nat, src: &mut impl RandomSource) -> Option<Nat> {
if bound.is_zero() {
return None;
}
let bits = bound.bit_len();
loop {
let candidate = Nat::random_bits(bits, src);
if &candidate < bound {
return Some(candidate);
}
}
}
}
impl Int {
pub fn random_below(bound: &Int, src: &mut impl RandomSource) -> Option<Int> {
if !bound.is_positive() {
return None;
}
let magnitude = bound.magnitude();
Nat::random_below(&magnitude, src).map(Int::from)
}
}