summaryrefslogtreecommitdiff
path: root/vendor/rdrand
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
committerValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
commit1b6a04ca5504955c571d1c97504fb45ea0befee4 (patch)
tree7579f518b23313e8a9748a88ab6173d5e030b227 /vendor/rdrand
parent5ecd8cf2cba827454317368b68571df0d13d7842 (diff)
downloadfparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.tar.xz
fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.zip
Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
Diffstat (limited to 'vendor/rdrand')
-rw-r--r--vendor/rdrand/.cargo-checksum.json1
-rw-r--r--vendor/rdrand/Cargo.toml28
-rw-r--r--vendor/rdrand/LICENSE12
-rw-r--r--vendor/rdrand/README.mkd8
-rw-r--r--vendor/rdrand/appveyor.yml27
-rw-r--r--vendor/rdrand/benches/rdrand.rs49
-rw-r--r--vendor/rdrand/benches/rdseed.rs49
-rw-r--r--vendor/rdrand/benches/std.rs31
-rw-r--r--vendor/rdrand/src/changelog.rs25
-rw-r--r--vendor/rdrand/src/lib.rs472
10 files changed, 702 insertions, 0 deletions
diff --git a/vendor/rdrand/.cargo-checksum.json b/vendor/rdrand/.cargo-checksum.json
new file mode 100644
index 0000000..c7b5a11
--- /dev/null
+++ b/vendor/rdrand/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"f11ed31fc1b481c7d0e24251d7d60d34442f1d25747c887c49dc9fbad7e13e59","LICENSE":"00d7b0c8bf95ea93162fccc84da96b906b15add708eade04f7ee6141f7b53141","README.mkd":"93853e9e773543ed0d0cf696b5fb151b15bddc1ad9c39996c9eb11b20a3c7ff6","appveyor.yml":"f502d8a0755b98e904a40b07e8ba270bccd729045b03c24a7db0dfbb4047b515","benches/rdrand.rs":"f3684c360d43bc8a780868c0a3af43b20d56975e03575122cee87277787cc8d0","benches/rdseed.rs":"520097b15a3f11c0c6a357e6cd23add598be22f37839bbc71040b827b05d1064","benches/std.rs":"6a5b52b070b2a594e735aa617f16fc6a861e64534634cdb61801c3297444f6fe","src/changelog.rs":"644e08c06836ecdf94f9a43aec109e9f05f9d85f00541683c72d0d3893ff8d6a","src/lib.rs":"8fc306db8a304d24c28fcefaec1849c0d8bbca97417420af7b81449c352b2e92"},"package":"678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"} \ No newline at end of file
diff --git a/vendor/rdrand/Cargo.toml b/vendor/rdrand/Cargo.toml
new file mode 100644
index 0000000..6b3c80a
--- /dev/null
+++ b/vendor/rdrand/Cargo.toml
@@ -0,0 +1,28 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g. crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+name = "rdrand"
+version = "0.4.0"
+authors = ["Simonas Kazlauskas <rdrand@kazlauskas.me>"]
+description = "An implementation of random number generator based on rdrand and rdseed instructions"
+documentation = "https://docs.rs/rdrand/0.4.0/"
+keywords = ["rand", "rdrand", "rdseed", "random"]
+license = "ISC"
+repository = "https://github.com/nagisa/rust_rdrand/"
+[dependencies.rand_core]
+version = "0.3"
+default-features = false
+
+[features]
+default = ["std"]
+std = []
diff --git a/vendor/rdrand/LICENSE b/vendor/rdrand/LICENSE
new file mode 100644
index 0000000..4d6f40d
--- /dev/null
+++ b/vendor/rdrand/LICENSE
@@ -0,0 +1,12 @@
+Copyright © 2014, Simonas Kazlauskas
+
+Permission to use, copy, modify, and/or distribute this software for any purpose with or without
+fee is hereby granted, provided that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
diff --git a/vendor/rdrand/README.mkd b/vendor/rdrand/README.mkd
new file mode 100644
index 0000000..55ab48b
--- /dev/null
+++ b/vendor/rdrand/README.mkd
@@ -0,0 +1,8 @@
+An implementation of random number generators based on `rdrand` and `rdseed` instructions.
+
+The random number generators provided by this crate are fairly slow (the latency for these
+instructions is pretty high), but provide high quality random bits. Caveat is: neither AMD’s
+nor Intel’s designs are public and therefore are not verifiable for lack of backdoors.
+
+Unless you know what you are doing, use the random number generators provided by the `rand`
+crate (such as `EntropyRng`) instead.
diff --git a/vendor/rdrand/appveyor.yml b/vendor/rdrand/appveyor.yml
new file mode 100644
index 0000000..2e915cf
--- /dev/null
+++ b/vendor/rdrand/appveyor.yml
@@ -0,0 +1,27 @@
+environment:
+ matrix:
+ - TARGET: 1.30.0-x86_64-pc-windows-msvc
+ - TARGET: 1.30.0-i686-pc-windows-msvc
+ - TARGET: 1.30.0-x86_64-pc-windows-gnu
+ - TARGET: 1.30.0-i686-pc-windows-gnu
+ - TARGET: nightly-x86_64-pc-windows-msvc
+ - TARGET: nightly-i686-pc-windows-msvc
+install:
+ - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:TARGET}.exe" -FileName "rust.exe"
+ - ps: .\rust.exe /VERYSILENT /NORESTART /DIR="C:\rust" | Out-Null
+ - ps: $env:PATH="$env:PATH;C:\rust\bin"
+ - rustc -vV
+ - cargo -vV
+build: off
+
+test_script:
+- cargo test
+- cargo test --no-default-features
+
+for:
+- matrix:
+ only:
+ - TARGET: nightly-x86_64-pc-windows-msvc
+ - TARGET: nightly-i686-pc-windows-msvc
+ test_script:
+ - cargo bench
diff --git a/vendor/rdrand/benches/rdrand.rs b/vendor/rdrand/benches/rdrand.rs
new file mode 100644
index 0000000..7e70c23
--- /dev/null
+++ b/vendor/rdrand/benches/rdrand.rs
@@ -0,0 +1,49 @@
+#![feature(test)]
+extern crate rand_core;
+extern crate rdrand;
+extern crate test;
+
+use rand_core::RngCore;
+use test::Bencher;
+
+#[bench]
+fn bench_u16(b : &mut Bencher) {
+ if let Ok(gen) = rdrand::RdRand::new() {
+ b.bytes = 2;
+ b.iter(|| {
+ gen.try_next_u16().unwrap()
+ });
+ }
+}
+
+#[bench]
+fn bench_u32(b : &mut Bencher) {
+ if let Ok(mut gen) = rdrand::RdRand::new() {
+ b.bytes = 4;
+ b.iter(|| {
+ gen.next_u32()
+ });
+ }
+}
+
+#[bench]
+fn bench_u64(b : &mut Bencher) {
+ if let Ok(mut gen) = rdrand::RdRand::new() {
+ b.bytes = 8;
+ b.iter(|| {
+ gen.next_u64()
+ });
+ }
+}
+
+#[bench]
+fn bench_fill(b : &mut Bencher) {
+ if let Ok(mut gen) = rdrand::RdRand::new() {
+ let mut buffer = [0; 128];
+ b.bytes = 128;
+ b.iter(|| {
+ gen.fill_bytes(&mut buffer);
+ buffer
+ });
+ }
+}
diff --git a/vendor/rdrand/benches/rdseed.rs b/vendor/rdrand/benches/rdseed.rs
new file mode 100644
index 0000000..6bf8ceb
--- /dev/null
+++ b/vendor/rdrand/benches/rdseed.rs
@@ -0,0 +1,49 @@
+#![feature(test)]
+extern crate rand_core;
+extern crate rdrand;
+extern crate test;
+
+use rand_core::RngCore;
+use test::Bencher;
+
+#[bench]
+fn bench_rdseed_u16(b : &mut Bencher) {
+ if let Ok(gen) = rdrand::RdSeed::new() {
+ b.bytes = 2;
+ b.iter(|| {
+ gen.try_next_u16().unwrap()
+ });
+ }
+}
+
+#[bench]
+fn bench_rdseed_u32(b : &mut Bencher) {
+ if let Ok(mut gen) = rdrand::RdSeed::new() {
+ b.bytes = 4;
+ b.iter(|| {
+ gen.next_u32()
+ });
+ }
+}
+
+#[bench]
+fn bench_rdseed_u64(b : &mut Bencher) {
+ if let Ok(mut gen) = rdrand::RdSeed::new() {
+ b.bytes = 8;
+ b.iter(|| {
+ gen.next_u64()
+ });
+ }
+}
+
+#[bench]
+fn bench_fill(b : &mut Bencher) {
+ if let Ok(mut gen) = rdrand::RdSeed::new() {
+ let mut buffer = [0; 128];
+ b.bytes = 128;
+ b.iter(|| {
+ gen.fill_bytes(&mut buffer);
+ buffer
+ });
+ }
+}
diff --git a/vendor/rdrand/benches/std.rs b/vendor/rdrand/benches/std.rs
new file mode 100644
index 0000000..3fa8fad
--- /dev/null
+++ b/vendor/rdrand/benches/std.rs
@@ -0,0 +1,31 @@
+// #![feature(test)]
+// extern crate rand;
+// extern crate test;
+//
+// use test::Bencher;
+// use test::black_box;
+// use rand::Rng;
+// use rand::StdRng;
+// use rand::OsRng;
+//
+// // OsRng is supposed to be the default for crypto uses.
+// #[bench]
+// fn bench_osrng_u64(b : &mut Bencher) {
+// if let Ok(mut gen) = OsRng::new() {
+// b.bytes = 8;
+// b.iter(|| {
+// black_box(gen.next_u64());
+// });
+// }
+// }
+//
+// // StdRng is the default for everything else.
+// #[bench]
+// fn bench_stdrng_u64(b : &mut Bencher) {
+// if let Ok(mut gen) = StdRng::new() {
+// b.bytes = 8;
+// b.iter(|| {
+// gen.next_u64();
+// });
+// }
+// }
diff --git a/vendor/rdrand/src/changelog.rs b/vendor/rdrand/src/changelog.rs
new file mode 100644
index 0000000..503f738
--- /dev/null
+++ b/vendor/rdrand/src/changelog.rs
@@ -0,0 +1,25 @@
+//! Project changelog
+
+/// ## Breaking changes
+///
+/// Crate gained an enabled-by-default `std` feature. If you relied on rdrand being `core`-able
+/// change your dependency to appear as such:
+///
+/// ```toml
+/// rdrand = { version = "0.4", default-features = false }
+/// ```
+///
+/// This is done so that an advantage of the common feature detection functionality could be
+/// employed by users that are not constrained by `core`. This functionality is faster, caches the
+/// results and is shared between all users of the functionality.
+///
+/// For `core` usage the feature detection has also been improved and will not be done if e.g.
+/// crate is built with `rdrand` instructions enabled globally.
+pub mod r0_4_0 {}
+
+/// Crate now works on stable!
+///
+/// ## Breaking changes
+///
+/// * Updated to `rand_core = ^0.3`.
+pub mod r0_3_0 {}
diff --git a/vendor/rdrand/src/lib.rs b/vendor/rdrand/src/lib.rs
new file mode 100644
index 0000000..423ae21
--- /dev/null
+++ b/vendor/rdrand/src/lib.rs
@@ -0,0 +1,472 @@
+// Copyright © 2014, Simonas Kazlauskas <rdrand@kazlauskas.me>
+//
+// Permission to use, copy, modify, and/or distribute this software for any purpose with or without
+// fee is hereby granted, provided that the above copyright notice and this permission notice
+// appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+// SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+// NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+// OF THIS SOFTWARE.
+//! An implementation of random number generators based on `rdrand` and `rdseed` instructions.
+//!
+//! The random number generators provided by this crate are fairly slow (the latency for these
+//! instructions is pretty high), but provide high quality random bits. Caveat is: neither AMD’s
+//! nor Intel’s designs are public and therefore are not verifiable for lack of backdoors.
+//!
+//! Unless you know what you are doing, use the random number generators provided by the `rand`
+//! crate (such as `OsRng`) instead.
+//!
+//! Here are a measurements for select processor architectures. Check [Agner’s instruction tables]
+//! for up-to-date listings.
+//!
+//! <table>
+//! <tr>
+//! <th>Architecture</th>
+//! <th colspan="3">Latency (cycles)</th>
+//! <th>Maximum throughput (per core)</th>
+//! </tr>
+//! <tr>
+//! <td></td>
+//! <td>u16</td>
+//! <td>u32</td>
+//! <td>u64</td>
+//! <td></td>
+//! </tr>
+//! <tr>
+//! <td>AMD Ryzen</td>
+//! <td>~1200</td>
+//! <td>~1200</td>
+//! <td>~2500</td>
+//! <td>~12MB/s @ 3.7GHz</td>
+//! </tr>
+//! <tr>
+//! <td>Intel Skylake</td>
+//! <td>460</td>
+//! <td>460</td>
+//! <td>460</td>
+//! <td>~72MB/s @ 4.2GHz</td>
+//! </tr>
+//! <tr>
+//! <td>Intel Haswell</td>
+//! <td>320</td>
+//! <td>320</td>
+//! <td>320</td>
+//! <td>~110MB/s @ 4.4GHz</td>
+//! </tr>
+//! </table>
+//!
+//! [Agner’s instruction tables]: http://agner.org/optimize/
+#![cfg_attr(not(feature = "std"), no_std)]
+
+extern crate rand_core;
+
+#[cfg(feature = "std")]
+extern crate core;
+
+pub mod changelog;
+
+use rand_core::{RngCore, CryptoRng, Error, ErrorKind};
+use core::slice;
+
+const RETRY_LIMIT: u8 = 127;
+
+#[cold]
+#[inline(never)]
+pub(crate) fn busy_loop_fail() -> ! {
+ panic!("hardware generator failure");
+}
+
+/// A cryptographically secure statistically uniform, non-periodic and non-deterministic random bit
+/// generator.
+///
+/// Note that this generator may be implemented using a deterministic algorithm that is reseeded
+/// routinely from a non-deterministic entropy source to achieve the desirable properties.
+///
+/// This generator is a viable replacement to any generator, however, since nobody has audited
+/// Intel or AMD hardware yet, the usual disclaimers as to their suitability apply.
+///
+/// It is potentially faster than `OsRng`, but is only supported on more recent Intel (Ivy Bridge
+/// and later) and AMD (Ryzen and later) processors.
+#[derive(Clone, Copy)]
+pub struct RdRand(());
+
+/// A cryptographically secure non-deterministic random bit generator.
+///
+/// This generator produces high-entropy output and is suited to seed other pseudo-random
+/// generators.
+///
+/// This instruction currently is only available in Intel Broadwell (and later) and AMD Ryzen
+/// processors.
+///
+/// This generator is not intended for general random number generation purposes and should be used
+/// to seed other generators implementing [rand_core::SeedableRng].
+#[derive(Clone, Copy)]
+pub struct RdSeed(());
+
+impl CryptoRng for RdRand {}
+impl CryptoRng for RdSeed {}
+
+mod arch {
+ #[cfg(target_arch = "x86_64")]
+ pub use core::arch::x86_64::*;
+ #[cfg(target_arch = "x86")]
+ pub use core::arch::x86::*;
+
+ #[cfg(target_arch = "x86")]
+ pub(crate) unsafe fn _rdrand64_step(dest: &mut u64) -> i32 {
+ let mut ret1: u32 = ::core::mem::uninitialized();
+ let mut ret2: u32 = ::core::mem::uninitialized();
+ if _rdrand32_step(&mut ret1) != 0 && _rdrand32_step(&mut ret2) != 0 {
+ *dest = (ret1 as u64) << 32 | (ret2 as u64);
+ 1
+ } else {
+ 0
+ }
+ }
+
+ #[cfg(target_arch = "x86")]
+ pub(crate) unsafe fn _rdseed64_step(dest: &mut u64) -> i32 {
+ let mut ret1: u32 = ::core::mem::uninitialized();
+ let mut ret2: u32 = ::core::mem::uninitialized();
+ if _rdseed32_step(&mut ret1) != 0 && _rdseed32_step(&mut ret2) != 0 {
+ *dest = (ret1 as u64) << 32 | (ret2 as u64);
+ 1
+ } else {
+ 0
+ }
+ }
+}
+
+#[cfg(not(feature = "std"))]
+macro_rules! is_x86_feature_detected {
+ ("rdrand") => {{
+ if cfg!(target_feature="rdrand") {
+ true
+ } else if cfg!(target_env = "sgx") {
+ false
+ } else {
+ const FLAG : u32 = 1 << 30;
+ unsafe { ::arch::__cpuid(1).ecx & FLAG == FLAG }
+ }
+ }};
+ ("rdseed") => {{
+ if cfg!(target_feature = "rdseed") {
+ true
+ } else if cfg!(target_env = "sgx") {
+ false
+ } else {
+ const FLAG : u32 = 1 << 18;
+ unsafe { ::arch::__cpuid(7).ebx & FLAG == FLAG }
+ }
+ }};
+}
+
+macro_rules! loop_rand {
+ ($el: ty, $step: path) => { {
+ let mut idx = 0;
+ loop {
+ let mut el: $el = ::core::mem::uninitialized();
+ if $step(&mut el) != 0 {
+ break Some(el);
+ } else if idx == RETRY_LIMIT {
+ break None;
+ }
+ idx += 1;
+ }
+ } }
+}
+
+macro_rules! impl_rand {
+ ($gen:ident, $feat:tt, $step16: path, $step32:path, $step64:path,
+ maxstep = $maxstep:path, maxty = $maxty: ty) => {
+ impl $gen {
+ /// Create a new instance of the random number generator.
+ ///
+ /// This constructor checks whether the CPU the program is running on supports the
+ /// instruction necessary for this generator to operate. If the instruction is not
+ /// supported, an error is returned.
+ pub fn new() -> Result<Self, Error> {
+ if is_x86_feature_detected!($feat) {
+ Ok($gen(()))
+ } else {
+ Err(Error::new(rand_core::ErrorKind::Unavailable,
+ "the instruction is not supported"))
+ }
+ }
+
+ /// Generate a single random `u16` value.
+ ///
+ /// The underlying instruction may fail for variety reasons (such as actual hardware
+ /// failure or exhausted entropy), however the exact reason for the failure is not
+ /// usually exposed.
+ ///
+ /// This method will retry calling the instruction a few times, however if all the
+ /// attempts fail, it will return `None`.
+ ///
+ /// In case `None` is returned, the caller should assume that an non-recoverable
+ /// hardware failure has occured and use another random number genrator instead.
+ #[inline(always)]
+ pub fn try_next_u16(&self) -> Option<u16> {
+ #[target_feature(enable = $feat)]
+ unsafe fn imp()
+ -> Option<u16> {
+ loop_rand!(u16, $step16)
+ }
+ unsafe { imp() }
+ }
+
+ /// Generate a single random `u32` value.
+ ///
+ /// The underlying instruction may fail for variety reasons (such as actual hardware
+ /// failure or exhausted entropy), however the exact reason for the failure is not
+ /// usually exposed.
+ ///
+ /// This method will retry calling the instruction a few times, however if all the
+ /// attempts fail, it will return `None`.
+ ///
+ /// In case `None` is returned, the caller should assume that an non-recoverable
+ /// hardware failure has occured and use another random number genrator instead.
+ #[inline(always)]
+ pub fn try_next_u32(&self) -> Option<u32> {
+ #[target_feature(enable = $feat)]
+ unsafe fn imp()
+ -> Option<u32> {
+ loop_rand!(u32, $step32)
+ }
+ unsafe { imp() }
+ }
+
+ /// Generate a single random `u64` value.
+ ///
+ /// The underlying instruction may fail for variety reasons (such as actual hardware
+ /// failure or exhausted entropy), however the exact reason for the failure is not
+ /// usually exposed.
+ ///
+ /// This method will retry calling the instruction a few times, however if all the
+ /// attempts fail, it will return `None`.
+ ///
+ /// In case `None` is returned, the caller should assume that an non-recoverable
+ /// hardware failure has occured and use another random number genrator instead.
+ ///
+ /// Note, that on 32-bit targets, there’s no underlying instruction to generate a
+ /// 64-bit number, so it is emulated with the 32-bit version of the instruction.
+ #[inline(always)]
+ pub fn try_next_u64(&self) -> Option<u64> {
+ #[target_feature(enable = $feat)]
+ unsafe fn imp()
+ -> Option<u64> {
+ loop_rand!(u64, $step64)
+ }
+ unsafe { imp() }
+ }
+ }
+
+ impl RngCore for $gen {
+ /// Generate a single random `u32` value.
+ ///
+ /// The underlying instruction may fail for variety reasons (such as actual hardware
+ /// failure or exhausted entropy), however the exact reason for the failure is not
+ /// usually exposed.
+ ///
+ /// # Panic
+ ///
+ /// This method will retry calling the instruction a few times, however if all the
+ /// attempts fail, it will `panic`.
+ ///
+ /// In case `panic` occurs, the caller should assume that an non-recoverable
+ /// hardware failure has occured and use another random number genrator instead.
+ #[inline(always)]
+ fn next_u32(&mut self) -> u32 {
+ if let Some(result) = self.try_next_u32() {
+ result
+ } else {
+ busy_loop_fail()
+ }
+ }
+
+ /// Generate a single random `u64` value.
+ ///
+ /// The underlying instruction may fail for variety reasons (such as actual hardware
+ /// failure or exhausted entropy), however the exact reason for the failure is not
+ /// usually exposed.
+ ///
+ /// Note, that on 32-bit targets, there’s no underlying instruction to generate a
+ /// 64-bit number, so it is emulated with the 32-bit version of the instruction.
+ ///
+ /// # Panic
+ ///
+ /// This method will retry calling the instruction a few times, however if all the
+ /// attempts fail, it will `panic`.
+ ///
+ /// In case `panic` occurs, the caller should assume that an non-recoverable
+ /// hardware failure has occured and use another random number genrator instead.
+ #[inline(always)]
+ fn next_u64(&mut self) -> u64 {
+ if let Some(result) = self.try_next_u64() {
+ result
+ } else {
+ busy_loop_fail()
+ }
+ }
+
+ /// Fill a buffer `dest` with random data.
+ ///
+ /// See `try_fill_bytes` for a more extensive documentation.
+ ///
+ /// # Panic
+ ///
+ /// This method will panic any time `try_fill_bytes` would return an error.
+ #[inline(always)]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ if let Err(_) = self.try_fill_bytes(dest) {
+ busy_loop_fail()
+ }
+ }
+
+ /// Fill a buffer `dest` with random data.
+ ///
+ /// This method will use the most appropriate variant of the instruction available on
+ /// the machine to achieve the greatest single-core throughput, however it has a
+ /// slightly higher setup cost than the plain `next_u32` or `next_u64` methods.
+ ///
+ /// The underlying instruction may fail for variety reasons (such as actual hardware
+ /// failure or exhausted entropy), however the exact reason for the failure is not
+ /// usually exposed.
+ ///
+ /// This method will retry calling the instruction a few times, however if all the
+ /// attempts fail, it will return an error.
+ ///
+ /// If an error is returned, the caller should assume that an non-recoverable hardware
+ /// failure has occured and use another random number genrator instead.
+ #[inline(always)]
+ fn try_fill_bytes(&mut self, dest: &mut [u8])
+ -> Result<(), Error> {
+ #[target_feature(enable = $feat)]
+ unsafe fn imp(dest: &mut [u8])
+ -> Result<(), Error>
+ {
+ unsafe fn imp_less_fast(mut dest: &mut [u8], word: &mut $maxty,
+ buffer: &mut &[u8])
+ -> Result<(), Error>
+ {
+ while !dest.is_empty() {
+ if buffer.is_empty() {
+ if let Some(w) = loop_rand!($maxty, $maxstep) {
+ *word = w;
+ *buffer = slice::from_raw_parts(
+ word as *const _ as *const u8,
+ ::core::mem::size_of::<$maxty>()
+ );
+ } else {
+ return Err(Error::new(ErrorKind::Unexpected,
+ "hardware generator failure"));
+ }
+ }
+
+ let len = dest.len().min(buffer.len());
+ let (copy_src, leftover) = buffer.split_at(len);
+ let (copy_dest, dest_leftover) = { dest }.split_at_mut(len);
+ *buffer = leftover;
+ dest = dest_leftover;
+ ::core::ptr::copy_nonoverlapping(
+ copy_src.as_ptr(), copy_dest.as_mut_ptr(), len
+ );
+ }
+ Ok(())
+ }
+
+ let destlen = dest.len();
+ if destlen > ::core::mem::size_of::<$maxty>() {
+ let (left, mid, right) = dest.align_to_mut();
+ let mut word = 0;
+ let mut buffer: &[u8] = &[];
+
+ for el in mid {
+ if let Some(val) = loop_rand!($maxty, $maxstep) {
+ *el = val;
+ } else {
+ return Err(Error::new(ErrorKind::Unexpected,
+ "hardware generator failure"));
+ }
+ }
+
+ imp_less_fast(left, &mut word, &mut buffer)?;
+ imp_less_fast(right, &mut word, &mut buffer)
+ } else {
+ let mut word = 0;
+ let mut buffer: &[u8] = &[];
+ imp_less_fast(dest, &mut word, &mut buffer)
+ }
+ }
+ unsafe { imp(dest) }
+ }
+ }
+ }
+}
+
+#[cfg(target_arch = "x86_64")]
+impl_rand!(RdRand, "rdrand",
+ ::arch::_rdrand16_step, ::arch::_rdrand32_step, ::arch::_rdrand64_step,
+ maxstep = ::arch::_rdrand64_step, maxty = u64);
+#[cfg(target_arch = "x86_64")]
+impl_rand!(RdSeed, "rdseed",
+ ::arch::_rdseed16_step, ::arch::_rdseed32_step, ::arch::_rdseed64_step,
+ maxstep = ::arch::_rdseed64_step, maxty = u64);
+#[cfg(target_arch = "x86")]
+impl_rand!(RdRand, "rdrand",
+ ::arch::_rdrand16_step, ::arch::_rdrand32_step, ::arch::_rdrand64_step,
+ maxstep = ::arch::_rdrand32_step, maxty = u32);
+#[cfg(target_arch = "x86")]
+impl_rand!(RdSeed, "rdseed",
+ ::arch::_rdseed16_step, ::arch::_rdseed32_step, ::arch::_rdseed64_step,
+ maxstep = ::arch::_rdseed32_step, maxty = u32);
+
+#[test]
+fn rdrand_works() {
+ let _ = RdRand::new().map(|mut r| {
+ r.next_u32();
+ r.next_u64();
+ });
+}
+
+#[test]
+fn fill_fills_all_bytes() {
+ let _ = RdRand::new().map(|mut r| {
+ let mut peach;
+ let mut banana;
+ let mut start = 0;
+ let mut end = 128;
+ 'outer: while start < end {
+ banana = [0; 128];
+ for _ in 0..512 {
+ peach = [0; 128];
+ r.fill_bytes(&mut peach[start..end]);
+ for (b, p) in banana.iter_mut().zip(peach.iter()) {
+ *b = *b | *p;
+ }
+ if (&banana[start..end]).iter().all(|x| *x != 0) {
+ assert!(banana[..start].iter().all(|x| *x == 0), "all other values must be 0");
+ assert!(banana[end..].iter().all(|x| *x == 0), "all other values must be 0");
+ if start < 17 {
+ start += 1;
+ } else {
+ end -= 3;
+ }
+ continue 'outer;
+ }
+ }
+ panic!("wow, we broke it? {} {} {:?}", start, end, &banana[..])
+ }
+ });
+}
+
+#[test]
+fn rdseed_works() {
+ let _ = RdSeed::new().map(|mut r| {
+ r.next_u32();
+ r.next_u64();
+ });
+}