diff --git a/src/deprecated.rs b/src/deprecated.rs index aa1a3d89..0b6a71d5 100644 --- a/src/deprecated.rs +++ b/src/deprecated.rs @@ -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 { @@ -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 { rngs::JitterRng::new().map(JitterRng) } diff --git a/src/distributions/exponential.rs b/src/distributions/exponential.rs index de6564ea..e8dbdc9c 100644 --- a/src/distributions/exponential.rs +++ b/src/distributions/exponential.rs @@ -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 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 /// diff --git a/src/distributions/gamma.rs b/src/distributions/gamma.rs index 44e1c592..f02cf3b2 100644 --- a/src/distributions/gamma.rs +++ b/src/distributions/gamma.rs @@ -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, diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs index 43256284..9d093f1d 100644 --- a/src/distributions/mod.rs +++ b/src/distributions/mod.rs @@ -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 { /// Generate a random value of `T`, using `rng` as the source of randomness. fn sample(&self, rng: &mut R) -> T; diff --git a/src/distributions/normal.rs b/src/distributions/normal.rs index 69ee6a0d..f053fb6c 100644 --- a/src/distributions/normal.rs +++ b/src/distributions/normal.rs @@ -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 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 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 /// diff --git a/src/lib.rs b/src/lib.rs index e1987a82..8199f28e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; diff --git a/src/prng/chacha.rs b/src/prng/chacha.rs index 1bd8d995..425cb225 100644 --- a/src/prng/chacha.rs +++ b/src/prng/chacha.rs @@ -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 264 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 diff --git a/src/prng/hc128.rs b/src/prng/hc128.rs index 0d62af9f..5aa2d243 100644 --- a/src/prng/hc128.rs +++ b/src/prng/hc128.rs @@ -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 2128. 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 /// 21024*32+10-1 = 232777. @@ -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 diff --git a/src/prng/isaac.rs b/src/prng/isaac.rs index b2b0cb07..4a9a1b63 100644 --- a/src/prng/isaac.rs +++ b/src/prng/isaac.rs @@ -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 diff --git a/src/prng/isaac64.rs b/src/prng/isaac64.rs index a2a62afa..2a749b66 100644 --- a/src/prng/isaac64.rs +++ b/src/prng/isaac64.rs @@ -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 diff --git a/src/prng/xorshift.rs b/src/prng/xorshift.rs index 6a9775d8..4be4f0e1 100644 --- a/src/prng/xorshift.rs +++ b/src/prng/xorshift.rs @@ -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 { diff --git a/src/rngs/entropy.rs b/src/rngs/entropy.rs index e260af9c..b8f4be79 100644 --- a/src/rngs/entropy.rs +++ b/src/rngs/entropy.rs @@ -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 - { - 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 - { - 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 + 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 { + 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 { + 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 { + 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::*; diff --git a/src/rngs/jitter.rs b/src/rngs/jitter.rs index 6aa30294..292aae99 100644 --- a/src/rngs/jitter.rs +++ b/src/rngs/jitter.rs @@ -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 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 { 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; diff --git a/src/rngs/mod.rs b/src/rngs/mod.rs index bcc5ea5f..3e183387 100644 --- a/src/rngs/mod.rs +++ b/src/rngs/mod.rs @@ -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;