diff options
Diffstat (limited to 'rand/src')
| -rw-r--r-- | rand/src/deprecated.rs | 79 | ||||
| -rw-r--r-- | rand/src/distributions/integer.rs | 8 | ||||
| -rw-r--r-- | rand/src/distributions/mod.rs | 6 | ||||
| -rw-r--r-- | rand/src/distributions/uniform.rs | 31 | ||||
| -rw-r--r-- | rand/src/distributions/unit_circle.rs | 11 | ||||
| -rw-r--r-- | rand/src/distributions/unit_sphere.rs | 9 | ||||
| -rw-r--r-- | rand/src/distributions/utils.rs | 6 | ||||
| -rw-r--r-- | rand/src/lib.rs | 110 | ||||
| -rw-r--r-- | rand/src/rngs/entropy.rs | 54 | ||||
| -rw-r--r-- | rand/src/rngs/mod.rs | 39 | ||||
| -rw-r--r-- | rand/src/rngs/os.rs | 1275 | ||||
| -rw-r--r-- | rand/src/rngs/small.rs | 4 | ||||
| -rw-r--r-- | rand/src/rngs/thread.rs | 16 | 
13 files changed, 68 insertions, 1580 deletions
| diff --git a/rand/src/deprecated.rs b/rand/src/deprecated.rs index 985ae61..88eb09f 100644 --- a/rand/src/deprecated.rs +++ b/rand/src/deprecated.rs @@ -151,12 +151,12 @@ impl SeedableRng for ChaChaRng {  }  impl ChaChaRng { -    #[cfg(rust_1_26)] +    #[cfg(all(rustc_1_26, not(target_os = "emscripten")))]      pub fn get_word_pos(&self) -> u128 {          self.0.get_word_pos()      } -    #[cfg(rust_1_26)] +    #[cfg(all(rustc_1_26, not(target_os = "emscripten")))]      pub fn set_word_pos(&mut self, word_offset: u128) {          self.0.set_word_pos(word_offset)      } @@ -291,45 +291,12 @@ impl SeedableRng for StdRng {  impl CryptoRng for StdRng {} -#[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"), -              all(target_arch = "wasm32", feature = "wasm-bindgen"), -)))] +#[cfg(feature="rand_os")]  #[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"), -              all(target_arch = "wasm32", feature = "wasm-bindgen"), -)))] -#[cfg(feature="std")] +#[cfg(feature="rand_os")]  impl RngCore for OsRng {      #[inline(always)]      fn next_u32(&mut self) -> u32 { @@ -352,48 +319,14 @@ 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"), -              all(target_arch = "wasm32", feature = "wasm-bindgen"), -)))] -#[cfg(feature="std")] +#[cfg(feature="rand_os")]  impl OsRng {      pub fn new() -> Result<Self, Error> {          rngs::OsRng::new().map(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"), -              all(target_arch = "wasm32", feature = "wasm-bindgen"), -)))] -#[cfg(feature="std")] +#[cfg(feature="rand_os")]  impl CryptoRng for OsRng {} diff --git a/rand/src/distributions/integer.rs b/rand/src/distributions/integer.rs index 4e6604d..7e408db 100644 --- a/rand/src/distributions/integer.rs +++ b/rand/src/distributions/integer.rs @@ -45,7 +45,7 @@ impl Distribution<u64> for Standard {      }  } -#[cfg(rust_1_26)] +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))]  impl Distribution<u128> for Standard {      #[inline]      fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u128 { @@ -85,7 +85,7 @@ impl_int_from_uint! { i8, u8 }  impl_int_from_uint! { i16, u16 }  impl_int_from_uint! { i32, u32 }  impl_int_from_uint! { i64, u64 } -#[cfg(rust_1_26)] impl_int_from_uint! { i128, u128 } +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] impl_int_from_uint! { i128, u128 }  impl_int_from_uint! { isize, usize }  #[cfg(feature="simd_support")] @@ -147,7 +147,7 @@ mod tests {          rng.sample::<i16, _>(Standard);          rng.sample::<i32, _>(Standard);          rng.sample::<i64, _>(Standard); -        #[cfg(rust_1_26)] +        #[cfg(all(rustc_1_26, not(target_os = "emscripten")))]          rng.sample::<i128, _>(Standard);          rng.sample::<usize, _>(Standard); @@ -155,7 +155,7 @@ mod tests {          rng.sample::<u16, _>(Standard);          rng.sample::<u32, _>(Standard);          rng.sample::<u64, _>(Standard); -        #[cfg(rust_1_26)] +        #[cfg(all(rustc_1_26, not(target_os = "emscripten")))]          rng.sample::<u128, _>(Standard);      }  } diff --git a/rand/src/distributions/mod.rs b/rand/src/distributions/mod.rs index 160cd31..5e879cb 100644 --- a/rand/src/distributions/mod.rs +++ b/rand/src/distributions/mod.rs @@ -182,7 +182,7 @@  //! [`Weibull`]: struct.Weibull.html  //! [`WeightedIndex`]: struct.WeightedIndex.html -#[cfg(any(rust_1_26, features="nightly"))] +#[cfg(any(rustc_1_26, features="nightly"))]  use core::iter;  use Rng; @@ -316,7 +316,7 @@ impl<'a, D, R, T> Iterator for DistIter<'a, D, R, T>      }  } -#[cfg(rust_1_26)] +#[cfg(rustc_1_26)]  impl<'a, D, R, T> iter::FusedIterator for DistIter<'a, D, R, T>      where D: Distribution<T>, R: Rng + 'a {} @@ -328,7 +328,7 @@ impl<'a, D, R, T> iter::TrustedLen for DistIter<'a, D, R, T>  /// A generic random value distribution, implemented for many primitive types.  /// Usually generates values with a numerically uniform distribution, and with a  /// range appropriate to the type. -///  +///  /// ## Built-in Implementations  ///  /// Assuming the provided `Rng` is well-behaved, these implementations diff --git a/rand/src/distributions/uniform.rs b/rand/src/distributions/uniform.rs index 5fb89e3..ceed77d 100644 --- a/rand/src/distributions/uniform.rs +++ b/rand/src/distributions/uniform.rs @@ -111,7 +111,7 @@  #[cfg(feature = "std")]  use std::time::Duration; -#[cfg(all(not(feature = "std"), rust_1_25))] +#[cfg(all(not(feature = "std"), rustc_1_25))]  use core::time::Duration;  use Rng; @@ -277,7 +277,7 @@ impl<X: SampleUniform> From<::core::ops::Range<X>> for Uniform<X> {      }  } -#[cfg(rust_1_27)] +#[cfg(rustc_1_27)]  impl<X: SampleUniform> From<::core::ops::RangeInclusive<X>> for Uniform<X> {      fn from(r: ::core::ops::RangeInclusive<X>) -> Uniform<X> {          Uniform::new_inclusive(r.start(), r.end()) @@ -452,8 +452,9 @@ macro_rules! uniform_int_impl {                          let ints_to_reject = (unsigned_max - range + 1) % range;                          unsigned_max - ints_to_reject                      } else { -                        // conservative but fast approximation -                       range << range.leading_zeros() +                        // conservative but fast approximation. `- 1` is necessary to allow the +                        // same comparison without bias. +                        (range << range.leading_zeros()).wrapping_sub(1)                      };                  loop { @@ -472,7 +473,7 @@ uniform_int_impl! { i8, i8, u8, i32, u32 }  uniform_int_impl! { i16, i16, u16, i32, u32 }  uniform_int_impl! { i32, i32, u32, i32, u32 }  uniform_int_impl! { i64, i64, u64, i64, u64 } -#[cfg(rust_1_26)] +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))]  uniform_int_impl! { i128, i128, u128, u128, u128 }  uniform_int_impl! { isize, isize, usize, isize, usize }  uniform_int_impl! { u8, i8, u8, i32, u32 } @@ -480,7 +481,7 @@ uniform_int_impl! { u16, i16, u16, i32, u32 }  uniform_int_impl! { u32, i32, u32, i32, u32 }  uniform_int_impl! { u64, i64, u64, i64, u64 }  uniform_int_impl! { usize, isize, usize, isize, usize } -#[cfg(rust_1_26)] +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))]  uniform_int_impl! { u128, u128, u128, i128, u128 }  #[cfg(all(feature = "simd_support", feature = "nightly"))] @@ -835,14 +836,14 @@ uniform_float_impl! { f64x8, u64x8, f64, u64, 64 - 52 }  ///  /// [`UniformSampler`]: trait.UniformSampler.html  /// [`Uniform`]: struct.Uniform.html -#[cfg(any(feature = "std", rust_1_25))] +#[cfg(any(feature = "std", rustc_1_25))]  #[derive(Clone, Copy, Debug)]  pub struct UniformDuration {      mode: UniformDurationMode,      offset: u32,  } -#[cfg(any(feature = "std", rust_1_25))] +#[cfg(any(feature = "std", rustc_1_25))]  #[derive(Debug, Copy, Clone)]  enum UniformDurationMode {      Small { @@ -859,12 +860,12 @@ enum UniformDurationMode {      }  } -#[cfg(any(feature = "std", rust_1_25))] +#[cfg(any(feature = "std", rustc_1_25))]  impl SampleUniform for Duration {      type Sampler = UniformDuration;  } -#[cfg(any(feature = "std", rust_1_25))] +#[cfg(any(feature = "std", rustc_1_25))]  impl UniformSampler for UniformDuration {      type X = Duration; @@ -989,7 +990,7 @@ mod tests {      fn test_integers() {          use core::{i8, i16, i32, i64, isize};          use core::{u8, u16, u32, u64, usize}; -        #[cfg(rust_1_26)] +        #[cfg(all(rustc_1_26, not(target_os = "emscripten")))]          use core::{i128, u128};          let mut rng = ::test::rng(251); @@ -1053,7 +1054,7 @@ mod tests {          }          t!(i8, i16, i32, i64, isize,             u8, u16, u32, u64, usize); -        #[cfg(rust_1_26)] +        #[cfg(all(rustc_1_26, not(target_os = "emscripten")))]          t!(i128, u128);          #[cfg(all(feature = "simd_support", feature = "nightly"))] @@ -1208,11 +1209,11 @@ mod tests {      #[test] -    #[cfg(any(feature = "std", rust_1_25))] +    #[cfg(any(feature = "std", rustc_1_25))]      fn test_durations() {          #[cfg(feature = "std")]          use std::time::Duration; -        #[cfg(all(not(feature = "std"), rust_1_25))] +        #[cfg(all(not(feature = "std"), rustc_1_25))]          use core::time::Duration;          let mut rng = ::test::rng(253); @@ -1283,7 +1284,7 @@ mod tests {          assert_eq!(r.inner.scale, 5.0);      } -    #[cfg(rust_1_27)] +    #[cfg(rustc_1_27)]      #[test]      fn test_uniform_from_std_range_inclusive() {          let r = Uniform::from(2u32..=6); diff --git a/rand/src/distributions/unit_circle.rs b/rand/src/distributions/unit_circle.rs index abb36dc..01ab76a 100644 --- a/rand/src/distributions/unit_circle.rs +++ b/rand/src/distributions/unit_circle.rs @@ -29,27 +29,26 @@ use distributions::{Distribution, Uniform};  ///       NBS Appl. Math. Ser., No. 12. Washington, DC: U.S. Government Printing  ///       Office, pp. 36-38.  #[derive(Clone, Copy, Debug)] -pub struct UnitCircle { -    uniform: Uniform<f64>, -} +pub struct UnitCircle;  impl UnitCircle {      /// Construct a new `UnitCircle` distribution.      #[inline]      pub fn new() -> UnitCircle { -        UnitCircle { uniform: Uniform::new(-1., 1.) } +        UnitCircle      }  }  impl Distribution<[f64; 2]> for UnitCircle {      #[inline]      fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [f64; 2] { +        let uniform = Uniform::new(-1., 1.);          let mut x1;          let mut x2;          let mut sum;          loop { -            x1 = self.uniform.sample(rng); -            x2 = self.uniform.sample(rng); +            x1 = uniform.sample(rng); +            x2 = uniform.sample(rng);              sum = x1*x1 + x2*x2;              if sum < 1. {                  break; diff --git a/rand/src/distributions/unit_sphere.rs b/rand/src/distributions/unit_sphere.rs index 61cbda5..37de88b 100644 --- a/rand/src/distributions/unit_sphere.rs +++ b/rand/src/distributions/unit_sphere.rs @@ -28,23 +28,22 @@ use distributions::{Distribution, Uniform};  ///       Sphere.*](https://doi.org/10.1214/aoms/1177692644)  ///       Ann. Math. Statist. 43, no. 2, 645--646.  #[derive(Clone, Copy, Debug)] -pub struct UnitSphereSurface { -    uniform: Uniform<f64>, -} +pub struct UnitSphereSurface;  impl UnitSphereSurface {      /// Construct a new `UnitSphereSurface` distribution.      #[inline]      pub fn new() -> UnitSphereSurface { -        UnitSphereSurface { uniform: Uniform::new(-1., 1.) } +        UnitSphereSurface      }  }  impl Distribution<[f64; 3]> for UnitSphereSurface {      #[inline]      fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [f64; 3] { +        let uniform = Uniform::new(-1., 1.);          loop { -            let (x1, x2) = (self.uniform.sample(rng), self.uniform.sample(rng)); +            let (x1, x2) = (uniform.sample(rng), uniform.sample(rng));              let sum = x1*x1 + x2*x2;              if sum >= 1. {                  continue; diff --git a/rand/src/distributions/utils.rs b/rand/src/distributions/utils.rs index a2112fd..d4d3642 100644 --- a/rand/src/distributions/utils.rs +++ b/rand/src/distributions/utils.rs @@ -61,7 +61,7 @@ macro_rules! wmul_impl {  wmul_impl! { u8, u16, 8 }  wmul_impl! { u16, u32, 16 }  wmul_impl! { u32, u64, 32 } -#[cfg(rust_1_26)] +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))]  wmul_impl! { u64, u128, 64 }  // This code is a translation of the __mulddi3 function in LLVM's @@ -125,9 +125,9 @@ macro_rules! wmul_impl_large {          )+      };  } -#[cfg(not(rust_1_26))] +#[cfg(not(all(rustc_1_26, not(target_os = "emscripten"))))]  wmul_impl_large! { u64, 32 } -#[cfg(rust_1_26)] +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))]  wmul_impl_large! { u128, 64 }  macro_rules! wmul_impl_usize { diff --git a/rand/src/lib.rs b/rand/src/lib.rs index d364bd1..ca231b5 100644 --- a/rand/src/lib.rs +++ b/rand/src/lib.rs @@ -13,7 +13,7 @@  //! useful types and distributions, and some randomness-related algorithms.  //!  //! # Quick Start -//!  +//!  //! To get you started quickly, the easiest and highest-level way to get  //! a random value is to use [`random()`]; alternatively you can use  //! [`thread_rng()`]. The [`Rng`] trait provides a useful API on all RNGs, while @@ -22,7 +22,7 @@  //!  //! ```  //! use rand::prelude::*; -//!  +//!  //! if rand::random() { // generates a boolean  //!     // Try printing a random unicode code point (probably a bad idea)!  //!     println!("char: {}", rand::random::<char>()); @@ -36,7 +36,7 @@  //! ```  //!  //! # The Book -//!  +//!  //! For the user guide and futher documentation, please read  //! [The Rust Rand Book](https://rust-random.github.io/book).  //! @@ -58,19 +58,14 @@  #![cfg_attr(not(feature="std"), no_std)]  #![cfg_attr(all(feature="alloc", not(feature="std")), feature(alloc))]  #![cfg_attr(all(feature="simd_support", feature="nightly"), feature(stdsimd))] -#![cfg_attr(feature = "stdweb", recursion_limit="128")]  #[cfg(feature = "std")] extern crate core;  #[cfg(all(feature = "alloc", not(feature="std")))] #[macro_use] extern crate alloc;  #[cfg(feature="simd_support")] extern crate packed_simd; -#[cfg(all(target_arch="wasm32", not(target_os="emscripten"), feature="stdweb"))] -#[macro_use] -extern crate stdweb; - -#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))] -extern crate wasm_bindgen; +#[cfg(feature = "rand_os")] +extern crate rand_os;  extern crate rand_core;  extern crate rand_isaac;    // only for deprecations @@ -119,23 +114,7 @@ pub mod seq;  #[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"), -              all(target_arch = "wasm32", feature = "wasm-bindgen"), -)))] +#[cfg(feature="rand_os")]  #[doc(hidden)]  pub use deprecated::OsRng; @@ -152,23 +131,7 @@ pub mod jitter {      pub use rngs::TimerError;  }  #[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"), -              all(target_arch = "wasm32", feature = "wasm-bindgen"), -)))] +#[cfg(feature="rand_os")]  #[doc(hidden)]  pub mod os {      pub use deprecated::OsRng; @@ -549,13 +512,13 @@ macro_rules! impl_as_byte_slice {  impl_as_byte_slice!(u16);  impl_as_byte_slice!(u32);  impl_as_byte_slice!(u64); -#[cfg(rust_1_26)] impl_as_byte_slice!(u128); +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] impl_as_byte_slice!(u128);  impl_as_byte_slice!(usize);  impl_as_byte_slice!(i8);  impl_as_byte_slice!(i16);  impl_as_byte_slice!(i32);  impl_as_byte_slice!(i64); -#[cfg(rust_1_26)] impl_as_byte_slice!(i128); +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] impl_as_byte_slice!(i128);  impl_as_byte_slice!(isize);  macro_rules! impl_as_byte_slice_arrays { @@ -712,61 +675,6 @@ pub fn random<T>() -> T where Standard: Distribution<T> {      thread_rng().gen()  } -// Due to rustwasm/wasm-bindgen#201 this can't be defined in the inner os -// modules, so hack around it for now and place it at the root. -#[cfg(all(feature = "wasm-bindgen", target_arch = "wasm32"))] -#[doc(hidden)] -#[allow(missing_debug_implementations)] -pub mod __wbg_shims { - -    // `extern { type Foo; }` isn't supported on 1.22 syntactically, so use a -    // macro to work around that. -    macro_rules! rust_122_compat { -        ($($t:tt)*) => ($($t)*) -    } - -    rust_122_compat! { -        extern crate wasm_bindgen; - -        pub use wasm_bindgen::prelude::*; - -        #[wasm_bindgen] -        extern "C" { -            pub type Function; -            #[wasm_bindgen(constructor)] -            pub fn new(s: &str) -> Function; -            #[wasm_bindgen(method)] -            pub fn call(this: &Function, self_: &JsValue) -> JsValue; - -            pub type This; -            #[wasm_bindgen(method, getter, structural, js_name = self)] -            pub fn self_(me: &This) -> JsValue; -            #[wasm_bindgen(method, getter, structural)] -            pub fn crypto(me: &This) -> JsValue; - -            #[derive(Clone, Debug)] -            pub type BrowserCrypto; - -            // TODO: these `structural` annotations here ideally wouldn't be here to -            // avoid a JS shim, but for now with feature detection they're -            // unavoidable. -            #[wasm_bindgen(method, js_name = getRandomValues, structural, getter)] -            pub fn get_random_values_fn(me: &BrowserCrypto) -> JsValue; -            #[wasm_bindgen(method, js_name = getRandomValues, structural)] -            pub fn get_random_values(me: &BrowserCrypto, buf: &mut [u8]); - -            #[wasm_bindgen(js_name = require)] -            pub fn node_require(s: &str) -> NodeCrypto; - -            #[derive(Clone, Debug)] -            pub type NodeCrypto; - -            #[wasm_bindgen(method, js_name = randomFillSync, structural)] -            pub fn random_fill_sync(me: &NodeCrypto, buf: &mut [u8]); -        } -    } -} -  #[cfg(test)]  mod test {      use rngs::mock::StepRng; diff --git a/rand/src/rngs/entropy.rs b/rand/src/rngs/entropy.rs index 8736324..372b4d7 100644 --- a/rand/src/rngs/entropy.rs +++ b/rand/src/rngs/entropy.rs @@ -191,43 +191,11 @@ impl EntropySource for NoSource {  } -#[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"), -              all(target_arch = "wasm32", feature = "wasm-bindgen"), -)))] +#[cfg(feature="rand_os")]  #[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"), -              all(target_arch = "wasm32", feature = "wasm-bindgen"), -)))] +#[cfg(feature="rand_os")]  impl EntropySource for Os {      fn new_and_fill(dest: &mut [u8]) -> Result<Self, Error> {          let mut rng = rngs::OsRng::new()?; @@ -240,23 +208,7 @@ impl EntropySource for Os {      }  } -#[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"), -                  all(target_arch = "wasm32", feature = "wasm-bindgen"), -))))] +#[cfg(not(feature="std"))]  type Os = NoSource; diff --git a/rand/src/rngs/mod.rs b/rand/src/rngs/mod.rs index 70c4506..847fc94 100644 --- a/rand/src/rngs/mod.rs +++ b/rand/src/rngs/mod.rs @@ -178,40 +178,5 @@ 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"), -              all(target_arch = "wasm32", feature = "wasm-bindgen"), -)))] -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"), -              all(target_arch = "wasm32", feature = "wasm-bindgen"), -)))] -pub use self::os::OsRng; +#[cfg(feature="rand_os")] +pub use rand_os::OsRng; diff --git a/rand/src/rngs/os.rs b/rand/src/rngs/os.rs deleted file mode 100644 index e609c50..0000000 --- a/rand/src/rngs/os.rs +++ /dev/null @@ -1,1275 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// Copyright 2013-2015 The Rust Project Developers. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Interface to the random number generator of the operating system. - -use std::fmt; -use rand_core::{CryptoRng, RngCore, Error, impls}; - -/// A random number generator that retrieves randomness straight from the -/// operating system. -/// -/// This is the preferred external source of entropy for most applications. -/// Commonly it is used to initialize a user-space RNG, which can then be used -/// to generate random values with much less overhead than `OsRng`. -/// -/// You may prefer to use [`EntropyRng`] instead of `OsRng`. It is unlikely, but -/// not entirely theoretical, for `OsRng` to fail. In such cases [`EntropyRng`] -/// falls back on a good alternative entropy source. -/// -/// `OsRng::new()` is guaranteed to be very cheap (after the first successful -/// call), and will never consume more than one file handle per process. -/// -/// # Platform sources -/// -/// | OS               | interface -/// |------------------|--------------------------------------------------------- -/// | Linux, Android   | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after reading from `/dev/random` once -/// | Windows          | [`RtlGenRandom`][3] -/// | macOS, iOS       | [`SecRandomCopyBytes`][4] -/// | FreeBSD          | [`kern.arandom`][5] -/// | OpenBSD, Bitrig  | [`getentropy`][6] -/// | NetBSD           | [`/dev/urandom`][7] after reading from `/dev/random` once -/// | Dragonfly BSD    | [`/dev/random`][8] -/// | Solaris, illumos | [`getrandom`][9] system call if available, otherwise [`/dev/random`][10] -/// | Fuchsia OS       | [`cprng_draw`][11] -/// | Redox            | [`rand:`][12] -/// | CloudABI         | [`random_get`][13] -/// | Haiku            | `/dev/random` (identical to `/dev/urandom`) -/// | Web browsers     | [`Crypto.getRandomValues`][14] (see [Support for WebAssembly and ams.js][14]) -/// | Node.js          | [`crypto.randomBytes`][15] (see [Support for WebAssembly and ams.js][16]) -/// -/// Rand doesn't have a blanket implementation for all Unix-like operating -/// systems that reads from `/dev/urandom`. This ensures all supported operating -/// systems are using the recommended interface and respect maximum buffer -/// sizes. -/// -/// ## Support for WebAssembly and ams.js -/// -/// The three Emscripten targets `asmjs-unknown-emscripten`, -/// `wasm32-unknown-emscripten` and `wasm32-experimental-emscripten` use -/// Emscripten's emulation of `/dev/random` on web browsers and Node.js. -/// -/// The bare Wasm target `wasm32-unknown-unknown` tries to call the javascript -/// methods directly, using either `stdweb` in combination with `cargo-web` or -/// `wasm-bindgen` depending on what features are activated for this crate. -/// -/// ## Early boot -/// -/// It is possible that early in the boot process the OS hasn't had enough time -/// yet to collect entropy to securely seed its RNG, especially on virtual -/// machines. -/// -/// Some operating systems always block the thread until the RNG is securely -/// seeded. This can take anywhere from a few seconds to more than a minute. -/// Others make a best effort to use a seed from before the shutdown and don't -/// document much. -/// -/// A few, Linux, NetBSD and Solaris, offer a choice between blocking, and -/// getting an error. With `try_fill_bytes` we choose to get the error -/// ([`ErrorKind::NotReady`]), while the other methods use a blocking interface. -/// -/// On Linux (when the `genrandom` system call is not available) and on NetBSD -/// reading from `/dev/urandom` never blocks, even when the OS hasn't collected -/// enough entropy yet. As a countermeasure we try to do a single read from -/// `/dev/random` until we know the OS RNG is initialized (and store this in a -/// global static). -/// -/// # Panics -/// -/// `OsRng` is extremely unlikely to fail if `OsRng::new()`, and one read from -/// it, where succesfull. But in case it does fail, only [`try_fill_bytes`] is -/// able to report the cause. Depending on the error the other [`RngCore`] -/// methods will retry several times, and panic in case the error remains. -/// -/// [`EntropyRng`]: struct.EntropyRng.html -/// [`RngCore`]: ../trait.RngCore.html -/// [`try_fill_bytes`]: ../trait.RngCore.html#method.tymethod.try_fill_bytes -/// [`ErrorKind::NotReady`]: ../enum.ErrorKind.html#variant.NotReady -/// -/// [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html -/// [2]: http://man7.org/linux/man-pages/man4/urandom.4.html -/// [3]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx -/// [4]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc -/// [5]: https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4 -/// [6]: https://man.openbsd.org/getentropy.2 -/// [7]: http://netbsd.gw.com/cgi-bin/man-cgi?random+4+NetBSD-current -/// [8]: https://leaf.dragonflybsd.org/cgi/web-man?command=random§ion=4 -/// [9]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html -/// [10]: https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html -/// [11]: https://fuchsia.googlesource.com/zircon/+/HEAD/docs/syscalls/cprng_draw.md -/// [12]: https://github.com/redox-os/randd/blob/master/src/main.rs -/// [13]: https://github.com/NuxiNL/cloudabi/blob/v0.20/cloudabi.txt#L1826 -/// [14]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues -/// [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback -/// [16]: #support-for-webassembly-and-amsjs - - -#[derive(Clone)] -pub struct OsRng(imp::OsRng); - -impl fmt::Debug for OsRng { -    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -        self.0.fmt(f) -    } -} - -impl OsRng { -    /// Create a new `OsRng`. -    pub fn new() -> Result<OsRng, Error> { -        imp::OsRng::new().map(OsRng) -    } -} - -impl CryptoRng for OsRng {} - -impl RngCore for OsRng { -    fn next_u32(&mut self) -> u32 { -        impls::next_u32_via_fill(self) -    } - -    fn next_u64(&mut self) -> u64 { -        impls::next_u64_via_fill(self) -    } - -    fn fill_bytes(&mut self, dest: &mut [u8]) { -        use std::{time, thread}; - -        // We cannot return Err(..), so we try to handle before panicking. -        const MAX_RETRY_PERIOD: u32 = 10; // max 10s -        const WAIT_DUR_MS: u32 = 100; // retry every 100ms -        let wait_dur = time::Duration::from_millis(WAIT_DUR_MS as u64); -        const RETRY_LIMIT: u32 = (MAX_RETRY_PERIOD * 1000) / WAIT_DUR_MS; -        const TRANSIENT_RETRIES: u32 = 8; -        let mut err_count = 0; -        let mut error_logged = false; - -        // Maybe block until the OS RNG is initialized -        let mut read = 0; -        if let Ok(n) = self.0.test_initialized(dest, true) { read = n }; -        let dest = &mut dest[read..]; - -        loop { -            if let Err(e) = self.try_fill_bytes(dest) { -                if err_count >= RETRY_LIMIT { -                    error!("OsRng failed too many times; last error: {}", e); -                    panic!("OsRng failed too many times; last error: {}", e); -                } - -                if e.kind.should_wait() { -                    if !error_logged { -                        warn!("OsRng failed; waiting up to {}s and retrying. Error: {}", -                                MAX_RETRY_PERIOD, e); -                        error_logged = true; -                    } -                    err_count += 1; -                    thread::sleep(wait_dur); -                    continue; -                } else if e.kind.should_retry() { -                    if !error_logged { -                        warn!("OsRng failed; retrying up to {} times. Error: {}", -                                TRANSIENT_RETRIES, e); -                        error_logged = true; -                    } -                    err_count += (RETRY_LIMIT + TRANSIENT_RETRIES - 1) -                            / TRANSIENT_RETRIES;    // round up -                    continue; -                } else { -                    error!("OsRng failed: {}", e); -                    panic!("OsRng fatal error: {}", e); -                } -            } - -            break; -        } -    } - -    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { -        // Some systems do not support reading 0 random bytes. -        // (And why waste a system call?) -        if dest.len() == 0 { return Ok(()); } - -        let read = self.0.test_initialized(dest, false)?; -        let dest = &mut dest[read..]; - -        let max = self.0.max_chunk_size(); -        if dest.len() <= max { -            trace!("OsRng: reading {} bytes via {}", -                   dest.len(), self.0.method_str()); -        } else { -            trace!("OsRng: reading {} bytes via {} in {} chunks of {} bytes", -                   dest.len(), self.0.method_str(), (dest.len() + max) / max, max); -        } -        for slice in dest.chunks_mut(max) { -            self.0.fill_chunk(slice)?; -        } -        Ok(()) -    } -} - -trait OsRngImpl where Self: Sized { -    // Create a new `OsRng` platform interface. -    fn new() -> Result<Self, Error>; - -    // Fill a chunk with random bytes. -    fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error>; - -    // Test whether the OS RNG is initialized. This method may not be possible -    // to support cheaply (or at all) on all operating systems. -    // -    // If `blocking` is set, this will cause the OS the block execution until -    // its RNG is initialized. -    // -    // Random values that are read while this are stored in `dest`, the amount -    // of read bytes is returned. -    fn test_initialized(&mut self, _dest: &mut [u8], _blocking: bool) -        -> Result<usize, Error> { Ok(0) } - -    // Maximum chunk size supported. -    fn max_chunk_size(&self) -> usize { ::core::usize::MAX } - -    // Name of the OS interface (used for logging). -    fn method_str(&self) -> &'static str; -} - - - - -// Helper functions to read from a random device such as `/dev/urandom`. -// -// All instances use a single internal file handle, to prevent possible -// exhaustion of file descriptors. -#[cfg(any(target_os = "linux", target_os = "android", -          target_os = "netbsd", target_os = "dragonfly", -          target_os = "solaris", target_os = "redox", -          target_os = "haiku", target_os = "emscripten"))] -mod random_device { -    use {Error, ErrorKind}; -    use std::fs::File; -    use std::io; -    use std::io::Read; -    use std::sync::{Once, Mutex, ONCE_INIT}; - -    // TODO: remove outer Option when `Mutex::new(None)` is a constant expression -    static mut READ_RNG_FILE: Option<Mutex<Option<File>>> = None; -    static READ_RNG_ONCE: Once = ONCE_INIT; - -    #[allow(unused)] -    pub fn open<F>(path: &'static str, open_fn: F) -> Result<(), Error> -        where F: Fn(&'static str) -> Result<File, io::Error> -    { -        READ_RNG_ONCE.call_once(|| { -            unsafe { READ_RNG_FILE = Some(Mutex::new(None)) } -        }); - -        // We try opening the file outside the `call_once` fn because we cannot -        // clone the error, thus we must retry on failure. - -        let mutex = unsafe { READ_RNG_FILE.as_ref().unwrap() }; -        let mut guard = mutex.lock().unwrap(); -        if (*guard).is_none() { -            info!("OsRng: opening random device {}", path); -            let file = open_fn(path).map_err(map_err)?; -            *guard = Some(file); -        }; -        Ok(()) -    } - -    pub fn read(dest: &mut [u8]) -> Result<(), Error> { -        // We expect this function only to be used after `random_device::open` -        // was succesful. Therefore we can assume that our memory was set with a -        // valid object. -        let mutex = unsafe { READ_RNG_FILE.as_ref().unwrap() }; -        let mut guard = mutex.lock().unwrap(); -        let file = (*guard).as_mut().unwrap(); - -        // Use `std::io::read_exact`, which retries on `ErrorKind::Interrupted`. -        file.read_exact(dest).map_err(|err| { -            Error::with_cause(ErrorKind::Unavailable, -                              "error reading random device", err) -        }) - -    } - -    pub fn map_err(err: io::Error) -> Error { -        match err.kind() { -            io::ErrorKind::Interrupted => -                    Error::new(ErrorKind::Transient, "interrupted"), -            io::ErrorKind::WouldBlock => -                    Error::with_cause(ErrorKind::NotReady, -                    "OS RNG not yet seeded", err), -            _ => Error::with_cause(ErrorKind::Unavailable, -                    "error while opening random device", err) -        } -    } -} - - -#[cfg(any(target_os = "linux", target_os = "android"))] -mod imp { -    extern crate libc; - -    use {Error, ErrorKind}; -    use super::random_device; -    use super::OsRngImpl; - -    use std::io; -    use std::io::Read; -    use std::fs::{File, OpenOptions}; -    use std::os::unix::fs::OpenOptionsExt; -    use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; -    use std::sync::{Once, ONCE_INIT}; - -    #[derive(Clone, Debug)] -    pub struct OsRng { -        method: OsRngMethod, -        initialized: bool, -    } - -    #[derive(Clone, Debug)] -    enum OsRngMethod { -        GetRandom, -        RandomDevice, -    } - -    impl OsRngImpl for OsRng { -        fn new() -> Result<OsRng, Error> { -            if is_getrandom_available() { -                return Ok(OsRng { method: OsRngMethod::GetRandom, -                                  initialized: false }); -            } -            random_device::open("/dev/urandom", &|p| File::open(p))?; -            Ok(OsRng { method: OsRngMethod::RandomDevice, initialized: false }) -        } - -        fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { -            match self.method { -                OsRngMethod::GetRandom => getrandom_try_fill(dest, false), -                OsRngMethod::RandomDevice => random_device::read(dest), -            } -        } - -        fn test_initialized(&mut self, dest: &mut [u8], blocking: bool) -            -> Result<usize, Error> -        { -            static OS_RNG_INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; -            if !self.initialized { -                self.initialized = OS_RNG_INITIALIZED.load(Ordering::Relaxed); -            } -            if self.initialized { return Ok(0); } - -            let result = match self.method { -                OsRngMethod::GetRandom => { -                    getrandom_try_fill(dest, blocking)?; -                    Ok(dest.len()) -                } -                OsRngMethod::RandomDevice => { -                    info!("OsRng: testing random device /dev/random"); -                    let mut file = OpenOptions::new() -                        .read(true) -                        .custom_flags(if blocking { 0 } else { libc::O_NONBLOCK }) -                        .open("/dev/random") -                        .map_err(random_device::map_err)?; -                    file.read(&mut dest[..1]).map_err(random_device::map_err)?; -                    Ok(1) -                } -            }; -            OS_RNG_INITIALIZED.store(true, Ordering::Relaxed); -            self.initialized = true; -            result -        } - -        fn method_str(&self) -> &'static str { -            match self.method { -                OsRngMethod::GetRandom => "getrandom", -                OsRngMethod::RandomDevice => "/dev/urandom", -            } -        } -    } - -    #[cfg(target_arch = "x86_64")] -    const NR_GETRANDOM: libc::c_long = 318; -    #[cfg(target_arch = "x86")] -    const NR_GETRANDOM: libc::c_long = 355; -    #[cfg(target_arch = "arm")] -    const NR_GETRANDOM: libc::c_long = 384; -    #[cfg(target_arch = "aarch64")] -    const NR_GETRANDOM: libc::c_long = 278; -     #[cfg(target_arch = "s390x")] -    const NR_GETRANDOM: libc::c_long = 349; -    #[cfg(target_arch = "powerpc")] -    const NR_GETRANDOM: libc::c_long = 359; -    #[cfg(target_arch = "powerpc64")] -    const NR_GETRANDOM: libc::c_long = 359; -    #[cfg(target_arch = "mips")] // old ABI -    const NR_GETRANDOM: libc::c_long = 4353; -    #[cfg(target_arch = "mips64")] -    const NR_GETRANDOM: libc::c_long = 5313; -    #[cfg(target_arch = "sparc")] -    const NR_GETRANDOM: libc::c_long = 347; -    #[cfg(target_arch = "sparc64")] -    const NR_GETRANDOM: libc::c_long = 347; -    #[cfg(not(any(target_arch = "x86_64", target_arch = "x86", -                  target_arch = "arm", target_arch = "aarch64", -                  target_arch = "s390x", target_arch = "powerpc", -                  target_arch = "powerpc64", target_arch = "mips", -                  target_arch = "mips64", target_arch = "sparc", -                  target_arch = "sparc64")))] -    const NR_GETRANDOM: libc::c_long = 0; - -    fn getrandom(buf: &mut [u8], blocking: bool) -> libc::c_long { -        const GRND_NONBLOCK: libc::c_uint = 0x0001; - -        if NR_GETRANDOM == 0 { return -1 }; - -        unsafe { -            libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), -                          if blocking { 0 } else { GRND_NONBLOCK }) -        } -    } - -    fn getrandom_try_fill(dest: &mut [u8], blocking: bool) -> Result<(), Error> { -        let mut read = 0; -        while read < dest.len() { -            let result = getrandom(&mut dest[read..], blocking); -            if result == -1 { -                let err = io::Error::last_os_error(); -                let kind = err.kind(); -                if kind == io::ErrorKind::Interrupted { -                    continue; -                } else if kind == io::ErrorKind::WouldBlock { -                    return Err(Error::with_cause( -                        ErrorKind::NotReady, -                        "getrandom not ready", -                        err, -                    )); -                } else { -                    return Err(Error::with_cause( -                        ErrorKind::Unavailable, -                        "unexpected getrandom error", -                        err, -                    )); -                } -            } else { -                read += result as usize; -            } -        } -        Ok(()) -    } - -    fn is_getrandom_available() -> bool { -        static CHECKER: Once = ONCE_INIT; -        static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT; - -        if NR_GETRANDOM == 0 { return false }; - -        CHECKER.call_once(|| { -            debug!("OsRng: testing getrandom"); -            let mut buf: [u8; 0] = []; -            let result = getrandom(&mut buf, false); -            let available = if result == -1 { -                let err = io::Error::last_os_error().raw_os_error(); -                err != Some(libc::ENOSYS) -            } else { -                true -            }; -            AVAILABLE.store(available, Ordering::Relaxed); -            info!("OsRng: using {}", if available { "getrandom" } else { "/dev/urandom" }); -        }); - -        AVAILABLE.load(Ordering::Relaxed) -    } -} - - -#[cfg(target_os = "netbsd")] -mod imp { -    use Error; -    use super::random_device; -    use super::OsRngImpl; - -    use std::fs::File; -    use std::io::Read; -    use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; - -    #[derive(Clone, Debug)] -    pub struct OsRng { initialized: bool } - -    impl OsRngImpl for OsRng { -        fn new() -> Result<OsRng, Error> { -            random_device::open("/dev/urandom", &|p| File::open(p))?; -            Ok(OsRng { initialized: false }) -        } - -        fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { -            random_device::read(dest) -        } - -        // Read a single byte from `/dev/random` to determine if the OS RNG is -        // already seeded. NetBSD always blocks if not yet ready. -        fn test_initialized(&mut self, dest: &mut [u8], _blocking: bool) -            -> Result<usize, Error> -        { -            static OS_RNG_INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; -            if !self.initialized { -                self.initialized = OS_RNG_INITIALIZED.load(Ordering::Relaxed); -            } -            if self.initialized { return Ok(0); } - -            info!("OsRng: testing random device /dev/random"); -            let mut file = -                File::open("/dev/random").map_err(random_device::map_err)?; -            file.read(&mut dest[..1]).map_err(random_device::map_err)?; - -            OS_RNG_INITIALIZED.store(true, Ordering::Relaxed); -            self.initialized = true; -            Ok(1) -        } - -        fn method_str(&self) -> &'static str { "/dev/urandom" } -    } -} - - -#[cfg(any(target_os = "dragonfly", -          target_os = "haiku", -          target_os = "emscripten"))] -mod imp { -    use Error; -    use super::random_device; -    use super::OsRngImpl; -    use std::fs::File; - -    #[derive(Clone, Debug)] -    pub struct OsRng(); - -    impl OsRngImpl for OsRng { -        fn new() -> Result<OsRng, Error> { -            random_device::open("/dev/random", &|p| File::open(p))?; -            Ok(OsRng()) -        } - -        fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { -            random_device::read(dest) -        } - -        #[cfg(target_os = "emscripten")] -        fn max_chunk_size(&self) -> usize { -            // `Crypto.getRandomValues` documents `dest` should be at most 65536 -            // bytes. `crypto.randomBytes` documents: "To minimize threadpool -            // task length variation, partition large randomBytes requests when -            // doing so as part of fulfilling a client request. -            65536 -        } - -        fn method_str(&self) -> &'static str { "/dev/random" } -    } -} - - -// Read from `/dev/random`, with chunks of limited size (1040 bytes). -// `/dev/random` uses the Hash_DRBG with SHA512 algorithm from NIST SP 800-90A. -// `/dev/urandom` uses the FIPS 186-2 algorithm, which is considered less -// secure. We choose to read from `/dev/random`. -// -// Since Solaris 11.3 the `getrandom` syscall is available. To make sure we can -// compile on both Solaris and on OpenSolaris derivatives, that do not have the -// function, we do a direct syscall instead of calling a library function. -// -// We have no way to differentiate between Solaris, illumos, SmartOS, etc. -#[cfg(target_os = "solaris")] -mod imp { -    extern crate libc; - -    use {Error, ErrorKind}; -    use super::random_device; -    use super::OsRngImpl; - -    use std::io; -    use std::io::Read; -    use std::fs::{File, OpenOptions}; -    use std::os::unix::fs::OpenOptionsExt; -    use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; - -    #[derive(Clone, Debug)] -    pub struct OsRng { -        method: OsRngMethod, -        initialized: bool, -    } - -    #[derive(Clone, Debug)] -    enum OsRngMethod { -        GetRandom, -        RandomDevice, -    } - -    impl OsRngImpl for OsRng { -        fn new() -> Result<OsRng, Error> { -            if is_getrandom_available() { -                return Ok(OsRng { method: OsRngMethod::GetRandom, -                                  initialized: false }); -            } -            let open = |p| OpenOptions::new() -                .read(true) -                .custom_flags(libc::O_NONBLOCK) -                .open(p); -            random_device::open("/dev/random", &open)?; -            Ok(OsRng { method: OsRngMethod::RandomDevice, initialized: false }) -        } - -        fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { -            match self.method { -                OsRngMethod::GetRandom => getrandom_try_fill(dest, false), -                OsRngMethod::RandomDevice => random_device::read(dest), -            } -        } - -        fn test_initialized(&mut self, dest: &mut [u8], blocking: bool) -            -> Result<usize, Error> -        { -            static OS_RNG_INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; -            if !self.initialized { -                self.initialized = OS_RNG_INITIALIZED.load(Ordering::Relaxed); -            } -            if self.initialized { return Ok(0); } - -            let chunk_len = ::core::cmp::min(1024, dest.len()); -            let dest = &mut dest[..chunk_len]; - -            match self.method { -                OsRngMethod::GetRandom => getrandom_try_fill(dest, blocking)?, -                OsRngMethod::RandomDevice => { -                    if blocking { -                        info!("OsRng: testing random device /dev/random"); -                        // We already have a non-blocking handle, but now need a -                        // blocking one. Not much choice except opening it twice -                        let mut file = File::open("/dev/random") -                            .map_err(random_device::map_err)?; -                        file.read(dest).map_err(random_device::map_err)?; -                    } else { -                        self.fill_chunk(dest)?; -                    } -                } -            }; -            OS_RNG_INITIALIZED.store(true, Ordering::Relaxed); -            self.initialized = true; -            Ok(chunk_len) -        } - -        fn max_chunk_size(&self) -> usize { -            // The documentation says 1024 is the maximum for getrandom, but -            // 1040 for /dev/random. -            1024 -        } - -        fn method_str(&self) -> &'static str { -            match self.method { -                OsRngMethod::GetRandom => "getrandom", -                OsRngMethod::RandomDevice => "/dev/random", -            } -        } -    } - -    fn getrandom(buf: &mut [u8], blocking: bool) -> libc::c_long { -        extern "C" { -            fn syscall(number: libc::c_long, ...) -> libc::c_long; -        } - -        const SYS_GETRANDOM: libc::c_long = 143; -        const GRND_NONBLOCK: libc::c_uint = 0x0001; -        const GRND_RANDOM: libc::c_uint = 0x0002; - -        unsafe { -            syscall(SYS_GETRANDOM, buf.as_mut_ptr(), buf.len(), -                    if blocking { 0 } else { GRND_NONBLOCK } | GRND_RANDOM) -        } -    } - -    fn getrandom_try_fill(dest: &mut [u8], blocking: bool) -> Result<(), Error> { -        let result = getrandom(dest, blocking); -        if result == -1 || result == 0 { -            let err = io::Error::last_os_error(); -            let kind = err.kind(); -            if kind == io::ErrorKind::WouldBlock { -                return Err(Error::with_cause( -                    ErrorKind::NotReady, -                    "getrandom not ready", -                    err, -                )); -            } else { -                return Err(Error::with_cause( -                    ErrorKind::Unavailable, -                    "unexpected getrandom error", -                    err, -                )); -            } -        } else if result != dest.len() as i64 { -            return Err(Error::new(ErrorKind::Unavailable, -                                  "unexpected getrandom error")); -        } -        Ok(()) -    } - -    fn is_getrandom_available() -> bool { -        use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; -        use std::sync::{Once, ONCE_INIT}; - -        static CHECKER: Once = ONCE_INIT; -        static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT; - -        CHECKER.call_once(|| { -            debug!("OsRng: testing getrandom"); -            let mut buf: [u8; 0] = []; -            let result = getrandom(&mut buf, false); -            let available = if result == -1 { -                let err = io::Error::last_os_error().raw_os_error(); -                err != Some(libc::ENOSYS) -            } else { -                true -            }; -            AVAILABLE.store(available, Ordering::Relaxed); -            info!("OsRng: using {}", if available { "getrandom" } else { "/dev/random" }); -        }); - -        AVAILABLE.load(Ordering::Relaxed) -    } -} - - -#[cfg(target_os = "cloudabi")] -mod imp { -    extern crate cloudabi; - -    use std::io; -    use {Error, ErrorKind}; -    use super::OsRngImpl; - -    #[derive(Clone, Debug)] -    pub struct OsRng; - -    impl OsRngImpl for OsRng { -        fn new() -> Result<OsRng, Error> { Ok(OsRng) } - -        fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { -            let errno = unsafe { cloudabi::random_get(dest) }; -            if errno == cloudabi::errno::SUCCESS { -                Ok(()) -            } else { -                // Cloudlibc provides its own `strerror` implementation so we -                // can use `from_raw_os_error` here. -                Err(Error::with_cause( -                    ErrorKind::Unavailable, -                    "random_get() system call failed", -                    io::Error::from_raw_os_error(errno as i32), -                )) -            } -        } - -        fn method_str(&self) -> &'static str { "cloudabi::random_get" } -    } -} - - -#[cfg(any(target_os = "macos", target_os = "ios"))] -mod imp { -    extern crate libc; - -    use {Error, ErrorKind}; -    use super::OsRngImpl; - -    use std::io; -    use self::libc::{c_int, size_t}; - -    #[derive(Clone, Debug)] -    pub struct OsRng; - -    enum SecRandom {} - -    #[allow(non_upper_case_globals)] -    const kSecRandomDefault: *const SecRandom = 0 as *const SecRandom; - -    #[link(name = "Security", kind = "framework")] -    extern { -        fn SecRandomCopyBytes(rnd: *const SecRandom, -                              count: size_t, bytes: *mut u8) -> c_int; -    } - -    impl OsRngImpl for OsRng { -        fn new() -> Result<OsRng, Error> { Ok(OsRng) } - -        fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { -            let ret = unsafe { -                SecRandomCopyBytes(kSecRandomDefault, -                                   dest.len() as size_t, -                                   dest.as_mut_ptr()) -            }; -            if ret == -1 { -                Err(Error::with_cause( -                    ErrorKind::Unavailable, -                    "couldn't generate random bytes", -                    io::Error::last_os_error())) -            } else { -                Ok(()) -            } -        } - -        fn method_str(&self) -> &'static str { "SecRandomCopyBytes" } -    } -} - - -#[cfg(target_os = "freebsd")] -mod imp { -    extern crate libc; - -    use {Error, ErrorKind}; -    use super::OsRngImpl; - -    use std::ptr; -    use std::io; - -    #[derive(Clone, Debug)] -    pub struct OsRng; - -    impl OsRngImpl for OsRng { -        fn new() -> Result<OsRng, Error> { Ok(OsRng) } - -        fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { -            let mib = [libc::CTL_KERN, libc::KERN_ARND]; -            let mut len = dest.len(); -            let ret = unsafe { -                libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint, -                             dest.as_mut_ptr() as *mut _, &mut len, -                             ptr::null(), 0) -            }; -            if ret == -1 || len != dest.len() { -                return Err(Error::with_cause( -                    ErrorKind::Unavailable, -                    "kern.arandom sysctl failed", -                    io::Error::last_os_error())); -            } -            Ok(()) -        } - -        fn max_chunk_size(&self) -> usize { 256 } - -        fn method_str(&self) -> &'static str { "kern.arandom" } -    } -} - - -#[cfg(any(target_os = "openbsd", target_os = "bitrig"))] -mod imp { -    extern crate libc; - -    use {Error, ErrorKind}; -    use super::OsRngImpl; - -    use std::io; - -    #[derive(Clone, Debug)] -    pub struct OsRng; - -    impl OsRngImpl for OsRng { -        fn new() -> Result<OsRng, Error> { Ok(OsRng) } - -        fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { -            let ret = unsafe { -                libc::getentropy(dest.as_mut_ptr() as *mut libc::c_void, dest.len()) -            }; -            if ret == -1 { -                return Err(Error::with_cause( -                    ErrorKind::Unavailable, -                    "getentropy failed", -                    io::Error::last_os_error())); -            } -            Ok(()) -        } - -        fn max_chunk_size(&self) -> usize { 256 } - -        fn method_str(&self) -> &'static str { "getentropy" } -    } -} - - -#[cfg(target_os = "redox")] -mod imp { -    use Error; -    use super::random_device; -    use super::OsRngImpl; -    use std::fs::File; - -    #[derive(Clone, Debug)] -    pub struct OsRng(); - -    impl OsRngImpl for OsRng { -        fn new() -> Result<OsRng, Error> { -            random_device::open("rand:", &|p| File::open(p))?; -            Ok(OsRng()) -        } - -        fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { -            random_device::read(dest) -        } - -        fn method_str(&self) -> &'static str { "'rand:'" } -    } -} - - -#[cfg(target_os = "fuchsia")] -mod imp { -    extern crate fuchsia_zircon; - -    use {Error, ErrorKind}; -    use super::OsRngImpl; - -    #[derive(Clone, Debug)] -    pub struct OsRng; - -    impl OsRngImpl for OsRng { -        fn new() -> Result<OsRng, Error> { Ok(OsRng) } - -        fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { -            let mut read = 0; -            while read < dest.len() { -                match fuchsia_zircon::cprng_draw(&mut dest[read..]) { -                    Ok(actual) => read += actual, -                    Err(e) => { -                        return Err(Error::with_cause( -                            ErrorKind::Unavailable, -                            "cprng_draw failed", -                            e.into_io_error())); -                    } -                }; -            } -            Ok(()) -        } - -        fn max_chunk_size(&self) -> usize { -            fuchsia_zircon::sys::ZX_CPRNG_DRAW_MAX_LEN -        } - -        fn method_str(&self) -> &'static str { "cprng_draw" } -    } -} - - -#[cfg(windows)] -mod imp { -    extern crate winapi; - -    use {Error, ErrorKind}; -    use super::OsRngImpl; - -    use std::io; - -    use self::winapi::shared::minwindef::ULONG; -    use self::winapi::um::ntsecapi::RtlGenRandom; -    use self::winapi::um::winnt::PVOID; - -    #[derive(Clone, Debug)] -    pub struct OsRng; - -    impl OsRngImpl for OsRng { -        fn new() -> Result<OsRng, Error> { Ok(OsRng) } - -        fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { -            let ret = unsafe { -                RtlGenRandom(dest.as_mut_ptr() as PVOID, dest.len() as ULONG) -            }; -            if ret == 0 { -                return Err(Error::with_cause( -                    ErrorKind::Unavailable, -                    "couldn't generate random bytes", -                    io::Error::last_os_error())); -            } -            Ok(()) -        } - -        fn max_chunk_size(&self) -> usize { <ULONG>::max_value() as usize } - -        fn method_str(&self) -> &'static str { "RtlGenRandom" } -    } -} - - -#[cfg(all(target_arch = "wasm32", -          not(target_os = "emscripten"), -          feature = "stdweb"))] -mod imp { -    use std::mem; -    use stdweb::unstable::TryInto; -    use stdweb::web::error::Error as WebError; -    use {Error, ErrorKind}; -    use super::OsRngImpl; - -    #[derive(Clone, Debug)] -    enum OsRngMethod { -        Browser, -        Node -    } - -    #[derive(Clone, Debug)] -    pub struct OsRng(OsRngMethod); - -    impl OsRngImpl for OsRng { -        fn new() -> Result<OsRng, Error> { -            let result = js! { -                try { -                    if ( -                        typeof self === "object" && -                        typeof self.crypto === "object" && -                        typeof self.crypto.getRandomValues === "function" -                    ) { -                        return { success: true, ty: 1 }; -                    } - -                    if (typeof require("crypto").randomBytes === "function") { -                        return { success: true, ty: 2 }; -                    } - -                    return { success: false, error: new Error("not supported") }; -                } catch(err) { -                    return { success: false, error: err }; -                } -            }; - -            if js!{ return @{ result.as_ref() }.success } == true { -                let ty = js!{ return @{ result }.ty }; - -                if ty == 1 { Ok(OsRng(OsRngMethod::Browser)) } -                else if ty == 2 { Ok(OsRng(OsRngMethod::Node)) } -                else { unreachable!() } -            } else { -                let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); -                Err(Error::with_cause(ErrorKind::Unavailable, "WASM Error", err)) -            } -        } - - -        fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { -            assert_eq!(mem::size_of::<usize>(), 4); - -            let len = dest.len() as u32; -            let ptr = dest.as_mut_ptr() as i32; - -            let result = match self.0 { -                OsRngMethod::Browser => js! { -                    try { -                        let array = new Uint8Array(@{ len }); -                        self.crypto.getRandomValues(array); -                        HEAPU8.set(array, @{ ptr }); - -                        return { success: true }; -                    } catch(err) { -                        return { success: false, error: err }; -                    } -                }, -                OsRngMethod::Node => js! { -                    try { -                        let bytes = require("crypto").randomBytes(@{ len }); -                        HEAPU8.set(new Uint8Array(bytes), @{ ptr }); - -                        return { success: true }; -                    } catch(err) { -                        return { success: false, error: err }; -                    } -                } -            }; - -            if js!{ return @{ result.as_ref() }.success } == true { -                Ok(()) -            } else { -                let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); -                Err(Error::with_cause(ErrorKind::Unexpected, "WASM Error", err)) -            } -        } - -        fn max_chunk_size(&self) -> usize { 65536 } - -        fn method_str(&self) -> &'static str { -            match self.0 { -                OsRngMethod::Browser => "Crypto.getRandomValues", -                OsRngMethod::Node => "crypto.randomBytes", -            } -        } -    } -} - -#[cfg(all(target_arch = "wasm32", -          not(target_os = "emscripten"), -          not(feature = "stdweb"), -          feature = "wasm-bindgen"))] -mod imp { -    use __wbg_shims::*; - -    use {Error, ErrorKind}; -    use super::OsRngImpl; - -    #[derive(Clone, Debug)] -    pub enum OsRng { -        Node(NodeCrypto), -        Browser(BrowserCrypto), -    } - -    impl OsRngImpl for OsRng { -        fn new() -> Result<OsRng, Error> { -            // First up we need to detect if we're running in node.js or a -            // browser. To do this we get ahold of the `this` object (in a bit -            // of a roundabout fashion). -            // -            // Once we have `this` we look at its `self` property, which is -            // only defined on the web (either a main window or web worker). -            let this = Function::new("return this").call(&JsValue::undefined()); -            assert!(this != JsValue::undefined()); -            let this = This::from(this); -            let is_browser = this.self_() != JsValue::undefined(); - -            if !is_browser { -                return Ok(OsRng::Node(node_require("crypto"))) -            } - -            // If `self` is defined then we're in a browser somehow (main window -            // or web worker). Here we want to try to use -            // `crypto.getRandomValues`, but if `crypto` isn't defined we assume -            // we're in an older web browser and the OS RNG isn't available. -            let crypto = this.crypto(); -            if crypto.is_undefined() { -                let msg = "self.crypto is undefined"; -                return Err(Error::new(ErrorKind::Unavailable, msg)) -            } - -            // Test if `crypto.getRandomValues` is undefined as well -            let crypto: BrowserCrypto = crypto.into(); -            if crypto.get_random_values_fn().is_undefined() { -                let msg = "crypto.getRandomValues is undefined"; -                return Err(Error::new(ErrorKind::Unavailable, msg)) -            } - -            // Ok! `self.crypto.getRandomValues` is a defined value, so let's -            // assume we can do browser crypto. -            Ok(OsRng::Browser(crypto)) -        } - -        fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { -            match *self { -                OsRng::Node(ref n) => n.random_fill_sync(dest), -                OsRng::Browser(ref n) => n.get_random_values(dest), -            } -            Ok(()) -        } - -        fn max_chunk_size(&self) -> usize { -            match *self { -                OsRng::Node(_) => usize::max_value(), -                OsRng::Browser(_) => { -                    // see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues -                    // -                    // where it says: -                    // -                    // > A QuotaExceededError DOMException is thrown if the -                    // > requested length is greater than 65536 bytes. -                    65536 -                } -            } -        } - -        fn method_str(&self) -> &'static str { -            match *self { -                OsRng::Node(_) => "crypto.randomFillSync", -                OsRng::Browser(_) => "crypto.getRandomValues", -            } -        } -    } -} - - -#[cfg(test)] -mod test { -    use RngCore; -    use super::OsRng; - -    #[test] -    fn test_os_rng() { -        let mut r = OsRng::new().unwrap(); - -        r.next_u32(); -        r.next_u64(); - -        let mut v1 = [0u8; 1000]; -        r.fill_bytes(&mut v1); - -        let mut v2 = [0u8; 1000]; -        r.fill_bytes(&mut v2); - -        let mut n_diff_bits = 0; -        for i in 0..v1.len() { -            n_diff_bits += (v1[i] ^ v2[i]).count_ones(); -        } - -        // Check at least 1 bit per byte differs. p(failure) < 1e-1000 with random input. -        assert!(n_diff_bits >= v1.len() as u32); -    } - -    #[test] -    fn test_os_rng_empty() { -        let mut r = OsRng::new().unwrap(); - -        let mut empty = [0u8; 0]; -        r.fill_bytes(&mut empty); -    } - -    #[test] -    fn test_os_rng_huge() { -        let mut r = OsRng::new().unwrap(); - -        let mut huge = [0u8; 100_000]; -        r.fill_bytes(&mut huge); -    } - -    #[cfg(not(any(target_arch = "wasm32", target_arch = "asmjs")))] -    #[test] -    fn test_os_rng_tasks() { -        use std::sync::mpsc::channel; -        use std::thread; - -        let mut txs = vec!(); -        for _ in 0..20 { -            let (tx, rx) = channel(); -            txs.push(tx); - -            thread::spawn(move|| { -                // wait until all the tasks are ready to go. -                rx.recv().unwrap(); - -                // deschedule to attempt to interleave things as much -                // as possible (XXX: is this a good test?) -                let mut r = OsRng::new().unwrap(); -                thread::yield_now(); -                let mut v = [0u8; 1000]; - -                for _ in 0..100 { -                    r.next_u32(); -                    thread::yield_now(); -                    r.next_u64(); -                    thread::yield_now(); -                    r.fill_bytes(&mut v); -                    thread::yield_now(); -                } -            }); -        } - -        // start all the tasks -        for tx in txs.iter() { -            tx.send(()).unwrap(); -        } -    } -} diff --git a/rand/src/rngs/small.rs b/rand/src/rngs/small.rs index e74a83e..b652c8c 100644 --- a/rand/src/rngs/small.rs +++ b/rand/src/rngs/small.rs @@ -10,9 +10,9 @@  use {RngCore, SeedableRng, Error}; -#[cfg(all(rust_1_26, target_pointer_width = "64"))] +#[cfg(all(all(rustc_1_26, not(target_os = "emscripten")), target_pointer_width = "64"))]  type Rng = ::rand_pcg::Pcg64Mcg; -#[cfg(not(all(rust_1_26, target_pointer_width = "64")))] +#[cfg(not(all(all(rustc_1_26, not(target_os = "emscripten")), target_pointer_width = "64")))]  type Rng = ::rand_pcg::Pcg32;  /// An RNG recommended when small state, cheap initialization and good diff --git a/rand/src/rngs/thread.rs b/rand/src/rngs/thread.rs index ff772e3..7977d85 100644 --- a/rand/src/rngs/thread.rs +++ b/rand/src/rngs/thread.rs @@ -87,10 +87,11 @@ thread_local!(      }  ); -/// Retrieve the lazily-initialized thread-local random number -/// generator, seeded by the system. Intended to be used in method -/// chaining style, e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g. -/// `let mut rng = thread_rng();`. +/// Retrieve the lazily-initialized thread-local random number generator, +/// seeded by the system. Intended to be used in method chaining style, +/// e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g. +/// `let mut rng = thread_rng();`.  Invoked by the `Default` trait, making +/// `ThreadRng::default()` equivelent.  ///  /// For more information see [`ThreadRng`].  /// @@ -99,6 +100,12 @@ pub fn thread_rng() -> ThreadRng {      ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.get()) }  } +impl Default for ThreadRng { +    fn default() -> ThreadRng { +        ::prelude::thread_rng() +    } +} +  impl RngCore for ThreadRng {      #[inline(always)]      fn next_u32(&mut self) -> u32 { @@ -125,7 +132,6 @@ impl CryptoRng for ThreadRng {}  #[cfg(test)]  mod test {      #[test] -    #[cfg(not(feature="stdweb"))]      fn test_thread_rng() {          use Rng;          let mut r = ::thread_rng(); | 
