use num_bigint::BigUint;
use num_integer::Integer;
use num_traits::{ToPrimitive, Zero};
use rand::distr::uniform::Error;
use rand::Rng;
fn random_bits<R>(rng: &mut R, data: &mut [u32], rem: u64)
where
R: Rng + ?Sized,
{
rng.fill(data);
if rem > 0 {
let last = data.len() - 1;
data[last] >>= 32 - rem;
}
}
fn random_biguint<R>(rng: &mut R, bit_size: u64) -> BigUint
where
R: Rng + ?Sized,
{
let (digits, rem) = bit_size.div_rem(&32);
let len = (digits + (rem > 0) as u64)
.to_usize()
.expect("capacity overflow");
let mut data = vec![0u32; len];
random_bits(rng, &mut data, rem);
BigUint::new(data)
}
fn random_biguint_below<R>(rng: &mut R, bound: &BigUint) -> BigUint
where
R: Rng + ?Sized,
{
assert!(!bound.is_zero());
let bits = bound.bits();
loop {
let n = random_biguint(rng, bits);
if n < *bound {
return n;
}
}
}
pub(super) struct UniformBigUint {
base: BigUint,
len: BigUint,
}
impl UniformBigUint {
pub(super) fn new(low: &BigUint, high: &BigUint) -> Result<Self, Error> {
if low >= high {
return Err(Error::EmptyRange);
}
Ok(UniformBigUint {
len: high - low,
base: low.clone(),
})
}
pub(super) fn new_inclusive(low: &BigUint, high: &BigUint) -> Result<Self, Error> {
if low > high {
return Err(Error::EmptyRange);
}
Self::new(low, &(high + 1u32))
}
pub(super) fn sample<R>(&self, rng: &mut R) -> BigUint
where
R: Rng + ?Sized,
{
&self.base + random_biguint_below(rng, &self.len)
}
}