+65
-2
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
///
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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. 39–47, 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. 39–47, 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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user