use rand_core::{SeedableRng, TryCryptoRng, TryRng};
#[derive(Debug)]
pub struct ReseedingRng<R, Rsdr> {
inner: R,
reseeder: Rsdr,
threshold: i64,
bytes_until_reseed: i64,
}
impl<R, Rsdr> ReseedingRng<R, Rsdr>
where
R: SeedableRng,
Rsdr: TryRng,
{
pub fn new(threshold: u64, mut reseeder: Rsdr) -> Result<Self, Rsdr::Error> {
let threshold = if threshold == 0 || threshold > i64::MAX as u64 {
i64::MAX
} else {
threshold as i64
};
let inner = R::try_from_rng(&mut reseeder)?;
Ok(Self {
inner,
reseeder,
threshold,
bytes_until_reseed: threshold,
})
}
pub fn reseed(&mut self) -> Result<(), Rsdr::Error> {
self.inner = R::try_from_rng(&mut self.reseeder)?;
self.bytes_until_reseed = self.threshold;
Ok(())
}
#[inline(always)]
fn before_generate(&mut self, num_bytes: usize) {
if self.bytes_until_reseed <= 0 {
self.reseed_at_threshold();
}
self.bytes_until_reseed -= num_bytes as i64;
}
#[inline(never)]
fn reseed_at_threshold(&mut self) {
trace!("Reseeding RNG (periodic reseed)");
if let Err(e) = self.reseed() {
warn!("Reseeding RNG failed: {}", display2format!(e));
let _ = e;
self.bytes_until_reseed = self.threshold;
}
}
}
impl<R, Rsdr> TryRng for ReseedingRng<R, Rsdr>
where
R: SeedableRng + TryRng,
Rsdr: TryRng,
{
type Error = R::Error;
#[inline(always)]
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
self.before_generate(4);
self.inner.try_next_u32()
}
#[inline(always)]
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
self.before_generate(8);
self.inner.try_next_u64()
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
self.before_generate(dest.len());
self.inner.try_fill_bytes(dest)
}
}
impl<R, Rsdr> TryCryptoRng for ReseedingRng<R, Rsdr>
where
R: SeedableRng + TryCryptoRng,
Rsdr: TryCryptoRng,
{
}
impl<R, Rsdr> Clone for ReseedingRng<R, Rsdr>
where
R: SeedableRng + Clone,
Rsdr: TryRng + Clone,
{
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
reseeder: self.reseeder.clone(),
threshold: self.threshold,
bytes_until_reseed: 0, }
}
}