From 6daae3e9536c82aad78d612a307189fbb76ad9c2 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Thu, 16 May 2019 13:12:20 +0100 Subject: [PATCH 1/9] rand_core: remove ErrorKind enum This is virtually no usage, thus it was decided to remove --- rand_core/src/error.rs | 105 ++++++---------------------------- rand_core/src/lib.rs | 2 +- rand_jitter/src/error.rs | 7 ++- rand_os/src/lib.rs | 7 +-- src/lib.rs | 9 +-- src/rngs/adapter/read.rs | 17 ++---- src/rngs/adapter/reseeding.rs | 22 +++---- src/rngs/os.rs | 7 +-- 8 files changed, 43 insertions(+), 133 deletions(-) diff --git a/rand_core/src/error.rs b/rand_core/src/error.rs index 5a8459ea8be..6d343be14f4 100644 --- a/rand_core/src/error.rs +++ b/rand_core/src/error.rs @@ -15,80 +15,18 @@ use std::error::Error as stdError; #[cfg(feature="std")] use std::io; -/// Error kind which can be matched over. -#[derive(PartialEq, Eq, Debug, Copy, Clone)] -pub enum ErrorKind { - /// Feature is not available; not recoverable. - /// - /// This is the most permanent failure type and implies the error cannot be - /// resolved simply by retrying (e.g. the feature may not exist in this - /// build of the application or on the current platform). - Unavailable, - /// General failure; there may be a chance of recovery on retry. - /// - /// This is the catch-all kind for errors from known and unknown sources - /// which do not have a more specific kind / handling method. - /// - /// It is suggested to retry a couple of times or retry later when - /// handling; some error sources may be able to resolve themselves, - /// although this is not likely. - Unexpected, - /// A transient failure which likely can be resolved or worked around. - /// - /// This error kind exists for a few specific cases where it is known that - /// the error likely can be resolved internally, but is reported anyway. - Transient, - /// Not ready yet: recommended to try again a little later. - /// - /// This error kind implies the generator needs more time or needs some - /// other part of the application to do something else first before it is - /// ready for use; for example this may be used by external generators - /// which require time for initialization. - NotReady, - #[doc(hidden)] - __Nonexhaustive, -} - -impl ErrorKind { - /// True if this kind of error may resolve itself on retry. - /// - /// See also `should_wait()`. - pub fn should_retry(self) -> bool { - self != ErrorKind::Unavailable - } - - /// True if we should retry but wait before retrying - /// - /// This implies `should_retry()` is true. - pub fn should_wait(self) -> bool { - self == ErrorKind::NotReady - } - - /// A description of this error kind - pub fn description(self) -> &'static str { - match self { - ErrorKind::Unavailable => "permanently unavailable", - ErrorKind::Unexpected => "unexpected failure", - ErrorKind::Transient => "transient failure", - ErrorKind::NotReady => "not ready yet", - ErrorKind::__Nonexhaustive => unreachable!(), - } - } -} /// Error type of random number generators /// /// This is a relatively simple error type, designed for compatibility with and -/// without the Rust `std` library. It embeds a "kind" code, a message (static -/// string only), and an optional chained cause (`std` only). The `kind` and -/// `msg` fields can be accessed directly; cause can be accessed via +/// without the Rust `std` library. It embeds a message (static +/// string only), and an optional chained cause (`std` only). The +/// `msg` field can be accessed directly; cause can be accessed via /// `std::error::Error::cause` or `Error::take_cause`. Construction can only be /// done via `Error::new` or `Error::with_cause`. #[derive(Debug)] pub struct Error { - /// The error kind - pub kind: ErrorKind, /// The error message pub msg: &'static str, #[cfg(feature="std")] @@ -96,18 +34,17 @@ pub struct Error { } impl Error { - /// Create a new instance, with specified kind and a message. - pub fn new(kind: ErrorKind, msg: &'static str) -> Self { + /// Create a new instance, with a message. + pub fn new(msg: &'static str) -> Self { #[cfg(feature="std")] { - Error { kind, msg, cause: None } + Error { msg, cause: None } } #[cfg(not(feature="std"))] { - Error { kind, msg } + Error { msg } } } - /// Create a new instance, with specified kind, message, and a - /// chained cause. + /// Create a new instance, with a message and a chained cause. /// /// Note: `stdError` is an alias for `std::error::Error`. /// @@ -116,19 +53,18 @@ impl Error { /// type `E` (because both `Box` and `stdError` are unavailable), and the /// `cause` is ignored. #[cfg(feature="std")] - pub fn with_cause(kind: ErrorKind, msg: &'static str, cause: E) -> Self + pub fn with_cause(msg: &'static str, cause: E) -> Self where E: Into> { - Error { kind, msg, cause: Some(cause.into()) } + Error { msg, cause: Some(cause.into()) } } - /// Create a new instance, with specified kind, message, and a - /// chained cause. + /// Create a new instance, with a message and a chained cause. /// /// In `no_std` mode the *cause* is ignored. #[cfg(not(feature="std"))] - pub fn with_cause(kind: ErrorKind, msg: &'static str, _cause: E) -> Self { - Error { kind, msg } + pub fn with_cause(msg: &'static str, _cause: E) -> Self { + Error { msg } } /// Take the cause, if any. This allows the embedded cause to be extracted. @@ -143,11 +79,11 @@ impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { #[cfg(feature="std")] { if let Some(ref cause) = self.cause { - return write!(f, "{} ({}); cause: {}", - self.msg, self.kind.description(), cause); + return write!(f, "{}; cause: {}", + self.msg, cause); } } - write!(f, "{} ({})", self.msg, self.kind.description()) + write!(f, "{}", self.msg) } } @@ -165,13 +101,6 @@ impl stdError for Error { #[cfg(feature="std")] impl From for io::Error { fn from(error: Error) -> Self { - use std::io::ErrorKind::*; - match error.kind { - ErrorKind::Unavailable => io::Error::new(NotFound, error), - ErrorKind::Unexpected | - ErrorKind::Transient => io::Error::new(Other, error), - ErrorKind::NotReady => io::Error::new(WouldBlock, error), - ErrorKind::__Nonexhaustive => unreachable!(), - } + io::Error::new(io::ErrorKind::Other, error) } } diff --git a/rand_core/src/lib.rs b/rand_core/src/lib.rs index 4b0e6e48b01..6d48e892592 100644 --- a/rand_core/src/lib.rs +++ b/rand_core/src/lib.rs @@ -50,7 +50,7 @@ use core::ptr::copy_nonoverlapping; #[cfg(all(feature="alloc", not(feature="std")))] use alloc::boxed::Box; -pub use error::{ErrorKind, Error}; +pub use error::Error; mod error; diff --git a/rand_jitter/src/error.rs b/rand_jitter/src/error.rs index a3483e84d0f..b643aebc9db 100644 --- a/rand_jitter/src/error.rs +++ b/rand_jitter/src/error.rs @@ -7,7 +7,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rand_core::{Error, ErrorKind}; +use rand_core::Error; use core::fmt; /// An error that can occur when [`JitterRng::test_timer`] fails. @@ -60,10 +60,11 @@ impl From for Error { // Timer check is already quite permissive of failures so we don't // expect false-positive failures, i.e. any error is irrecoverable. #[cfg(feature = "std")] { - Error::with_cause(ErrorKind::Unavailable, "timer jitter failed basic quality tests", err) + Error::with_cause("timer jitter failed basic quality tests", err) } #[cfg(not(feature = "std"))] { - Error::new(ErrorKind::Unavailable, "timer jitter failed basic quality tests") + let _ = err; + Error::new("timer jitter failed basic quality tests") } } } diff --git a/rand_os/src/lib.rs b/rand_os/src/lib.rs index 2849f4fa2d8..34ec811039b 100644 --- a/rand_os/src/lib.rs +++ b/rand_os/src/lib.rs @@ -35,13 +35,13 @@ pub use rand_core; // re-export use getrandom::getrandom; -use rand_core::{CryptoRng, RngCore, Error, ErrorKind, impls}; +use rand_core::{CryptoRng, RngCore, Error, impls}; /// A random number generator that retrieves randomness from from the /// operating system. /// /// This is a zero-sized struct. It can be freely constructed with `OsRng`. -/// +/// /// The implementation is provided by the [getrandom] crate. Refer to /// [getrandom] documentation for details. /// @@ -88,8 +88,7 @@ impl RngCore for OsRng { // (And why waste a system call?) if dest.len() == 0 { return Ok(()); } - getrandom(dest).map_err(|e| - Error::with_cause(ErrorKind::Unavailable, "OsRng failed", e)) + getrandom(dest).map_err(|e| Error::with_cause("OsRng failed", e)) } } diff --git a/src/lib.rs b/src/lib.rs index 35ac0b94d48..dbaf668eae4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,8 +79,7 @@ extern crate rand_pcg; // Re-exports from rand_core -pub use rand_core::{RngCore, CryptoRng, SeedableRng}; -pub use rand_core::{ErrorKind, Error}; +pub use rand_core::{RngCore, CryptoRng, SeedableRng, Error}; // Public exports #[cfg(feature="std")] pub use rngs::thread::thread_rng; @@ -276,10 +275,8 @@ pub trait Rng: RngCore { /// On big-endian platforms this performs byte-swapping to ensure /// portability of results from reproducible generators. /// - /// This uses [`try_fill_bytes`] internally and forwards all RNG errors. In - /// some cases errors may be resolvable; see [`ErrorKind`] and - /// documentation for the RNG in use. If you do not plan to handle these - /// errors you may prefer to use [`fill`]. + /// This is identical to [`fill`] except that it uses [`try_fill_bytes`] + /// internally and forwards RNG errors. /// /// # Example /// diff --git a/src/rngs/adapter/read.rs b/src/rngs/adapter/read.rs index b7787702d6a..4c08f97362b 100644 --- a/src/rngs/adapter/read.rs +++ b/src/rngs/adapter/read.rs @@ -11,7 +11,7 @@ use std::io::Read; -use rand_core::{RngCore, Error, ErrorKind, impls}; +use rand_core::{RngCore, Error, impls}; /// An RNG that reads random bytes straight from any type supporting @@ -73,22 +73,15 @@ impl RngCore for ReadRng { fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { if dest.len() == 0 { 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(|err| + Error::with_cause("error reading from Read source", err)) } } #[cfg(test)] mod test { use super::ReadRng; - use {RngCore, ErrorKind}; + use RngCore; #[test] fn test_reader_rng_u64() { @@ -131,6 +124,6 @@ mod test { let mut rng = ReadRng::new(&v[..]); - assert!(rng.try_fill_bytes(&mut w).err().unwrap().kind == ErrorKind::Unavailable); + assert!(rng.try_fill_bytes(&mut w).is_err()); } } diff --git a/src/rngs/adapter/reseeding.rs b/src/rngs/adapter/reseeding.rs index d58ce569f0e..30e8288ff0e 100644 --- a/src/rngs/adapter/reseeding.rs +++ b/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 @@ -240,21 +240,13 @@ where R: BlockRngCore + SeedableRng, let num_bytes = results.as_ref().len() * size_of::<::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); } } diff --git a/src/rngs/os.rs b/src/rngs/os.rs index e71ea80498c..02333ac68c1 100644 --- a/src/rngs/os.rs +++ b/src/rngs/os.rs @@ -9,13 +9,13 @@ //! Interface to the random number generator of the operating system. use getrandom::getrandom; -use rand_core::{CryptoRng, RngCore, Error, ErrorKind, impls}; +use rand_core::{CryptoRng, RngCore, Error, impls}; /// A random number generator that retrieves randomness from from the /// operating system. /// /// This is a zero-sized struct. It can be freely constructed with `OsRng`. -/// +/// /// The implementation is provided by the [getrandom] crate. Refer to /// [getrandom] documentation for details. /// @@ -60,8 +60,7 @@ impl RngCore for OsRng { } fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - getrandom(dest).map_err(|e| - Error::with_cause(ErrorKind::Unavailable, "OsRng failed", e)) + getrandom(dest).map_err(|e| Error::with_cause("OsRng failed", e)) } } From a4e5f019f76175dfc42e9cdd4e8f3feb6ae2df71 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Thu, 16 May 2019 15:38:44 +0100 Subject: [PATCH 2/9] Support From for rand_core::Error This gives us an alternative to feature-specific behaviour --- rand_core/Cargo.toml | 3 +- rand_core/src/error.rs | 73 +++++++++++++++++++++++++++--------------- rand_os/src/lib.rs | 3 +- src/rngs/os.rs | 3 +- 4 files changed, 53 insertions(+), 29 deletions(-) diff --git a/rand_core/Cargo.toml b/rand_core/Cargo.toml index 98e47ddf899..8c39865486a 100644 --- a/rand_core/Cargo.toml +++ b/rand_core/Cargo.toml @@ -18,10 +18,11 @@ travis-ci = { repository = "rust-random/rand" } appveyor = { repository = "rust-random/rand" } [features] -std = ["alloc"] # use std library; should be default but for above bug +std = ["alloc", "getrandom", "getrandom/std"] # use std library; should be default but for above bug alloc = [] # enables Vec and Box support without std serde1 = ["serde", "serde_derive"] # enables serde for BlockRng wrapper [dependencies] serde = { version = "1", optional = true } serde_derive = { version = "^1.0.38", optional = true } +getrandom = { version = "0.1", optional = true } diff --git a/rand_core/src/error.rs b/rand_core/src/error.rs index 6d343be14f4..f803399e8d8 100644 --- a/rand_core/src/error.rs +++ b/rand_core/src/error.rs @@ -9,13 +9,13 @@ //! Error types use core::fmt; - -#[cfg(feature="std")] -use std::error::Error as stdError; -#[cfg(feature="std")] -use std::io; +#[cfg(not(feature="std"))] +use core::num::NonZeroU32; +// A randomly-chosen 24-bit prefix for our codes. +#[cfg(not(feature="std"))] +pub(crate) const CODE_PREFIX: u32 = 0x517e8100; /// Error type of random number generators /// @@ -30,7 +30,9 @@ pub struct Error { /// The error message pub msg: &'static str, #[cfg(feature="std")] - cause: Option>, + cause: Option>, + #[cfg(not(feature="std"))] + code: NonZeroU32, } impl Error { @@ -40,39 +42,45 @@ impl Error { Error { msg, cause: None } } #[cfg(not(feature="std"))] { - Error { msg } + Error { msg, code: NonZeroU32::new(CODE_PREFIX).unwrap() } } } /// Create a new instance, with a message and a chained cause. - /// - /// Note: `stdError` is an alias for `std::error::Error`. - /// - /// If not targetting `std` (i.e. `no_std`), this function is replaced by - /// another with the same prototype, except that there are no bounds on the - /// type `E` (because both `Box` and `stdError` are unavailable), and the - /// `cause` is ignored. + /// + /// This function is only available with the `std` feature. + // NOTE: with specialisation we could support both. #[cfg(feature="std")] pub fn with_cause(msg: &'static str, cause: E) -> Self - where E: Into> + where E: Into> { Error { msg, cause: Some(cause.into()) } } - /// Create a new instance, with a message and a chained cause. - /// - /// In `no_std` mode the *cause* is ignored. + /// Create a new instance, with a message and an error code. + /// + /// This function is only available without the `std` feature. #[cfg(not(feature="std"))] - pub fn with_cause(msg: &'static str, _cause: E) -> Self { - Error { msg } + pub fn with_code(msg: &'static str, code: NonZeroU32) -> Self { + Error { msg, code } } /// Take the cause, if any. This allows the embedded cause to be extracted. /// This uses `Option::take`, leaving `self` with no cause. + /// + /// This function is only available with the `std` feature. #[cfg(feature="std")] - pub fn take_cause(&mut self) -> Option> { + pub fn take_cause(&mut self) -> Option> { self.cause.take() } + + /// Retrieve the error code. + /// + /// This function is only available without the `std` feature. + #[cfg(not(feature="std"))] + pub fn code(&self) -> NonZeroU32 { + self.code + } } impl fmt::Display for Error { @@ -87,20 +95,33 @@ impl fmt::Display for Error { } } +#[cfg(feature="getrandom")] +impl From for Error { + fn from(error: getrandom::Error) -> Self { + let msg = "getrandom error"; + #[cfg(feature="std")] { + Error { msg, cause: Some(Box::new(error)) } + } + #[cfg(not(feature="std"))] { + Error { msg, code: error.code() } + } + } +} + #[cfg(feature="std")] -impl stdError for Error { +impl std::error::Error for Error { fn description(&self) -> &str { self.msg } - fn cause(&self) -> Option<&stdError> { - self.cause.as_ref().map(|e| e.as_ref() as &stdError) + fn cause(&self) -> Option<&std::error::Error> { + self.cause.as_ref().map(|e| e.as_ref() as &std::error::Error) } } #[cfg(feature="std")] -impl From for io::Error { +impl From for std::io::Error { fn from(error: Error) -> Self { - io::Error::new(io::ErrorKind::Other, error) + std::io::Error::new(std::io::ErrorKind::Other, error) } } diff --git a/rand_os/src/lib.rs b/rand_os/src/lib.rs index 34ec811039b..39530d812a7 100644 --- a/rand_os/src/lib.rs +++ b/rand_os/src/lib.rs @@ -88,7 +88,8 @@ impl RngCore for OsRng { // (And why waste a system call?) if dest.len() == 0 { return Ok(()); } - getrandom(dest).map_err(|e| Error::with_cause("OsRng failed", e)) + getrandom(dest)?; + Ok(()) } } diff --git a/src/rngs/os.rs b/src/rngs/os.rs index 02333ac68c1..bdba2f6eabb 100644 --- a/src/rngs/os.rs +++ b/src/rngs/os.rs @@ -60,7 +60,8 @@ impl RngCore for OsRng { } fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - getrandom(dest).map_err(|e| Error::with_cause("OsRng failed", e)) + getrandom(dest)?; + Ok(()) } } From 25650c4a347dca72090fb71c3a178a3f4acf979f Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Thu, 16 May 2019 15:51:11 +0100 Subject: [PATCH 3/9] Update and synchronise OsRng modules --- rand_os/src/lib.rs | 35 +++++++++++++++-------------------- src/rngs/os.rs | 27 ++++++++++++++++++++++++--- 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/rand_os/src/lib.rs b/rand_os/src/lib.rs index 39530d812a7..9090ab8250a 100644 --- a/rand_os/src/lib.rs +++ b/rand_os/src/lib.rs @@ -8,19 +8,8 @@ // except according to those terms. //! Interface to the random number generator of the operating system. -//! -//! # Blocking and error handling -//! -//! It is possible that when used during early boot the first call to `OsRng` -//! will block until the system's RNG is initialised. It is also possible -//! (though highly unlikely) for `OsRng` to fail on some platforms, most -//! likely due to system mis-configuration. -//! -//! After the first successful call, it is highly unlikely that failures or -//! significant delays will occur (although performance should be expected to -//! be much slower than a user-space PRNG). -//! -//! [getrandom]: https://crates.io/crates/getrandom +// Note: keep this code in sync with the rand::rngs::os module! + #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", html_favicon_url = "https://www.rust-lang.org/favicon.ico", html_root_url = "https://rust-random.github.io/rand/")] @@ -28,8 +17,6 @@ #![deny(missing_debug_implementations)] #![doc(test(attr(allow(unused_variables), deny(warnings))))] -#![cfg_attr(feature = "stdweb", recursion_limit="128")] - #![no_std] // but see getrandom crate pub use rand_core; // re-export @@ -45,9 +32,21 @@ use rand_core::{CryptoRng, RngCore, Error, impls}; /// The implementation is provided by the [getrandom] crate. Refer to /// [getrandom] documentation for details. /// +/// # Blocking and error handling +/// +/// It is possible that when used during early boot the first call to `OsRng` +/// will block until the system's RNG is initialised. It is also possible +/// (though highly unlikely) for `OsRng` to fail on some platforms, most +/// likely due to system mis-configuration. +/// +/// After the first successful call, it is highly unlikely that failures or +/// significant delays will occur (although performance should be expected to +/// be much slower than a user-space PRNG). +/// /// # Usage example /// ``` -/// use rand_os::{OsRng, rand_core::RngCore}; +/// use rand_os::rand_core::RngCore; +/// use rand_os::OsRng; /// /// let mut key = [0u8; 16]; /// OsRng.fill_bytes(&mut key); @@ -84,10 +83,6 @@ impl RngCore for OsRng { } fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { - // Some systems do not support reading 0 random bytes. - // (And why waste a system call?) - if dest.len() == 0 { return Ok(()); } - getrandom(dest)?; Ok(()) } diff --git a/src/rngs/os.rs b/src/rngs/os.rs index bdba2f6eabb..c7fc75f6941 100644 --- a/src/rngs/os.rs +++ b/src/rngs/os.rs @@ -7,6 +7,7 @@ // except according to those terms. //! Interface to the random number generator of the operating system. +// Note: keep this code in sync with the rand_os crate! use getrandom::getrandom; use rand_core::{CryptoRng, RngCore, Error, impls}; @@ -19,15 +20,29 @@ use rand_core::{CryptoRng, RngCore, Error, impls}; /// The implementation is provided by the [getrandom] crate. Refer to /// [getrandom] documentation for details. /// -/// ## Example +/// # Blocking and error handling /// +/// It is possible that when used during early boot the first call to `OsRng` +/// will block until the system's RNG is initialised. It is also possible +/// (though highly unlikely) for `OsRng` to fail on some platforms, most +/// likely due to system mis-configuration. +/// +/// After the first successful call, it is highly unlikely that failures or +/// significant delays will occur (although performance should be expected to +/// be much slower than a user-space PRNG). +/// +/// # Usage example /// ``` /// use rand::rngs::{StdRng, OsRng}; /// use rand::{RngCore, SeedableRng}; /// -/// println!("Random number, straight from the OS: {}", OsRng.next_u32()); +/// let mut key = [0u8; 16]; +/// OsRng.fill_bytes(&mut key); +/// let random_u64 = OsRng.next_u64(); +/// +/// // OsRng is especially useful for seeding other RNGs (see also from_entropy) /// let mut rng = StdRng::from_rng(OsRng).unwrap(); -/// println!("Another random number: {}", rng.next_u32()); +/// let _ = rng.next_u32(); /// ``` /// /// [getrandom]: https://crates.io/crates/getrandom @@ -72,3 +87,9 @@ fn test_os_rng() { assert!(x != 0); assert!(x != y); } + +#[test] +fn test_construction() { + let mut rng = OsRng::default(); + assert!(rng.next_u64() != 0); +} From b61e61b3a7c8e9b7b1df1653f6e333ed3efd69cb Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Thu, 16 May 2019 17:12:04 +0100 Subject: [PATCH 4/9] Move from_entropy to SeedableRng and update RngCore doc --- rand_core/src/lib.rs | 84 ++++++++++++++++++++-------------- rand_distr/tests/uniformity.rs | 3 +- src/lib.rs | 50 -------------------- src/prelude.rs | 2 +- src/rngs/mod.rs | 4 +- src/rngs/small.rs | 6 +-- tests/wasm_bindgen/src/lib.rs | 1 - 7 files changed, 55 insertions(+), 95 deletions(-) diff --git a/rand_core/src/lib.rs b/rand_core/src/lib.rs index 6d48e892592..7472a666038 100644 --- a/rand_core/src/lib.rs +++ b/rand_core/src/lib.rs @@ -213,10 +213,6 @@ pub trait CryptoRng {} /// This trait encapsulates the low-level functionality common to all /// pseudo-random number generators (PRNGs, or algorithmic generators). /// -/// The `FromEntropy` trait from the [`rand`] crate is automatically -/// implemented for every type implementing `SeedableRng`, providing -/// a convenient `from_entropy()` constructor. -/// /// [`rand`]: https://docs.rs/rand pub trait SeedableRng: Sized { /// Seed type, which is restricted to types mutably-dereferencable as `u8` @@ -270,14 +266,18 @@ pub trait SeedableRng: Sized { /// /// PRNG implementations are allowed to assume that bits in the seed are /// well distributed. That means usually that the number of one and zero - /// bits are about equal, and values like 0, 1 and (size - 1) are unlikely. - /// - /// PRNG implementations are recommended to be reproducible. A PRNG seeded - /// using this function with a fixed seed should produce the same sequence - /// of output in the future and on different architectures (with for example - /// different endianness). - /// - /// It is however not required that this function yield the same state as a + /// bits are roughly equal, and values like 0, 1 and (size - 1) are unlikely. + /// Note that many non-cryptographic PRNGs will show poor quality output + /// if this is not adhered to. If you wish to seed from simple numbers, use + /// `seed_from_u64` instead. + /// + /// All PRNG implementations should be reproducible unless otherwise noted: + /// given a fixed `seed`, the same sequence of output should be produced + /// on all runs, library versions and architectures (e.g. check endianness). + /// Any "value-breaking" changes to the generator should require bumping at + /// least the minor version and documentation of the change. + /// + /// It is not required that this function yield the same state as a /// reference implementation of the PRNG given equivalent seed; if necessary /// another constructor replicating behaviour from a reference /// implementation can be added. @@ -330,33 +330,26 @@ pub trait SeedableRng: Sized { /// Create a new PRNG seeded from another `Rng`. /// - /// This is the recommended way to initialize PRNGs with fresh entropy. The - /// `FromEntropy` trait from the [`rand`] crate provides a convenient - /// `from_entropy` method based on `from_rng`. - /// - /// Usage of this method is not recommended when reproducibility is required - /// since implementing PRNGs are not required to fix Endianness and are - /// allowed to modify implementations in new releases. + /// This may be useful when needing to rapidly seed many PRNGs from a master + /// PRNG, and to allow forking of PRNGs. It may be considered deterministic. /// - /// It is important to use a good source of randomness to initialize the - /// PRNG. Cryptographic PRNG may be rendered insecure when seeded from a - /// non-cryptographic PRNG or with insufficient entropy. - /// Many non-cryptographic PRNGs will show statistical bias in their first - /// results if their seed numbers are small or if there is a simple pattern - /// between them. + /// The master PRNG should be at least as high quality as the child PRNGs. + /// When seeding non-cryptographic child PRNGs, we recommend using a + /// different algorithm for the master PRNG (ideally a CSPRNG) to avoid + /// correlations between the child PRNGs. If this is not possible (e.g. + /// forking using small non-crypto PRNGs) ensure that your PRNG has a good + /// mixing function on the output or consider use of a hash function with + /// `from_seed`. /// - /// Prefer to seed from a strong external entropy source like `OsRng` from - /// the [`rand_os`] crate or from a cryptographic PRNG; if creating a new - /// generator for cryptographic uses you *must* seed from a strong source. - /// - /// Seeding a small PRNG from another small PRNG is possible, but - /// something to be careful with. An extreme example of how this can go - /// wrong is seeding an Xorshift RNG from another Xorshift RNG, which - /// will effectively clone the generator. In general seeding from a - /// generator which is hard to predict is probably okay. + /// Note that seeding `XorShiftRng` from another `XorShiftRng` provides an + /// extreme example of what can go wrong: the new PRNG will be a clone + /// of the parent. /// /// PRNG implementations are allowed to assume that a good RNG is provided /// for seeding, and that it is cryptographically secure when appropriate. + /// As of `rand` 0.7 / `rand_core` 0.5, implementations overriding this + /// method should ensure the implementation satisfies reproducibility + /// (in prior versions this was not required). /// /// [`rand`]: https://docs.rs/rand /// [`rand_os`]: https://docs.rs/rand_os @@ -365,6 +358,29 @@ pub trait SeedableRng: Sized { rng.try_fill_bytes(seed.as_mut())?; Ok(Self::from_seed(seed)) } + + /// Creates a new instance of the RNG seeded via [`getrandom`]. + /// + /// This method is the recommended way to construct non-deterministic PRNGs + /// since it is convenient and secure. + /// + /// In case the overhead of using [`getrandom`] to seed *many* PRNGs is an + /// issue, one may prefer to seed from a local PRNG, e.g. + /// `from_rng(thread_rng()).unwrap()`. + /// + /// # Panics + /// + /// If [`getrandom`] is unable to provide secure entropy this method will panic. + /// + /// [`getrandom`]: https://docs.rs/getrandom + #[cfg(feature="getrandom")] + fn from_entropy() -> Self { + let mut seed = Self::Seed::default(); + if let Err(err) = getrandom::getrandom(seed.as_mut()) { + panic!("from_entropy failed: {}", err); + } + Self::from_seed(seed) + } } // Implement `RngCore` for references to an `RngCore`. diff --git a/rand_distr/tests/uniformity.rs b/rand_distr/tests/uniformity.rs index 3b9c7493e14..6ecea032be1 100644 --- a/rand_distr/tests/uniformity.rs +++ b/rand_distr/tests/uniformity.rs @@ -13,8 +13,7 @@ extern crate average; extern crate rand; use average::Histogram; -use rand::distributions::Distribution; -use rand::FromEntropy; +use rand::prelude::*; use std as core; const N_BINS: usize = 100; diff --git a/src/lib.rs b/src/lib.rs index dbaf668eae4..8fbdc80df21 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -451,56 +451,6 @@ impl_as_byte_slice_arrays!(32, N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N impl_as_byte_slice_arrays!(!div 4096, N,N,N,N,N,N,N,); -/// A convenience extension to [`SeedableRng`] allowing construction from fresh -/// entropy. This trait is automatically implemented for any PRNG implementing -/// [`SeedableRng`] and is not intended to be implemented by users. -/// -/// This is equivalent to using `SeedableRng::from_rng(OsRng)` then -/// unwrapping the result. -/// -/// Since this is convenient and secure, it is the recommended way to create -/// PRNGs, though two alternatives may be considered: -/// -/// * Deterministic creation using [`SeedableRng::from_seed`] with a fixed seed -/// * Seeding from `thread_rng`: `SeedableRng::from_rng(thread_rng())?`; -/// this will usually be faster and should also be secure, but requires -/// trusting one extra component. -/// -/// ## Example -/// -/// ``` -/// use rand::{Rng, FromEntropy}; -/// use rand::rngs::StdRng; -/// -/// let mut rng = StdRng::from_entropy(); -/// println!("Random die roll: {}", rng.gen_range(1, 7)); -/// ``` -/// -/// [`OsRng`]: rngs::OsRng -#[cfg(feature="std")] -pub trait FromEntropy: SeedableRng { - /// Creates a new instance of the RNG seeded from [`OsRng`]. - /// - /// This method is equivalent to `SeedableRng::from_rng(OsRng).unwrap()`. - /// - /// # Panics - /// - /// If [`OsRng`] is unable to obtain secure entropy this method will panic. - /// It is also possible for an RNG overriding the [`SeedableRng::from_rng`] - /// method to cause a panic. Both causes are extremely unlikely to occur; - /// most users need not worry about this. - fn from_entropy() -> Self; -} - -#[cfg(feature="std")] -impl FromEntropy for R { - fn from_entropy() -> R { - R::from_rng(rngs::OsRng).unwrap_or_else(|err| - panic!("FromEntropy::from_entropy() failed: {}", err)) - } -} - - /// Generates a random value using the thread-local random number generator. /// /// This is simply a shortcut for `thread_rng().gen()`. See [`thread_rng`] for diff --git a/src/prelude.rs b/src/prelude.rs index 5d8a0e9b2aa..5218c91c975 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -23,5 +23,5 @@ #[doc(no_inline)] pub use rngs::{SmallRng, StdRng}; #[doc(no_inline)] #[cfg(feature="std")] pub use rngs::ThreadRng; #[doc(no_inline)] pub use {Rng, RngCore, CryptoRng, SeedableRng}; -#[doc(no_inline)] #[cfg(feature="std")] pub use {FromEntropy, random, thread_rng}; +#[doc(no_inline)] #[cfg(feature="std")] pub use {random, thread_rng}; #[doc(no_inline)] pub use seq::{SliceRandom, IteratorRandom}; diff --git a/src/rngs/mod.rs b/src/rngs/mod.rs index 08dde4496f2..940dfab20af 100644 --- a/src/rngs/mod.rs +++ b/src/rngs/mod.rs @@ -42,9 +42,7 @@ //! - `from_seed` accepts a type specific to the PRNG //! - `from_rng` allows a PRNG to be seeded from any other RNG //! - `seed_from_u64` allows any PRNG to be seeded from a `u64` insecurely -//! -//! Additionally, [`FromEntropy::from_entropy`] is a shortcut for seeding from -//! [`OsRng`]. +//! - `from_entropy` securely seeds a PRNG from fresh entropy //! //! Use the [`rand_core`] crate when implementing your own RNGs. //! diff --git a/src/rngs/small.rs b/src/rngs/small.rs index 9874d2469b8..0e39adba9c1 100644 --- a/src/rngs/small.rs +++ b/src/rngs/small.rs @@ -34,11 +34,10 @@ type Rng = ::rand_pcg::Pcg32; /// /// # Examples /// -/// Initializing `SmallRng` with a random seed can be done using [`FromEntropy`]: +/// Initializing `SmallRng` with a random seed can be done using [`SeedableRng::from_entropy`]: /// /// ``` -/// # use rand::Rng; -/// use rand::FromEntropy; +/// use rand::{Rng, SeedableRng}; /// use rand::rngs::SmallRng; /// /// // Create small, cheap to initialize and fast RNG with a random seed. @@ -66,7 +65,6 @@ type Rng = ::rand_pcg::Pcg32; /// .collect(); /// ``` /// -/// [`FromEntropy`]: crate::FromEntropy /// [`StdRng`]: crate::rngs::StdRng /// [`thread_rng`]: crate::thread_rng /// [rand_pcg]: https://crates.io/crates/rand_pcg diff --git a/tests/wasm_bindgen/src/lib.rs b/tests/wasm_bindgen/src/lib.rs index 6610b8cbdbc..9de50958a2c 100644 --- a/tests/wasm_bindgen/src/lib.rs +++ b/tests/wasm_bindgen/src/lib.rs @@ -15,7 +15,6 @@ extern crate wasm_bindgen; extern crate wasm_bindgen_test; use rand::rngs::{OsRng, StdRng}; -use rand::FromEntropy; use rand::{Rng, SeedableRng}; use wasm_bindgen::prelude::*; From f42abf8ff197b8c7b15122c1bbfafe12f4b66a45 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Thu, 16 May 2019 17:14:33 +0100 Subject: [PATCH 5/9] Make Error::msg a private field --- rand_core/src/error.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rand_core/src/error.rs b/rand_core/src/error.rs index f803399e8d8..95b62e4eb9e 100644 --- a/rand_core/src/error.rs +++ b/rand_core/src/error.rs @@ -27,8 +27,7 @@ pub(crate) const CODE_PREFIX: u32 = 0x517e8100; /// done via `Error::new` or `Error::with_cause`. #[derive(Debug)] pub struct Error { - /// The error message - pub msg: &'static str, + msg: &'static str, #[cfg(feature="std")] cause: Option>, #[cfg(not(feature="std"))] @@ -64,6 +63,11 @@ impl Error { pub fn with_code(msg: &'static str, code: NonZeroU32) -> Self { Error { msg, code } } + + /// Retrieve the error message. + pub fn msg(&self) -> &str { + self.msg + } /// Take the cause, if any. This allows the embedded cause to be extracted. /// This uses `Option::take`, leaving `self` with no cause. From 959043d7d6f727ad085c97a21e2547c4c34b1f4f Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Fri, 17 May 2019 17:52:22 +0100 Subject: [PATCH 6/9] rand_core::Error: support using a code also with std --- rand_core/src/error.rs | 46 ++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/rand_core/src/error.rs b/rand_core/src/error.rs index 95b62e4eb9e..cad05ab78a7 100644 --- a/rand_core/src/error.rs +++ b/rand_core/src/error.rs @@ -9,7 +9,6 @@ //! Error types use core::fmt; -#[cfg(not(feature="std"))] use core::num::NonZeroU32; @@ -57,11 +56,13 @@ impl Error { } /// Create a new instance, with a message and an error code. - /// - /// This function is only available without the `std` feature. - #[cfg(not(feature="std"))] pub fn with_code(msg: &'static str, code: NonZeroU32) -> Self { - Error { msg, code } + #[cfg(feature="std")] { + Error { msg, cause: Some(Box::new(ErrorCode(code))) } + } + #[cfg(not(feature="std"))] { + Error { msg, code } + } } /// Retrieve the error message. @@ -78,23 +79,20 @@ impl Error { self.cause.take() } - /// Retrieve the error code. - /// - /// This function is only available without the `std` feature. + /// Retrieve the error code, if any. #[cfg(not(feature="std"))] - pub fn code(&self) -> NonZeroU32 { - self.code + pub fn code(&self) -> Option { + #[cfg(feature="std")] { + self.cause.as_ref().and_then(|b| b.downcast_ref::()).map(|c| c.0) + } + #[cfg(not(feature="std"))] { + Some(self.code) + } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - #[cfg(feature="std")] { - if let Some(ref cause) = self.cause { - return write!(f, "{}; cause: {}", - self.msg, cause); - } - } write!(f, "{}", self.msg) } } @@ -118,7 +116,7 @@ impl std::error::Error for Error { self.msg } - fn cause(&self) -> Option<&std::error::Error> { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { self.cause.as_ref().map(|e| e.as_ref() as &std::error::Error) } } @@ -129,3 +127,17 @@ impl From for std::io::Error { std::io::Error::new(std::io::ErrorKind::Other, error) } } + +#[cfg(feature="std")] +#[derive(Debug, Copy, Clone)] +struct ErrorCode(NonZeroU32); + +#[cfg(feature="std")] +impl fmt::Display for ErrorCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "ErrorCode({})", self.0) + } +} + +#[cfg(feature="std")] +impl std::error::Error for ErrorCode {} From ca1b7c429af3155f9bd2aecfe7f9014d9b4afff3 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Tue, 28 May 2019 10:27:26 +0100 Subject: [PATCH 7/9] rand_core::Error: replace internal representation and adjust API This is a significant breaking change, discussed in #800. Also rand::rngs::adapter::read is no longer publically exported. --- rand_core/src/error.rs | 113 ++++++++++++++++++--------------------- src/rngs/adapter/mod.rs | 4 +- src/rngs/adapter/read.rs | 25 +++++++-- 3 files changed, 76 insertions(+), 66 deletions(-) diff --git a/rand_core/src/error.rs b/rand_core/src/error.rs index cad05ab78a7..7e8f0c9ba32 100644 --- a/rand_core/src/error.rs +++ b/rand_core/src/error.rs @@ -12,78 +12,58 @@ use core::fmt; use core::num::NonZeroU32; -// A randomly-chosen 24-bit prefix for our codes. -#[cfg(not(feature="std"))] -pub(crate) const CODE_PREFIX: u32 = 0x517e8100; - /// Error type of random number generators -/// -/// This is a relatively simple error type, designed for compatibility with and -/// without the Rust `std` library. It embeds a message (static -/// string only), and an optional chained cause (`std` only). The -/// `msg` field can be accessed directly; cause can be accessed via -/// `std::error::Error::cause` or `Error::take_cause`. Construction can only be -/// done via `Error::new` or `Error::with_cause`. +/// +/// In order to be compatible with `std` and `no_std`, this type has two +/// possible implementations: with `std` a boxed `Error` trait object is stored, +/// while with `no_std` we merely store an error code. #[derive(Debug)] pub struct Error { - msg: &'static str, #[cfg(feature="std")] - cause: Option>, + inner: Box, #[cfg(not(feature="std"))] code: NonZeroU32, } impl Error { - /// Create a new instance, with a message. - pub fn new(msg: &'static str) -> Self { - #[cfg(feature="std")] { - Error { msg, cause: None } - } - #[cfg(not(feature="std"))] { - Error { msg, code: NonZeroU32::new(CODE_PREFIX).unwrap() } - } - } - - /// Create a new instance, with a message and a chained cause. - /// - /// This function is only available with the `std` feature. - // NOTE: with specialisation we could support both. + /// Construct from any type supporting `std::error::Error` + /// + /// Available only when configured with `std`. + /// + /// See also `From`, which is available with and without `std`. #[cfg(feature="std")] - pub fn with_cause(msg: &'static str, cause: E) -> Self - where E: Into> + pub fn new(err: E) -> Self + where E: Into> { - Error { msg, cause: Some(cause.into()) } + Error { inner: err.into() } } - /// Create a new instance, with a message and an error code. - pub fn with_code(msg: &'static str, code: NonZeroU32) -> Self { - #[cfg(feature="std")] { - Error { msg, cause: Some(Box::new(ErrorCode(code))) } - } - #[cfg(not(feature="std"))] { - Error { msg, code } - } - } - - /// Retrieve the error message. - pub fn msg(&self) -> &str { - self.msg + /// Reference the inner error (`std` only) + /// + /// When configured with `std`, this is a trivial operation and never + /// panics. Without `std`, this method is simply unavailable. + #[cfg(feature="std")] + pub fn inner(&self) -> &(dyn std::error::Error + Send + Sync + 'static) { + &*self.inner } - /// Take the cause, if any. This allows the embedded cause to be extracted. - /// This uses `Option::take`, leaving `self` with no cause. - /// - /// This function is only available with the `std` feature. + /// Unwrap the inner error (`std` only) + /// + /// When configured with `std`, this is a trivial operation and never + /// panics. Without `std`, this method is simply unavailable. #[cfg(feature="std")] - pub fn take_cause(&mut self) -> Option> { - self.cause.take() + pub fn take_inner(self) -> Box { + self.inner } /// Retrieve the error code, if any. - #[cfg(not(feature="std"))] + /// + /// If this `Error` was constructed via `From`, then this method + /// will return this `NonZeroU32` code (for `no_std` this is always the + /// case). Otherwise, this method will return `None`. pub fn code(&self) -> Option { #[cfg(feature="std")] { - self.cause.as_ref().and_then(|b| b.downcast_ref::()).map(|c| c.0) + self.inner.downcast_ref::().map(|c| c.0) } #[cfg(not(feature="std"))] { Some(self.code) @@ -93,31 +73,42 @@ impl Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.msg) + #[cfg(feature="std")] { + write!(f, "{}", self.inner) + } + #[cfg(not(feature="std"))] { + write!(f, "error code {}", self.code) + } + } +} + +impl From for Error { + fn from(code: NonZeroU32) -> Self { + #[cfg(feature="std")] { + Error { inner: Box::new(ErrorCode(code)) } + } + #[cfg(not(feature="std"))] { + Error { code } + } } } #[cfg(feature="getrandom")] impl From for Error { fn from(error: getrandom::Error) -> Self { - let msg = "getrandom error"; #[cfg(feature="std")] { - Error { msg, cause: Some(Box::new(error)) } + Error { inner: Box::new(error) } } #[cfg(not(feature="std"))] { - Error { msg, code: error.code() } + Error { code: error.code() } } } } #[cfg(feature="std")] impl std::error::Error for Error { - fn description(&self) -> &str { - self.msg - } - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - self.cause.as_ref().map(|e| e.as_ref() as &std::error::Error) + self.inner.source() } } @@ -135,7 +126,7 @@ struct ErrorCode(NonZeroU32); #[cfg(feature="std")] impl fmt::Display for ErrorCode { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "ErrorCode({})", self.0) + write!(f, "error code {}", self.0) } } diff --git a/src/rngs/adapter/mod.rs b/src/rngs/adapter/mod.rs index 60b832e9a4d..659ff26218d 100644 --- a/src/rngs/adapter/mod.rs +++ b/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/src/rngs/adapter/read.rs b/src/rngs/adapter/read.rs index 4c08f97362b..53b741491ab 100644 --- a/src/rngs/adapter/read.rs +++ b/src/rngs/adapter/read.rs @@ -10,6 +10,7 @@ //! A wrapper around any Read to treat it as an RNG. use std::io::Read; +use std::fmt; use rand_core::{RngCore, Error, impls}; @@ -73,11 +74,27 @@ impl RngCore for ReadRng { fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { if dest.len() == 0 { return Ok(()); } // Use `std::io::read_exact`, which retries on `ErrorKind::Interrupted`. - self.reader.read_exact(dest).map_err(|err| - Error::with_cause("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; @@ -124,6 +141,8 @@ mod test { let mut rng = ReadRng::new(&v[..]); - assert!(rng.try_fill_bytes(&mut w).is_err()); + let result = rng.try_fill_bytes(&mut w); + assert!(result.is_err()); + println!("Error: {}", result.unwrap_err()); } } From c5a5ab17937a3c96ca8f08fe711714d1e14061a4 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Tue, 28 May 2019 10:54:17 +0100 Subject: [PATCH 8/9] Fix support for getrandom without std --- .travis.yml | 1 + Cargo.toml | 8 +++++--- src/lib.rs | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4e754799448..4baf810c8bd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -268,6 +268,7 @@ before_install: script: - cargo test --tests --no-default-features + - cargo test --no-default-features --features getrandom # TODO: add simd_support feature: - cargo test --features=serde1,log - cargo test --examples diff --git a/Cargo.toml b/Cargo.toml index 7d80b25f934..14e4cd9bf80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,8 +28,9 @@ i128_support = [] # enables i128 and u128 support simd_support = ["packed_simd"] # enables SIMD support serde1 = ["rand_core/serde1", "rand_isaac/serde1", "rand_xorshift/serde1"] # enables serialization for PRNGs # re-export optional WASM dependencies to avoid breakage: -wasm-bindgen = ["getrandom/wasm-bindgen"] -stdweb = ["getrandom/stdweb"] +wasm-bindgen = ["getrandom_package/wasm-bindgen"] +stdweb = ["getrandom_package/stdweb"] +getrandom = ["getrandom_package", "rand_core/getrandom"] [workspace] members = [ @@ -50,7 +51,8 @@ members = [ rand_core = { path = "rand_core", version = "0.4" } rand_pcg = { path = "rand_pcg", version = "0.1" } rand_hc = { path = "rand_hc", version = "0.1" } -getrandom = { version = "0.1.1", optional = true } +# Do not depend on 'getrandom_package' directly; use the 'getrandom' feature! +getrandom_package = { version = "0.1.1", package = "getrandom", optional = true } log = { version = "0.4", optional = true } [dependencies.packed_simd] diff --git a/src/lib.rs b/src/lib.rs index 1ea2fb2e8a9..dcfdb8bbf03 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,7 +59,7 @@ #[cfg(feature="simd_support")] extern crate packed_simd; #[cfg(feature = "getrandom")] -extern crate getrandom; +extern crate getrandom_package as getrandom; extern crate rand_core; extern crate rand_hc; From 2d5594760ee5cfd5099e8e66bd676f7373b5fce2 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Tue, 28 May 2019 14:22:46 +0100 Subject: [PATCH 9/9] Fix rand_jitter error conversion --- rand_jitter/src/error.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/rand_jitter/src/error.rs b/rand_jitter/src/error.rs index b643aebc9db..3ea72c38424 100644 --- a/rand_jitter/src/error.rs +++ b/rand_jitter/src/error.rs @@ -11,20 +11,23 @@ use rand_core::Error; use core::fmt; /// An error that can occur when [`JitterRng::test_timer`] fails. +/// +/// All variants have a value of 0x6e530400 = 1850934272 plus a small +/// increment (1 through 5). /// /// [`JitterRng::test_timer`]: crate::JitterRng::test_timer #[derive(Debug, Clone, PartialEq, Eq)] pub enum TimerError { /// No timer available. - NoTimer, + NoTimer = 0x6e530401, /// Timer too coarse to use as an entropy source. - CoarseTimer, + CoarseTimer = 0x6e530402, /// Timer is not monotonically increasing. - NotMonotonic, + NotMonotonic = 0x6e530403, /// Variations of deltas of time too small. - TinyVariantions, + TinyVariantions = 0x6e530404, /// Too many stuck results (indicating no added entropy). - TooManyStuck, + TooManyStuck = 0x6e530405, #[doc(hidden)] __Nonexhaustive, } @@ -60,11 +63,10 @@ impl From for Error { // Timer check is already quite permissive of failures so we don't // expect false-positive failures, i.e. any error is irrecoverable. #[cfg(feature = "std")] { - Error::with_cause("timer jitter failed basic quality tests", err) + Error::new(err) } #[cfg(not(feature = "std"))] { - let _ = err; - Error::new("timer jitter failed basic quality tests") + Error::from(core::num::NonZeroU32::new(err as u32).unwrap()) } } }