From a2c3059e72292ca32d1e4abb27af2264e4643325 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Wed, 7 Mar 2018 18:31:15 +0000 Subject: [PATCH] Implement some of my suggestions for BlockRng --- src/impls.rs | 45 +++++++++++++++++++++++---------------------- src/reseeding.rs | 38 +++++++++++++++++--------------------- 2 files changed, 40 insertions(+), 43 deletions(-) diff --git a/src/impls.rs b/src/impls.rs index 64a3702ccb..fc5708f1fc 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -211,7 +211,7 @@ impl> RngCore for BlockRng { #[inline(always)] fn next_u32(&mut self) -> u32 { if self.index >= self.results.as_ref().len() { - let _ = self.core.generate(&mut self.results).unwrap(); + self.core.generate(&mut self.results).unwrap(); self.index = 0; } @@ -224,26 +224,30 @@ impl> RngCore for BlockRng { fn next_u64(&mut self) -> u64 { let len = self.results.as_ref().len(); - let index = self.index; - if index < len-1 { - self.index += 2; - // Read an u64 from the current index + let read_u64 = |results: &[u32], index| { if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { - unsafe { *(&self.results.as_ref()[index] as *const u32 as *const u64) } + // requires little-endian CPU supporting unaligned reads: + unsafe { *(&results[index] as *const u32 as *const u64) } } else { - let x = self.results.as_ref()[index] as u64; - let y = self.results.as_ref()[index + 1] as u64; + let x = results[index] as u64; + let y = results[index + 1] as u64; (y << 32) | x } + }; + + let index = self.index; + if index < len-1 { + // Read an u64 from the current index + let index = self.index; + self.index += 2; + read_u64(self.results.as_ref(), index) } else if index >= len { - let _ = self.core.generate(&mut self.results); + self.core.generate(&mut self.results).unwrap(); self.index = 2; - let x = self.results.as_ref()[0] as u64; - let y = self.results.as_ref()[1] as u64; - (y << 32) | x + read_u64(self.results.as_ref(), 0) } else { let x = self.results.as_ref()[len-1] as u64; - let _ = self.core.generate(&mut self.results); + self.core.generate(&mut self.results).unwrap(); self.index = 1; let y = self.results.as_ref()[0] as u64; (y << 32) | x @@ -251,7 +255,7 @@ impl> RngCore for BlockRng { } fn fill_bytes(&mut self, dest: &mut [u8]) { - let _ = self.try_fill_bytes(dest); + self.try_fill_bytes(dest).unwrap(); } // As an optimization we try to write directly into the output buffer. @@ -260,7 +264,6 @@ impl> RngCore for BlockRng { #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { let mut filled = 0; - let mut res = Ok(()); // Continue filling from the current set of results if self.index < self.results.as_ref().len() { @@ -274,21 +277,19 @@ impl> RngCore for BlockRng { let len_remainder = (dest.len() - filled) % (self.results.as_ref().len() * 4); - let len_direct = dest.len() - len_remainder; + let end_direct = dest.len() - len_remainder; - while filled < len_direct { + while filled < end_direct { let dest_u32: &mut R::Results = unsafe { ::core::mem::transmute(dest[filled..].as_mut_ptr()) }; - let res2 = self.core.generate(dest_u32); - if res2.is_err() && res.is_ok() { res = res2 }; + self.core.generate(dest_u32)?; filled += self.results.as_ref().len() * 4; } self.index = self.results.as_ref().len(); if len_remainder > 0 { - let res2 = self.core.generate(&mut self.results); - if res2.is_err() && res.is_ok() { res = res2 }; + self.core.generate(&mut self.results)?; let (consumed_u32, _) = fill_via_u32_chunks(&mut self.results.as_ref(), @@ -296,7 +297,7 @@ impl> RngCore for BlockRng { self.index = consumed_u32; } - res + Ok(()) } #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] diff --git a/src/reseeding.rs b/src/reseeding.rs index cb4b450a3a..adccea4c07 100644 --- a/src/reseeding.rs +++ b/src/reseeding.rs @@ -52,7 +52,7 @@ use impls::BlockRng; /// methods will continue generating data from the wrapped PRNG without /// reseeding. #[derive(Debug)] -pub struct ReseedingRng(BlockRng>) +pub struct ReseedingRng(BlockRng>) where R: BlockRngCore + SeedableRng, Rsdr: RngCore; @@ -74,8 +74,8 @@ where R: BlockRngCore + SeedableRng, let results_empty = R::Results::default(); ReseedingRng( BlockRng { - core: Reseeder { - core: rng, + core: ReseedingCore { + inner: rng, reseeder: reseeder, threshold: threshold as i64, bytes_until_reseed: threshold as i64, @@ -113,14 +113,14 @@ impl + SeedableRng, Rsdr: RngCore> RngCore for ReseedingRng } #[derive(Debug)] -struct Reseeder { - core: R, +struct ReseedingCore { + inner: R, reseeder: Rsdr, threshold: i64, bytes_until_reseed: i64, } -impl BlockRngCore for Reseeder +impl BlockRngCore for ReseedingCore where R: BlockRngCore + SeedableRng, Rsdr: RngCore { @@ -138,29 +138,26 @@ where R: BlockRngCore + SeedableRng, return self.reseed_and_generate(results); } self.bytes_until_reseed -= results.as_ref().len() as i64 * 4; - self.core.generate(results) + self.inner.generate(results) } } -impl Reseeder +impl ReseedingCore where R: BlockRngCore + SeedableRng, Rsdr: RngCore { - /// Reseed the internal PRNG. - fn reseed(&mut self) -> Result<(), Error> { - R::from_rng(&mut self.reseeder).map(|result| self.core = result) - } - /// Reseed the internal PRNG. /// /// If reseeding fails, this will try to work around errors intelligently - /// through some combination of retrying and delaying reseeding until later. - /// It will also report the error with `ErrorKind::Transient` with the - /// original error as cause. - fn auto_reseed(&mut self) -> Result<(), Error> { + /// by adjusting the delay until automatic reseeding next occurs. + /// It will still report the error but with kind changed to + /// `ErrorKind::Transient`. + fn reseed(&mut self) -> Result<(), Error> { trace!("Reseeding RNG after {} generated bytes", self.threshold - self.bytes_until_reseed); - if let Err(mut e) = self.reseed() { + if let Err(mut e) = R::from_rng(&mut self.reseeder) + .map(|result| self.inner = result) + { let delay = match e.kind { ErrorKind::Transient => 0, kind @ _ if kind.should_retry() => self.threshold >> 8, @@ -182,10 +179,9 @@ where R: BlockRngCore + SeedableRng, results: &mut >::Results) -> Result<(), Error> { - let res1 = self.auto_reseed(); + let _result = self.reseed(); // reseeding errors are not fatal self.bytes_until_reseed -= results.as_ref().len() as i64 * 4; - let res2 = self.core.generate(results); - if res2.is_err() { res2 } else { res1 } + self.inner.generate(results) } }