summaryrefslogtreecommitdiff
path: root/rand/src/rngs/adapter
diff options
context:
space:
mode:
Diffstat (limited to 'rand/src/rngs/adapter')
-rw-r--r--rand/src/rngs/adapter/mod.rs4
-rw-r--r--rand/src/rngs/adapter/read.rs53
-rw-r--r--rand/src/rngs/adapter/reseeding.rs89
3 files changed, 72 insertions, 74 deletions
diff --git a/rand/src/rngs/adapter/mod.rs b/rand/src/rngs/adapter/mod.rs
index 60b832e..659ff26 100644
--- a/rand/src/rngs/adapter/mod.rs
+++ b/rand/src/rngs/adapter/mod.rs
@@ -8,8 +8,8 @@
//! Wrappers / adapters forming RNGs
-#[cfg(feature="std")] #[doc(hidden)] pub mod read;
+#[cfg(feature="std")] mod read;
mod reseeding;
-#[cfg(feature="std")] pub use self::read::ReadRng;
+#[cfg(feature="std")] pub use self::read::{ReadRng, ReadError};
pub use self::reseeding::ReseedingRng;
diff --git a/rand/src/rngs/adapter/read.rs b/rand/src/rngs/adapter/read.rs
index 30b6de6..901462e 100644
--- a/rand/src/rngs/adapter/read.rs
+++ b/rand/src/rngs/adapter/read.rs
@@ -10,12 +10,13 @@
//! A wrapper around any Read to treat it as an RNG.
use std::io::Read;
+use std::fmt;
-use rand_core::{RngCore, Error, ErrorKind, impls};
+use rand_core::{RngCore, Error, impls};
/// An RNG that reads random bytes straight from any type supporting
-/// `std::io::Read`, for example files.
+/// [`std::io::Read`], for example files.
///
/// This will work best with an infinite reader, but that is not required.
///
@@ -24,10 +25,10 @@ use rand_core::{RngCore, Error, ErrorKind, impls};
///
/// # Panics
///
-/// `ReadRng` uses `std::io::read_exact`, which retries on interrupts. All other
-/// errors from the underlying reader, including when it does not have enough
-/// data, will only be reported through [`try_fill_bytes`]. The other
-/// [`RngCore`] methods will panic in case of an error.
+/// `ReadRng` uses [`std::io::Read::read_exact`], which retries on interrupts.
+/// All other errors from the underlying reader, including when it does not
+/// have enough data, will only be reported through [`try_fill_bytes`].
+/// The other [`RngCore`] methods will panic in case of an error.
///
/// # Example
///
@@ -40,9 +41,8 @@ use rand_core::{RngCore, Error, ErrorKind, impls};
/// println!("{:x}", rng.gen::<u32>());
/// ```
///
-/// [`OsRng`]: ../struct.OsRng.html
-/// [`RngCore`]: ../../trait.RngCore.html
-/// [`try_fill_bytes`]: ../../trait.RngCore.html#method.tymethod.try_fill_bytes
+/// [`OsRng`]: crate::rngs::OsRng
+/// [`try_fill_bytes`]: RngCore::try_fill_bytes
#[derive(Debug)]
pub struct ReadRng<R> {
reader: R
@@ -72,24 +72,33 @@ impl<R: Read> RngCore for ReadRng<R> {
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
- if dest.len() == 0 { return Ok(()); }
+ if dest.is_empty() { return Ok(()); }
// Use `std::io::read_exact`, which retries on `ErrorKind::Interrupted`.
- self.reader.read_exact(dest).map_err(|err| {
- match err.kind() {
- ::std::io::ErrorKind::UnexpectedEof => Error::with_cause(
- ErrorKind::Unavailable,
- "not enough bytes available, reached end of source", err),
- _ => Error::with_cause(ErrorKind::Unavailable,
- "error reading from Read source", err)
- }
- })
+ self.reader.read_exact(dest).map_err(|e| Error::new(ReadError(e)))
}
}
+/// `ReadRng` error type
+#[derive(Debug)]
+pub struct ReadError(std::io::Error);
+
+impl fmt::Display for ReadError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ReadError: {}", self.0)
+ }
+}
+
+impl std::error::Error for ReadError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ Some(&self.0)
+ }
+}
+
+
#[cfg(test)]
mod test {
use super::ReadRng;
- use {RngCore, ErrorKind};
+ use crate::RngCore;
#[test]
fn test_reader_rng_u64() {
@@ -132,6 +141,8 @@ mod test {
let mut rng = ReadRng::new(&v[..]);
- assert!(rng.try_fill_bytes(&mut w).err().unwrap().kind == ErrorKind::Unavailable);
+ let result = rng.try_fill_bytes(&mut w);
+ assert!(result.is_err());
+ println!("Error: {}", result.unwrap_err());
}
}
diff --git a/rand/src/rngs/adapter/reseeding.rs b/rand/src/rngs/adapter/reseeding.rs
index 016afab..ec88efe 100644
--- a/rand/src/rngs/adapter/reseeding.rs
+++ b/rand/src/rngs/adapter/reseeding.rs
@@ -12,7 +12,7 @@
use core::mem::size_of;
-use rand_core::{RngCore, CryptoRng, SeedableRng, Error, ErrorKind};
+use rand_core::{RngCore, CryptoRng, SeedableRng, Error};
use rand_core::block::{BlockRngCore, BlockRng};
/// A wrapper around any PRNG that implements [`BlockRngCore`], that adds the
@@ -24,7 +24,7 @@ use rand_core::block::{BlockRngCore, BlockRng};
/// - After `clone()`, the clone will be reseeded on first use.
/// - After a process is forked, the RNG in the child process is reseeded within
/// the next few generated values, depending on the block size of the
-/// underlying PRNG. For [`ChaChaCore`] and [`Hc128Core`] this is a maximum of
+/// underlying PRNG. For ChaCha and Hc128 this is a maximum of
/// 15 `u32` values before reseeding.
/// - After the PRNG has generated a configurable number of random bytes.
///
@@ -57,33 +57,24 @@ use rand_core::block::{BlockRngCore, BlockRng};
/// # Example
///
/// ```
-/// # extern crate rand;
-/// # extern crate rand_chacha;
-/// # fn main() {
/// use rand::prelude::*;
-/// use rand_chacha::ChaChaCore; // Internal part of ChaChaRng that
+/// use rand_chacha::ChaCha20Core; // Internal part of ChaChaRng that
/// // implements BlockRngCore
/// use rand::rngs::OsRng;
/// use rand::rngs::adapter::ReseedingRng;
///
-/// let prng = ChaChaCore::from_entropy();
-// FIXME: it is better to use EntropyRng as reseeder, but that doesn't implement
-// clone yet.
-/// let reseeder = OsRng::new().unwrap();
-/// let mut reseeding_rng = ReseedingRng::new(prng, 0, reseeder);
+/// let prng = ChaCha20Core::from_entropy();
+/// let mut reseeding_rng = ReseedingRng::new(prng, 0, OsRng);
///
/// println!("{}", reseeding_rng.gen::<u64>());
///
/// let mut cloned_rng = reseeding_rng.clone();
/// assert!(reseeding_rng.gen::<u64>() != cloned_rng.gen::<u64>());
-/// # }
/// ```
///
-/// [`ChaChaCore`]: ../../../rand_chacha/struct.ChaChaCore.html
-/// [`Hc128Core`]: ../../../rand_hc/struct.Hc128Core.html
-/// [`BlockRngCore`]: ../../../rand_core/block/trait.BlockRngCore.html
-/// [`ReseedingRng::new`]: struct.ReseedingRng.html#method.new
-/// [`reseed()`]: struct.ReseedingRng.html#method.reseed
+/// [`BlockRngCore`]: rand_core::block::BlockRngCore
+/// [`ReseedingRng::new`]: ReseedingRng::new
+/// [`reseed()`]: ReseedingRng::reseed
#[derive(Debug)]
pub struct ReseedingRng<R, Rsdr>(BlockRng<ReseedingCore<R, Rsdr>>)
where R: BlockRngCore + SeedableRng,
@@ -234,6 +225,7 @@ where R: BlockRngCore + SeedableRng,
results: &mut <Self as BlockRngCore>::Results,
global_fork_counter: usize)
{
+ #![allow(clippy::if_same_then_else)] // false positive
if self.is_forked(global_fork_counter) {
info!("Fork detected, reseeding RNG");
} else {
@@ -243,21 +235,13 @@ where R: BlockRngCore + SeedableRng,
let num_bytes =
results.as_ref().len() * size_of::<<R as BlockRngCore>::Item>();
- let threshold = if let Err(e) = self.reseed() {
- let delay = match e.kind {
- ErrorKind::Transient => num_bytes as i64,
- kind @ _ if kind.should_retry() => self.threshold >> 8,
- _ => self.threshold,
- };
- warn!("Reseeding RNG delayed reseeding by {} bytes due to \
- error from source: {}", delay, e);
- delay
- } else {
- self.fork_counter = global_fork_counter;
- self.threshold
- };
+ if let Err(e) = self.reseed() {
+ warn!("Reseeding RNG failed: {}", e);
+ let _ = e;
+ }
+ self.fork_counter = global_fork_counter;
- self.bytes_until_reseed = threshold - num_bytes as i64;
+ self.bytes_until_reseed = self.threshold - num_bytes as i64;
self.inner.generate(results);
}
}
@@ -282,12 +266,11 @@ where R: BlockRngCore + SeedableRng + CryptoRng,
Rsdr: RngCore + CryptoRng {}
-#[cfg(all(feature="std", unix, not(target_os="emscripten")))]
+#[cfg(all(unix, not(target_os="emscripten")))]
mod fork {
- extern crate libc;
-
- use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
- use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
+ use core::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
+ #[allow(deprecated)] // Required for compatibility with Rust < 1.24.
+ use core::sync::atomic::{ATOMIC_USIZE_INIT, ATOMIC_BOOL_INIT};
// Fork protection
//
@@ -301,12 +284,14 @@ mod fork {
// don't update `fork_counter`, so a reseed is attempted as soon as
// possible.
+ #[allow(deprecated)]
static RESEEDING_RNG_FORK_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
pub fn get_fork_counter() -> usize {
RESEEDING_RNG_FORK_COUNTER.load(Ordering::Relaxed)
}
+ #[allow(deprecated)]
static FORK_HANDLER_REGISTERED: AtomicBool = ATOMIC_BOOL_INIT;
extern fn fork_handler() {
@@ -316,14 +301,14 @@ mod fork {
}
pub fn register_fork_handler() {
- if FORK_HANDLER_REGISTERED.load(Ordering::Relaxed) == false {
+ if !FORK_HANDLER_REGISTERED.load(Ordering::Relaxed) {
unsafe { libc::pthread_atfork(None, None, Some(fork_handler)) };
FORK_HANDLER_REGISTERED.store(true, Ordering::Relaxed);
}
}
}
-#[cfg(not(all(feature="std", unix, not(target_os="emscripten"))))]
+#[cfg(not(all(unix, not(target_os="emscripten"))))]
mod fork {
pub fn get_fork_counter() -> usize { 0 }
pub fn register_fork_handler() {}
@@ -332,25 +317,27 @@ mod fork {
#[cfg(test)]
mod test {
- use {Rng, SeedableRng};
- use rand_chacha::ChaChaCore;
- use rngs::mock::StepRng;
+ use crate::{Rng, SeedableRng};
+ use crate::rngs::std::Core;
+ use crate::rngs::mock::StepRng;
use super::ReseedingRng;
#[test]
fn test_reseeding() {
let mut zero = StepRng::new(0, 0);
- let rng = ChaChaCore::from_rng(&mut zero).unwrap();
- let mut reseeding = ReseedingRng::new(rng, 32*4, zero);
-
- // Currently we only support for arrays up to length 32.
- // TODO: cannot generate seq via Rng::gen because it uses different alg
- let mut buf = [0u32; 32]; // Needs to be a multiple of the RNGs result
- // size to test exactly.
- reseeding.fill(&mut buf);
+ let rng = Core::from_rng(&mut zero).unwrap();
+ let thresh = 1; // reseed every time the buffer is exhausted
+ let mut reseeding = ReseedingRng::new(rng, thresh, zero);
+
+ // RNG buffer size is [u32; 64]
+ // Debug is only implemented up to length 32 so use two arrays
+ let mut buf = ([0u32; 32], [0u32; 32]);
+ reseeding.fill(&mut buf.0);
+ reseeding.fill(&mut buf.1);
let seq = buf;
for _ in 0..10 {
- reseeding.fill(&mut buf);
+ reseeding.fill(&mut buf.0);
+ reseeding.fill(&mut buf.1);
assert_eq!(buf, seq);
}
}
@@ -358,7 +345,7 @@ mod test {
#[test]
fn test_clone_reseeding() {
let mut zero = StepRng::new(0, 0);
- let rng = ChaChaCore::from_rng(&mut zero).unwrap();
+ let rng = Core::from_rng(&mut zero).unwrap();
let mut rng1 = ReseedingRng::new(rng, 32*4, zero);
let first: u32 = rng1.gen();