Merge pull request #514 from pitdicker/merge_0.5

Merge 0.5
This commit is contained in:
Diggory Hardy
2018-06-16 09:47:02 +01:00
committed by GitHub
14 changed files with 424 additions and 169 deletions
+65 -2
View File
@@ -249,11 +249,42 @@ impl SeedableRng for StdRng {
impl CryptoRng for StdRng {}
#[cfg(feature="std")]
#[cfg(all(feature="std",
any(target_os = "linux", target_os = "android",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "haiku",
target_os = "emscripten",
target_os = "solaris",
target_os = "cloudabi",
target_os = "macos", target_os = "ios",
target_os = "freebsd",
target_os = "openbsd", target_os = "bitrig",
target_os = "redox",
target_os = "fuchsia",
windows,
all(target_arch = "wasm32", feature = "stdweb")
)))]
#[derive(Clone, Debug)]
#[deprecated(since="0.6.0", note="import with rand::rngs::OsRng instead")]
pub struct OsRng(rngs::OsRng);
#[cfg(all(feature="std",
any(target_os = "linux", target_os = "android",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "haiku",
target_os = "emscripten",
target_os = "solaris",
target_os = "cloudabi",
target_os = "macos", target_os = "ios",
target_os = "freebsd",
target_os = "openbsd", target_os = "bitrig",
target_os = "redox",
target_os = "fuchsia",
windows,
all(target_arch = "wasm32", feature = "stdweb")
)))]
#[cfg(feature="std")]
impl RngCore for OsRng {
#[inline(always)]
@@ -277,6 +308,22 @@ impl RngCore for OsRng {
}
}
#[cfg(all(feature="std",
any(target_os = "linux", target_os = "android",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "haiku",
target_os = "emscripten",
target_os = "solaris",
target_os = "cloudabi",
target_os = "macos", target_os = "ios",
target_os = "freebsd",
target_os = "openbsd", target_os = "bitrig",
target_os = "redox",
target_os = "fuchsia",
windows,
all(target_arch = "wasm32", feature = "stdweb")
)))]
#[cfg(feature="std")]
impl OsRng {
pub fn new() -> Result<Self, Error> {
@@ -284,6 +331,22 @@ impl OsRng {
}
}
#[cfg(all(feature="std",
any(target_os = "linux", target_os = "android",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "haiku",
target_os = "emscripten",
target_os = "solaris",
target_os = "cloudabi",
target_os = "macos", target_os = "ios",
target_os = "freebsd",
target_os = "openbsd", target_os = "bitrig",
target_os = "redox",
target_os = "fuchsia",
windows,
all(target_arch = "wasm32", feature = "stdweb")
)))]
#[cfg(feature="std")]
impl CryptoRng for OsRng {}
@@ -361,7 +424,7 @@ impl RngCore for JitterRng {
}
impl JitterRng {
#[cfg(feature="std")]
#[cfg(all(feature="std", not(target_arch = "wasm32")))]
pub fn new() -> Result<JitterRng, rngs::TimerError> {
rngs::JitterRng::new().map(JitterRng)
}
+9 -9
View File
@@ -19,14 +19,14 @@ use distributions::{ziggurat, ziggurat_tables, Distribution};
///
/// See `Exp` for the general exponential distribution.
///
/// Implemented via the ZIGNOR variant[1] of the Ziggurat method. The
/// exact description in the paper was adjusted to use tables for the
/// exponential distribution rather than normal.
/// Implemented via the ZIGNOR variant[^1] of the Ziggurat method. The exact
/// description in the paper was adjusted to use tables for the exponential
/// distribution rather than normal.
///
/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
/// Generate Normal Random
/// Samples*](https://www.doornik.com/research/ziggurat.pdf). Nuffield
/// College, Oxford
/// [^1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
/// Generate Normal Random Samples*](
/// https://www.doornik.com/research/ziggurat.pdf).
/// Nuffield College, Oxford
///
/// # Example
/// ```
@@ -61,8 +61,8 @@ impl Distribution<f64> for Exp1 {
/// The exponential distribution `Exp(lambda)`.
///
/// This distribution has density function: `f(x) = lambda *
/// exp(-lambda * x)` for `x > 0`.
/// This distribution has density function: `f(x) = lambda * exp(-lambda * x)`
/// for `x > 0`.
///
/// # Example
///
+6 -6
View File
@@ -28,9 +28,9 @@ use distributions::{Distribution, Exp, Open01};
/// where `Γ` is the Gamma function, `k` is the shape and `θ` is the
/// scale and both `k` and `θ` are strictly positive.
///
/// The algorithm used is that described by Marsaglia & Tsang 2000[1],
/// The algorithm used is that described by Marsaglia & Tsang 2000[^1],
/// falling back to directly sampling from an Exponential for `shape
/// == 1`, and using the boosting technique described in [1] for
/// == 1`, and using the boosting technique described in that paper for
/// `shape < 1`.
///
/// # Example
@@ -43,10 +43,10 @@ use distributions::{Distribution, Exp, Open01};
/// println!("{} is from a Gamma(2, 5) distribution", v);
/// ```
///
/// [1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method
/// for Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3
/// (September 2000),
/// 363-372. DOI:[10.1145/358407.358414](https://doi.acm.org/10.1145/358407.358414)
/// [^1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method for
/// Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3
/// (September 2000), 363-372.
/// DOI:[10.1145/358407.358414](https://doi.acm.org/10.1145/358407.358414)
#[derive(Clone, Copy, Debug)]
pub struct Gamma {
repr: GammaRepr,
+7 -3
View File
@@ -142,7 +142,6 @@
//! [`Rng::gen_range`]: ../trait.Rng.html#method.gen_range
//! [`Rng::gen()`]: ../trait.Rng.html#method.gen
//! [`Rng`]: ../trait.Rng.html
//! [`sample_iter`]: trait.Distribution.html#method.sample_iter
//! [`uniform` module]: uniform/index.html
//! [Floating point implementation]: struct.Standard.html#floating-point-implementation
// distributions
@@ -166,6 +165,8 @@
//! [`StandardNormal`]: struct.StandardNormal.html
//! [`StudentT`]: struct.StudentT.html
//! [`Uniform`]: struct.Uniform.html
//! [`Uniform::new`]: struct.Uniform.html#method.new
//! [`Uniform::new_inclusive`]: struct.Uniform.html#method.new_inclusive
use Rng;
@@ -220,15 +221,18 @@ mod ziggurat_tables;
use distributions::float::IntoFloat;
/// Types (distributions) that can be used to create a random instance of `T`.
///
///
/// It is possible to sample from a distribution through both the
/// [`Distribution`] and [`Rng`] traits, via `distr.sample(&mut rng)` and
/// `Distribution` and [`Rng`] traits, via `distr.sample(&mut rng)` and
/// `rng.sample(distr)`. They also both offer the [`sample_iter`] method, which
/// produces an iterator that samples from the distribution.
///
/// All implementations are expected to be immutable; this has the significant
/// advantage of not needing to consider thread safety, and for most
/// distributions efficient state-less sampling algorithms are available.
///
/// [`Rng`]: ../trait.Rng.html
/// [`sample_iter`]: trait.Distribution.html#method.sample_iter
pub trait Distribution<T> {
/// Generate a random value of `T`, using `rng` as the source of randomness.
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> T;
+10 -10
View File
@@ -14,17 +14,17 @@ use Rng;
use distributions::{ziggurat, ziggurat_tables, Distribution, Open01};
/// Samples floating-point numbers according to the normal distribution
/// `N(0, 1)` (a.k.a. a standard normal, or Gaussian). This is equivalent to
/// `N(0, 1)` (a.k.a. a standard normal, or Gaussian). This is equivalent to
/// `Normal::new(0.0, 1.0)` but faster.
///
/// See `Normal` for the general normal distribution.
///
/// Implemented via the ZIGNOR variant[1] of the Ziggurat method.
/// Implemented via the ZIGNOR variant[^1] of the Ziggurat method.
///
/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
/// Generate Normal Random
/// Samples*](https://www.doornik.com/research/ziggurat.pdf). Nuffield
/// College, Oxford
/// [^1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
/// Generate Normal Random Samples*](
/// https://www.doornik.com/research/ziggurat.pdf).
/// Nuffield College, Oxford
///
/// # Example
/// ```
@@ -74,8 +74,8 @@ impl Distribution<f64> for StandardNormal {
/// The normal distribution `N(mean, std_dev**2)`.
///
/// This uses the ZIGNOR variant of the Ziggurat method, see
/// `StandardNormal` for more details.
/// This uses the ZIGNOR variant of the Ziggurat method, see `StandardNormal`
/// for more details.
///
/// # Example
///
@@ -119,8 +119,8 @@ impl Distribution<f64> for Normal {
/// The log-normal distribution `ln N(mean, std_dev**2)`.
///
/// If `X` is log-normal distributed, then `ln(X)` is `N(mean,
/// std_dev**2)` distributed.
/// If `X` is log-normal distributed, then `ln(X)` is `N(mean, std_dev**2)`
/// distributed.
///
/// # Example
///
+43 -3
View File
@@ -249,11 +249,16 @@ extern crate stdweb;
extern crate rand_core;
#[cfg(feature = "log")] #[macro_use] extern crate log;
#[allow(unused)]
#[cfg(not(feature = "log"))] macro_rules! trace { ($($x:tt)*) => () }
#[allow(unused)]
#[cfg(not(feature = "log"))] macro_rules! debug { ($($x:tt)*) => () }
#[allow(unused)]
#[cfg(not(feature = "log"))] macro_rules! info { ($($x:tt)*) => () }
#[allow(unused)]
#[cfg(not(feature = "log"))] macro_rules! warn { ($($x:tt)*) => () }
#[cfg(all(feature="std", not(feature = "log")))] macro_rules! error { ($($x:tt)*) => () }
#[allow(unused)]
#[cfg(not(feature = "log"))] macro_rules! error { ($($x:tt)*) => () }
// Re-exports from rand_core
@@ -279,7 +284,27 @@ pub mod seq;
#[doc(hidden)] pub use deprecated::ReseedingRng;
#[allow(deprecated)]
#[cfg(feature="std")] #[doc(hidden)] pub use deprecated::{EntropyRng, OsRng};
#[cfg(feature="std")] #[doc(hidden)] pub use deprecated::EntropyRng;
#[allow(deprecated)]
#[cfg(all(feature="std",
any(target_os = "linux", target_os = "android",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "haiku",
target_os = "emscripten",
target_os = "solaris",
target_os = "cloudabi",
target_os = "macos", target_os = "ios",
target_os = "freebsd",
target_os = "openbsd", target_os = "bitrig",
target_os = "redox",
target_os = "fuchsia",
windows,
all(target_arch = "wasm32", feature = "stdweb")
)))]
#[doc(hidden)]
pub use deprecated::OsRng;
#[allow(deprecated)]
#[doc(hidden)] pub use deprecated::{ChaChaRng, IsaacRng, Isaac64Rng, XorShiftRng};
@@ -294,7 +319,22 @@ pub mod jitter {
pub use rngs::TimerError;
}
#[allow(deprecated)]
#[cfg(feature="std")]
#[cfg(all(feature="std",
any(target_os = "linux", target_os = "android",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "haiku",
target_os = "emscripten",
target_os = "solaris",
target_os = "cloudabi",
target_os = "macos", target_os = "ios",
target_os = "freebsd",
target_os = "openbsd", target_os = "bitrig",
target_os = "redox",
target_os = "fuchsia",
windows,
all(target_arch = "wasm32", feature = "stdweb")
)))]
#[doc(hidden)]
pub mod os {
pub use deprecated::OsRng;
+7 -7
View File
@@ -20,10 +20,10 @@ const STATE_WORDS: usize = 16;
/// A cryptographically secure random number generator that uses the ChaCha
/// algorithm.
///
/// ChaCha is a stream cipher designed by Daniel J. Bernstein [1], that we use
/// ChaCha is a stream cipher designed by Daniel J. Bernstein [^1], that we use
/// as an RNG. It is an improved variant of the Salsa20 cipher family, which was
/// selected as one of the "stream ciphers suitable for widespread adoption" by
/// eSTREAM [2].
/// eSTREAM [^2].
///
/// ChaCha uses add-rotate-xor (ARX) operations as its basis. These are safe
/// against timing attacks, although that is mostly a concern for ciphers and
@@ -39,7 +39,7 @@ const STATE_WORDS: usize = 16;
/// configuration in the future.
///
/// We use a 64-bit counter and 64-bit stream identifier as in Benstein's
/// implementation [1] except that we use a stream identifier in place of a
/// implementation [^1] except that we use a stream identifier in place of a
/// nonce. A 64-bit counter over 64-byte (16 word) blocks allows 1 ZiB of output
/// before cycling, and the stream identifier allows 2<sup>64</sup> unique
/// streams of output per seed. Both counter and stream are initialized to zero
@@ -57,11 +57,11 @@ const STATE_WORDS: usize = 16;
/// This implementation uses an output buffer of sixteen `u32` words, and uses
/// [`BlockRng`] to implement the [`RngCore`] methods.
///
/// [1]: D. J. Bernstein, [*ChaCha, a variant of Salsa20*](
/// https://cr.yp.to/chacha.html)
/// [^1]: D. J. Bernstein, [*ChaCha, a variant of Salsa20*](
/// https://cr.yp.to/chacha.html)
///
/// [2]: [eSTREAM: the ECRYPT Stream Cipher Project](
/// http://www.ecrypt.eu.org/stream/)
/// [^2]: [eSTREAM: the ECRYPT Stream Cipher Project](
/// http://www.ecrypt.eu.org/stream/)
///
/// [`set_word_pos`]: #method.set_word_pos
/// [`set_stream`]: #method.set_stream
+19 -18
View File
@@ -19,13 +19,13 @@ const SEED_WORDS: usize = 8; // 128 bit key followed by 128 bit iv
/// A cryptographically secure random number generator that uses the HC-128
/// algorithm.
///
/// HC-128 is a stream cipher designed by Hongjun Wu [1], that we use as an RNG.
/// It is selected as one of the "stream ciphers suitable for widespread
/// adoption" by eSTREAM [2].
/// HC-128 is a stream cipher designed by Hongjun Wu[^1], that we use as an
/// RNG. It is selected as one of the "stream ciphers suitable for widespread
/// adoption" by eSTREAM[^2].
///
/// HC-128 is an array based RNG. In this it is similar to RC-4 and ISAAC before
/// it, but those have never been proven cryptographically secure (or have even
/// been significantly compromised, as in the case of RC-4 [5]).
/// been significantly compromised, as in the case of RC-4[^5]).
///
/// Because HC-128 works with simple indexing into a large array and with a few
/// operations that parallelize well, it has very good performance. The size of
@@ -33,11 +33,12 @@ const SEED_WORDS: usize = 8; // 128 bit key followed by 128 bit iv
///
/// This implementation is not based on the version of HC-128 submitted to the
/// eSTREAM contest, but on a later version by the author with a few small
/// improvements from December 15, 2009 [3].
/// improvements from December 15, 2009[^3].
///
/// HC-128 has no known weaknesses that are easier to exploit than doing a
/// brute-force search of 2<sup>128</sup>. A very comprehensive analysis of the
/// current state of known attacks / weaknesses of HC-128 is given in [4].
/// current state of known attacks / weaknesses of HC-128 is given in *Some
/// Results On Analysis And Implementation Of HC-128 Stream Cipher*[^4].
///
/// The average cycle length is expected to be
/// 2<sup>1024*32+10-1</sup> = 2<sup>32777</sup>.
@@ -48,22 +49,22 @@ const SEED_WORDS: usize = 8; // 128 bit key followed by 128 bit iv
/// [`BlockRng`] to implement the [`RngCore`] methods.
///
/// ## References
/// [1]: Hongjun Wu (2008). ["The Stream Cipher HC-128"](
/// http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf).
/// *The eSTREAM Finalists*, LNCS 4986, pp. 3947, Springer-Verlag.
/// [^1]: Hongjun Wu (2008). ["The Stream Cipher HC-128"](
/// http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf).
/// *The eSTREAM Finalists*, LNCS 4986, pp. 3947, Springer-Verlag.
///
/// [2]: [eSTREAM: the ECRYPT Stream Cipher Project](
/// http://www.ecrypt.eu.org/stream/)
/// [^2]: [eSTREAM: the ECRYPT Stream Cipher Project](
/// http://www.ecrypt.eu.org/stream/)
///
/// [3]: Hongjun Wu, [Stream Ciphers HC-128 and HC-256](
/// https://www.ntu.edu.sg/home/wuhj/research/hc/index.html)
/// [^3]: Hongjun Wu, [Stream Ciphers HC-128 and HC-256](
/// https://www.ntu.edu.sg/home/wuhj/research/hc/index.html)
///
/// [4]: Shashwat Raizada (January 2015),["Some Results On Analysis And
/// Implementation Of HC-128 Stream Cipher"](
/// http://library.isical.ac.in:8080/jspui/bitstream/123456789/6636/1/TH431.pdf).
/// [^4]: Shashwat Raizada (January 2015),["Some Results On Analysis And
/// Implementation Of HC-128 Stream Cipher"](
/// http://library.isical.ac.in:8080/jspui/bitstream/123456789/6636/1/TH431.pdf).
///
/// [5]: Internet Engineering Task Force (February 2015),
/// ["Prohibiting RC4 Cipher Suites"](https://tools.ietf.org/html/rfc7465).
/// [^5]: Internet Engineering Task Force (February 2015),
/// ["Prohibiting RC4 Cipher Suites"](https://tools.ietf.org/html/rfc7465).
///
/// [`BlockRng`]: ../../../rand_core/block/struct.BlockRng.html
/// [`RngCore`]: ../../trait.RngCore.html
+12 -12
View File
@@ -27,7 +27,7 @@ const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are
/// the principal bitwise operations employed. It is the most advanced of a
/// series of array based random number generator designed by Robert Jenkins
/// in 1996[1][2].
/// in 1996[^1][^2].
///
/// ISAAC is notably fast and produces excellent quality random numbers for
/// non-cryptographic applications.
@@ -39,7 +39,7 @@ const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
/// the stream-ciphers selected the by eSTREAM contest.
///
/// In 2006 an improvement to ISAAC was suggested by Jean-Philippe Aumasson,
/// named ISAAC+[3]. But because the specification is not complete, because
/// named ISAAC+[^3]. But because the specification is not complete, because
/// there is no good implementation, and because the suggested bias may not
/// exist, it is not implemented here.
///
@@ -78,14 +78,14 @@ const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
/// This implementation uses [`BlockRng`] to implement the [`RngCore`] methods.
///
/// ## References
/// [1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number generator*](
/// http://burtleburtle.net/bob/rand/isaacafa.html)
/// [^1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number generator*](
/// http://burtleburtle.net/bob/rand/isaacafa.html)
///
/// [2]: Bob Jenkins, [*ISAAC and RC4*](
/// http://burtleburtle.net/bob/rand/isaac.html)
/// [^2]: Bob Jenkins, [*ISAAC and RC4*](
/// http://burtleburtle.net/bob/rand/isaac.html)
///
/// [3]: Jean-Philippe Aumasson, [*On the pseudo-random generator ISAAC*](
/// https://eprint.iacr.org/2006/438)
/// [^3]: Jean-Philippe Aumasson, [*On the pseudo-random generator ISAAC*](
/// https://eprint.iacr.org/2006/438)
///
/// [`Hc128Rng`]: ../hc128/struct.Hc128Rng.html
/// [`BlockRng`]: ../../../rand_core/block/struct.BlockRng.html
@@ -243,11 +243,11 @@ impl IsaacCore {
/// will take as much time to brute force as 40-bit keys usually will). You
/// could fill the remainder with 0, but set the last array element to the
/// length of the key provided (to distinguish keys that differ only by
/// different amounts of 0 padding). You do still need to call randinit() to
/// make sure the initial state isn't uniform-looking."
/// different amounts of 0 padding). You do still need to call `randinit()`
/// to make sure the initial state isn't uniform-looking."
/// "After publishing ISAAC, I wanted to limit the key to half the size of
/// r[], and repeat it twice. That would have made it hard to provide a key
/// that sets the whole internal state to anything convenient. But I'd
/// `r[]`, and repeat it twice. That would have made it hard to provide a
/// key that sets the whole internal state to anything convenient. But I'd
/// already published it."
///
/// And his answer to the question "For my code, would repeating the key
+3 -3
View File
@@ -28,7 +28,7 @@ const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are
/// the principal bitwise operations employed. It is the most advanced of a
/// series of array based random number generator designed by Robert Jenkins
/// in 1996[1].
/// in 1996[^1].
///
/// ISAAC-64 is mostly similar to ISAAC. Because it operates on 64-bit integers
/// instead of 32-bit, it uses twice as much memory to hold its state and
@@ -73,8 +73,8 @@ const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
///
/// See for more information the documentation of [`IsaacRng`].
///
/// [1]: Bob Jenkins, [*ISAAC and RC4*](
/// http://burtleburtle.net/bob/rand/isaac.html)
/// [^1]: Bob Jenkins, [*ISAAC and RC4*](
/// http://burtleburtle.net/bob/rand/isaac.html)
///
/// [`IsaacRng`]: ../isaac/struct.IsaacRng.html
/// [`Hc128Rng`]: ../hc128/struct.Hc128Rng.html
+5 -6
View File
@@ -14,16 +14,15 @@ use core::num::Wrapping as w;
use core::{fmt, slice};
use rand_core::{RngCore, SeedableRng, Error, impls, le};
/// An Xorshift[1] random number
/// generator.
/// An Xorshift random number generator.
///
/// The Xorshift algorithm is not suitable for cryptographic purposes
/// The Xorshift[^1] algorithm is not suitable for cryptographic purposes
/// but is very fast. If you do not know for sure that it fits your
/// requirements, use a more secure one such as `IsaacRng` or `OsRng`.
///
/// [1]: Marsaglia, George (July 2003). ["Xorshift
/// RNGs"](https://www.jstatsoft.org/v08/i14/paper). *Journal of
/// Statistical Software*. Vol. 8 (Issue 14).
/// [^1]: Marsaglia, George (July 2003).
/// ["Xorshift RNGs"](https://www.jstatsoft.org/v08/i14/paper).
/// *Journal of Statistical Software*. Vol. 8 (Issue 14).
#[derive(Clone)]
#[cfg_attr(feature="serde1", derive(Serialize,Deserialize))]
pub struct XorShiftRng {
+191 -72
View File
@@ -10,8 +10,9 @@
//! Entropy generator, or wrapper around external generators
use rand_core::{RngCore, CryptoRng, Error, impls};
use rngs::{OsRng, JitterRng};
use rand_core::{RngCore, CryptoRng, Error, ErrorKind, impls};
#[allow(unused)]
use rngs;
/// An interface returning random data from external source(s), provided
/// specifically for securely seeding algorithmic generators (PRNGs).
@@ -46,13 +47,14 @@ use rngs::{OsRng, JitterRng};
/// [`try_fill_bytes`]: ../trait.RngCore.html#method.tymethod.try_fill_bytes
#[derive(Debug)]
pub struct EntropyRng {
rng: EntropySource,
source: Source,
}
#[derive(Debug)]
enum EntropySource {
Os(OsRng),
Jitter(JitterRng),
enum Source {
Os(Os),
Custom(Custom),
Jitter(Jitter),
None,
}
@@ -63,7 +65,7 @@ impl EntropyRng {
/// those are done on first use. This is done to make `new` infallible,
/// and `try_fill_bytes` the only place to report errors.
pub fn new() -> Self {
EntropyRng { rng: EntropySource::None }
EntropyRng { source: Source::None }
}
}
@@ -88,82 +90,199 @@ impl RngCore for EntropyRng {
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
fn try_os_new(dest: &mut [u8]) -> Result<OsRng, Error>
{
let mut rng = OsRng::new()?;
rng.try_fill_bytes(dest)?;
Ok(rng)
}
let mut reported_error = None;
fn try_jitter_new(dest: &mut [u8]) -> Result<JitterRng, Error>
{
let mut rng = JitterRng::new()?;
rng.try_fill_bytes(dest)?;
Ok(rng)
}
let mut switch_rng = None;
match self.rng {
EntropySource::None => {
let os_rng_result = try_os_new(dest);
match os_rng_result {
Ok(os_rng) => {
debug!("EntropyRng: using OsRng");
switch_rng = Some(EntropySource::Os(os_rng));
}
Err(os_rng_error) => {
warn!("EntropyRng: OsRng failed [falling back to JitterRng]: {}",
os_rng_error);
match try_jitter_new(dest) {
Ok(jitter_rng) => {
debug!("EntropyRng: using JitterRng");
switch_rng = Some(EntropySource::Jitter(jitter_rng));
}
Err(_jitter_error) => {
warn!("EntropyRng: JitterRng failed: {}",
_jitter_error);
return Err(os_rng_error);
}
}
}
}
if let Source::Os(ref mut os_rng) = self.source {
match os_rng.fill(dest) {
Ok(()) => return Ok(()),
Err(err) => {
warn!("EntropyRng: OsRng failed \
[trying other entropy sources]: {}", err);
reported_error = Some(err);
},
}
EntropySource::Os(ref mut rng) => {
let os_rng_result = rng.try_fill_bytes(dest);
if let Err(os_rng_error) = os_rng_result {
warn!("EntropyRng: OsRng failed [falling back to JitterRng]: {}",
os_rng_error);
match try_jitter_new(dest) {
Ok(jitter_rng) => {
debug!("EntropyRng: using JitterRng");
switch_rng = Some(EntropySource::Jitter(jitter_rng));
}
Err(_jitter_error) => {
warn!("EntropyRng: JitterRng failed: {}",
_jitter_error);
return Err(os_rng_error);
}
}
}
}
EntropySource::Jitter(ref mut rng) => {
if let Ok(os_rng) = try_os_new(dest) {
} else if Os::is_supported() {
match Os::new_and_fill(dest) {
Ok(os_rng) => {
debug!("EntropyRng: using OsRng");
switch_rng = Some(EntropySource::Os(os_rng));
} else {
return rng.try_fill_bytes(dest); // use JitterRng
}
self.source = Source::Os(os_rng);
return Ok(());
},
Err(err) => { reported_error = reported_error.or(Some(err)) },
}
}
if let Some(rng) = switch_rng {
self.rng = rng;
if let Source::Custom(ref mut rng) = self.source {
match rng.fill(dest) {
Ok(()) => return Ok(()),
Err(err) => {
warn!("EntropyRng: custom entropy source failed \
[trying other entropy sources]: {}", err);
reported_error = Some(err);
},
}
} else if Custom::is_supported() {
match Custom::new_and_fill(dest) {
Ok(custom) => {
debug!("EntropyRng: using custom entropy source");
self.source = Source::Custom(custom);
return Ok(());
},
Err(err) => { reported_error = reported_error.or(Some(err)) },
}
}
if let Source::Jitter(ref mut jitter_rng) = self.source {
match jitter_rng.fill(dest) {
Ok(()) => return Ok(()),
Err(err) => {
warn!("EntropyRng: JitterRng failed: {}", err);
reported_error = Some(err);
},
}
} else if Jitter::is_supported() {
match Jitter::new_and_fill(dest) {
Ok(jitter_rng) => {
debug!("EntropyRng: using JitterRng");
self.source = Source::Jitter(jitter_rng);
return Ok(());
},
Err(err) => { reported_error = reported_error.or(Some(err)) },
}
}
if let Some(err) = reported_error {
Err(Error::with_cause(ErrorKind::Unavailable,
"All entropy sources failed",
err))
} else {
Err(Error::new(ErrorKind::Unavailable,
"No entropy sources available"))
}
Ok(())
}
}
impl CryptoRng for EntropyRng {}
trait EntropySource {
fn new_and_fill(dest: &mut [u8]) -> Result<Self, Error>
where Self: Sized;
fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error>;
fn is_supported() -> bool { true }
}
#[allow(unused)]
#[derive(Clone, Debug)]
struct NoSource;
#[allow(unused)]
impl EntropySource for NoSource {
fn new_and_fill(dest: &mut [u8]) -> Result<Self, Error> {
Err(Error::new(ErrorKind::Unavailable, "Source not supported"))
}
fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error> {
unreachable!()
}
fn is_supported() -> bool { false }
}
#[cfg(all(feature="std",
any(target_os = "linux", target_os = "android",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "haiku",
target_os = "emscripten",
target_os = "solaris",
target_os = "cloudabi",
target_os = "macos", target_os = "ios",
target_os = "freebsd",
target_os = "openbsd", target_os = "bitrig",
target_os = "redox",
target_os = "fuchsia",
windows,
all(target_arch = "wasm32", feature = "stdweb")
)))]
#[derive(Clone, Debug)]
pub struct Os(rngs::OsRng);
#[cfg(all(feature="std",
any(target_os = "linux", target_os = "android",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "haiku",
target_os = "emscripten",
target_os = "solaris",
target_os = "cloudabi",
target_os = "macos", target_os = "ios",
target_os = "freebsd",
target_os = "openbsd", target_os = "bitrig",
target_os = "redox",
target_os = "fuchsia",
windows,
all(target_arch = "wasm32", feature = "stdweb")
)))]
impl EntropySource for Os {
fn new_and_fill(dest: &mut [u8]) -> Result<Self, Error> {
let mut rng = rngs::OsRng::new()?;
rng.try_fill_bytes(dest)?;
Ok(Os(rng))
}
fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.0.try_fill_bytes(dest)
}
}
#[cfg(not(all(feature="std",
any(target_os = "linux", target_os = "android",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "haiku",
target_os = "emscripten",
target_os = "solaris",
target_os = "cloudabi",
target_os = "macos", target_os = "ios",
target_os = "freebsd",
target_os = "openbsd", target_os = "bitrig",
target_os = "redox",
target_os = "fuchsia",
windows,
all(target_arch = "wasm32", feature = "stdweb")
))))]
type Os = NoSource;
type Custom = NoSource;
#[cfg(not(target_arch = "wasm32"))]
#[derive(Clone, Debug)]
pub struct Jitter(rngs::JitterRng);
#[cfg(not(target_arch = "wasm32"))]
impl EntropySource for Jitter {
fn new_and_fill(dest: &mut [u8]) -> Result<Self, Error> {
let mut rng = rngs::JitterRng::new()?;
rng.try_fill_bytes(dest)?;
Ok(Jitter(rng))
}
fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.0.try_fill_bytes(dest)
}
}
#[cfg(target_arch = "wasm32")]
type Jitter = NoSource;
#[cfg(test)]
mod test {
use super::*;
+11 -16
View File
@@ -24,7 +24,7 @@
use rand_core::{RngCore, CryptoRng, Error, ErrorKind, impls};
use core::{fmt, mem, ptr};
#[cfg(feature="std")]
#[cfg(all(feature="std", not(target_arch = "wasm32")))]
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
const MEMORY_BLOCKS: usize = 64;
@@ -54,6 +54,10 @@ const MEMORY_SIZE: usize = MEMORY_BLOCKS * MEMORY_BLOCKSIZE;
/// This implementation is based on
/// [Jitterentropy](http://www.chronox.de/jent.html) version 2.1.0.
///
/// Note: There is no accurate timer available on Wasm platforms, to help
/// prevent fingerprinting or timing side-channel attacks. Therefore
/// [`JitterRng::new()`] is not available on Wasm.
///
/// # Quality testing
///
/// [`JitterRng::new()`] has build-in, but limited, quality testing, however
@@ -268,7 +272,7 @@ impl From<TimerError> for Error {
}
// Initialise to zero; must be positive
#[cfg(feature="std")]
#[cfg(all(feature="std", not(target_arch = "wasm32")))]
static JITTER_ROUNDS: AtomicUsize = ATOMIC_USIZE_INIT;
impl JitterRng {
@@ -279,7 +283,7 @@ impl JitterRng {
/// During initialization CPU execution timing jitter is measured a few
/// hundred times. If this does not pass basic quality tests, an error is
/// returned. The test result is cached to make subsequent calls faster.
#[cfg(feature="std")]
#[cfg(all(feature="std", not(target_arch = "wasm32")))]
pub fn new() -> Result<JitterRng, TimerError> {
let mut state = JitterRng::new_with_timer(platform::get_nstime);
let mut rounds = JITTER_ROUNDS.load(Ordering::Relaxed) as u8;
@@ -771,8 +775,9 @@ impl JitterRng {
#[cfg(feature="std")]
mod platform {
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows",
all(target_arch = "wasm32", not(target_os = "emscripten")))))]
#[cfg(not(any(target_os = "macos", target_os = "ios",
target_os = "windows",
target_arch = "wasm32")))]
pub fn get_nstime() -> u64 {
use std::time::{SystemTime, UNIX_EPOCH};
@@ -805,16 +810,6 @@ mod platform {
*t.QuadPart() as u64
}
}
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
pub fn get_nstime() -> u64 {
// We don't use the timer from the standard library, because it panics
// at runtime.
//
// There is no accurate timer available on Wasm platforms, to help
// prevent fingerprinting or timing side-channel attacks.
0 // Will make `test_timer` fail with `NoTimer`.
}
}
// A function that is opaque to the optimizer to assist in avoiding dead-code
@@ -865,7 +860,7 @@ impl CryptoRng for JitterRng {}
mod test_jitter_init {
use super::JitterRng;
#[cfg(feature="std")]
#[cfg(all(feature="std", not(target_arch = "wasm32")))]
#[test]
fn test_jitter_init() {
use RngCore;
+36 -2
View File
@@ -171,7 +171,6 @@ pub mod adapter;
mod jitter;
pub mod mock; // Public so we don't export `StepRng` directly, making it a bit
// more clear it is intended for testing.
#[cfg(feature="std")] mod os;
mod small;
mod std;
#[cfg(feature="std")] pub(crate) mod thread;
@@ -179,8 +178,43 @@ mod std;
pub use self::jitter::{JitterRng, TimerError};
#[cfg(feature="std")] pub use self::entropy::EntropyRng;
#[cfg(feature="std")] pub use self::os::OsRng;
pub use self::small::SmallRng;
pub use self::std::StdRng;
#[cfg(feature="std")] pub use self::thread::ThreadRng;
#[cfg(all(feature="std",
any(target_os = "linux", target_os = "android",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "haiku",
target_os = "emscripten",
target_os = "solaris",
target_os = "cloudabi",
target_os = "macos", target_os = "ios",
target_os = "freebsd",
target_os = "openbsd", target_os = "bitrig",
target_os = "redox",
target_os = "fuchsia",
windows,
all(target_arch = "wasm32", feature = "stdweb")
)))]
mod os;
#[cfg(all(feature="std",
any(target_os = "linux", target_os = "android",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "haiku",
target_os = "emscripten",
target_os = "solaris",
target_os = "cloudabi",
target_os = "macos", target_os = "ios",
target_os = "freebsd",
target_os = "openbsd", target_os = "bitrig",
target_os = "redox",
target_os = "fuchsia",
windows,
all(target_arch = "wasm32", feature = "stdweb")
)))]
pub use self::os::OsRng;