From 7d13dbdd98c348c772a3b5b511a8bd8cb51035f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Sun, 6 Jan 2019 23:14:26 +0300 Subject: [PATCH 1/3] rand_os backward compatibility --- rand_os/src/{ => impls}/cloudabi.rs | 0 .../{ => impls}/dragonfly_haiku_emscripten.rs | 0 rand_os/src/{ => impls}/dummy_log.rs | 0 rand_os/src/{ => impls}/freebsd.rs | 0 rand_os/src/{ => impls}/fuchsia.rs | 0 rand_os/src/{ => impls}/linux_android.rs | 0 rand_os/src/{ => impls}/macos.rs | 0 rand_os/src/impls/mod.rs | 188 ++++++++++++++ rand_os/src/{ => impls}/netbsd.rs | 0 rand_os/src/{ => impls}/openbsd_bitrig.rs | 0 rand_os/src/{ => impls}/random_device.rs | 0 rand_os/src/{ => impls}/redox.rs | 0 rand_os/src/{ => impls}/solaris.rs | 0 rand_os/src/{ => impls}/wasm32_bindgen.rs | 0 rand_os/src/{ => impls}/wasm32_stdweb.rs | 0 rand_os/src/{ => impls}/windows.rs | 0 rand_os/src/lib.rs | 237 ++++-------------- src/rngs/entropy.rs | 6 +- src/rngs/mod.rs | 18 +- 19 files changed, 259 insertions(+), 190 deletions(-) rename rand_os/src/{ => impls}/cloudabi.rs (100%) rename rand_os/src/{ => impls}/dragonfly_haiku_emscripten.rs (100%) rename rand_os/src/{ => impls}/dummy_log.rs (100%) rename rand_os/src/{ => impls}/freebsd.rs (100%) rename rand_os/src/{ => impls}/fuchsia.rs (100%) rename rand_os/src/{ => impls}/linux_android.rs (100%) rename rand_os/src/{ => impls}/macos.rs (100%) create mode 100644 rand_os/src/impls/mod.rs rename rand_os/src/{ => impls}/netbsd.rs (100%) rename rand_os/src/{ => impls}/openbsd_bitrig.rs (100%) rename rand_os/src/{ => impls}/random_device.rs (100%) rename rand_os/src/{ => impls}/redox.rs (100%) rename rand_os/src/{ => impls}/solaris.rs (100%) rename rand_os/src/{ => impls}/wasm32_bindgen.rs (100%) rename rand_os/src/{ => impls}/wasm32_stdweb.rs (100%) rename rand_os/src/{ => impls}/windows.rs (100%) diff --git a/rand_os/src/cloudabi.rs b/rand_os/src/impls/cloudabi.rs similarity index 100% rename from rand_os/src/cloudabi.rs rename to rand_os/src/impls/cloudabi.rs diff --git a/rand_os/src/dragonfly_haiku_emscripten.rs b/rand_os/src/impls/dragonfly_haiku_emscripten.rs similarity index 100% rename from rand_os/src/dragonfly_haiku_emscripten.rs rename to rand_os/src/impls/dragonfly_haiku_emscripten.rs diff --git a/rand_os/src/dummy_log.rs b/rand_os/src/impls/dummy_log.rs similarity index 100% rename from rand_os/src/dummy_log.rs rename to rand_os/src/impls/dummy_log.rs diff --git a/rand_os/src/freebsd.rs b/rand_os/src/impls/freebsd.rs similarity index 100% rename from rand_os/src/freebsd.rs rename to rand_os/src/impls/freebsd.rs diff --git a/rand_os/src/fuchsia.rs b/rand_os/src/impls/fuchsia.rs similarity index 100% rename from rand_os/src/fuchsia.rs rename to rand_os/src/impls/fuchsia.rs diff --git a/rand_os/src/linux_android.rs b/rand_os/src/impls/linux_android.rs similarity index 100% rename from rand_os/src/linux_android.rs rename to rand_os/src/impls/linux_android.rs diff --git a/rand_os/src/macos.rs b/rand_os/src/impls/macos.rs similarity index 100% rename from rand_os/src/macos.rs rename to rand_os/src/impls/macos.rs diff --git a/rand_os/src/impls/mod.rs b/rand_os/src/impls/mod.rs new file mode 100644 index 00000000000..c08522911bf --- /dev/null +++ b/rand_os/src/impls/mod.rs @@ -0,0 +1,188 @@ +use std::fmt; +use rand_core::{CryptoRng, RngCore, Error, impls}; + +#[cfg(not(feature = "log"))] +#[macro_use] +mod dummy_log; + +/// A random number generator that retrieves randomness straight from the +/// operating system. +#[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 { + 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; + + // 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 { Ok(0) } + + // Maximum chunk size supported. + fn max_chunk_size(&self) -> usize { ::std::usize::MAX } + + // Name of the OS interface (used for logging). + fn method_str(&self) -> &'static str; +} + +#[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; + +macro_rules! mod_use { + ($cond:meta, $module:ident) => { + #[$cond] + mod $module; + #[$cond] + use self::$module as imp; + } +} + +mod_use!(cfg(target_os = "android"), linux_android); +mod_use!(cfg(target_os = "bitrig"), openbsd_bitrig); +mod_use!(cfg(target_os = "cloudabi"), cloudabi); +mod_use!(cfg(target_os = "dragonfly"), dragonfly_haiku_emscripten); +mod_use!(cfg(target_os = "emscripten"), dragonfly_haiku_emscripten); +mod_use!(cfg(target_os = "freebsd"), freebsd); +mod_use!(cfg(target_os = "fuchsia"), fuchsia); +mod_use!(cfg(target_os = "haiku"), dragonfly_haiku_emscripten); +mod_use!(cfg(target_os = "ios"), macos); +mod_use!(cfg(target_os = "linux"), linux_android); +mod_use!(cfg(target_os = "macos"), macos); +mod_use!(cfg(target_os = "netbsd"), netbsd); +mod_use!(cfg(target_os = "openbsd"), openbsd_bitrig); +mod_use!(cfg(target_os = "redox"), redox); +mod_use!(cfg(target_os = "solaris"), solaris); +mod_use!(cfg(windows), windows); + +mod_use!( + cfg(all( + target_arch = "wasm32", + not(target_os = "emscripten"), + not(feature = "stdweb"), + feature = "wasm-bindgen" + )), + wasm32_bindgen +); + +mod_use!( + cfg(all( + target_arch = "wasm32", + not(target_os = "emscripten"), + not(feature = "wasm-bindgen"), + feature = "stdweb", + )), + wasm32_stdweb +); + diff --git a/rand_os/src/netbsd.rs b/rand_os/src/impls/netbsd.rs similarity index 100% rename from rand_os/src/netbsd.rs rename to rand_os/src/impls/netbsd.rs diff --git a/rand_os/src/openbsd_bitrig.rs b/rand_os/src/impls/openbsd_bitrig.rs similarity index 100% rename from rand_os/src/openbsd_bitrig.rs rename to rand_os/src/impls/openbsd_bitrig.rs diff --git a/rand_os/src/random_device.rs b/rand_os/src/impls/random_device.rs similarity index 100% rename from rand_os/src/random_device.rs rename to rand_os/src/impls/random_device.rs diff --git a/rand_os/src/redox.rs b/rand_os/src/impls/redox.rs similarity index 100% rename from rand_os/src/redox.rs rename to rand_os/src/impls/redox.rs diff --git a/rand_os/src/solaris.rs b/rand_os/src/impls/solaris.rs similarity index 100% rename from rand_os/src/solaris.rs rename to rand_os/src/impls/solaris.rs diff --git a/rand_os/src/wasm32_bindgen.rs b/rand_os/src/impls/wasm32_bindgen.rs similarity index 100% rename from rand_os/src/wasm32_bindgen.rs rename to rand_os/src/impls/wasm32_bindgen.rs diff --git a/rand_os/src/wasm32_stdweb.rs b/rand_os/src/impls/wasm32_stdweb.rs similarity index 100% rename from rand_os/src/wasm32_stdweb.rs rename to rand_os/src/impls/wasm32_stdweb.rs diff --git a/rand_os/src/windows.rs b/rand_os/src/impls/windows.rs similarity index 100% rename from rand_os/src/windows.rs rename to rand_os/src/impls/windows.rs diff --git a/rand_os/src/lib.rs b/rand_os/src/lib.rs index 979392ad85e..50ba9777656 100644 --- a/rand_os/src/lib.rs +++ b/rand_os/src/lib.rs @@ -142,194 +142,50 @@ extern crate wasm_bindgen; feature = "stdweb"))] #[macro_use] extern crate stdweb; +#[cfg(any( + target_os = "android", + target_os = "bitrig", + target_os = "cloudabi", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + windows, + all(target_arch = "wasm32", any(feature = "wasm-bindgen", feature = "stdweb")) +))] +mod impls; -#[cfg(not(feature = "log"))] -#[macro_use] -mod dummy_log; - -use std::fmt; -use rand_core::{CryptoRng, RngCore, Error, impls}; - -/// A random number generator that retrieves randomness straight from the -/// operating system. -#[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 { - 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; - - // 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 { Ok(0) } - - // Maximum chunk size supported. - fn max_chunk_size(&self) -> usize { ::std::usize::MAX } - - // Name of the OS interface (used for logging). - fn method_str(&self) -> &'static str; -} - -#[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; - -macro_rules! mod_use { - ($cond:meta, $module:ident) => { - #[$cond] - mod $module; - #[$cond] - use $module as imp; - } -} - -mod_use!(cfg(target_os = "android"), linux_android); -mod_use!(cfg(target_os = "bitrig"), openbsd_bitrig); -mod_use!(cfg(target_os = "cloudabi"), cloudabi); -mod_use!(cfg(target_os = "dragonfly"), dragonfly_haiku_emscripten); -mod_use!(cfg(target_os = "emscripten"), dragonfly_haiku_emscripten); -mod_use!(cfg(target_os = "freebsd"), freebsd); -mod_use!(cfg(target_os = "fuchsia"), fuchsia); -mod_use!(cfg(target_os = "haiku"), dragonfly_haiku_emscripten); -mod_use!(cfg(target_os = "ios"), macos); -mod_use!(cfg(target_os = "linux"), linux_android); -mod_use!(cfg(target_os = "macos"), macos); -mod_use!(cfg(target_os = "netbsd"), netbsd); -mod_use!(cfg(target_os = "openbsd"), openbsd_bitrig); -mod_use!(cfg(target_os = "redox"), redox); -mod_use!(cfg(target_os = "solaris"), solaris); -mod_use!(cfg(windows), windows); - -mod_use!( - cfg(all( - target_arch = "wasm32", - not(target_os = "emscripten"), - feature = "wasm-bindgen" - )), - wasm32_bindgen -); - -mod_use!( - cfg(all( - target_arch = "wasm32", - not(target_os = "emscripten"), - not(feature = "wasm-bindgen"), - feature = "stdweb", - )), - wasm32_stdweb -); +#[cfg(any( + target_os = "android", + target_os = "bitrig", + target_os = "cloudabi", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + windows, + all(target_arch = "wasm32", any(feature = "wasm-bindgen", feature = "stdweb")) +))] +pub use impls::OsRng; +// compile-time errors are temporarily disabled, see https://github.com/rust-random/rand/issues/681 +/* #[cfg(all( target_arch = "wasm32", not(target_os = "emscripten"), @@ -338,6 +194,14 @@ mod_use!( ))] compile_error!("enable either wasm_bindgen or stdweb feature"); +#[cfg(all( + target_arch = "wasm32", + not(target_os = "emscripten"), + feature = "wasm-bindgen", + feature = "stdweb", +))] +compile_error!("wasm_bindgen and stdweb features should not be enabled together"); + #[cfg(not(any( target_os = "android", target_os = "bitrig", @@ -358,3 +222,4 @@ compile_error!("enable either wasm_bindgen or stdweb feature"); target_arch = "wasm32", )))] compile_error!("OS RNG support is not available for this platform"); +*/ diff --git a/src/rngs/entropy.rs b/src/rngs/entropy.rs index 8736324aaa3..783bb162555 100644 --- a/src/rngs/entropy.rs +++ b/src/rngs/entropy.rs @@ -191,7 +191,7 @@ impl EntropySource for NoSource { } -#[cfg(all(feature="std", +#[cfg(all(feature="rand_os", any(target_os = "linux", target_os = "android", target_os = "netbsd", target_os = "dragonfly", @@ -211,7 +211,7 @@ impl EntropySource for NoSource { #[derive(Clone, Debug)] pub struct Os(rngs::OsRng); -#[cfg(all(feature="std", +#[cfg(all(feature="rand_os", any(target_os = "linux", target_os = "android", target_os = "netbsd", target_os = "dragonfly", @@ -240,7 +240,7 @@ impl EntropySource for Os { } } -#[cfg(not(all(feature="std", +#[cfg(not(all(feature="rand_os", any(target_os = "linux", target_os = "android", target_os = "netbsd", target_os = "dragonfly", diff --git a/src/rngs/mod.rs b/src/rngs/mod.rs index 528e24d42a5..5994f3bba01 100644 --- a/src/rngs/mod.rs +++ b/src/rngs/mod.rs @@ -178,5 +178,21 @@ pub use self::small::SmallRng; pub use self::std::StdRng; #[cfg(feature="std")] pub use self::thread::ThreadRng; -#[cfg(feature="std")] +#[cfg(all(feature="rand_os", + 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 rand_os::OsRng; From e6032c3f36514ba9d88dbb7f401f9f049bfd2c11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Mon, 7 Jan 2019 23:45:47 +0300 Subject: [PATCH 2/3] remove winapi feature --- rand_os/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rand_os/Cargo.toml b/rand_os/Cargo.toml index af03e3dd506..e428ec308d4 100644 --- a/rand_os/Cargo.toml +++ b/rand_os/Cargo.toml @@ -23,7 +23,7 @@ libc = "0.2" # TODO: check if all features are required [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["minwindef", "ntsecapi", "profileapi", "winnt"] } +winapi = { version = "0.3", features = ["minwindef", "ntsecapi", "winnt"] } [target.'cfg(target_os = "cloudabi")'.dependencies] cloudabi = "0.0.3" From e9872004324f12a1727b16942cefff328971a00d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Mon, 7 Jan 2019 23:46:39 +0300 Subject: [PATCH 3/3] remove TODO --- rand_os/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/rand_os/Cargo.toml b/rand_os/Cargo.toml index e428ec308d4..723a49a3ec9 100644 --- a/rand_os/Cargo.toml +++ b/rand_os/Cargo.toml @@ -21,7 +21,6 @@ log = { version = "0.4", optional = true } [target.'cfg(unix)'.dependencies] libc = "0.2" -# TODO: check if all features are required [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["minwindef", "ntsecapi", "winnt"] }