aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Mueller <deso@posteo.net>2019-01-16 17:26:30 -0800
committerDaniel Mueller <deso@posteo.net>2019-01-16 17:26:30 -0800
commit8350ac6afb2d678b74581000a6aafe1994b72231 (patch)
tree2330da01a806921b3849c9e64d2b9f506495e2c0
parentd6652b913b33e432a748187f9f5623cec1e9926e (diff)
downloadnitrocli-8350ac6afb2d678b74581000a6aafe1994b72231.tar.gz
nitrocli-8350ac6afb2d678b74581000a6aafe1994b72231.tar.bz2
Update nitrokey crate to 0.3.3
This change updates the nitrokey crate to version 0.3.3. Along with that change we update rand to 0.6.4 because rand 0.6.1 does not yet contain a publicly accessible rand_os. Note that we no longer require all crates in rand's workspace, but only rand_os and rand_core, which is a significant reduction in the number of lines of code compiled. Import subrepo nitrokey/:nitrokey at 7cf747d56ddc0b7eeedc3caf36dcc909907a171c Import subrepo rand/:rand at 4336232dda03323634b10ec72ddf27914aebc3a2
-rw-r--r--nitrocli/CHANGELOG.md3
-rw-r--r--nitrocli/Cargo.lock78
-rw-r--r--nitrocli/Cargo.toml6
-rw-r--r--nitrokey/.builds/archlinux-use-system-lib.yaml22
-rw-r--r--nitrokey/.builds/archlinux.yml21
-rw-r--r--nitrokey/CHANGELOG.md9
-rw-r--r--nitrokey/Cargo.toml5
-rw-r--r--nitrokey/TODO.md3
-rw-r--r--nitrokey/src/auth.rs5
-rw-r--r--nitrokey/src/device.rs130
-rw-r--r--nitrokey/src/lib.rs9
-rw-r--r--nitrokey/src/pws.rs29
-rw-r--r--nitrokey/src/util.rs26
-rw-r--r--nitrokey/tests/device.rs57
-rw-r--r--nitrokey/tests/lib.rs3
-rw-r--r--nitrokey/tests/pws.rs23
-rw-r--r--rand/.travis.yml31
-rw-r--r--rand/CHANGELOG.md25
-rw-r--r--rand/Cargo.toml44
-rw-r--r--rand/README.md11
-rw-r--r--rand/appveyor.yml3
-rw-r--r--rand/benches/distributions.rs22
-rw-r--r--rand/benches/generators.rs40
-rw-r--r--rand/build.rs18
-rw-r--r--rand/rand_chacha/CHANGELOG.md4
-rw-r--r--rand/rand_chacha/Cargo.toml4
-rw-r--r--rand/rand_chacha/build.rs9
-rw-r--r--rand/rand_chacha/src/chacha.rs6
-rw-r--r--rand/rand_chacha/src/lib.rs2
-rw-r--r--rand/rand_hc/src/lib.rs2
-rw-r--r--rand/rand_isaac/CHANGELOG.md4
-rw-r--r--rand/rand_isaac/Cargo.toml4
-rw-r--r--rand/rand_isaac/src/lib.rs2
-rw-r--r--rand/rand_os/CHANGELOG.md13
-rw-r--r--rand/rand_os/COPYRIGHT12
-rw-r--r--rand/rand_os/Cargo.toml38
-rw-r--r--rand/rand_os/LICENSE-APACHE201
-rw-r--r--rand/rand_os/LICENSE-MIT26
-rw-r--r--rand/rand_os/README.md33
-rw-r--r--rand/rand_os/src/cloudabi.rs39
-rw-r--r--rand/rand_os/src/dragonfly_haiku_emscripten.rs39
-rw-r--r--rand/rand_os/src/dummy_log.rs10
-rw-r--r--rand/rand_os/src/freebsd.rs45
-rw-r--r--rand/rand_os/src/fuchsia.rs43
-rw-r--r--rand/rand_os/src/lib.rs439
-rw-r--r--rand/rand_os/src/linux_android.rs182
-rw-r--r--rand/rand_os/src/macos.rs53
-rw-r--r--rand/rand_os/src/netbsd.rs54
-rw-r--r--rand/rand_os/src/openbsd_bitrig.rs40
-rw-r--r--rand/rand_os/src/random_device.rs70
-rw-r--r--rand/rand_os/src/redox.rs30
-rw-r--r--rand/rand_os/src/sgx.rs38
-rw-r--r--rand/rand_os/src/solaris.rs175
-rw-r--r--rand/rand_os/src/wasm32_bindgen.rs125
-rw-r--r--rand/rand_os/src/wasm32_stdweb.rs107
-rw-r--r--rand/rand_os/src/windows.rs44
-rw-r--r--rand/rand_os/tests/mod.rs80
-rw-r--r--rand/rand_pcg/CHANGELOG.md5
-rw-r--r--rand/rand_pcg/Cargo.toml2
-rw-r--r--rand/rand_pcg/build.rs9
-rw-r--r--rand/rand_pcg/src/lib.rs6
-rw-r--r--rand/rand_pcg/tests/mcg128xsl64.rs2
-rw-r--r--rand/rand_xorshift/CHANGELOG.md3
-rw-r--r--rand/rand_xorshift/Cargo.toml2
-rw-r--r--rand/rand_xorshift/src/lib.rs2
-rw-r--r--rand/rand_xoshiro/CHANGELOG.md8
-rw-r--r--rand/rand_xoshiro/COPYRIGHT12
-rw-r--r--rand/rand_xoshiro/Cargo.toml19
-rw-r--r--rand/rand_xoshiro/LICENSE-APACHE201
-rw-r--r--rand/rand_xoshiro/LICENSE-MIT25
-rw-r--r--rand/rand_xoshiro/README.md28
-rw-r--r--rand/rand_xoshiro/src/common.rs243
-rw-r--r--rand/rand_xoshiro/src/lib.rs106
-rw-r--r--rand/rand_xoshiro/src/splitmix64.rs150
-rw-r--r--rand/rand_xoshiro/src/xoroshiro128plus.rs132
-rw-r--r--rand/rand_xoshiro/src/xoroshiro128starstar.rs129
-rw-r--r--rand/rand_xoshiro/src/xoroshiro64star.rs97
-rw-r--r--rand/rand_xoshiro/src/xoroshiro64starstar.rs96
-rw-r--r--rand/rand_xoshiro/src/xoshiro128plus.rs114
-rw-r--r--rand/rand_xoshiro/src/xoshiro128starstar.rs113
-rw-r--r--rand/rand_xoshiro/src/xoshiro256plus.rs133
-rw-r--r--rand/rand_xoshiro/src/xoshiro256starstar.rs130
-rw-r--r--rand/rand_xoshiro/src/xoshiro512plus.rs124
-rw-r--r--rand/rand_xoshiro/src/xoshiro512starstar.rs124
-rw-r--r--rand/src/deprecated.rs79
-rw-r--r--rand/src/distributions/integer.rs8
-rw-r--r--rand/src/distributions/mod.rs6
-rw-r--r--rand/src/distributions/uniform.rs31
-rw-r--r--rand/src/distributions/unit_circle.rs11
-rw-r--r--rand/src/distributions/unit_sphere.rs9
-rw-r--r--rand/src/distributions/utils.rs6
-rw-r--r--rand/src/lib.rs110
-rw-r--r--rand/src/rngs/entropy.rs54
-rw-r--r--rand/src/rngs/mod.rs39
-rw-r--r--rand/src/rngs/os.rs1275
-rw-r--r--rand/src/rngs/small.rs4
-rw-r--r--rand/src/rngs/thread.rs16
-rwxr-xr-xrand/utils/ci/install_cargo_web.sh15
-rw-r--r--rand/utils/ci/script.sh2
99 files changed, 4517 insertions, 1759 deletions
diff --git a/nitrocli/CHANGELOG.md b/nitrocli/CHANGELOG.md
index fec91fb..98296eb 100644
--- a/nitrocli/CHANGELOG.md
+++ b/nitrocli/CHANGELOG.md
@@ -3,7 +3,8 @@ Unreleased
- Store cached PINs on a per-device basis to better support multi-device
scenarios
- Further decreased binary size by using system allocator
-- Bumped `nitrokey` dependency to `0.3.2`
+- Bumped `nitrokey` dependency to `0.3.3`
+ - Bumped `rand` dependency to `0.6.4`
- Bumped `nitrokey-sys` dependency to `3.4.3`
- Bumped `libc` dependency to `0.2.46`
diff --git a/nitrocli/Cargo.lock b/nitrocli/Cargo.lock
index 092dc92..2f01846 100644
--- a/nitrocli/Cargo.lock
+++ b/nitrocli/Cargo.lock
@@ -76,18 +76,19 @@ dependencies = [
"argparse 0.2.2",
"base32 0.4.0",
"libc 0.2.46",
- "nitrokey 0.3.2",
+ "nitrokey 0.3.3",
"nitrokey-test 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nitrokey"
-version = "0.3.2"
+version = "0.3.3"
dependencies = [
"libc 0.2.46",
"nitrokey-sys 3.4.3",
- "rand 0.6.1",
+ "rand_core 0.3.0",
+ "rand_os 0.1.1",
]
[[package]]
@@ -124,59 +125,25 @@ dependencies = [
]
[[package]]
-name = "rand"
-version = "0.6.1"
-dependencies = [
- "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.46",
- "rand_chacha 0.1.0",
- "rand_core 0.3.0",
- "rand_hc 0.1.0",
- "rand_isaac 0.1.0",
- "rand_pcg 0.1.1",
- "rand_xorshift 0.1.0",
- "rustc_version 0.2.3",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.1.0"
-dependencies = [
- "rand_core 0.3.0",
- "rustc_version 0.2.3",
-]
-
-[[package]]
name = "rand_core"
version = "0.3.0"
[[package]]
-name = "rand_hc"
-version = "0.1.0"
-dependencies = [
- "rand_core 0.3.0",
-]
-
-[[package]]
-name = "rand_isaac"
-version = "0.1.0"
-dependencies = [
- "rand_core 0.3.0",
-]
-
-[[package]]
-name = "rand_pcg"
+name = "rand_os"
version = "0.1.1"
dependencies = [
+ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.46",
"rand_core 0.3.0",
- "rustc_version 0.2.3",
+ "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "rand_xorshift"
-version = "0.1.0"
+name = "rdrand"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.0",
]
@@ -202,24 +169,6 @@ dependencies = [
]
[[package]]
-name = "rustc_version"
-version = "0.2.3"
-dependencies = [
- "semver 0.9.0",
-]
-
-[[package]]
-name = "semver"
-version = "0.9.0"
-dependencies = [
- "semver-parser 0.7.0",
-]
-
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-
-[[package]]
name = "syn"
version = "0.15.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -288,6 +237,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum nitrokey-test 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6226eaa31d1bbb031314d9288eb0e1bf6a70e7053da7960fea13ee84cab330ea"
"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09"
"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
+"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f"
"checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1"
"checksum syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9545a6a093a3f0bd59adb472700acc08cad3776f860f16a897dfce8c88721cbc"
diff --git a/nitrocli/Cargo.toml b/nitrocli/Cargo.toml
index 7b8dfc7..fe4ad7f 100644
--- a/nitrocli/Cargo.toml
+++ b/nitrocli/Cargo.toml
@@ -67,7 +67,5 @@ cc = { path = "../cc" }
libc = { path = "../libc" }
nitrokey = { path = "../nitrokey" }
nitrokey-sys = { path = "../nitrokey-sys" }
-rand = { path = "../rand" }
-rustc_version = { path = "../rustc_version" }
-semver = { path = "../semver" }
-semver-parser = { path = "../semver-parser" }
+rand_core = { path = "../rand/rand_core" }
+rand_os = { path = "../rand/rand_os" }
diff --git a/nitrokey/.builds/archlinux-use-system-lib.yaml b/nitrokey/.builds/archlinux-use-system-lib.yaml
new file mode 100644
index 0000000..6fba33a
--- /dev/null
+++ b/nitrokey/.builds/archlinux-use-system-lib.yaml
@@ -0,0 +1,22 @@
+image: archlinux
+packages:
+ - rust
+ - libnitrokey
+environment:
+ USE_SYSTEM_LIBNITROKEY: "1"
+sources:
+ - https://git.sr.ht/~ireas/nitrokey-rs
+tasks:
+ - build: |
+ cd nitrokey-rs
+ cargo build --release
+ - test: |
+ cd nitrokey-rs
+ cargo test
+ - format: |
+ cd nitrokey-rs
+ cargo fmt -- --check
+triggers:
+ - action: email
+ condition: failure
+ to: nitrokey-rs-dev <nitrokey-rs-dev@ireas.org>
diff --git a/nitrokey/.builds/archlinux.yml b/nitrokey/.builds/archlinux.yml
new file mode 100644
index 0000000..9d45386
--- /dev/null
+++ b/nitrokey/.builds/archlinux.yml
@@ -0,0 +1,21 @@
+image: archlinux
+packages:
+ - rust
+ - hidapi
+ - gcc
+sources:
+ - https://git.sr.ht/~ireas/nitrokey-rs
+tasks:
+ - build: |
+ cd nitrokey-rs
+ cargo build --release
+ - test: |
+ cd nitrokey-rs
+ cargo test
+ - format: |
+ cd nitrokey-rs
+ cargo fmt -- --check
+triggers:
+ - action: email
+ condition: failure
+ to: nitrokey-rs-dev <nitrokey-rs-dev@ireas.org>
diff --git a/nitrokey/CHANGELOG.md b/nitrokey/CHANGELOG.md
index 72e6986..3845aaf 100644
--- a/nitrokey/CHANGELOG.md
+++ b/nitrokey/CHANGELOG.md
@@ -1,3 +1,12 @@
+# v0.3.3 (2019-01-16)
+- Add the `get_production_info` and `clear_new_sd_card_warning` methods to the
+ `Storage` struct.
+- Use `rand_os` instead of `rand` for random data creation.
+ - (Re-)add `CommandError::RngError` variant.
+- Account for the possibility that an empty string returned by libnitrokey can
+ not only indicate an error but also be a valid return value.
+- Make test cases more robust and avoid side effects on other test cases.
+
# v0.3.2 (2019-01-12)
- Make three additional error codes known: `CommandError::StringTooLong`,
`CommandError::InvalidHexString` and `CommandError::TargetBufferTooSmall`.
diff --git a/nitrokey/Cargo.toml b/nitrokey/Cargo.toml
index 09811f0..802d022 100644
--- a/nitrokey/Cargo.toml
+++ b/nitrokey/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "nitrokey"
-version = "0.3.2"
+version = "0.3.3"
authors = ["Robin Krahl <robin.krahl@ireas.org>"]
edition = "2018"
homepage = "https://code.ireas.org/nitrokey-rs/"
@@ -19,7 +19,8 @@ test-storage = []
[dependencies]
libc = "0.2"
nitrokey-sys = "3.4"
-rand = "0.6"
+rand_core = {version = "0.3", default-features = false}
+rand_os = {version = "0.1"}
[dev-dependencies]
nitrokey-test = {version = "0.1"}
diff --git a/nitrokey/TODO.md b/nitrokey/TODO.md
index 7c8c5e6..28bd3b8 100644
--- a/nitrokey/TODO.md
+++ b/nitrokey/TODO.md
@@ -1,19 +1,16 @@
- Add support for the currently unsupported commands:
- `NK_is_AES_supported`
- `NK_send_startup`
- - `NK_clear_new_sd_card_warning`
- `NK_fill_SD_card_with_random_data`
- `NK_get_SD_usage_data_as_string`
- `NK_get_progress_bar_value`
- `NK_list_devices_by_cpuID`
- `NK_connect_with_ID`
- - `NK_get_storage_production_info`
- Fix timing issues with the `totp_no_pin` and `totp_pin` test cases.
- Clear passwords from memory.
- Find a nicer syntax for the `write_config` test.
- Prevent construction of internal types.
- More specific error checking in the tests.
-- Differentiate empty strings and errors (see `result_from_string`).
- Check integer conversions.
- Consider implementing `Into<CommandError>` for `(Device, CommandError)`
- Lock password safe in `PasswordSafe::drop()` (see [nitrokey-storage-firmware
diff --git a/nitrokey/src/auth.rs b/nitrokey/src/auth.rs
index a129bd8..3280924 100644
--- a/nitrokey/src/auth.rs
+++ b/nitrokey/src/auth.rs
@@ -149,7 +149,10 @@ where
A: AuthenticatedDevice<D>,
T: Fn(*const i8, *const i8) -> c_int,
{
- let temp_password = generate_password(TEMPORARY_PASSWORD_LENGTH);
+ let temp_password = match generate_password(TEMPORARY_PASSWORD_LENGTH) {
+ Ok(temp_password) => temp_password,
+ Err(err) => return Err((device, err)),
+ };
let password = match get_cstring(password) {
Ok(password) => password,
Err(err) => return Err((device, err)),
diff --git a/nitrokey/src/device.rs b/nitrokey/src/device.rs
index f247f58..9813c50 100644
--- a/nitrokey/src/device.rs
+++ b/nitrokey/src/device.rs
@@ -208,6 +208,38 @@ pub struct VolumeStatus {
pub active: bool,
}
+/// Information about the SD card in a Storage device.
+#[derive(Debug)]
+pub struct SdCardData {
+ /// The serial number of the SD card.
+ pub serial_number: u32,
+ /// The size of the SD card in GB.
+ pub size: u8,
+ /// The year the card was manufactured, e. g. 17 for 2017.
+ pub manufacturing_year: u8,
+ /// The month the card was manufactured.
+ pub manufacturing_month: u8,
+ /// The OEM ID.
+ pub oem: u16,
+ /// The manufacturer ID.
+ pub manufacturer: u8,
+}
+
+#[derive(Debug)]
+/// Production information for a Storage device.
+pub struct StorageProductionInfo {
+ /// The major firmware version, e. g. 0 in v0.40.
+ pub firmware_version_major: u8,
+ /// The minor firmware version, e. g. 40 in v0.40.
+ pub firmware_version_minor: u8,
+ /// The internal firmware version.
+ pub firmware_version_internal: u8,
+ /// The serial number of the CPU.
+ pub serial_number_cpu: u32,
+ /// Information about the SD card.
+ pub sd_card: SdCardData,
+}
+
/// The status of a Nitrokey Storage device.
#[derive(Debug)]
pub struct StorageStatus {
@@ -566,7 +598,7 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
///
/// The AES key is used to encrypt the password safe and the encrypted volume. You may need
/// to call this method after a factory reset, either using [`factory_reset`][] or using `gpg
- /// --card-edit`. You can also use it to destory the data stored in the password safe or on
+ /// --card-edit`. You can also use it to destroy the data stored in the password safe or on
/// the encrypted volume.
///
/// # Errors
@@ -1166,6 +1198,83 @@ impl Storage {
result.and(Ok(StorageStatus::from(raw_status)))
}
+ /// Returns the production information for the connected storage device.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// # use nitrokey::CommandError;
+ ///
+ /// fn use_volume() {}
+ ///
+ /// # fn try_main() -> Result<(), CommandError> {
+ /// let device = nitrokey::Storage::connect()?;
+ /// match device.get_production_info() {
+ /// Ok(data) => {
+ /// println!("SD card ID: {:#x}", data.sd_card.serial_number);
+ /// println!("SD card size: {} GB", data.sd_card.size);
+ /// },
+ /// Err(err) => println!("Could not get Storage production info: {}", err),
+ /// };
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn get_production_info(&self) -> Result<StorageProductionInfo, CommandError> {
+ let mut raw_data = nitrokey_sys::NK_storage_ProductionTest {
+ FirmwareVersion_au8: [0, 2],
+ FirmwareVersionInternal_u8: 0,
+ SD_Card_Size_u8: 0,
+ CPU_CardID_u32: 0,
+ SmartCardID_u32: 0,
+ SD_CardID_u32: 0,
+ SC_UserPwRetryCount: 0,
+ SC_AdminPwRetryCount: 0,
+ SD_Card_ManufacturingYear_u8: 0,
+ SD_Card_ManufacturingMonth_u8: 0,
+ SD_Card_OEM_u16: 0,
+ SD_WriteSpeed_u16: 0,
+ SD_Card_Manufacturer_u8: 0,
+ };
+ let raw_result = unsafe { nitrokey_sys::NK_get_storage_production_info(&mut raw_data) };
+ let result = get_command_result(raw_result);
+ result.and(Ok(StorageProductionInfo::from(raw_data)))
+ }
+
+ /// Clears the warning for a new SD card.
+ ///
+ /// The Storage status contains a field for a new SD card warning. After a factory reset, the
+ /// field is set to true. After filling the SD card with random data, it is set to false.
+ /// This method can be used to set it to false without filling the SD card with random data.
+ ///
+ /// # Errors
+ ///
+ /// - [`InvalidString`][] if the provided password contains a null byte
+ /// - [`WrongPassword`][] if the provided admin password is wrong
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// # use nitrokey::CommandError;
+ ///
+ /// # fn try_main() -> Result<(), CommandError> {
+ /// let device = nitrokey::Storage::connect()?;
+ /// match device.clear_new_sd_card_warning("12345678") {
+ /// Ok(()) => println!("Cleared the new SD card warning."),
+ /// Err(err) => println!("Could not set the clear the new SD card warning: {}", err),
+ /// };
+ /// # Ok(())
+ /// # }
+ /// ```
+ ///
+ /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword
+ pub fn clear_new_sd_card_warning(&self, admin_pin: &str) -> Result<(), CommandError> {
+ let admin_pin = get_cstring(admin_pin)?;
+ get_command_result(unsafe {
+ nitrokey_sys::NK_clear_new_sd_card_warning(admin_pin.as_ptr())
+ })
+ }
+
/// Blinks the red and green LED alternatively and infinitely until the device is reconnected.
pub fn wink(&self) -> Result<(), CommandError> {
get_command_result(unsafe { nitrokey_sys::NK_wink() })
@@ -1209,6 +1318,25 @@ impl Device for Storage {
impl GenerateOtp for Storage {}
+impl From<nitrokey_sys::NK_storage_ProductionTest> for StorageProductionInfo {
+ fn from(data: nitrokey_sys::NK_storage_ProductionTest) -> Self {
+ Self {
+ firmware_version_major: data.FirmwareVersion_au8[0],
+ firmware_version_minor: data.FirmwareVersion_au8[1],
+ firmware_version_internal: data.FirmwareVersionInternal_u8,
+ serial_number_cpu: data.CPU_CardID_u32,
+ sd_card: SdCardData {
+ serial_number: data.SD_CardID_u32,
+ size: data.SD_Card_Size_u8,
+ manufacturing_year: data.SD_Card_ManufacturingYear_u8,
+ manufacturing_month: data.SD_Card_ManufacturingMonth_u8,
+ oem: data.SD_Card_OEM_u16,
+ manufacturer: data.SD_Card_Manufacturer_u8,
+ },
+ }
+ }
+}
+
impl From<nitrokey_sys::NK_storage_status> for StorageStatus {
fn from(status: nitrokey_sys::NK_storage_status) -> Self {
StorageStatus {
diff --git a/nitrokey/src/lib.rs b/nitrokey/src/lib.rs
index c50b713..02a622b 100644
--- a/nitrokey/src/lib.rs
+++ b/nitrokey/src/lib.rs
@@ -98,8 +98,8 @@ use nitrokey_sys;
pub use crate::auth::{Admin, Authenticate, User};
pub use crate::config::Config;
pub use crate::device::{
- connect, connect_model, Device, DeviceWrapper, Model, Pro, Storage, StorageStatus, VolumeMode,
- VolumeStatus,
+ connect, connect_model, Device, DeviceWrapper, Model, Pro, SdCardData, Storage,
+ StorageProductionInfo, StorageStatus, VolumeMode, VolumeStatus,
};
pub use crate::otp::{ConfigureOtp, GenerateOtp, OtpMode, OtpSlotData};
pub use crate::pws::{GetPasswordSafe, PasswordSafe, SLOT_COUNT};
@@ -111,12 +111,13 @@ pub use crate::util::{CommandError, LogLevel};
/// version.
#[derive(Clone, Debug, PartialEq)]
pub struct Version {
- /// The library version as a string.
+ /// The Git library version as a string.
///
/// The library version is the output of `git describe --always` at compile time, for example
/// `v3.3` or `v3.4.1`. If the library has not been built from a release, the version string
/// contains the number of commits since the last release and the hash of the current commit, for
- /// example `v3.3-19-gaee920b`.
+ /// example `v3.3-19-gaee920b`. If the library has not been built from a Git checkout, this
+ /// string may be empty.
pub git: String,
/// The major library version.
pub major: u32,
diff --git a/nitrokey/src/pws.rs b/nitrokey/src/pws.rs
index ebd5fcd..28f0681 100644
--- a/nitrokey/src/pws.rs
+++ b/nitrokey/src/pws.rs
@@ -129,6 +129,14 @@ fn get_password_safe<'a>(
result.map(|()| PasswordSafe { _device: device })
}
+fn get_pws_result(s: String) -> Result<String, CommandError> {
+ if s.is_empty() {
+ Err(CommandError::SlotNotProgrammed)
+ } else {
+ Ok(s)
+ }
+}
+
impl<'a> PasswordSafe<'a> {
/// Returns the status of all password slots.
///
@@ -172,10 +180,12 @@ impl<'a> PasswordSafe<'a> {
/// Returns the name of the given slot (if it is programmed).
///
+ /// This method also returns a `SlotNotProgrammed` error if the name is empty.
+ ///
/// # Errors
///
/// - [`InvalidSlot`][] if the given slot is out of range
- /// - [`Undefined`][] if the slot is not programmed
+ /// - [`SlotNotProgrammed`][] if the slot is not programmed
///
/// # Example
///
@@ -199,17 +209,20 @@ impl<'a> PasswordSafe<'a> {
/// ```
///
/// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
- /// [`Undefined`]: enum.CommandError.html#variant.Undefined
+ /// [`SlotNotProgrammed`]: enum.CommandError.html#variant.SlotNotProgrammed
pub fn get_slot_name(&self, slot: u8) -> Result<String, CommandError> {
unsafe { result_from_string(nitrokey_sys::NK_get_password_safe_slot_name(slot)) }
+ .and_then(get_pws_result)
}
/// Returns the login for the given slot (if it is programmed).
///
+ /// This method also returns a `SlotNotProgrammed` error if the login is empty.
+ ///
/// # Errors
///
/// - [`InvalidSlot`][] if the given slot is out of range
- /// - [`Undefined`][] if the slot is not programmed
+ /// - [`SlotNotProgrammed`][] if the slot is not programmed
///
/// # Example
///
@@ -229,17 +242,20 @@ impl<'a> PasswordSafe<'a> {
/// ```
///
/// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
- /// [`Undefined`]: enum.CommandError.html#variant.Undefined
+ /// [`SlotNotProgrammed`]: enum.CommandError.html#variant.SlotNotProgrammed
pub fn get_slot_login(&self, slot: u8) -> Result<String, CommandError> {
unsafe { result_from_string(nitrokey_sys::NK_get_password_safe_slot_login(slot)) }
+ .and_then(get_pws_result)
}
/// Returns the password for the given slot (if it is programmed).
///
+ /// This method also returns a `SlotNotProgrammed` error if the password is empty.
+ ///
/// # Errors
///
/// - [`InvalidSlot`][] if the given slot is out of range
- /// - [`Undefined`][] if the slot is not programmed
+ /// - [`SlotNotProgrammed`][] if the slot is not programmed
///
/// # Example
///
@@ -259,9 +275,10 @@ impl<'a> PasswordSafe<'a> {
/// ```
///
/// [`InvalidSlot`]: enum.CommandError.html#variant.InvalidSlot
- /// [`Undefined`]: enum.CommandError.html#variant.Undefined
+ /// [`SlotNotProgrammed`]: enum.CommandError.html#variant.SlotNotProgrammed
pub fn get_slot_password(&self, slot: u8) -> Result<String, CommandError> {
unsafe { result_from_string(nitrokey_sys::NK_get_password_safe_slot_password(slot)) }
+ .and_then(get_pws_result)
}
/// Writes the given slot with the given name, login and password.
diff --git a/nitrokey/src/util.rs b/nitrokey/src/util.rs
index cb109d0..567c478 100644
--- a/nitrokey/src/util.rs
+++ b/nitrokey/src/util.rs
@@ -4,7 +4,8 @@ use std::fmt;
use std::os::raw::{c_char, c_int};
use libc::{c_void, free};
-use rand::Rng;
+use rand_core::RngCore;
+use rand_os::OsRng;
/// Error types returned by Nitrokey device or by the library.
#[derive(Clone, Copy, Debug, PartialEq)]
@@ -44,6 +45,8 @@ pub enum CommandError {
InvalidHexString,
/// The target buffer was smaller than the source.
TargetBufferTooSmall,
+ /// An error occurred during random number generation.
+ RngError,
}
/// Log level for libnitrokey.
@@ -80,10 +83,13 @@ pub fn result_from_string(ptr: *const c_char) -> Result<String, CommandError> {
unsafe {
let s = owned_str_from_ptr(ptr);
free(ptr as *mut c_void);
+ // An empty string can both indicate an error or be a valid return value. In this case, we
+ // have to check the last command status to decide what to return.
if s.is_empty() {
- return Err(get_last_error());
+ get_last_result().map(|_| s)
+ } else {
+ Ok(s)
}
- return Ok(s);
}
}
@@ -106,10 +112,11 @@ pub fn get_last_error() -> CommandError {
};
}
-pub fn generate_password(length: usize) -> Vec<u8> {
+pub fn generate_password(length: usize) -> Result<Vec<u8>, CommandError> {
+ let mut rng = OsRng::new()?;
let mut data = vec![0u8; length];
- rand::thread_rng().fill(&mut data[..]);
- return data;
+ rng.fill_bytes(&mut data[..]);
+ Ok(data)
}
pub fn get_cstring<T: Into<Vec<u8>>>(s: T) -> Result<CString, CommandError> {
@@ -146,6 +153,7 @@ impl CommandError {
"The supplied string is not in hexadecimal format".into()
}
CommandError::TargetBufferTooSmall => "The target buffer is too small".into(),
+ CommandError::RngError => "An error occurred during random number generation".into(),
}
}
}
@@ -178,6 +186,12 @@ impl From<c_int> for CommandError {
}
}
+impl From<rand_core::Error> for CommandError {
+ fn from(_error: rand_core::Error) -> Self {
+ CommandError::RngError
+ }
+}
+
impl Into<i32> for LogLevel {
fn into(self) -> i32 {
match self {
diff --git a/nitrokey/tests/device.rs b/nitrokey/tests/device.rs
index e40ae12..849d2ff 100644
--- a/nitrokey/tests/device.rs
+++ b/nitrokey/tests/device.rs
@@ -260,6 +260,15 @@ fn unlock_user_pin(device: DeviceWrapper) {
#[test_device]
fn factory_reset(device: DeviceWrapper) {
+ let admin = device.authenticate_admin(ADMIN_PASSWORD).unwrap();
+ let otp_data = OtpSlotData::new(1, "test", "0123468790", OtpMode::SixDigits);
+ assert_eq!(Ok(()), admin.write_totp_slot(otp_data, 30));
+
+ let device = admin.device();
+ let pws = device.get_password_safe(USER_PASSWORD).unwrap();
+ assert_eq!(Ok(()), pws.write_slot(0, "test", "testlogin", "testpw"));
+ drop(pws);
+
assert_eq!(
Ok(()),
device.change_user_pin(USER_PASSWORD, USER_NEW_PASSWORD)
@@ -269,15 +278,6 @@ fn factory_reset(device: DeviceWrapper) {
device.change_admin_pin(ADMIN_PASSWORD, ADMIN_NEW_PASSWORD)
);
- let admin = device.authenticate_admin(ADMIN_NEW_PASSWORD).unwrap();
- let otp_data = OtpSlotData::new(1, "test", "0123468790", OtpMode::SixDigits);
- assert_eq!(Ok(()), admin.write_totp_slot(otp_data, 30));
-
- let device = admin.device();
- let pws = device.get_password_safe(USER_NEW_PASSWORD).unwrap();
- assert_eq!(Ok(()), pws.write_slot(0, "test", "testlogin", "testpw"));
- drop(pws);
-
assert_eq!(
Err(CommandError::WrongPassword),
device.factory_reset(USER_NEW_PASSWORD)
@@ -439,6 +439,45 @@ fn get_storage_status(device: Storage) {
}
#[test_device]
+fn get_production_info(device: Storage) {
+ let info = device.get_production_info().unwrap();
+ assert_eq!(0, info.firmware_version_major);
+ assert!(info.firmware_version_minor != 0);
+ assert!(info.serial_number_cpu != 0);
+ assert!(info.sd_card.serial_number != 0);
+ assert!(info.sd_card.size > 0);
+ assert!(info.sd_card.manufacturing_year > 10);
+ assert!(info.sd_card.manufacturing_year < 100);
+ // TODO: month value is not valid atm
+ // assert!(info.sd_card.manufacturing_month < 12);
+ assert!(info.sd_card.oem != 0);
+ assert!(info.sd_card.manufacturer != 0);
+
+ let status = device.get_status().unwrap();
+ assert_eq!(status.firmware_version_major, info.firmware_version_major);
+ assert_eq!(status.firmware_version_minor, info.firmware_version_minor);
+ assert_eq!(status.serial_number_sd_card, info.sd_card.serial_number);
+}
+
+#[test_device]
+fn clear_new_sd_card_warning(device: Storage) {
+ assert_eq!(Ok(()), device.factory_reset(ADMIN_PASSWORD));
+ thread::sleep(time::Duration::from_secs(3));
+ assert_eq!(Ok(()), device.build_aes_key(ADMIN_PASSWORD));
+
+ // We have to perform an SD card operation to reset the new_sd_card_found field
+ assert_eq!(Ok(()), device.lock());
+
+ let status = device.get_status().unwrap();
+ assert!(status.new_sd_card_found);
+
+ assert_eq!(Ok(()), device.clear_new_sd_card_warning(ADMIN_PASSWORD));
+
+ let status = device.get_status().unwrap();
+ assert!(!status.new_sd_card_found);
+}
+
+#[test_device]
fn export_firmware(device: Storage) {
assert_eq!(
Err(CommandError::WrongPassword),
diff --git a/nitrokey/tests/lib.rs b/nitrokey/tests/lib.rs
index 06de0ad..c92e224 100644
--- a/nitrokey/tests/lib.rs
+++ b/nitrokey/tests/lib.rs
@@ -2,7 +2,6 @@
fn get_library_version() {
let version = nitrokey::get_library_version();
- assert!(!version.git.is_empty());
- assert!(version.git.starts_with("v"));
+ assert!(version.git.is_empty() || version.git.starts_with("v"));
assert!(version.major > 0);
}
diff --git a/nitrokey/tests/pws.rs b/nitrokey/tests/pws.rs
index b349558..fbcc0c1 100644
--- a/nitrokey/tests/pws.rs
+++ b/nitrokey/tests/pws.rs
@@ -20,7 +20,7 @@ fn get_slot_name_direct(slot: u8) -> Result<String, CommandError> {
true => {
let error = unsafe { nitrokey_sys::NK_get_last_command_status() } as c_int;
match error {
- 0 => Err(CommandError::Undefined),
+ 0 => Ok(s),
other => Err(CommandError::from(other)),
}
}
@@ -92,10 +92,12 @@ fn get_data(device: DeviceWrapper) {
assert_eq!("password", pws.get_slot_password(1).unwrap());
assert_eq!(Ok(()), pws.erase_slot(1));
- // TODO: check error codes
- assert_eq!(Err(CommandError::Undefined), pws.get_slot_name(1));
- assert_eq!(Err(CommandError::Undefined), pws.get_slot_login(1));
- assert_eq!(Err(CommandError::Undefined), pws.get_slot_password(1));
+ assert_eq!(Err(CommandError::SlotNotProgrammed), pws.get_slot_name(1));
+ assert_eq!(Err(CommandError::SlotNotProgrammed), pws.get_slot_login(1));
+ assert_eq!(
+ Err(CommandError::SlotNotProgrammed),
+ pws.get_slot_password(1)
+ );
let name = "with å";
let login = "pär@test.com";
@@ -129,19 +131,22 @@ fn write(device: DeviceWrapper) {
);
assert_eq!(Ok(()), pws.write_slot(0, "", "login", "password"));
- assert_eq!(Err(CommandError::Undefined), pws.get_slot_name(0));
+ assert_eq!(Err(CommandError::SlotNotProgrammed), pws.get_slot_name(0));
assert_eq!(Ok(String::from("login")), pws.get_slot_login(0));
assert_eq!(Ok(String::from("password")), pws.get_slot_password(0));
assert_eq!(Ok(()), pws.write_slot(0, "name", "", "password"));
assert_eq!(Ok(String::from("name")), pws.get_slot_name(0));
- assert_eq!(Err(CommandError::Undefined), pws.get_slot_login(0));
+ assert_eq!(Err(CommandError::SlotNotProgrammed), pws.get_slot_login(0));
assert_eq!(Ok(String::from("password")), pws.get_slot_password(0));
assert_eq!(Ok(()), pws.write_slot(0, "name", "login", ""));
assert_eq!(Ok(String::from("name")), pws.get_slot_name(0));
assert_eq!(Ok(String::from("login")), pws.get_slot_login(0));
- assert_eq!(Err(CommandError::Undefined), pws.get_slot_password(0));
+ assert_eq!(
+ Err(CommandError::SlotNotProgrammed),
+ pws.get_slot_password(0)
+ );
}
#[test_device]
@@ -152,5 +157,5 @@ fn erase(device: DeviceWrapper) {
assert_eq!(Ok(()), pws.write_slot(0, "name", "login", "password"));
assert_eq!(Ok(()), pws.erase_slot(0));
assert_eq!(Ok(()), pws.erase_slot(0));
- assert_eq!(Err(CommandError::Undefined), pws.get_slot_name(0));
+ assert_eq!(Err(CommandError::SlotNotProgrammed), pws.get_slot_name(0));
}
diff --git a/rand/.travis.yml b/rand/.travis.yml
index 2f0bb79..b41e681 100644
--- a/rand/.travis.yml
+++ b/rand/.travis.yml
@@ -71,8 +71,10 @@ matrix:
- cargo test --manifest-path rand_isaac/Cargo.toml --features=serde1
# TODO: cannot test rand_pcg due to explicit dependency on i128
- cargo test --manifest-path rand_xorshift/Cargo.toml --features=serde1
+ - cargo test --manifest-path rand_xoshiro/Cargo.toml
- cargo test --manifest-path rand_chacha/Cargo.toml
- cargo test --manifest-path rand_hc/Cargo.toml
+ - cargo test --manifest-path rand_os/Cargo.toml
- rust: stable
env: DESCRIPTION="stable Rust release, macOS, iOS (cross-compile only)"
@@ -90,8 +92,10 @@ matrix:
- cargo test --manifest-path rand_isaac/Cargo.toml --features=serde1
- cargo test --manifest-path rand_pcg/Cargo.toml --features=serde1
- cargo test --manifest-path rand_xorshift/Cargo.toml --features=serde1
+ - cargo test --manifest-path rand_xoshiro/Cargo.toml
- cargo test --manifest-path rand_chacha/Cargo.toml
- cargo test --manifest-path rand_hc/Cargo.toml
+ - cargo test --manifest-path rand_os/Cargo.toml
- cargo build --target=aarch64-apple-ios
- rust: beta
@@ -115,8 +119,10 @@ matrix:
- cargo test --manifest-path rand_isaac/Cargo.toml --features=serde1
- cargo test --manifest-path rand_pcg/Cargo.toml --features=serde1
- cargo test --manifest-path rand_xorshift/Cargo.toml --features=serde1
+ - cargo test --manifest-path rand_xoshiro/Cargo.toml
- cargo test --manifest-path rand_chacha/Cargo.toml
- cargo test --manifest-path rand_hc/Cargo.toml
+ - cargo test --manifest-path rand_os/Cargo.toml
# remove cached documentation, otherwise files from previous PRs can get included
- rm -rf target/doc
- cargo doc --no-deps --all --all-features
@@ -129,21 +135,22 @@ matrix:
install:
- rustup target add wasm32-unknown-unknown
- rustup target add wasm32-unknown-emscripten
- # cargo-web takes ±10 min. to install, and cargo and cargo-update offer
- # no reliable update-or-install command. We ignore updating for now
- # (just drop the Travis' caches when necessary)
- - cargo --list | egrep "^\s*web$" -q || cargo install cargo-web
+ - nvm install 9
+ - ./utils/ci/install_cargo_web.sh
+ - cargo web prepare-emscripten
- cargo web -V
addons:
chrome: stable
script:
- # testing wasm32-unknown-emscripten fails because of rust-lang/rust#49877
- - cargo build --target wasm32-unknown-emscripten
+ # Testing wasm32-unknown-emscripten fails because of rust-lang/rust#49877
+ # However, we can still build and link all tests to make sure that works.
+ # This is actually useful as it finds stuff such as rust-random/rand#669
+ - EMCC_CFLAGS="-s ERROR_ON_UNDEFINED_SYMBOLS=0" cargo web test --target wasm32-unknown-emscripten --no-run
#- cargo web test --target wasm32-unknown-emscripten
#- cargo web test --nodejs --target wasm32-unknown-emscripten
- - cargo build --target wasm32-unknown-unknown # without any features
- - cargo web test --nodejs --target wasm32-unknown-unknown --features=stdweb
+ #- cargo build --target wasm32-unknown-unknown # without any features
- cargo build --target wasm32-unknown-unknown --features=wasm-bindgen
+ - cargo web test --target wasm32-unknown-unknown --features=stdweb
- rust: nightly
env: DESCRIPTION="cross-platform builder (doesn't run tests)"
@@ -198,12 +205,18 @@ script:
- cargo test --manifest-path rand_isaac/Cargo.toml --features=serde1
- cargo test --manifest-path rand_pcg/Cargo.toml --features=serde1
- cargo test --manifest-path rand_xorshift/Cargo.toml --features=serde1
+ - cargo test --manifest-path rand_xoshiro/Cargo.toml
- cargo test --manifest-path rand_chacha/Cargo.toml
- cargo test --manifest-path rand_hc/Cargo.toml
+ - cargo test --manifest-path rand_os/Cargo.toml
after_script: set +e
-cache: cargo
+cache:
+ cargo: true
+ directories:
+ - .local/share/cargo-web
+
before_cache:
# Travis can't cache files that are not readable by "others"
- chmod -R a+r $HOME/.cargo
diff --git a/rand/CHANGELOG.md b/rand/CHANGELOG.md
index 489df48..6aa0a24 100644
--- a/rand/CHANGELOG.md
+++ b/rand/CHANGELOG.md
@@ -9,6 +9,31 @@ A [separate changelog is kept for rand_core](rand_core/CHANGELOG.md).
You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.html) useful.
+## [0.6.4] - 2019-01-08
+### Fixes
+- Move wasm-bindgen shims to correct crate (#686)
+- Make `wasm32-unknown-unknown` compile but fail at run-time if missing bindingsg (#686)
+
+## [0.6.3] - 2019-01-04
+### Fixes
+- Make the `std` feature require the optional `rand_os` dependency (#675)
+- Re-export the optional WASM dependencies of `rand_os` from `rand` to avoid breakage (#674)
+
+## [0.6.2] - 2019-01-04
+### Additions
+- Add `Default` for `ThreadRng` (#657)
+- Move `rngs::OsRng` to `rand_os` sub-crate; clean up code; use as dependency (#643) ##BLOCKER##
+- Add `rand_xoshiro` sub-crate, plus benchmarks (#642, #668)
+
+### Fixes
+- Fix bias in `UniformInt::sample_single` (#662)
+- Use `autocfg` instead of `rustc_version` for rustc version detection (#664)
+- Disable `i128` and `u128` if the `target_os` is `emscripten` (#671: work-around Emscripten limitation)
+- CI fixes (#660, #671)
+
+### Optimisations
+- Optimise memory usage of `UnitCircle` and `UnitSphereSurface` distributions (no PR)
+
## [0.6.1] - 2018-11-22
- Support sampling `Duration` also for `no_std` (only since Rust 1.25) (#649)
- Disable default features of `libc` (#647)
diff --git a/rand/Cargo.toml b/rand/Cargo.toml
index 5f95c37..d802d36 100644
--- a/rand/Cargo.toml
+++ b/rand/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "rand"
-version = "0.6.1"
+version = "0.6.4"
authors = ["The Rand Project Developers", "The Rust Project Developers"]
license = "MIT/Apache-2.0"
readme = "README.md"
@@ -20,20 +20,33 @@ travis-ci = { repository = "rust-random/rand" }
appveyor = { repository = "rust-random/rand" }
[features]
-default = ["std" ] # without "std" rand uses libcore
+default = ["std", "rand_os"] # without "std" rand uses libcore
nightly = ["simd_support"] # enables all features requiring nightly rust
-std = ["rand_core/std", "alloc", "libc", "winapi", "cloudabi", "fuchsia-zircon"]
+std = ["rand_core/std", "alloc", "rand_os"]
alloc = ["rand_core/alloc"] # enables Vec and Box support (without std)
i128_support = [] # enables i128 and u128 support
simd_support = ["packed_simd"] # enables SIMD support
serde1 = ["rand_core/serde1", "rand_isaac/serde1", "rand_xorshift/serde1"] # enables serialization for PRNGs
+# re-export optional WASM dependencies to avoid breakage:
+wasm-bindgen = ["rand_os/wasm-bindgen"]
+stdweb = ["rand_os/stdweb"]
[workspace]
-members = ["rand_core", "rand_isaac", "rand_chacha", "rand_hc", "rand_pcg", "rand_xorshift"]
+members = [
+ "rand_core",
+ "rand_os",
+ "rand_isaac",
+ "rand_chacha",
+ "rand_hc",
+ "rand_pcg",
+ "rand_xorshift",
+ "rand_xoshiro",
+]
[dependencies]
rand_core = { path = "rand_core", version = "0.3", default-features = false }
rand_pcg = { path = "rand_pcg", version = "0.1" }
+rand_os = { path = "rand_os", version = "0.1", optional = true }
# only for deprecations and benches:
rand_isaac = { path = "rand_isaac", version = "0.1" }
rand_chacha = { path = "rand_chacha", version = "0.1" }
@@ -49,28 +62,23 @@ optional = true
features = ["into_bits"]
[target.'cfg(unix)'.dependencies]
-libc = { version = "0.2", optional = true, default-features = false }
+libc = { version = "0.2", default-features = false }
+# TODO: check if all features are required
[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = ["minwindef", "ntsecapi", "profileapi", "winnt"], optional = true }
-
-[target.'cfg(target_os = "cloudabi")'.dependencies]
-cloudabi = { version = "0.0.3", optional = true }
-
-[target.'cfg(target_os = "fuchsia")'.dependencies]
-fuchsia-zircon = { version = "0.3.2", optional = true }
-
-[target.wasm32-unknown-unknown.dependencies]
-# use with `--target wasm32-unknown-unknown --features=stdweb`
-stdweb = { version = "0.4", optional = true }
-wasm-bindgen = { version = "0.2.12", optional = true }
+winapi = { version = "0.3", features = ["minwindef", "ntsecapi", "profileapi", "winnt"] }
[dev-dependencies]
# This has a histogram implementation used for testing uniformity.
average = "0.9.2"
+# Only for benches:
+rand_xoshiro = { path = "rand_xoshiro", version = "0.1" }
[build-dependencies]
-rustc_version = "0.2"
+autocfg = "0.1"
[package.metadata.docs.rs]
all-features = true
+
+[patch.crates-io]
+rand_core = { path = "rand_core", version = "0.3", default-features = false }
diff --git a/rand/README.md b/rand/README.md
index 95970af..314a57f 100644
--- a/rand/README.md
+++ b/rand/README.md
@@ -74,8 +74,15 @@ pinned version of Rustc if you require compatibility with a specific version.
## Crate Features
-Rand is built with only the `std` feature enabled by default. The following
-optional features are available:
+Rand is built with the `std` and `rand_os` features enabled by default:
+
+- `std` enables functionality dependent on the `std` lib and implies `alloc`
+ and `rand_os`
+- `rand_os` enables the `rand_os` crate, `rngs::OsRng` and enables its usage;
+ the continued existance of this feature is not guaranteed so users are
+ encouraged to specify `std` instead
+
+The following optional features are available:
- `alloc` can be used instead of `std` to provide `Vec` and `Box`.
- `log` enables some logging via the `log` crate.
diff --git a/rand/appveyor.yml b/rand/appveyor.yml
index a0e518e..70e4326 100644
--- a/rand/appveyor.yml
+++ b/rand/appveyor.yml
@@ -41,6 +41,7 @@ test_script:
- cargo test --package rand_core --no-default-features --features=alloc
- cargo test --package rand_isaac --features=serde1
- cargo test --package rand_xorshift --features=serde1
+ - cargo test --package rand_xoshiro
- cargo test --package rand_chacha
- cargo test --package rand_hc
- cargo test --manifest-path rand_core/Cargo.toml
@@ -48,5 +49,7 @@ test_script:
- cargo test --manifest-path rand_isaac/Cargo.toml --features=serde1
- cargo test --manifest-path rand_pcg/Cargo.toml --features=serde1
- cargo test --manifest-path rand_xorshift/Cargo.toml --features=serde1
+ - cargo test --manifest-path rand_xoshiro/Cargo.toml
- cargo test --manifest-path rand_chacha/Cargo.toml
- cargo test --manifest-path rand_hc/Cargo.toml
+ - cargo test --manifest-path rand_os/Cargo.toml
diff --git a/rand/benches/distributions.rs b/rand/benches/distributions.rs
index 7ac1a6a..069a828 100644
--- a/rand/benches/distributions.rs
+++ b/rand/benches/distributions.rs
@@ -101,6 +101,26 @@ macro_rules! distr {
}
}
+macro_rules! distr_arr {
+ ($fnn:ident, $ty:ty, $distr:expr) => {
+ #[bench]
+ fn $fnn(b: &mut Bencher) {
+ let mut rng = SmallRng::from_entropy();
+ let distr = $distr;
+
+ b.iter(|| {
+ let mut accum = 0u32;
+ for _ in 0..::RAND_BENCH_N {
+ let x: $ty = distr.sample(&mut rng);
+ accum = accum.wrapping_add(x[0] as u32);
+ }
+ accum
+ });
+ b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N;
+ }
+ }
+}
+
// uniform
distr_int!(distr_uniform_i8, i8, Uniform::new(20i8, 100));
distr_int!(distr_uniform_i16, i16, Uniform::new(-500i16, 2000));
@@ -158,6 +178,8 @@ distr_float!(distr_cauchy, f64, Cauchy::new(4.2, 6.9));
distr_int!(distr_binomial, u64, Binomial::new(20, 0.7));
distr_int!(distr_poisson, u64, Poisson::new(4.0));
distr!(distr_bernoulli, bool, Bernoulli::new(0.18));
+distr_arr!(distr_circle, [f64; 2], UnitCircle::new());
+distr_arr!(distr_sphere_surface, [f64; 3], UnitSphereSurface::new());
// Weighted
distr_int!(distr_weighted_i8, usize, WeightedIndex::new(&[1i8, 2, 3, 4, 12, 0, 2, 1]).unwrap());
diff --git a/rand/benches/generators.rs b/rand/benches/generators.rs
index a12b5a6..a6e3a42 100644
--- a/rand/benches/generators.rs
+++ b/rand/benches/generators.rs
@@ -15,6 +15,7 @@ extern crate rand_chacha;
extern crate rand_hc;
extern crate rand_pcg;
extern crate rand_xorshift;
+extern crate rand_xoshiro;
const RAND_BENCH_N: u64 = 1000;
const BYTES_LEN: usize = 1024;
@@ -30,6 +31,9 @@ use rand_chacha::ChaChaRng;
use rand_hc::{Hc128Rng, Hc128Core};
use rand_pcg::{Lcg64Xsh32, Mcg128Xsl64};
use rand_xorshift::XorShiftRng;
+use rand_xoshiro::{Xoshiro256StarStar, Xoshiro256Plus, Xoshiro128StarStar,
+ Xoshiro128Plus, Xoroshiro128StarStar, Xoroshiro128Plus, SplitMix64,
+ Xoroshiro64StarStar, Xoroshiro64Star};
macro_rules! gen_bytes {
($fnn:ident, $gen:expr) => {
@@ -49,6 +53,15 @@ macro_rules! gen_bytes {
}
gen_bytes!(gen_bytes_xorshift, XorShiftRng::from_entropy());
+gen_bytes!(gen_bytes_xoshiro256starstar, Xoshiro256StarStar::from_entropy());
+gen_bytes!(gen_bytes_xoshiro256plus, Xoshiro256Plus::from_entropy());
+gen_bytes!(gen_bytes_xoshiro128starstar, Xoshiro128StarStar::from_entropy());
+gen_bytes!(gen_bytes_xoshiro128plus, Xoshiro128Plus::from_entropy());
+gen_bytes!(gen_bytes_xoroshiro128starstar, Xoroshiro128StarStar::from_entropy());
+gen_bytes!(gen_bytes_xoroshiro128plus, Xoroshiro128Plus::from_entropy());
+gen_bytes!(gen_bytes_xoroshiro64starstar, Xoroshiro64StarStar::from_entropy());
+gen_bytes!(gen_bytes_xoroshiro64star, Xoroshiro64Star::from_entropy());
+gen_bytes!(gen_bytes_splitmix64, SplitMix64::from_entropy());
gen_bytes!(gen_bytes_lcg64_xsh32, Lcg64Xsh32::from_entropy());
gen_bytes!(gen_bytes_mcg128_xsh64, Mcg128Xsl64::from_entropy());
gen_bytes!(gen_bytes_chacha20, ChaChaRng::from_entropy());
@@ -77,6 +90,15 @@ macro_rules! gen_uint {
}
gen_uint!(gen_u32_xorshift, u32, XorShiftRng::from_entropy());
+gen_uint!(gen_u32_xoshiro256starstar, u32, Xoshiro256StarStar::from_entropy());
+gen_uint!(gen_u32_xoshiro256plus, u32, Xoshiro256Plus::from_entropy());
+gen_uint!(gen_u32_xoshiro128starstar, u32, Xoshiro128StarStar::from_entropy());
+gen_uint!(gen_u32_xoshiro128plus, u32, Xoshiro128Plus::from_entropy());
+gen_uint!(gen_u32_xoroshiro128starstar, u32, Xoroshiro128StarStar::from_entropy());
+gen_uint!(gen_u32_xoroshiro128plus, u32, Xoroshiro128Plus::from_entropy());
+gen_uint!(gen_u32_xoroshiro64starstar, u32, Xoroshiro64StarStar::from_entropy());
+gen_uint!(gen_u32_xoroshiro64star, u32, Xoroshiro64Star::from_entropy());
+gen_uint!(gen_u32_splitmix64, u32, SplitMix64::from_entropy());
gen_uint!(gen_u32_lcg64_xsh32, u32, Lcg64Xsh32::from_entropy());
gen_uint!(gen_u32_mcg128_xsh64, u32, Mcg128Xsl64::from_entropy());
gen_uint!(gen_u32_chacha20, u32, ChaChaRng::from_entropy());
@@ -88,6 +110,15 @@ gen_uint!(gen_u32_small, u32, SmallRng::from_entropy());
gen_uint!(gen_u32_os, u32, OsRng::new().unwrap());
gen_uint!(gen_u64_xorshift, u64, XorShiftRng::from_entropy());
+gen_uint!(gen_u64_xoshiro256starstar, u64, Xoshiro256StarStar::from_entropy());
+gen_uint!(gen_u64_xoshiro256plus, u64, Xoshiro256Plus::from_entropy());
+gen_uint!(gen_u64_xoshiro128starstar, u64, Xoshiro128StarStar::from_entropy());
+gen_uint!(gen_u64_xoshiro128plus, u64, Xoshiro128Plus::from_entropy());
+gen_uint!(gen_u64_xoroshiro128starstar, u64, Xoroshiro128StarStar::from_entropy());
+gen_uint!(gen_u64_xoroshiro128plus, u64, Xoroshiro128Plus::from_entropy());
+gen_uint!(gen_u64_xoroshiro64starstar, u64, Xoroshiro64StarStar::from_entropy());
+gen_uint!(gen_u64_xoroshiro64star, u64, Xoroshiro64Star::from_entropy());
+gen_uint!(gen_u64_splitmix64, u64, SplitMix64::from_entropy());
gen_uint!(gen_u64_lcg64_xsh32, u64, Lcg64Xsh32::from_entropy());
gen_uint!(gen_u64_mcg128_xsh64, u64, Mcg128Xsl64::from_entropy());
gen_uint!(gen_u64_chacha20, u64, ChaChaRng::from_entropy());
@@ -123,6 +154,15 @@ macro_rules! init_gen {
}
init_gen!(init_xorshift, XorShiftRng);
+init_gen!(init_xoshiro256starstar, Xoshiro256StarStar);
+init_gen!(init_xoshiro256plus, Xoshiro256Plus);
+init_gen!(init_xoshiro128starstar, Xoshiro128StarStar);
+init_gen!(init_xoshiro128plus, Xoshiro128Plus);
+init_gen!(init_xoroshiro128starstar, Xoroshiro128StarStar);
+init_gen!(init_xoroshiro128plus, Xoroshiro128Plus);
+init_gen!(init_xoroshiro64starstar, Xoroshiro64StarStar);
+init_gen!(init_xoroshiro64star, Xoroshiro64Star);
+init_gen!(init_splitmix64, SplitMix64);
init_gen!(init_lcg64_xsh32, Lcg64Xsh32);
init_gen!(init_mcg128_xsh64, Mcg128Xsl64);
init_gen!(init_hc128, Hc128Rng);
diff --git a/rand/build.rs b/rand/build.rs
index e44b643..a554ad9 100644
--- a/rand/build.rs
+++ b/rand/build.rs
@@ -1,14 +1,10 @@
-extern crate rustc_version;
-use rustc_version::{version, Version};
+extern crate autocfg;
fn main() {
- if version().unwrap() >= Version::parse("1.25.0").unwrap() {
- println!("cargo:rustc-cfg=rust_1_25");
- }
- if version().unwrap() >= Version::parse("1.26.0").unwrap() {
- println!("cargo:rustc-cfg=rust_1_26");
- }
- if version().unwrap() >= Version::parse("1.27.0").unwrap() {
- println!("cargo:rustc-cfg=rust_1_27");
- }
+ println!("cargo:rerun-if-changed=build.rs");
+
+ let ac = autocfg::new();
+ ac.emit_rustc_version(1, 25);
+ ac.emit_rustc_version(1, 26);
+ ac.emit_rustc_version(1, 27);
}
diff --git a/rand/rand_chacha/CHANGELOG.md b/rand/rand_chacha/CHANGELOG.md
index d0c4a2f..a1979f6 100644
--- a/rand/rand_chacha/CHANGELOG.md
+++ b/rand/rand_chacha/CHANGELOG.md
@@ -4,5 +4,9 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.1.1] - 2019-01-04
+- Disable `i128` and `u128` if the `target_os` is `emscripten` (#671: work-around Emscripten limitation)
+- Update readme and doc links
+
## [0.1.0] - 2018-10-17
- Pulled out of the Rand crate
diff --git a/rand/rand_chacha/Cargo.toml b/rand/rand_chacha/Cargo.toml
index af70969..028428c 100644
--- a/rand/rand_chacha/Cargo.toml
+++ b/rand/rand_chacha/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "rand_chacha"
-version = "0.1.0"
+version = "0.1.1"
authors = ["The Rand Project Developers", "The Rust Project Developers"]
license = "MIT/Apache-2.0"
readme = "README.md"
@@ -22,4 +22,4 @@ appveyor = { repository = "rust-random/rand" }
rand_core = { path = "../rand_core", version = ">=0.2, <0.4", default-features=false }
[build-dependencies]
-rustc_version = "0.2"
+autocfg = "0.1"
diff --git a/rand/rand_chacha/build.rs b/rand/rand_chacha/build.rs
index cb3ae20..06e12a4 100644
--- a/rand/rand_chacha/build.rs
+++ b/rand/rand_chacha/build.rs
@@ -1,8 +1,7 @@
-extern crate rustc_version;
-use rustc_version::{version, Version};
+extern crate autocfg;
fn main() {
- if version().unwrap() >= Version::parse("1.26.0").unwrap() {
- println!("cargo:rustc-cfg=rust_1_26");
- }
+ println!("cargo:rerun-if-changed=build.rs");
+ let ac = autocfg::new();
+ ac.emit_rustc_version(1, 26);
}
diff --git a/rand/rand_chacha/src/chacha.rs b/rand/rand_chacha/src/chacha.rs
index 3e90409..86f191e 100644
--- a/rand/rand_chacha/src/chacha.rs
+++ b/rand/rand_chacha/src/chacha.rs
@@ -114,7 +114,7 @@ impl ChaChaRng {
/// byte-offset.
///
/// Note: this function is currently only available with Rust 1.26 or later.
- #[cfg(rust_1_26)]
+ #[cfg(all(rustc_1_26, not(target_os = "emscripten")))]
pub fn get_word_pos(&self) -> u128 {
let mut c = (self.0.core.state[13] as u64) << 32
| (self.0.core.state[12] as u64);
@@ -135,7 +135,7 @@ impl ChaChaRng {
/// 60 bits.
///
/// Note: this function is currently only available with Rust 1.26 or later.
- #[cfg(rust_1_26)]
+ #[cfg(all(rustc_1_26, not(target_os = "emscripten")))]
pub fn set_word_pos(&mut self, word_offset: u128) {
let index = (word_offset as usize) & 0xF;
let counter = (word_offset >> 4) as u64;
@@ -330,7 +330,7 @@ mod test {
}
#[test]
- #[cfg(rust_1_26)]
+ #[cfg(all(rustc_1_26, not(target_os = "emscripten")))]
fn test_chacha_true_values_c() {
// Test vector 4 from
// https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
diff --git a/rand/rand_chacha/src/lib.rs b/rand/rand_chacha/src/lib.rs
index 8cff03a..74ad466 100644
--- a/rand/rand_chacha/src/lib.rs
+++ b/rand/rand_chacha/src/lib.rs
@@ -18,7 +18,7 @@
#![no_std]
-extern crate rand_core;
+pub extern crate rand_core;
mod chacha;
diff --git a/rand/rand_hc/src/lib.rs b/rand/rand_hc/src/lib.rs
index f1d772d..10466cf 100644
--- a/rand/rand_hc/src/lib.rs
+++ b/rand/rand_hc/src/lib.rs
@@ -18,7 +18,7 @@
#![no_std]
-extern crate rand_core;
+pub extern crate rand_core;
mod hc128;
diff --git a/rand/rand_isaac/CHANGELOG.md b/rand/rand_isaac/CHANGELOG.md
index d0c4a2f..fb1ab3f 100644
--- a/rand/rand_isaac/CHANGELOG.md
+++ b/rand/rand_isaac/CHANGELOG.md
@@ -4,5 +4,9 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.1.1] - 2018-11-26
+- Fix `rand_core` version requirement
+- Fix doc links
+
## [0.1.0] - 2018-10-17
- Pulled out of the Rand crate
diff --git a/rand/rand_isaac/Cargo.toml b/rand/rand_isaac/Cargo.toml
index 07c4a36..b35d0ab 100644
--- a/rand/rand_isaac/Cargo.toml
+++ b/rand/rand_isaac/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "rand_isaac"
-version = "0.1.0"
+version = "0.1.1"
authors = ["The Rand Project Developers", "The Rust Project Developers"]
license = "MIT/Apache-2.0"
readme = "README.md"
@@ -21,7 +21,7 @@ appveyor = { repository = "rust-random/rand" }
serde1 = ["serde", "serde_derive", "rand_core/serde1"]
[dependencies]
-rand_core = { path = "../rand_core", version = ">=0.2, <0.4", default-features=false }
+rand_core = { path = "../rand_core", version = "0.3", default-features=false }
serde = { version = "1", optional = true }
serde_derive = { version = "^1.0.38", optional = true }
diff --git a/rand/rand_isaac/src/lib.rs b/rand/rand_isaac/src/lib.rs
index ec82d8e..285d631 100644
--- a/rand/rand_isaac/src/lib.rs
+++ b/rand/rand_isaac/src/lib.rs
@@ -18,7 +18,7 @@
#![cfg_attr(not(all(feature="serde1", test)), no_std)]
-extern crate rand_core;
+pub extern crate rand_core;
#[cfg(feature="serde1")] extern crate serde;
#[cfg(feature="serde1")] #[macro_use] extern crate serde_derive;
diff --git a/rand/rand_os/CHANGELOG.md b/rand/rand_os/CHANGELOG.md
new file mode 100644
index 0000000..459f7bd
--- /dev/null
+++ b/rand/rand_os/CHANGELOG.md
@@ -0,0 +1,13 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+
+## [0.1.1] - 2019-01-08
+### Additions
+- Add support for x86_64-fortanix-unknown-sgx target (#670)
+
+## [0.1.0] - 2019-01-04
+Initial release.
diff --git a/rand/rand_os/COPYRIGHT b/rand/rand_os/COPYRIGHT
new file mode 100644
index 0000000..468d907
--- /dev/null
+++ b/rand/rand_os/COPYRIGHT
@@ -0,0 +1,12 @@
+Copyrights in the Rand project are retained by their contributors. No
+copyright assignment is required to contribute to the Rand project.
+
+For full authorship information, see the version control history.
+
+Except as otherwise noted (below and/or in individual files), Rand is
+licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or
+<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option.
+
+The Rand project includes code from the Rust project
+published under these same licenses.
diff --git a/rand/rand_os/Cargo.toml b/rand/rand_os/Cargo.toml
new file mode 100644
index 0000000..2f9224a
--- /dev/null
+++ b/rand/rand_os/Cargo.toml
@@ -0,0 +1,38 @@
+[package]
+name = "rand_os"
+version = "0.1.1"
+authors = ["The Rand Project Developers"]
+license = "MIT/Apache-2.0"
+readme = "README.md"
+repository = "https://github.com/rust-random/rand"
+documentation = "https://docs.rs/rand_os"
+homepage = "https://crates.io/crates/rand_os"
+description = "OS backed Random Number Generator"
+keywords = ["random", "rng", "os"]
+
+[badges]
+travis-ci = { repository = "rust-random/rand" }
+appveyor = { repository = "rust-random/rand" }
+
+[dependencies]
+rand_core = { path = "../rand_core", version = "0.3", default-features = false }
+log = { version = "0.4", optional = true }
+
+[target.'cfg(unix)'.dependencies]
+libc = "0.2"
+
+[target.'cfg(windows)'.dependencies]
+winapi = { version = "0.3", features = ["minwindef", "ntsecapi", "winnt"] }
+
+[target.'cfg(target_os = "cloudabi")'.dependencies]
+cloudabi = "0.0.3"
+
+[target.'cfg(target_os = "fuchsia")'.dependencies]
+fuchsia-zircon = "0.3.2"
+
+[target.wasm32-unknown-unknown.dependencies]
+wasm-bindgen = { version = "0.2.12", optional = true }
+stdweb = { version = "0.4", optional = true }
+
+[target.'cfg(target_env = "sgx")'.dependencies]
+rdrand = "0.4.0"
diff --git a/rand/rand_os/LICENSE-APACHE b/rand/rand_os/LICENSE-APACHE
new file mode 100644
index 0000000..17d7468
--- /dev/null
+++ b/rand/rand_os/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/rand/rand_os/LICENSE-MIT b/rand/rand_os/LICENSE-MIT
new file mode 100644
index 0000000..d93b5ba
--- /dev/null
+++ b/rand/rand_os/LICENSE-MIT
@@ -0,0 +1,26 @@
+Copyright 2018 Developers of the Rand project
+Copyright (c) 2014 The Rust Project Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/rand/rand_os/README.md b/rand/rand_os/README.md
new file mode 100644
index 0000000..4f48b63
--- /dev/null
+++ b/rand/rand_os/README.md
@@ -0,0 +1,33 @@
+# rand_os
+
+[![Build Status](https://travis-ci.org/rust-random/rand.svg?branch=master)](https://travis-ci.org/rust-random/rand)
+[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand)
+[![Latest version](https://img.shields.io/crates/v/rand_os.svg)](https://crates.io/crates/rand_os)
+[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/)
+[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_os)
+[![API](https://docs.rs/rand_os/badge.svg)](https://docs.rs/rand_os)
+[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
+
+A random number generator that retrieves randomness straight from the
+operating system.
+
+This crate depends on [rand_core](https://crates.io/crates/rand_core) and is
+part of the [Rand project](https://github.com/rust-random/rand).
+
+This crate aims to support all of Rust's `std` platforms with a system-provided
+entropy source. Unlike other Rand crates, this crate does not support `no_std`
+(handling this gracefully is a current discussion topic).
+
+Links:
+
+- [API documentation (master)](https://rust-random.github.io/rand/rand_os)
+- [API documentation (docs.rs)](https://docs.rs/rand_os)
+- [Changelog](CHANGELOG.md)
+
+## License
+
+`rand_os` is distributed under the terms of both the MIT license and the
+Apache License (Version 2.0).
+
+See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and
+[COPYRIGHT](COPYRIGHT) for details.
diff --git a/rand/rand_os/src/cloudabi.rs b/rand/rand_os/src/cloudabi.rs
new file mode 100644
index 0000000..8b96a2b
--- /dev/null
+++ b/rand/rand_os/src/cloudabi.rs
@@ -0,0 +1,39 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+//! Implementation for CloudABI
+
+extern crate cloudabi;
+
+use std::io;
+use rand_core::{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" }
+}
diff --git a/rand/rand_os/src/dragonfly_haiku_emscripten.rs b/rand/rand_os/src/dragonfly_haiku_emscripten.rs
new file mode 100644
index 0000000..6132d7a
--- /dev/null
+++ b/rand/rand_os/src/dragonfly_haiku_emscripten.rs
@@ -0,0 +1,39 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+//! Implementation for DragonFly / Haiku / Emscripten
+
+use rand_core::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" }
+}
diff --git a/rand/rand_os/src/dummy_log.rs b/rand/rand_os/src/dummy_log.rs
new file mode 100644
index 0000000..ccfe4ba
--- /dev/null
+++ b/rand/rand_os/src/dummy_log.rs
@@ -0,0 +1,10 @@
+#[allow(unused)]
+macro_rules! trace { ($($x:tt)*) => () }
+#[allow(unused)]
+macro_rules! debug { ($($x:tt)*) => () }
+#[allow(unused)]
+macro_rules! info { ($($x:tt)*) => () }
+#[allow(unused)]
+macro_rules! warn { ($($x:tt)*) => () }
+#[allow(unused)]
+macro_rules! error { ($($x:tt)*) => () }
diff --git a/rand/rand_os/src/freebsd.rs b/rand/rand_os/src/freebsd.rs
new file mode 100644
index 0000000..6b8e672
--- /dev/null
+++ b/rand/rand_os/src/freebsd.rs
@@ -0,0 +1,45 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+//! Implementation for FreeBSD
+
+extern crate libc;
+
+use rand_core::{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" }
+}
diff --git a/rand/rand_os/src/fuchsia.rs b/rand/rand_os/src/fuchsia.rs
new file mode 100644
index 0000000..7063ff6
--- /dev/null
+++ b/rand/rand_os/src/fuchsia.rs
@@ -0,0 +1,43 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+//! Implementation for Fuchsia Zircon
+
+extern crate fuchsia_zircon;
+
+use rand_core::{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" }
+}
diff --git a/rand/rand_os/src/lib.rs b/rand/rand_os/src/lib.rs
new file mode 100644
index 0000000..67b0dfe
--- /dev/null
+++ b/rand/rand_os/src/lib.rs
@@ -0,0 +1,439 @@
+// 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.
+//!
+//! `OsRng` 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.
+//!
+//! # Usage example
+//! ```
+//! use rand_os::OsRng;
+//! use rand_os::rand_core::RngCore;
+//!
+//! let mut os_rng = OsRng::new().unwrap();
+//! let mut key = [0u8; 16];
+//! os_rng.fill_bytes(&mut key);
+//! let random_u64 = os_rng.next_u64();
+//! ```
+//!
+//! # 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` or `wasm-bindgen` depending on what
+//! features are activated for this crate. Note that if both features are
+//! enabled `wasm-bindgen` will be used.
+//!
+//! ## 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 and error handling
+//!
+//! We cannot guarantee that `OsRng` will fail, but if it does, it will likely
+//! be either when `OsRng::new()` is first called or when data is first read.
+//! If you wish to catch errors early, then test reading of at least one byte
+//! from `OsRng` via [`try_fill_bytes`]. If this succeeds, it is extremely
+//! unlikely that any further errors will occur.
+//!
+//! Only [`try_fill_bytes`] is able to report the cause of an error; the other
+//! [`RngCore`] methods may (depending on the error kind) retry several times,
+//! but must eventually panic if the error persists.
+//!
+//! [`EntropyRng`]: ../rand/rngs/struct.EntropyRng.html
+//! [`RngCore`]: ../rand_core/trait.RngCore.html
+//! [`try_fill_bytes`]: ../rand_core/trait.RngCore.html#method.tymethod.try_fill_bytes
+//! [`ErrorKind::NotReady`]: ../rand_core/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&section=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
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
+ html_favicon_url = "https://www.rust-lang.org/favicon.ico",
+ html_root_url = "https://rust-random.github.io/rand/")]
+#![deny(missing_docs)]
+#![deny(missing_debug_implementations)]
+#![doc(test(attr(allow(unused_variables), deny(warnings))))]
+
+#![cfg_attr(feature = "stdweb", recursion_limit="128")]
+
+pub extern crate rand_core;
+#[cfg(feature = "log")]
+#[macro_use] extern crate log;
+
+// We have to do it here because we load macros
+#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten"),
+ feature = "wasm-bindgen"))]
+extern crate wasm_bindgen;
+#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten"),
+ not(feature = "wasm-bindgen"),
+ feature = "stdweb"))]
+#[macro_use] extern crate stdweb;
+
+#[cfg(target_env = "sgx")]
+extern crate rdrand;
+
+#[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<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 { ::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(target_env = "sgx"), sgx);
+
+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
+);
+
+/// Per #678 we use run-time failure where WASM bindings are missing
+#[cfg(all(
+ target_arch = "wasm32",
+ not(target_os = "emscripten"),
+ not(feature = "wasm-bindgen"),
+ not(feature = "stdweb"),
+))]
+mod imp {
+ use rand_core::{Error, ErrorKind};
+ use super::OsRngImpl;
+
+ #[derive(Clone, Debug)]
+ pub struct OsRng;
+
+ impl OsRngImpl for OsRng {
+ fn new() -> Result<OsRng, Error> {
+ Err(Error::new(ErrorKind::Unavailable,
+ "OsRng: support for wasm32 requires emscripten, stdweb or wasm-bindgen"))
+ }
+
+ fn fill_chunk(&mut self, _dest: &mut [u8]) -> Result<(), Error> {
+ unimplemented!()
+ }
+
+ fn method_str(&self) -> &'static str { unimplemented!() }
+ }
+}
+
+#[cfg(not(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,
+ target_arch = "wasm32",
+ target_env = "sgx"
+)))]
+compile_error!("OS RNG support is not available for this platform");
+
+// 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]);
+ }
+ }
+}
diff --git a/rand/rand_os/src/linux_android.rs b/rand/rand_os/src/linux_android.rs
new file mode 100644
index 0000000..9622f93
--- /dev/null
+++ b/rand/rand_os/src/linux_android.rs
@@ -0,0 +1,182 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+//! Implementation for Linux / Android
+
+extern crate libc;
+
+use rand_core::{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)
+}
diff --git a/rand/rand_os/src/macos.rs b/rand/rand_os/src/macos.rs
new file mode 100644
index 0000000..6c67251
--- /dev/null
+++ b/rand/rand_os/src/macos.rs
@@ -0,0 +1,53 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+//! Implementation for MacOS / iOS
+
+extern crate libc;
+
+use rand_core::{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" }
+}
diff --git a/rand/rand_os/src/netbsd.rs b/rand/rand_os/src/netbsd.rs
new file mode 100644
index 0000000..cf4b6c7
--- /dev/null
+++ b/rand/rand_os/src/netbsd.rs
@@ -0,0 +1,54 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+//! Implementation for NetBSD
+
+use rand_core::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" }
+}
diff --git a/rand/rand_os/src/openbsd_bitrig.rs b/rand/rand_os/src/openbsd_bitrig.rs
new file mode 100644
index 0000000..c9b35a6
--- /dev/null
+++ b/rand/rand_os/src/openbsd_bitrig.rs
@@ -0,0 +1,40 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+//! Implementation for OpenBSD / Bitrig
+
+extern crate libc;
+
+use rand_core::{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" }
+}
diff --git a/rand/rand_os/src/random_device.rs b/rand/rand_os/src/random_device.rs
new file mode 100644
index 0000000..5da9194
--- /dev/null
+++ b/rand/rand_os/src/random_device.rs
@@ -0,0 +1,70 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+//! 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.
+use rand_core::{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)
+ }
+}
diff --git a/rand/rand_os/src/redox.rs b/rand/rand_os/src/redox.rs
new file mode 100644
index 0000000..36fae26
--- /dev/null
+++ b/rand/rand_os/src/redox.rs
@@ -0,0 +1,30 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+//! Implementation for Redox
+
+use rand_core::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:'" }
+}
diff --git a/rand/rand_os/src/sgx.rs b/rand/rand_os/src/sgx.rs
new file mode 100644
index 0000000..43ae0ef
--- /dev/null
+++ b/rand/rand_os/src/sgx.rs
@@ -0,0 +1,38 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+use super::OsRngImpl;
+use Error;
+use rdrand::RdRand;
+use rand_core::RngCore;
+use std::fmt::{Debug, Formatter, Result as FmtResult};
+
+#[derive(Clone)]
+pub struct OsRng{
+ gen: RdRand
+}
+
+impl OsRngImpl for OsRng {
+ fn new() -> Result<OsRng, Error> {
+ let rng = RdRand::new()?;
+ Ok(OsRng{ gen: rng })
+ }
+
+ fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.gen.try_fill_bytes(dest)
+ }
+
+ fn method_str(&self) -> &'static str { "RDRAND" }
+}
+
+impl Debug for OsRng {
+ fn fmt(&self, f: &mut Formatter) -> FmtResult {
+ f.debug_struct("OsRng")
+ .finish()
+ }
+}
diff --git a/rand/rand_os/src/solaris.rs b/rand/rand_os/src/solaris.rs
new file mode 100644
index 0000000..e8965fd
--- /dev/null
+++ b/rand/rand_os/src/solaris.rs
@@ -0,0 +1,175 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+//! Implementation for the Solaris family
+//!
+//! 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.
+extern crate libc;
+
+use rand_core::{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::cmp;
+
+#[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 = 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)
+}
diff --git a/rand/rand_os/src/wasm32_bindgen.rs b/rand/rand_os/src/wasm32_bindgen.rs
new file mode 100644
index 0000000..8e7c979
--- /dev/null
+++ b/rand/rand_os/src/wasm32_bindgen.rs
@@ -0,0 +1,125 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+//! Implementation for WASM via wasm-bindgen
+
+use rand_core::{Error, ErrorKind};
+use super::OsRngImpl;
+
+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]);
+}
+
+#[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",
+ }
+ }
+}
diff --git a/rand/rand_os/src/wasm32_stdweb.rs b/rand/rand_os/src/wasm32_stdweb.rs
new file mode 100644
index 0000000..3be0ce6
--- /dev/null
+++ b/rand/rand_os/src/wasm32_stdweb.rs
@@ -0,0 +1,107 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+//! Implementation for WASM via stdweb
+
+use std::mem;
+use stdweb::unstable::TryInto;
+use stdweb::web::error::Error as WebError;
+use rand_core::{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",
+ }
+ }
+}
diff --git a/rand/rand_os/src/windows.rs b/rand/rand_os/src/windows.rs
new file mode 100644
index 0000000..6b06c7a
--- /dev/null
+++ b/rand/rand_os/src/windows.rs
@@ -0,0 +1,44 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+//! Implementation for Windows
+
+extern crate winapi;
+
+use rand_core::{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" }
+}
diff --git a/rand/rand_os/tests/mod.rs b/rand/rand_os/tests/mod.rs
new file mode 100644
index 0000000..2130e16
--- /dev/null
+++ b/rand/rand_os/tests/mod.rs
@@ -0,0 +1,80 @@
+extern crate rand_os;
+
+use rand_os::rand_core::RngCore;
+use rand_os::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/rand_pcg/CHANGELOG.md b/rand/rand_pcg/CHANGELOG.md
index d37408d..6f793cf 100644
--- a/rand/rand_pcg/CHANGELOG.md
+++ b/rand/rand_pcg/CHANGELOG.md
@@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.1.2] - unreleased
+- potential blocker: https://github.com/TyOverby/bincode/issues/250
+- make `bincode` a dev-dependency again
+- clean up tests and Serde support
+
## [0.1.1] - 2018-10-04
- make `bincode` an explicit dependency when using Serde
diff --git a/rand/rand_pcg/Cargo.toml b/rand/rand_pcg/Cargo.toml
index c8a29fc..c2fcb7d 100644
--- a/rand/rand_pcg/Cargo.toml
+++ b/rand/rand_pcg/Cargo.toml
@@ -34,4 +34,4 @@ serde_derive = { version = "^1.0.38", optional = true }
bincode = { version = "1", features = ["i128"] }
[build-dependencies]
-rustc_version = "0.2"
+autocfg = "0.1"
diff --git a/rand/rand_pcg/build.rs b/rand/rand_pcg/build.rs
index cb3ae20..06e12a4 100644
--- a/rand/rand_pcg/build.rs
+++ b/rand/rand_pcg/build.rs
@@ -1,8 +1,7 @@
-extern crate rustc_version;
-use rustc_version::{version, Version};
+extern crate autocfg;
fn main() {
- if version().unwrap() >= Version::parse("1.26.0").unwrap() {
- println!("cargo:rustc-cfg=rust_1_26");
- }
+ println!("cargo:rerun-if-changed=build.rs");
+ let ac = autocfg::new();
+ ac.emit_rustc_version(1, 26);
}
diff --git a/rand/rand_pcg/src/lib.rs b/rand/rand_pcg/src/lib.rs
index 5160e87..9648e85 100644
--- a/rand/rand_pcg/src/lib.rs
+++ b/rand/rand_pcg/src/lib.rs
@@ -36,13 +36,13 @@
#![no_std]
-extern crate rand_core;
+pub extern crate rand_core;
#[cfg(feature="serde1")] extern crate serde;
#[cfg(feature="serde1")] #[macro_use] extern crate serde_derive;
mod pcg64;
-#[cfg(rust_1_26)] mod pcg128;
+#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] mod pcg128;
pub use self::pcg64::{Pcg32, Lcg64Xsh32};
-#[cfg(rust_1_26)] pub use self::pcg128::{Pcg64Mcg, Mcg128Xsl64};
+#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] pub use self::pcg128::{Pcg64Mcg, Mcg128Xsl64};
diff --git a/rand/rand_pcg/tests/mcg128xsl64.rs b/rand/rand_pcg/tests/mcg128xsl64.rs
index 2508917..3279536 100644
--- a/rand/rand_pcg/tests/mcg128xsl64.rs
+++ b/rand/rand_pcg/tests/mcg128xsl64.rs
@@ -1,4 +1,4 @@
-#![cfg(rust_1_26)]
+#![cfg(rustc_1_26)]
extern crate rand_pcg;
extern crate rand_core;
#[cfg(all(feature="serde1", test))] extern crate bincode;
diff --git a/rand/rand_xorshift/CHANGELOG.md b/rand/rand_xorshift/CHANGELOG.md
index 9a896a5..539af41 100644
--- a/rand/rand_xorshift/CHANGELOG.md
+++ b/rand/rand_xorshift/CHANGELOG.md
@@ -4,5 +4,8 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.1.1] - 2019-01-04
+- Reorganise code and tests; tweak doc
+
## [0.1.0] - 2018-07-16
- Pulled out of the Rand crate
diff --git a/rand/rand_xorshift/Cargo.toml b/rand/rand_xorshift/Cargo.toml
index b763bfc..114fee9 100644
--- a/rand/rand_xorshift/Cargo.toml
+++ b/rand/rand_xorshift/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "rand_xorshift"
-version = "0.1.0"
+version = "0.1.1"
authors = ["The Rand Project Developers", "The Rust Project Developers"]
license = "MIT/Apache-2.0"
readme = "README.md"
diff --git a/rand/rand_xorshift/src/lib.rs b/rand/rand_xorshift/src/lib.rs
index aad74e4..db42ba2 100644
--- a/rand/rand_xorshift/src/lib.rs
+++ b/rand/rand_xorshift/src/lib.rs
@@ -17,7 +17,7 @@
#![no_std]
-extern crate rand_core;
+pub extern crate rand_core;
#[cfg(feature="serde1")] extern crate serde;
#[cfg(feature="serde1")] #[macro_use] extern crate serde_derive;
diff --git a/rand/rand_xoshiro/CHANGELOG.md b/rand/rand_xoshiro/CHANGELOG.md
new file mode 100644
index 0000000..b23c990
--- /dev/null
+++ b/rand/rand_xoshiro/CHANGELOG.md
@@ -0,0 +1,8 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [0.1.0] - 2019-01-04
+Initial release.
diff --git a/rand/rand_xoshiro/COPYRIGHT b/rand/rand_xoshiro/COPYRIGHT
new file mode 100644
index 0000000..468d907
--- /dev/null
+++ b/rand/rand_xoshiro/COPYRIGHT
@@ -0,0 +1,12 @@
+Copyrights in the Rand project are retained by their contributors. No
+copyright assignment is required to contribute to the Rand project.
+
+For full authorship information, see the version control history.
+
+Except as otherwise noted (below and/or in individual files), Rand is
+licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or
+<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option.
+
+The Rand project includes code from the Rust project
+published under these same licenses.
diff --git a/rand/rand_xoshiro/Cargo.toml b/rand/rand_xoshiro/Cargo.toml
new file mode 100644
index 0000000..8d174c7
--- /dev/null
+++ b/rand/rand_xoshiro/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "rand_xoshiro"
+version = "0.1.0" # NB: When modifying, also modify html_root_url in lib.rs
+authors = ["The Rand Project Developers"]
+license = "MIT/Apache-2.0"
+readme = "README.md"
+repository = "https://github.com/rust-random/rand"
+documentation = "https://docs.rs/rand_xoshiro"
+homepage = "https://crates.io/crates/rand_xoshiro"
+description = "Xoshiro, xoroshiro and splitmix64 random number generators"
+keywords = ["random", "rng"]
+categories = ["algorithms"]
+
+[dependencies]
+byteorder = { version = "1", default-features=false }
+rand_core = { path = "../rand_core", version = "0.3", default-features=false }
+
+[dev-dependencies]
+rand = { path = "..", version = "0.6", default-features=false } # needed for doctests
diff --git a/rand/rand_xoshiro/LICENSE-APACHE b/rand/rand_xoshiro/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/rand/rand_xoshiro/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/rand/rand_xoshiro/LICENSE-MIT b/rand/rand_xoshiro/LICENSE-MIT
new file mode 100644
index 0000000..a5e040c
--- /dev/null
+++ b/rand/rand_xoshiro/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2018 Developers of the Rand project
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/rand/rand_xoshiro/README.md b/rand/rand_xoshiro/README.md
new file mode 100644
index 0000000..014477e
--- /dev/null
+++ b/rand/rand_xoshiro/README.md
@@ -0,0 +1,28 @@
+# rand_xoshiro
+
+[![Build Status](https://travis-ci.org/rust-random/rand.svg?branch=master)](https://travis-ci.org/rust-random/rand)
+[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand)
+[![Latest version](https://img.shields.io/crates/v/rand_xoshiro.svg)](https://crates.io/crates/rand_xoshiro)
+[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/)
+[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_xoshiro)
+[![API](https://docs.rs/rand_xoshiro/badge.svg)](https://docs.rs/rand_xoshiro)
+[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
+
+Rust implementation of the [xoshiro, xoroshiro and splitmix64](http://xoshiro.di.unimi.it) random number generators.
+
+This crate depends on [rand_core](https://crates.io/crates/rand_core) and is
+part of the [Rand project](https://github.com/rust-random/rand).
+
+Links:
+
+- [API documentation (master)](https://rust-random.github.io/rand/rand_xoshiro)
+- [API documentation (docs.rs)](https://docs.rs/rand_xoshiro)
+- [Changelog](CHANGELOG.md)
+
+## License
+
+`rand_xoshiro` is distributed under the terms of both the MIT license and the
+Apache License (Version 2.0).
+
+See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and
+[COPYRIGHT](COPYRIGHT) for details.
diff --git a/rand/rand_xoshiro/src/common.rs b/rand/rand_xoshiro/src/common.rs
new file mode 100644
index 0000000..9ee09e2
--- /dev/null
+++ b/rand/rand_xoshiro/src/common.rs
@@ -0,0 +1,243 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+/// Initialize a RNG from a `u64` seed using `SplitMix64`.
+macro_rules! from_splitmix {
+ ($seed:expr) => { {
+ let mut rng = ::SplitMix64::seed_from_u64($seed);
+ Self::from_rng(&mut rng).unwrap()
+ } }
+}
+
+/// Apply the ** scrambler used by some RNGs from the xoshiro family.
+macro_rules! starstar_u64 {
+ ($x:expr) => {
+ $x.wrapping_mul(5).rotate_left(7).wrapping_mul(9)
+ }
+}
+
+/// Apply the ** scrambler used by some RNGs from the xoshiro family.
+macro_rules! starstar_u32 {
+ ($x:expr) => {
+ $x.wrapping_mul(0x9E3779BB).rotate_left(5).wrapping_mul(5)
+ }
+}
+
+/// Implement a jump function for an RNG from the xoshiro family.
+macro_rules! impl_jump {
+ (u32, $self:expr, [$j0:expr, $j1:expr]) => {
+ const JUMP: [u32; 2] = [$j0, $j1];
+ let mut s0 = 0;
+ let mut s1 = 0;
+ for j in &JUMP {
+ for b in 0..32 {
+ if (j & 1 << b) != 0 {
+ s0 ^= $self.s0;
+ s1 ^= $self.s1;
+ }
+ $self.next_u32();
+ }
+ }
+ $self.s0 = s0;
+ $self.s1 = s1;
+ };
+ (u64, $self:expr, [$j0:expr, $j1:expr]) => {
+ const JUMP: [u64; 2] = [$j0, $j1];
+ let mut s0 = 0;
+ let mut s1 = 0;
+ for j in &JUMP {
+ for b in 0..64 {
+ if (j & 1 << b) != 0 {
+ s0 ^= $self.s0;
+ s1 ^= $self.s1;
+ }
+ $self.next_u64();
+ }
+ }
+ $self.s0 = s0;
+ $self.s1 = s1;
+ };
+ (u32, $self:expr, [$j0:expr, $j1:expr, $j2:expr, $j3:expr]) => {
+ const JUMP: [u32; 4] = [$j0, $j1, $j2, $j3];
+ let mut s0 = 0;
+ let mut s1 = 0;
+ let mut s2 = 0;
+ let mut s3 = 0;
+ for j in &JUMP {
+ for b in 0..32 {
+ if (j & 1 << b) != 0 {
+ s0 ^= $self.s[0];
+ s1 ^= $self.s[1];
+ s2 ^= $self.s[2];
+ s3 ^= $self.s[3];
+ }
+ $self.next_u32();
+ }
+ }
+ $self.s[0] = s0;
+ $self.s[1] = s1;
+ $self.s[2] = s2;
+ $self.s[3] = s3;
+ };
+ (u64, $self:expr, [$j0:expr, $j1:expr, $j2:expr, $j3:expr]) => {
+ const JUMP: [u64; 4] = [$j0, $j1, $j2, $j3];
+ let mut s0 = 0;
+ let mut s1 = 0;
+ let mut s2 = 0;
+ let mut s3 = 0;
+ for j in &JUMP {
+ for b in 0..64 {
+ if (j & 1 << b) != 0 {
+ s0 ^= $self.s[0];
+ s1 ^= $self.s[1];
+ s2 ^= $self.s[2];
+ s3 ^= $self.s[3];
+ }
+ $self.next_u64();
+ }
+ }
+ $self.s[0] = s0;
+ $self.s[1] = s1;
+ $self.s[2] = s2;
+ $self.s[3] = s3;
+ };
+ (u64, $self:expr, [$j0:expr, $j1:expr, $j2:expr, $j3:expr,
+ $j4:expr, $j5:expr, $j6:expr, $j7:expr]) => {
+ const JUMP: [u64; 8] = [$j0, $j1, $j2, $j3, $j4, $j5, $j6, $j7];
+ let mut s = [0; 8];
+ for j in &JUMP {
+ for b in 0..64 {
+ if (j & 1 << b) != 0 {
+ s[0] ^= $self.s[0];
+ s[1] ^= $self.s[1];
+ s[2] ^= $self.s[2];
+ s[3] ^= $self.s[3];
+ s[4] ^= $self.s[4];
+ s[5] ^= $self.s[5];
+ s[6] ^= $self.s[6];
+ s[7] ^= $self.s[7];
+ }
+ $self.next_u64();
+ }
+ }
+ $self.s = s;
+ };
+}
+
+/// Implement the xoroshiro iteration.
+macro_rules! impl_xoroshiro_u32 {
+ ($self:expr) => {
+ $self.s1 ^= $self.s0;
+ $self.s0 = $self.s0.rotate_left(26) ^ $self.s1 ^ ($self.s1 << 9);
+ $self.s1 = $self.s1.rotate_left(13);
+ }
+}
+
+/// Implement the xoroshiro iteration.
+macro_rules! impl_xoroshiro_u64 {
+ ($self:expr) => {
+ $self.s1 ^= $self.s0;
+ $self.s0 = $self.s0.rotate_left(24) ^ $self.s1 ^ ($self.s1 << 16);
+ $self.s1 = $self.s1.rotate_left(37);
+ }
+}
+
+/// Implement the xoshiro iteration for `u32` output.
+macro_rules! impl_xoshiro_u32 {
+ ($self:expr) => {
+ let t = $self.s[1] << 9;
+
+ $self.s[2] ^= $self.s[0];
+ $self.s[3] ^= $self.s[1];
+ $self.s[1] ^= $self.s[2];
+ $self.s[0] ^= $self.s[3];
+
+ $self.s[2] ^= t;
+
+ $self.s[3] = $self.s[3].rotate_left(11);
+ }
+}
+
+/// Implement the xoshiro iteration for `u64` output.
+macro_rules! impl_xoshiro_u64 {
+ ($self:expr) => {
+ let t = $self.s[1] << 17;
+
+ $self.s[2] ^= $self.s[0];
+ $self.s[3] ^= $self.s[1];
+ $self.s[1] ^= $self.s[2];
+ $self.s[0] ^= $self.s[3];
+
+ $self.s[2] ^= t;
+
+ $self.s[3] = $self.s[3].rotate_left(45);
+ }
+}
+
+/// Implement the large-state xoshiro iteration.
+macro_rules! impl_xoshiro_large {
+ ($self:expr) => {
+ let t = $self.s[1] << 11;
+
+ $self.s[2] ^= $self.s[0];
+ $self.s[5] ^= $self.s[1];
+ $self.s[1] ^= $self.s[2];
+ $self.s[7] ^= $self.s[3];
+ $self.s[3] ^= $self.s[4];
+ $self.s[4] ^= $self.s[5];
+ $self.s[0] ^= $self.s[6];
+ $self.s[6] ^= $self.s[7];
+
+ $self.s[6] ^= t;
+
+ $self.s[7] = $self.s[7].rotate_left(21);
+ }
+}
+
+/// Map an all-zero seed to a different one.
+macro_rules! deal_with_zero_seed {
+ ($seed:expr, $Self:ident) => {
+ if $seed.iter().all(|&x| x == 0) {
+ return $Self::seed_from_u64(0);
+ }
+ }
+}
+
+/// 512-bit seed for a generator.
+///
+/// This wrapper is necessary, because some traits required for a seed are not
+/// implemented on large arrays.
+#[derive(Clone)]
+pub struct Seed512(pub [u8; 64]);
+
+use core;
+impl Seed512 {
+ /// Return an iterator over the seed.
+ pub fn iter(&self) -> core::slice::Iter<u8> {
+ self.0.iter()
+ }
+}
+
+impl core::fmt::Debug for Seed512 {
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+ self.0[..].fmt(f)
+ }
+}
+
+impl Default for Seed512 {
+ fn default() -> Seed512 {
+ Seed512([0; 64])
+ }
+}
+
+impl AsMut<[u8]> for Seed512 {
+ fn as_mut(&mut self) -> &mut [u8] {
+ &mut self.0
+ }
+}
+
diff --git a/rand/rand_xoshiro/src/lib.rs b/rand/rand_xoshiro/src/lib.rs
new file mode 100644
index 0000000..634db31
--- /dev/null
+++ b/rand/rand_xoshiro/src/lib.rs
@@ -0,0 +1,106 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+//! This crate implements the [xoshiro] family of pseudorandom number generators
+//! designed by David Blackman and Sebastiano Vigna. They feature high
+//! perfomance and a small state and superseed the previous xorshift-based
+//! generators. However, they are no cryptographically secure and their output
+//! can be predicted by observing a few samples.
+//!
+//! The following generators are implemented:
+//!
+//! # 64-bit generators
+//! - [`Xoshiro256StarStar`]: Recommended for all purposes. Excellent speed and
+//! a state space (256 bits) large enough for any parallel application.
+//! - [`Xoshiro256Plus`]: Recommended for generating 64-bit floating-point
+//! numbers. About 15% faster than `Xoshiro256StarStar`, but has a [low linear
+//! complexity] in the lowest bits (which are discarded when generating
+//! floats), making it fail linearity tests. This is unlikely to have any
+//! impact in practise.
+//! - [`Xoroshiro128StarStar`]: An alternative to `Xoshiro256StarStar`, having
+//! the same speed but using half the state. Only suited for low-scale parallel
+//! applications.
+//! - [`Xoroshiro128Plus`]: An alternative to `Xoshiro256Plus`, having the same
+//! speed but using half the state. Only suited for low-scale parallel
+//! applications. Has a [low linear complexity] in the lowest bits (which are
+//! discarded when generating floats), making it fail linearity tests. This is
+//! unlikely to have any impact in practise.
+//! - [`Xoshiro512StarStar`]: An alternative to `Xoshiro256StarStar` with more
+//! state and the same speed.
+//! - [`Xoshiro512Plus`]: An alternative to `Xoshiro512Plus` with more
+//! state and the same speed. Has a [low linear complexity] in the lowest bits
+//! (which are discarded when generating floats), making it fail linearity
+//! tests. This is unlikely to have any impact in practise.
+//! - [`SplitMix64`]: Recommended for initializing generators of the xoshiro
+//! familiy from a 64-bit seed. Used for implementing `seed_from_u64`.
+//!
+//! # 32-bit generators
+//! - [`Xoshiro128StarStar`]: Recommended for all purposes. Excellent speed.
+//! - [`Xoshiro128Plus`]: Recommended for generating 32-bit floating-point
+//! numbers. Faster than `Xoshiro128StarStar`, but has a [low linear
+//! complexity] in the lowest bits (which are discarded when generating
+//! floats), making it fail linearity tests. This is unlikely to have any
+//! impact in practise.
+//! - [`Xoroshiro64StarStar`]: An alternative to `Xoshiro128StarStar`, having
+//! the same speed but using half the state.
+//! - [`Xoroshiro64Star`]: An alternative to `Xoshiro128Plus`, having the
+//! same speed but using half the state. Has a [low linear complexity] in the
+//! lowest bits (which are discarded when generating floats), making it fail
+//! linearity tests. This is unlikely to have any impact in practise.
+//!
+//! [xoshiro]: http://xoshiro.di.unimi.it/
+//! [low linear complexity]: http://xoshiro.di.unimi.it/lowcomp.php
+//! [`Xoshiro256StarStar`]: ./struct.Xoshiro256StarStar.html
+//! [`Xoshiro256Plus`]: ./struct.Xoshiro256Plus.html
+//! [`Xoroshiro128StarStar`]: ./struct.Xoroshiro128StarStar.html
+//! [`Xoroshiro128Plus`]: ./struct.Xoroshiro128Plus.html
+//! [`Xoshiro512StarStar`]: ./struct.Xoshiro512StarStar.html
+//! [`Xoshiro512Plus`]: ./struct.Xoshiro512Plus.html
+//! [`SplitMix64`]: ./struct.SplitMix64.html
+//! [`Xoshiro128StarStar`]: ./struct.Xoshiro128StarStar.html
+//! [`Xoshiro128Plus`]: ./struct.Xoshiro128Plus.html
+//! [`Xoroshiro64StarStar`]: ./struct.Xoroshiro64StarStar.html
+//! [`Xoroshiro64Star`]: ./struct.Xoroshiro64Star.html
+
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
+ html_favicon_url = "https://www.rust-lang.org/favicon.ico",
+ html_root_url = "https://docs.rs/rand_xoshiro/0.1.0")]
+
+#![deny(missing_docs)]
+#![deny(missing_debug_implementations)]
+#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]
+#![no_std]
+extern crate byteorder;
+pub extern crate rand_core;
+
+#[macro_use]
+mod common;
+mod splitmix64;
+mod xoshiro128starstar;
+mod xoshiro128plus;
+mod xoshiro256starstar;
+mod xoshiro256plus;
+mod xoshiro512starstar;
+mod xoshiro512plus;
+mod xoroshiro128plus;
+mod xoroshiro128starstar;
+mod xoroshiro64starstar;
+mod xoroshiro64star;
+
+pub use splitmix64::SplitMix64;
+pub use xoshiro128starstar::Xoshiro128StarStar;
+pub use xoshiro128plus::Xoshiro128Plus;
+pub use xoshiro256starstar::Xoshiro256StarStar;
+pub use xoshiro256plus::Xoshiro256Plus;
+pub use common::Seed512;
+pub use xoshiro512starstar::Xoshiro512StarStar;
+pub use xoshiro512plus::Xoshiro512Plus;
+pub use xoroshiro128plus::Xoroshiro128Plus;
+pub use xoroshiro128starstar::Xoroshiro128StarStar;
+pub use xoroshiro64starstar::Xoroshiro64StarStar;
+pub use xoroshiro64star::Xoroshiro64Star;
diff --git a/rand/rand_xoshiro/src/splitmix64.rs b/rand/rand_xoshiro/src/splitmix64.rs
new file mode 100644
index 0000000..a7cac9f
--- /dev/null
+++ b/rand/rand_xoshiro/src/splitmix64.rs
@@ -0,0 +1,150 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+use byteorder::{ByteOrder, LittleEndian};
+use rand_core::le::read_u64_into;
+use rand_core::impls::fill_bytes_via_next;
+use rand_core::{RngCore, SeedableRng, Error};
+
+/// A splitmix64 random number generator.
+///
+/// The splitmix algorithm is not suitable for cryptographic purposes, but is
+/// very fast and has a 64 bit state.
+///
+/// The algorithm used here is translated from [the `splitmix64.c`
+/// reference source code](http://xoshiro.di.unimi.it/splitmix64.c) by
+/// Sebastiano Vigna. For `next_u32`, a more efficient mixing function taken
+/// from [`dsiutils`](http://dsiutils.di.unimi.it/) is used.
+#[allow(missing_copy_implementations)]
+#[derive(Debug, Clone)]
+pub struct SplitMix64 {
+ x: u64,
+}
+
+const PHI: u64 = 0x9e3779b97f4a7c15;
+
+impl RngCore for SplitMix64 {
+ #[inline]
+ fn next_u32(&mut self) -> u32 {
+ self.x = self.x.wrapping_add(PHI);
+ let mut z = self.x;
+ // David Stafford's
+ // (http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html)
+ // "Mix4" variant of the 64-bit finalizer in Austin Appleby's
+ // MurmurHash3 algorithm.
+ z = (z ^ (z >> 33)).wrapping_mul(0x62A9D9ED799705F5);
+ z = (z ^ (z >> 28)).wrapping_mul(0xCB24D0A5C88C35B3);
+ (z >> 32) as u32
+ }
+
+ #[inline]
+ fn next_u64(&mut self) -> u64 {
+ self.x = self.x.wrapping_add(PHI);
+ let mut z = self.x;
+ z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
+ z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
+ z ^ (z >> 31)
+ }
+
+ #[inline]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ fill_bytes_via_next(self, dest);
+ }
+
+ #[inline]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.fill_bytes(dest);
+ Ok(())
+ }
+}
+
+impl SeedableRng for SplitMix64 {
+ type Seed = [u8; 8];
+
+ /// Create a new `SplitMix64`.
+ fn from_seed(seed: [u8; 8]) -> SplitMix64 {
+ let mut state = [0; 1];
+ read_u64_into(&seed, &mut state);
+ SplitMix64 {
+ x: state[0],
+ }
+ }
+
+ /// Seed a `SplitMix64` from a `u64`.
+ fn seed_from_u64(seed: u64) -> SplitMix64 {
+ let mut x = [0; 8];
+ LittleEndian::write_u64(&mut x, seed);
+ SplitMix64::from_seed(x)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn reference() {
+ let mut rng = SplitMix64::seed_from_u64(1477776061723855037);
+ // These values were produced with the reference implementation:
+ // http://xoshiro.di.unimi.it/splitmix64.c
+ let expected : [u64 ; 50]= [
+ 1985237415132408290, 2979275885539914483, 13511426838097143398,
+ 8488337342461049707, 15141737807933549159, 17093170987380407015,
+ 16389528042912955399, 13177319091862933652, 10841969400225389492,
+ 17094824097954834098, 3336622647361835228, 9678412372263018368,
+ 11111587619974030187, 7882215801036322410, 5709234165213761869,
+ 7799681907651786826, 4616320717312661886, 4251077652075509767,
+ 7836757050122171900, 5054003328188417616, 12919285918354108358,
+ 16477564761813870717, 5124667218451240549, 18099554314556827626,
+ 7603784838804469118, 6358551455431362471, 3037176434532249502,
+ 3217550417701719149, 9958699920490216947, 5965803675992506258,
+ 12000828378049868312, 12720568162811471118, 245696019213873792,
+ 8351371993958923852, 14378754021282935786, 5655432093647472106,
+ 5508031680350692005, 8515198786865082103, 6287793597487164412,
+ 14963046237722101617, 3630795823534910476, 8422285279403485710,
+ 10554287778700714153, 10871906555720704584, 8659066966120258468,
+ 9420238805069527062, 10338115333623340156, 13514802760105037173,
+ 14635952304031724449, 15419692541594102413,
+ ];
+ for &e in expected.iter() {
+ assert_eq!(rng.next_u64(), e);
+ }
+ }
+
+ #[test]
+ fn next_u32() {
+ let mut rng = SplitMix64::seed_from_u64(10);
+ // These values were produced with the reference implementation:
+ // http://dsiutils.di.unimi.it/dsiutils-2.5.1-src.tar.gz
+ let expected : [u32 ; 100]= [
+ 3930361779, 4016923089, 4113052479, 925926767, 1755287528,
+ 802865554, 954171070, 3724185978, 173676273, 1414488795, 12664133,
+ 1784889697, 1303817078, 261610523, 941280008, 2571813643,
+ 2954453492, 378291111, 2546873158, 3923319175, 645257028,
+ 3881821278, 2681538690, 3037029984, 1999958137, 1853970361,
+ 2989951788, 2126166628, 839962987, 3989679659, 3656977858,
+ 684284364, 1673258011, 170979192, 3037622326, 1600748179,
+ 1780764218, 1141430714, 4139736875, 3336905707, 2262051600,
+ 3830850262, 2430765325, 1073032139, 1668888979, 2716938970,
+ 4102420032, 40305196, 386350562, 2754480591, 622869439, 2129598760,
+ 2306038241, 4218338739, 412298926, 3453855056, 3061469690,
+ 4284292697, 994843708, 1591016681, 414726151, 1238182607, 18073498,
+ 1237631493, 351884714, 2347486264, 2488990876, 802846256, 645670443,
+ 957607012, 3126589776, 1966356370, 3036485766, 868696717,
+ 2808613630, 2070968151, 1025536863, 1743949425, 466212687,
+ 2994327271, 209776458, 1246125124, 3344380309, 2203947859,
+ 968313105, 2805485302, 197484837, 3472483632, 3931823935,
+ 3288490351, 4165666529, 3671080416, 689542830, 1272555356,
+ 1039141475, 3984640460, 4142959054, 2252788890, 2459379590,
+ 991872507,
+ ];
+ for &e in expected.iter() {
+ assert_eq!(rng.next_u32(), e);
+ }
+ }
+}
diff --git a/rand/rand_xoshiro/src/xoroshiro128plus.rs b/rand/rand_xoshiro/src/xoroshiro128plus.rs
new file mode 100644
index 0000000..df032c8
--- /dev/null
+++ b/rand/rand_xoshiro/src/xoroshiro128plus.rs
@@ -0,0 +1,132 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+use rand_core;
+use rand_core::le::read_u64_into;
+use rand_core::impls::fill_bytes_via_next;
+use rand_core::{RngCore, SeedableRng};
+
+/// A xoroshiro128+ random number generator.
+///
+/// The xoroshiro128+ algorithm is not suitable for cryptographic purposes, but
+/// is very fast and has good statistical properties, besides a low linear
+/// complexity in the lowest bits.
+///
+/// The algorithm used here is translated from [the `xoroshiro128plus.c`
+/// reference source code](http://xoshiro.di.unimi.it/xoroshiro128plus.c) by
+/// David Blackman and Sebastiano Vigna.
+#[allow(missing_copy_implementations)]
+#[derive(Debug, Clone)]
+pub struct Xoroshiro128Plus {
+ s0: u64,
+ s1: u64,
+}
+
+impl Xoroshiro128Plus {
+ /// Jump forward, equivalently to 2^64 calls to `next_u64()`.
+ ///
+ /// This can be used to generate 2^64 non-overlapping subsequences for
+ /// parallel computations.
+ ///
+ /// ```
+ /// # extern crate rand;
+ /// # extern crate rand_xoshiro;
+ /// # fn main() {
+ /// use rand::SeedableRng;
+ /// use rand_xoshiro::Xoroshiro128Plus;
+ ///
+ /// let rng1 = Xoroshiro128Plus::seed_from_u64(0);
+ /// let mut rng2 = rng1.clone();
+ /// rng2.jump();
+ /// let mut rng3 = rng2.clone();
+ /// rng3.jump();
+ /// # }
+ /// ```
+ pub fn jump(&mut self) {
+ impl_jump!(u64, self, [0xdf900294d8f554a5, 0x170865df4b3201fc]);
+ }
+
+ /// Jump forward, equivalently to 2^96 calls to `next_u64()`.
+ ///
+ /// This can be used to generate 2^32 starting points, from each of which
+ /// `jump()` will generate 2^32 non-overlapping subsequences for parallel
+ /// distributed computations.
+ pub fn long_jump(&mut self) {
+ impl_jump!(u64, self, [0xd2a98b26625eee7b, 0xdddf9b1090aa7ac1]);
+ }
+}
+
+impl RngCore for Xoroshiro128Plus {
+ #[inline]
+ fn next_u32(&mut self) -> u32 {
+ // The two lowest bits have some linear dependencies, so we use the
+ // upper bits instead.
+ (self.next_u64() >> 32) as u32
+ }
+
+ #[inline]
+ fn next_u64(&mut self) -> u64 {
+ let r = self.s0.wrapping_add(self.s1);
+ impl_xoroshiro_u64!(self);
+ r
+ }
+
+ #[inline]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ fill_bytes_via_next(self, dest);
+ }
+
+ #[inline]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
+ self.fill_bytes(dest);
+ Ok(())
+ }
+}
+
+impl SeedableRng for Xoroshiro128Plus {
+ type Seed = [u8; 16];
+
+ /// Create a new `Xoroshiro128Plus`. If `seed` is entirely 0, it will be
+ /// mapped to a different seed.
+ fn from_seed(seed: [u8; 16]) -> Xoroshiro128Plus {
+ deal_with_zero_seed!(seed, Self);
+ let mut s = [0; 2];
+ read_u64_into(&seed, &mut s);
+
+ Xoroshiro128Plus {
+ s0: s[0],
+ s1: s[1],
+ }
+ }
+
+ /// Seed a `Xoroshiro128Plus` from a `u64` using `SplitMix64`.
+ fn seed_from_u64(seed: u64) -> Xoroshiro128Plus {
+ from_splitmix!(seed)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn reference() {
+ let mut rng = Xoroshiro128Plus::from_seed(
+ [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0]);
+ // These values were produced with the reference implementation:
+ // http://xoshiro.di.unimi.it/xoshiro128starstar.c
+ let expected = [
+ 3, 412333834243, 2360170716294286339, 9295852285959843169,
+ 2797080929874688578, 6019711933173041966, 3076529664176959358,
+ 3521761819100106140, 7493067640054542992, 920801338098114767,
+ ];
+ for &e in &expected {
+ assert_eq!(rng.next_u64(), e);
+ }
+ }
+}
diff --git a/rand/rand_xoshiro/src/xoroshiro128starstar.rs b/rand/rand_xoshiro/src/xoroshiro128starstar.rs
new file mode 100644
index 0000000..2d27850
--- /dev/null
+++ b/rand/rand_xoshiro/src/xoroshiro128starstar.rs
@@ -0,0 +1,129 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+use rand_core;
+use rand_core::le::read_u64_into;
+use rand_core::impls::fill_bytes_via_next;
+use rand_core::{RngCore, SeedableRng};
+
+/// A xoroshiro128** random number generator.
+///
+/// The xoroshiro128** algorithm is not suitable for cryptographic purposes, but
+/// is very fast and has excellent statistical properties.
+///
+/// The algorithm used here is translated from [the `xoroshiro128starstar.c`
+/// reference source code](http://xoshiro.di.unimi.it/xoroshiro128starstar.c) by
+/// David Blackman and Sebastiano Vigna.
+#[allow(missing_copy_implementations)]
+#[derive(Debug, Clone)]
+pub struct Xoroshiro128StarStar {
+ s0: u64,
+ s1: u64,
+}
+
+impl Xoroshiro128StarStar {
+ /// Jump forward, equivalently to 2^64 calls to `next_u64()`.
+ ///
+ /// This can be used to generate 2^64 non-overlapping subsequences for
+ /// parallel computations.
+ ///
+ /// ```
+ /// # extern crate rand;
+ /// # extern crate rand_xoshiro;
+ /// # fn main() {
+ /// use rand::SeedableRng;
+ /// use rand_xoshiro::Xoroshiro128StarStar;
+ ///
+ /// let rng1 = Xoroshiro128StarStar::seed_from_u64(0);
+ /// let mut rng2 = rng1.clone();
+ /// rng2.jump();
+ /// let mut rng3 = rng2.clone();
+ /// rng3.jump();
+ /// # }
+ /// ```
+ pub fn jump(&mut self) {
+ impl_jump!(u64, self, [0xdf900294d8f554a5, 0x170865df4b3201fc]);
+ }
+
+ /// Jump forward, equivalently to 2^96 calls to `next_u64()`.
+ ///
+ /// This can be used to generate 2^32 starting points, from each of which
+ /// `jump()` will generate 2^32 non-overlapping subsequences for parallel
+ /// distributed computations.
+ pub fn long_jump(&mut self) {
+ impl_jump!(u64, self, [0xd2a98b26625eee7b, 0xdddf9b1090aa7ac1]);
+ }
+}
+
+impl RngCore for Xoroshiro128StarStar {
+ #[inline]
+ fn next_u32(&mut self) -> u32 {
+ self.next_u64() as u32
+ }
+
+ #[inline]
+ fn next_u64(&mut self) -> u64 {
+ let r = starstar_u64!(self.s0);
+ impl_xoroshiro_u64!(self);
+ r
+ }
+
+ #[inline]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ fill_bytes_via_next(self, dest);
+ }
+
+ #[inline]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
+ self.fill_bytes(dest);
+ Ok(())
+ }
+}
+
+impl SeedableRng for Xoroshiro128StarStar {
+ type Seed = [u8; 16];
+
+ /// Create a new `Xoroshiro128StarStar`. If `seed` is entirely 0, it will be
+ /// mapped to a different seed.
+ fn from_seed(seed: [u8; 16]) -> Xoroshiro128StarStar {
+ deal_with_zero_seed!(seed, Self);
+ let mut s = [0; 2];
+ read_u64_into(&seed, &mut s);
+
+ Xoroshiro128StarStar {
+ s0: s[0],
+ s1: s[1],
+ }
+ }
+
+ /// Seed a `Xoroshiro128StarStar` from a `u64` using `SplitMix64`.
+ fn seed_from_u64(seed: u64) -> Xoroshiro128StarStar {
+ from_splitmix!(seed)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn reference() {
+ let mut rng = Xoroshiro128StarStar::from_seed(
+ [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0]);
+ // These values were produced with the reference implementation:
+ // http://xoshiro.di.unimi.it/xoshiro128starstar.c
+ let expected = [
+ 5760, 97769243520, 9706862127477703552, 9223447511460779954,
+ 8358291023205304566, 15695619998649302768, 8517900938696309774,
+ 16586480348202605369, 6959129367028440372, 16822147227405758281,
+ ];
+ for &e in &expected {
+ assert_eq!(rng.next_u64(), e);
+ }
+ }
+}
diff --git a/rand/rand_xoshiro/src/xoroshiro64star.rs b/rand/rand_xoshiro/src/xoroshiro64star.rs
new file mode 100644
index 0000000..86338fd
--- /dev/null
+++ b/rand/rand_xoshiro/src/xoroshiro64star.rs
@@ -0,0 +1,97 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+use byteorder::{ByteOrder, LittleEndian};
+use rand_core;
+use rand_core::le::read_u32_into;
+use rand_core::impls::{fill_bytes_via_next, next_u64_via_u32};
+use rand_core::{RngCore, SeedableRng};
+
+/// A xoroshiro64* random number generator.
+///
+/// The xoroshiro64* algorithm is not suitable for cryptographic purposes, but
+/// is very fast and has good statistical properties, besides a low linear
+/// complexity in the lowest bits.
+///
+/// The algorithm used here is translated from [the `xoroshiro64star.c`
+/// reference source code](http://xoshiro.di.unimi.it/xoroshiro64star.c) by
+/// David Blackman and Sebastiano Vigna.
+#[allow(missing_copy_implementations)]
+#[derive(Debug, Clone)]
+pub struct Xoroshiro64Star {
+ s0: u32,
+ s1: u32,
+}
+
+impl RngCore for Xoroshiro64Star {
+ #[inline]
+ fn next_u32(&mut self) -> u32 {
+ let r = self.s0.wrapping_mul(0x9E3779BB);
+ impl_xoroshiro_u32!(self);
+ r
+ }
+
+ #[inline]
+ fn next_u64(&mut self) -> u64 {
+ next_u64_via_u32(self)
+ }
+
+ #[inline]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ fill_bytes_via_next(self, dest);
+ }
+
+ #[inline]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
+ self.fill_bytes(dest);
+ Ok(())
+ }
+}
+
+impl SeedableRng for Xoroshiro64Star {
+ type Seed = [u8; 8];
+
+ /// Create a new `Xoroshiro64Star`. If `seed` is entirely 0, it will be
+ /// mapped to a different seed.
+ fn from_seed(seed: [u8; 8]) -> Xoroshiro64Star {
+ deal_with_zero_seed!(seed, Self);
+ let mut s = [0; 2];
+ read_u32_into(&seed, &mut s);
+
+ Xoroshiro64Star {
+ s0: s[0],
+ s1: s[1],
+ }
+ }
+
+ /// Seed a `Xoroshiro64Star` from a `u64` using `SplitMix64`.
+ fn seed_from_u64(seed: u64) -> Xoroshiro64Star {
+ let mut s = [0; 8];
+ LittleEndian::write_u64(&mut s, seed);
+ Xoroshiro64Star::from_seed(s)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn reference() {
+ let mut rng = Xoroshiro64Star::from_seed([1, 0, 0, 0, 2, 0, 0, 0]);
+ // These values were produced with the reference implementation:
+ // http://xoshiro.di.unimi.it/xoshiro64star.c
+ let expected = [
+ 2654435771, 327208753, 4063491769, 4259754937, 261922412, 168123673,
+ 552743735, 1672597395, 1031040050, 2755315674,
+ ];
+ for &e in &expected {
+ assert_eq!(rng.next_u32(), e);
+ }
+ }
+}
diff --git a/rand/rand_xoshiro/src/xoroshiro64starstar.rs b/rand/rand_xoshiro/src/xoroshiro64starstar.rs
new file mode 100644
index 0000000..a40baee
--- /dev/null
+++ b/rand/rand_xoshiro/src/xoroshiro64starstar.rs
@@ -0,0 +1,96 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+use byteorder::{ByteOrder, LittleEndian};
+use rand_core;
+use rand_core::le::read_u32_into;
+use rand_core::impls::{fill_bytes_via_next, next_u64_via_u32};
+use rand_core::{RngCore, SeedableRng};
+
+/// A Xoroshiro64** random number generator.
+///
+/// The xoshiro64** algorithm is not suitable for cryptographic purposes, but
+/// is very fast and has excellent statistical properties.
+///
+/// The algorithm used here is translated from [the `xoroshiro64starstar.c`
+/// reference source code](http://xoshiro.di.unimi.it/xoroshiro64starstar.c) by
+/// David Blackman and Sebastiano Vigna.
+#[allow(missing_copy_implementations)]
+#[derive(Debug, Clone)]
+pub struct Xoroshiro64StarStar {
+ s0: u32,
+ s1: u32,
+}
+
+impl RngCore for Xoroshiro64StarStar {
+ #[inline]
+ fn next_u32(&mut self) -> u32 {
+ let r = starstar_u32!(self.s0);
+ impl_xoroshiro_u32!(self);
+ r
+ }
+
+ #[inline]
+ fn next_u64(&mut self) -> u64 {
+ next_u64_via_u32(self)
+ }
+
+ #[inline]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ fill_bytes_via_next(self, dest);
+ }
+
+ #[inline]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
+ self.fill_bytes(dest);
+ Ok(())
+ }
+}
+
+impl SeedableRng for Xoroshiro64StarStar {
+ type Seed = [u8; 8];
+
+ /// Create a new `Xoroshiro64StarStar`. If `seed` is entirely 0, it will be
+ /// mapped to a different seed.
+ fn from_seed(seed: [u8; 8]) -> Xoroshiro64StarStar {
+ deal_with_zero_seed!(seed, Self);
+ let mut s = [0; 2];
+ read_u32_into(&seed, &mut s);
+
+ Xoroshiro64StarStar {
+ s0: s[0],
+ s1: s[1],
+ }
+ }
+
+ /// Seed a `Xoroshiro64StarStar` from a `u64`.
+ fn seed_from_u64(seed: u64) -> Xoroshiro64StarStar {
+ let mut s = [0; 8];
+ LittleEndian::write_u64(&mut s, seed);
+ Xoroshiro64StarStar::from_seed(s)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn reference() {
+ let mut rng = Xoroshiro64StarStar::from_seed([1, 0, 0, 0, 2, 0, 0, 0]);
+ // These values were produced with the reference implementation:
+ // http://xoshiro.di.unimi.it/xoshiro64starstar.c
+ let expected = [
+ 3802928447, 813792938, 1618621494, 2955957307, 3252880261,
+ 1129983909, 2539651700, 1327610908, 1757650787, 2763843748,
+ ];
+ for &e in &expected {
+ assert_eq!(rng.next_u32(), e);
+ }
+ }
+}
diff --git a/rand/rand_xoshiro/src/xoshiro128plus.rs b/rand/rand_xoshiro/src/xoshiro128plus.rs
new file mode 100644
index 0000000..b0c7cc7
--- /dev/null
+++ b/rand/rand_xoshiro/src/xoshiro128plus.rs
@@ -0,0 +1,114 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+use rand_core::impls::{next_u64_via_u32, fill_bytes_via_next};
+use rand_core::le::read_u32_into;
+use rand_core::{SeedableRng, RngCore, Error};
+
+/// A xoshiro128+ random number generator.
+///
+/// The xoshiro128+ algorithm is not suitable for cryptographic purposes, but
+/// is very fast and has good statistical properties, besides a low linear
+/// complexity in the lowest bits.
+///
+/// The algorithm used here is translated from [the `xoshiro128starstar.c`
+/// reference source code](http://xoshiro.di.unimi.it/xoshiro128starstar.c) by
+/// David Blackman and Sebastiano Vigna.
+#[derive(Debug, Clone)]
+pub struct Xoshiro128Plus {
+ s: [u32; 4],
+}
+
+impl Xoshiro128Plus {
+ /// Jump forward, equivalently to 2^64 calls to `next_u32()`.
+ ///
+ /// This can be used to generate 2^64 non-overlapping subsequences for
+ /// parallel computations.
+ ///
+ /// ```
+ /// # extern crate rand;
+ /// # extern crate rand_xoshiro;
+ /// # fn main() {
+ /// use rand::SeedableRng;
+ /// use rand_xoshiro::Xoroshiro128StarStar;
+ ///
+ /// let rng1 = Xoroshiro128StarStar::seed_from_u64(0);
+ /// let mut rng2 = rng1.clone();
+ /// rng2.jump();
+ /// let mut rng3 = rng2.clone();
+ /// rng3.jump();
+ /// # }
+ /// ```
+ pub fn jump(&mut self) {
+ impl_jump!(u32, self, [0x8764000b, 0xf542d2d3, 0x6fa035c3, 0x77f2db5b]);
+ }
+}
+
+impl SeedableRng for Xoshiro128Plus {
+ type Seed = [u8; 16];
+
+ /// Create a new `Xoshiro128Plus`. If `seed` is entirely 0, it will be
+ /// mapped to a different seed.
+ #[inline]
+ fn from_seed(seed: [u8; 16]) -> Xoshiro128Plus {
+ deal_with_zero_seed!(seed, Self);
+ let mut state = [0; 4];
+ read_u32_into(&seed, &mut state);
+ Xoshiro128Plus { s: state }
+ }
+
+ /// Seed a `Xoshiro128Plus` from a `u64` using `SplitMix64`.
+ fn seed_from_u64(seed: u64) -> Xoshiro128Plus {
+ from_splitmix!(seed)
+ }
+}
+
+impl RngCore for Xoshiro128Plus {
+ #[inline]
+ fn next_u32(&mut self) -> u32 {
+ let result_plus = self.s[0].wrapping_add(self.s[3]);
+ impl_xoshiro_u32!(self);
+ result_plus
+ }
+
+ #[inline]
+ fn next_u64(&mut self) -> u64 {
+ next_u64_via_u32(self)
+ }
+
+ #[inline]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ fill_bytes_via_next(self, dest);
+ }
+
+ #[inline]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.fill_bytes(dest);
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn reference() {
+ let mut rng = Xoshiro128Plus::from_seed(
+ [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0]);
+ // These values were produced with the reference implementation:
+ // http://xoshiro.di.unimi.it/xoshiro128plus.c
+ let expected = [
+ 5, 12295, 25178119, 27286542, 39879690, 1140358681, 3276312097,
+ 4110231701, 399823256, 2144435200,
+ ];
+ for &e in &expected {
+ assert_eq!(rng.next_u32(), e);
+ }
+ }
+}
diff --git a/rand/rand_xoshiro/src/xoshiro128starstar.rs b/rand/rand_xoshiro/src/xoshiro128starstar.rs
new file mode 100644
index 0000000..836864e
--- /dev/null
+++ b/rand/rand_xoshiro/src/xoshiro128starstar.rs
@@ -0,0 +1,113 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+use rand_core::impls::{next_u64_via_u32, fill_bytes_via_next};
+use rand_core::le::read_u32_into;
+use rand_core::{SeedableRng, RngCore, Error};
+
+/// A xoshiro128** random number generator.
+///
+/// The xoshiro128** algorithm is not suitable for cryptographic purposes, but
+/// is very fast and has excellent statistical properties.
+///
+/// The algorithm used here is translated from [the `xoshiro128starstar.c`
+/// reference source code](http://xoshiro.di.unimi.it/xoshiro128starstar.c) by
+/// David Blackman and Sebastiano Vigna.
+#[derive(Debug, Clone)]
+pub struct Xoshiro128StarStar {
+ s: [u32; 4],
+}
+
+impl Xoshiro128StarStar {
+ /// Jump forward, equivalently to 2^64 calls to `next_u32()`.
+ ///
+ /// This can be used to generate 2^64 non-overlapping subsequences for
+ /// parallel computations.
+ ///
+ /// ```
+ /// # extern crate rand;
+ /// # extern crate rand_xoshiro;
+ /// # fn main() {
+ /// use rand::SeedableRng;
+ /// use rand_xoshiro::Xoroshiro128StarStar;
+ ///
+ /// let rng1 = Xoroshiro128StarStar::seed_from_u64(0);
+ /// let mut rng2 = rng1.clone();
+ /// rng2.jump();
+ /// let mut rng3 = rng2.clone();
+ /// rng3.jump();
+ /// # }
+ /// ```
+ pub fn jump(&mut self) {
+ impl_jump!(u32, self, [0x8764000b, 0xf542d2d3, 0x6fa035c3, 0x77f2db5b]);
+ }
+}
+
+impl SeedableRng for Xoshiro128StarStar {
+ type Seed = [u8; 16];
+
+ /// Create a new `Xoshiro128StarStar`. If `seed` is entirely 0, it will be
+ /// mapped to a different seed.
+ #[inline]
+ fn from_seed(seed: [u8; 16]) -> Xoshiro128StarStar {
+ deal_with_zero_seed!(seed, Self);
+ let mut state = [0; 4];
+ read_u32_into(&seed, &mut state);
+ Xoshiro128StarStar { s: state }
+ }
+
+ /// Seed a `Xoshiro128StarStar` from a `u64` using `SplitMix64`.
+ fn seed_from_u64(seed: u64) -> Xoshiro128StarStar {
+ from_splitmix!(seed)
+ }
+}
+
+impl RngCore for Xoshiro128StarStar {
+ #[inline]
+ fn next_u32(&mut self) -> u32 {
+ let result_starstar = starstar_u64!(self.s[0]);
+ impl_xoshiro_u32!(self);
+ result_starstar
+ }
+
+ #[inline]
+ fn next_u64(&mut self) -> u64 {
+ next_u64_via_u32(self)
+ }
+
+ #[inline]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ fill_bytes_via_next(self, dest);
+ }
+
+ #[inline]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.fill_bytes(dest);
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn reference() {
+ let mut rng = Xoshiro128StarStar::from_seed(
+ [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0]);
+ // These values were produced with the reference implementation:
+ // http://xoshiro.di.unimi.it/xoshiro128starstar.c
+ let expected = [
+ 5760, 40320, 70819200, 3297914139, 2480851620, 1792823698,
+ 4118739149, 1251203317, 1581886583, 1721184582,
+ ];
+ for &e in &expected {
+ assert_eq!(rng.next_u32(), e);
+ }
+ }
+}
diff --git a/rand/rand_xoshiro/src/xoshiro256plus.rs b/rand/rand_xoshiro/src/xoshiro256plus.rs
new file mode 100644
index 0000000..08da5a8
--- /dev/null
+++ b/rand/rand_xoshiro/src/xoshiro256plus.rs
@@ -0,0 +1,133 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+use rand_core::impls::fill_bytes_via_next;
+use rand_core::le::read_u64_into;
+use rand_core::{SeedableRng, RngCore, Error};
+
+/// A xoshiro256+ random number generator.
+///
+/// The xoshiro256+ algorithm is not suitable for cryptographic purposes, but
+/// is very fast and has good statistical properties, besides a low linear
+/// complexity in the lowest bits.
+///
+/// The algorithm used here is translated from [the `xoshiro256plus.c`
+/// reference source code](http://xoshiro.di.unimi.it/xoshiro256plus.c) by
+/// David Blackman and Sebastiano Vigna.
+#[derive(Debug, Clone)]
+pub struct Xoshiro256Plus {
+ s: [u64; 4],
+}
+
+impl Xoshiro256Plus {
+ /// Jump forward, equivalently to 2^128 calls to `next_u64()`.
+ ///
+ /// This can be used to generate 2^128 non-overlapping subsequences for
+ /// parallel computations.
+ ///
+ /// ```
+ /// # extern crate rand;
+ /// # extern crate rand_xoshiro;
+ /// # fn main() {
+ /// use rand::SeedableRng;
+ /// use rand_xoshiro::Xoshiro256Plus;
+ ///
+ /// let rng1 = Xoshiro256Plus::seed_from_u64(0);
+ /// let mut rng2 = rng1.clone();
+ /// rng2.jump();
+ /// let mut rng3 = rng2.clone();
+ /// rng3.jump();
+ /// # }
+ /// ```
+ pub fn jump(&mut self) {
+ impl_jump!(u64, self, [
+ 0x180ec6d33cfd0aba, 0xd5a61266f0c9392c,
+ 0xa9582618e03fc9aa, 0x39abdc4529b1661c
+ ]);
+ }
+
+ /// Jump forward, equivalently to 2^192 calls to `next_u64()`.
+ ///
+ /// This can be used to generate 2^64 starting points, from each of which
+ /// `jump()` will generate 2^64 non-overlapping subsequences for parallel
+ /// distributed computations.
+ pub fn long_jump(&mut self) {
+ impl_jump!(u64, self, [
+ 0x76e15d3efefdcbbf, 0xc5004e441c522fb3,
+ 0x77710069854ee241, 0x39109bb02acbe635
+ ]);
+ }
+}
+
+impl SeedableRng for Xoshiro256Plus {
+ type Seed = [u8; 32];
+
+ /// Create a new `Xoshiro256Plus`. If `seed` is entirely 0, it will be
+ /// mapped to a different seed.
+ #[inline]
+ fn from_seed(seed: [u8; 32]) -> Xoshiro256Plus {
+ deal_with_zero_seed!(seed, Self);
+ let mut state = [0; 4];
+ read_u64_into(&seed, &mut state);
+ Xoshiro256Plus { s: state }
+ }
+
+ /// Seed a `Xoshiro256Plus` from a `u64` using `SplitMix64`.
+ fn seed_from_u64(seed: u64) -> Xoshiro256Plus {
+ from_splitmix!(seed)
+ }
+}
+
+impl RngCore for Xoshiro256Plus {
+ #[inline]
+ fn next_u32(&mut self) -> u32 {
+ // The lowest bits have some linear dependencies, so we use the
+ // upper bits instead.
+ (self.next_u64() >> 32) as u32
+ }
+
+ #[inline]
+ fn next_u64(&mut self) -> u64 {
+ let result_plus = self.s[0].wrapping_add(self.s[3]);
+ impl_xoshiro_u64!(self);
+ result_plus
+ }
+
+ #[inline]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ fill_bytes_via_next(self, dest);
+ }
+
+ #[inline]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.fill_bytes(dest);
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn reference() {
+ let mut rng = Xoshiro256Plus::from_seed(
+ [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0]);
+ // These values were produced with the reference implementation:
+ // http://xoshiro.di.unimi.it/xoshiro256plus.c
+ let expected = [
+ 5, 211106232532999, 211106635186183, 9223759065350669058,
+ 9250833439874351877, 13862484359527728515, 2346507365006083650,
+ 1168864526675804870, 34095955243042024, 3466914240207415127,
+ ];
+ for &e in &expected {
+ assert_eq!(rng.next_u64(), e);
+ }
+ }
+}
diff --git a/rand/rand_xoshiro/src/xoshiro256starstar.rs b/rand/rand_xoshiro/src/xoshiro256starstar.rs
new file mode 100644
index 0000000..fc0a208
--- /dev/null
+++ b/rand/rand_xoshiro/src/xoshiro256starstar.rs
@@ -0,0 +1,130 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+use rand_core::impls::fill_bytes_via_next;
+use rand_core::le::read_u64_into;
+use rand_core::{SeedableRng, RngCore, Error};
+
+/// A xoshiro256** random number generator.
+///
+/// The xoshiro256** algorithm is not suitable for cryptographic purposes, but
+/// is very fast and has excellent statistical properties.
+///
+/// The algorithm used here is translated from [the `xoshiro256starstar.c`
+/// reference source code](http://xoshiro.di.unimi.it/xoshiro256starstar.c) by
+/// David Blackman and Sebastiano Vigna.
+#[derive(Debug, Clone)]
+pub struct Xoshiro256StarStar {
+ s: [u64; 4],
+}
+
+impl Xoshiro256StarStar {
+ /// Jump forward, equivalently to 2^128 calls to `next_u64()`.
+ ///
+ /// This can be used to generate 2^128 non-overlapping subsequences for
+ /// parallel computations.
+ ///
+ /// ```
+ /// # extern crate rand;
+ /// # extern crate rand_xoshiro;
+ /// # fn main() {
+ /// use rand::SeedableRng;
+ /// use rand_xoshiro::Xoshiro256StarStar;
+ ///
+ /// let rng1 = Xoshiro256StarStar::seed_from_u64(0);
+ /// let mut rng2 = rng1.clone();
+ /// rng2.jump();
+ /// let mut rng3 = rng2.clone();
+ /// rng3.jump();
+ /// # }
+ /// ```
+ pub fn jump(&mut self) {
+ impl_jump!(u64, self, [
+ 0x180ec6d33cfd0aba, 0xd5a61266f0c9392c,
+ 0xa9582618e03fc9aa, 0x39abdc4529b1661c
+ ]);
+ }
+
+ /// Jump forward, equivalently to 2^192 calls to `next_u64()`.
+ ///
+ /// This can be used to generate 2^64 starting points, from each of which
+ /// `jump()` will generate 2^64 non-overlapping subsequences for parallel
+ /// distributed computations.
+ pub fn long_jump(&mut self) {
+ impl_jump!(u64, self, [
+ 0x76e15d3efefdcbbf, 0xc5004e441c522fb3,
+ 0x77710069854ee241, 0x39109bb02acbe635
+ ]);
+ }
+}
+
+impl SeedableRng for Xoshiro256StarStar {
+ type Seed = [u8; 32];
+
+ /// Create a new `Xoshiro256StarStar`. If `seed` is entirely 0, it will be
+ /// mapped to a different seed.
+ #[inline]
+ fn from_seed(seed: [u8; 32]) -> Xoshiro256StarStar {
+ deal_with_zero_seed!(seed, Self);
+ let mut state = [0; 4];
+ read_u64_into(&seed, &mut state);
+ Xoshiro256StarStar { s: state }
+ }
+
+ /// Seed a `Xoshiro256StarStar` from a `u64` using `SplitMix64`.
+ fn seed_from_u64(seed: u64) -> Xoshiro256StarStar {
+ from_splitmix!(seed)
+ }
+}
+
+impl RngCore for Xoshiro256StarStar {
+ #[inline]
+ fn next_u32(&mut self) -> u32 {
+ self.next_u64() as u32
+ }
+
+ #[inline]
+ fn next_u64(&mut self) -> u64 {
+ let result_starstar = starstar_u64!(self.s[1]);
+ impl_xoshiro_u64!(self);
+ result_starstar
+ }
+
+ #[inline]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ fill_bytes_via_next(self, dest);
+ }
+
+ #[inline]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.fill_bytes(dest);
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn reference() {
+ let mut rng = Xoshiro256StarStar::from_seed(
+ [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0]);
+ // These values were produced with the reference implementation:
+ // http://xoshiro.di.unimi.it/xoshiro128starstar.c
+ let expected = [
+ 11520, 0, 1509978240, 1215971899390074240, 1216172134540287360,
+ 607988272756665600, 16172922978634559625, 8476171486693032832,
+ 10595114339597558777, 2904607092377533576,
+ ];
+ for &e in &expected {
+ assert_eq!(rng.next_u64(), e);
+ }
+ }
+}
diff --git a/rand/rand_xoshiro/src/xoshiro512plus.rs b/rand/rand_xoshiro/src/xoshiro512plus.rs
new file mode 100644
index 0000000..fe982e4
--- /dev/null
+++ b/rand/rand_xoshiro/src/xoshiro512plus.rs
@@ -0,0 +1,124 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+use rand_core::impls::fill_bytes_via_next;
+use rand_core::le::read_u64_into;
+use rand_core::{SeedableRng, RngCore, Error};
+
+use Seed512;
+
+/// A xoshiro512+ random number generator.
+///
+/// The xoshiro512+ algorithm is not suitable for cryptographic purposes, but
+/// is very fast and has good statistical properties, besides a low linear
+/// complexity in the lowest bits.
+///
+/// The algorithm used here is translated from [the `xoshiro512plus.c`
+/// reference source code](http://xoshiro.di.unimi.it/xoshiro512plus.c) by
+/// David Blackman and Sebastiano Vigna.
+#[derive(Debug, Clone)]
+pub struct Xoshiro512Plus {
+ s: [u64; 8],
+}
+
+impl Xoshiro512Plus {
+ /// Jump forward, equivalently to 2^256 calls to `next_u64()`.
+ ///
+ /// This can be used to generate 2^256 non-overlapping subsequences for
+ /// parallel computations.
+ ///
+ /// ```
+ /// # extern crate rand;
+ /// # extern crate rand_xoshiro;
+ /// # fn main() {
+ /// use rand::SeedableRng;
+ /// use rand_xoshiro::Xoshiro512Plus;
+ ///
+ /// let rng1 = Xoshiro512Plus::seed_from_u64(0);
+ /// let mut rng2 = rng1.clone();
+ /// rng2.jump();
+ /// let mut rng3 = rng2.clone();
+ /// rng3.jump();
+ /// # }
+ /// ```
+ pub fn jump(&mut self) {
+ impl_jump!(u64, self, [
+ 0x33ed89b6e7a353f9, 0x760083d7955323be, 0x2837f2fbb5f22fae,
+ 0x4b8c5674d309511c, 0xb11ac47a7ba28c25, 0xf1be7667092bcc1c,
+ 0x53851efdb6df0aaf, 0x1ebbc8b23eaf25db
+ ]);
+ }
+}
+
+impl SeedableRng for Xoshiro512Plus {
+ type Seed = Seed512;
+
+ /// Create a new `Xoshiro512Plus`. If `seed` is entirely 0, it will be
+ /// mapped to a different seed.
+ #[inline]
+ fn from_seed(seed: Seed512) -> Xoshiro512Plus {
+ deal_with_zero_seed!(seed, Self);
+ let mut state = [0; 8];
+ read_u64_into(&seed.0, &mut state);
+ Xoshiro512Plus { s: state }
+ }
+
+ /// Seed a `Xoshiro512Plus` from a `u64` using `SplitMix64`.
+ fn seed_from_u64(seed: u64) -> Xoshiro512Plus {
+ from_splitmix!(seed)
+ }
+}
+
+impl RngCore for Xoshiro512Plus {
+ #[inline]
+ fn next_u32(&mut self) -> u32 {
+ self.next_u64() as u32
+ }
+
+ #[inline]
+ fn next_u64(&mut self) -> u64 {
+ let result_plus = self.s[0].wrapping_add(self.s[2]);
+ impl_xoshiro_large!(self);
+ result_plus
+ }
+
+ #[inline]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ fill_bytes_via_next(self, dest);
+ }
+
+ #[inline]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.fill_bytes(dest);
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn reference() {
+ let mut rng = Xoshiro512Plus::from_seed(Seed512(
+ [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
+ 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0,
+ 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0]));
+ // These values were produced with the reference implementation:
+ // http://xoshiro.di.unimi.it/xoshiro512plus.c
+ let expected = [
+ 4, 8, 4113, 25169936, 52776585412635, 57174648719367,
+ 9223482039571869716, 9331471677901559830, 9340533895746033672,
+ 14078399799840753678,
+ ];
+ for &e in &expected {
+ assert_eq!(rng.next_u64(), e);
+ }
+ }
+}
diff --git a/rand/rand_xoshiro/src/xoshiro512starstar.rs b/rand/rand_xoshiro/src/xoshiro512starstar.rs
new file mode 100644
index 0000000..1a33f0a
--- /dev/null
+++ b/rand/rand_xoshiro/src/xoshiro512starstar.rs
@@ -0,0 +1,124 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// 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.
+
+use rand_core::impls::fill_bytes_via_next;
+use rand_core::le::read_u64_into;
+use rand_core::{SeedableRng, RngCore, Error};
+
+use Seed512;
+
+/// A xoshiro512** random number generator.
+///
+/// The xoshiro512** algorithm is not suitable for cryptographic purposes, but
+/// is very fast and has excellent statistical properties.
+///
+/// The algorithm used here is translated from [the `xoshiro512starstar.c`
+/// reference source code](http://xoshiro.di.unimi.it/xoshiro512starstar.c) by
+/// David Blackman and Sebastiano Vigna.
+#[derive(Debug, Clone)]
+pub struct Xoshiro512StarStar {
+ s: [u64; 8],
+}
+
+impl Xoshiro512StarStar {
+ /// Jump forward, equivalently to 2^256 calls to `next_u64()`.
+ ///
+ /// This can be used to generate 2^256 non-overlapping subsequences for
+ /// parallel computations.
+ ///
+ /// ```
+ /// # extern crate rand;
+ /// # extern crate rand_xoshiro;
+ /// # fn main() {
+ /// use rand::SeedableRng;
+ /// use rand_xoshiro::Xoshiro512StarStar;
+ ///
+ /// let rng1 = Xoshiro512StarStar::seed_from_u64(0);
+ /// let mut rng2 = rng1.clone();
+ /// rng2.jump();
+ /// let mut rng3 = rng2.clone();
+ /// rng3.jump();
+ /// # }
+ /// ```
+ pub fn jump(&mut self) {
+ impl_jump!(u64, self, [
+ 0x33ed89b6e7a353f9, 0x760083d7955323be, 0x2837f2fbb5f22fae,
+ 0x4b8c5674d309511c, 0xb11ac47a7ba28c25, 0xf1be7667092bcc1c,
+ 0x53851efdb6df0aaf, 0x1ebbc8b23eaf25db
+ ]);
+ }
+}
+
+
+impl SeedableRng for Xoshiro512StarStar {
+ type Seed = Seed512;
+
+ /// Create a new `Xoshiro512StarStar`. If `seed` is entirely 0, it will be
+ /// mapped to a different seed.
+ #[inline]
+ fn from_seed(seed: Seed512) -> Xoshiro512StarStar {
+ deal_with_zero_seed!(seed, Self);
+ let mut state = [0; 8];
+ read_u64_into(&seed.0, &mut state);
+ Xoshiro512StarStar { s: state }
+ }
+
+ /// Seed a `Xoshiro512StarStar` from a `u64` using `SplitMix64`.
+ fn seed_from_u64(seed: u64) -> Xoshiro512StarStar {
+ from_splitmix!(seed)
+ }
+}
+
+impl RngCore for Xoshiro512StarStar {
+ #[inline]
+ fn next_u32(&mut self) -> u32 {
+ self.next_u64() as u32
+ }
+
+ #[inline]
+ fn next_u64(&mut self) -> u64 {
+ let result_starstar = starstar_u64!(self.s[1]);
+ impl_xoshiro_large!(self);
+ result_starstar
+ }
+
+ #[inline]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ fill_bytes_via_next(self, dest);
+ }
+
+ #[inline]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.fill_bytes(dest);
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn reference() {
+ let mut rng = Xoshiro512StarStar::from_seed(Seed512(
+ [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
+ 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0,
+ 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0]));
+ // These values were produced with the reference implementation:
+ // http://xoshiro.di.unimi.it/xoshiro512starstar.c
+ let expected = [
+ 11520, 0, 23040, 23667840, 144955163520, 303992986974289920,
+ 25332796375735680, 296904390158016, 13911081092387501979,
+ 15304787717237593024,
+ ];
+ for &e in &expected {
+ assert_eq!(rng.next_u64(), e);
+ }
+ }
+}
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&section=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();
diff --git a/rand/utils/ci/install_cargo_web.sh b/rand/utils/ci/install_cargo_web.sh
new file mode 100755
index 0000000..b35f069
--- /dev/null
+++ b/rand/utils/ci/install_cargo_web.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+set -euo pipefail
+IFS=$'\n\t'
+
+CARGO_WEB_RELEASE=$(curl -L -s -H 'Accept: application/json' https://github.com/koute/cargo-web/releases/latest)
+CARGO_WEB_VERSION=$(echo $CARGO_WEB_RELEASE | sed -e 's/.*"tag_name":"\([^"]*\)".*/\1/')
+CARGO_WEB_URL="https://github.com/koute/cargo-web/releases/download/$CARGO_WEB_VERSION/cargo-web-x86_64-unknown-linux-gnu.gz"
+
+echo "Downloading cargo-web from: $CARGO_WEB_URL"
+curl -L $CARGO_WEB_URL | gzip -d > cargo-web
+chmod +x cargo-web
+
+mkdir -p ~/.cargo/bin
+mv cargo-web ~/.cargo/bin
diff --git a/rand/utils/ci/script.sh b/rand/utils/ci/script.sh
index 33786f6..e8c1189 100644
--- a/rand/utils/ci/script.sh
+++ b/rand/utils/ci/script.sh
@@ -12,8 +12,10 @@ main() {
cross test --target $TARGET --manifest-path rand_isaac/Cargo.toml --features=serde1
cross test --target $TARGET --manifest-path rand_pcg/Cargo.toml --features=serde1
cross test --target $TARGET --manifest-path rand_xorshift/Cargo.toml --features=serde1
+ cross test --target $TARGET --manifest-path rand_xoshiro/Cargo.toml
cross test --target $TARGET --manifest-path rand_chacha/Cargo.toml
cross test --target $TARGET --manifest-path rand_hc/Cargo.toml
+ cross test --target $TARGET --manifest-path rand_os/Cargo.toml
}
# we don't run the "test phase" when doing deploys