aboutsummaryrefslogtreecommitdiff
path: root/src/random.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/random.rs')
-rw-r--r--src/random.rs263
1 files changed, 263 insertions, 0 deletions
diff --git a/src/random.rs b/src/random.rs
new file mode 100644
index 0000000..56a4668
--- /dev/null
+++ b/src/random.rs
@@ -0,0 +1,263 @@
+//! Instructions to generate random bits directly from the hardware (RDRAND and RDSEED).
+//!
+//! The decision process for which instruction to use is based on what
+//! the output will be used for. If you wish to seed another pseudorandom
+//! number generator (PRNG), use RDSEED. For all other purposes, use RDRAND
+//!
+//! See also: https://software.intel.com/en-us/blogs/2012/11/17/the-difference-between-rdrand-and-rdseed
+//!
+//! * RDRAND: Cryptographically secure pseudorandom number generator NIST:SP 800-90A
+//! * RDSEED: Non-deterministic random bit generator NIST: SP 800-90B & C (drafts)
+//!
+#[cfg(target_arch = "x86_64")]
+use core::arch::x86_64::{
+ _rdrand16_step, _rdrand32_step, _rdrand64_step, _rdseed16_step, _rdseed32_step, _rdseed64_step,
+};
+
+#[cfg(target_arch = "x86")]
+use core::arch::x86::{
+ _rdrand16_step, _rdrand32_step, _rdrand64_step, _rdseed16_step, _rdseed32_step, _rdseed64_step,
+};
+
+/// Generates a 16-bit random value and stores it in `e`.
+///
+/// # Unsafe
+/// Will crash if RDRAND instructions are not supported.
+#[inline(always)]
+pub unsafe fn rdrand16(e: &mut u16) -> bool {
+ _rdrand16_step(e) == 1
+}
+
+/// Generates a 32-bit random value and stores it in `e`.
+///
+/// # Unsafe
+/// Will crash if RDRAND instructions are not supported.
+#[inline(always)]
+pub unsafe fn rdrand32(e: &mut u32) -> bool {
+ _rdrand32_step(e) == 1
+}
+
+/// Generates a 64-bit random value and stores it in `e`.
+///
+/// # Unsafe
+/// Will crash if RDRAND instructions are not supported.
+#[inline(always)]
+pub unsafe fn rdrand64(e: &mut u64) -> bool {
+ _rdrand64_step(e) == 1
+}
+
+/// RdRand trait to implement the generic rdrand_slice function.
+pub trait RdRand {
+ /// Fills `self` with random bits. Returns true on success or false otherwise
+ ///
+ /// # Unsafe
+ /// RDRAND is not supported on all architctures, so using this may crash you.
+ unsafe fn fill_random(&mut self) -> bool;
+}
+
+impl RdRand for u16 {
+ /// Fills the 16-bit value with a random bit string
+ ///
+ /// # Unsafe
+ /// Will crash if RDRAND instructions are not supported.
+ unsafe fn fill_random(&mut self) -> bool {
+ rdrand16(self)
+ }
+}
+
+impl RdRand for u32 {
+ /// Fills the 32-bit value with a random bit string
+ ///
+ /// # Unsafe
+ /// Will crash if RDRAND instructions are not supported.
+ unsafe fn fill_random(&mut self) -> bool {
+ rdrand32(self)
+ }
+}
+
+impl RdRand for u64 {
+ /// Fills the 64-bit value with a random bit string
+ ///
+ /// # Unsafe
+ /// Will crash if RDRAND instructions are not supported.
+ unsafe fn fill_random(&mut self) -> bool {
+ rdrand64(self)
+ }
+}
+
+/// Fill a slice with random values.
+///
+/// Returns true if the iterator was successfully filled with
+/// random values, otherwise false.
+pub unsafe fn rdrand_slice<T: RdRand>(buffer: &mut [T]) -> bool {
+ let mut worked = true;
+ for element in buffer {
+ worked &= element.fill_random();
+ }
+ worked
+}
+
+/// Generates a 16-bit random value and stores it in `e`.
+///
+/// # Unsafe
+/// Will crash if RDSEED instructions are not supported.
+#[inline(always)]
+pub unsafe fn rdseed16(e: &mut u16) -> bool {
+ _rdseed16_step(e) == 1
+}
+
+/// Generates a 32-bit random value and stores it in `e`.
+///
+/// # Unsafe
+/// Will crash if RDSEED instructions are not supported.
+#[inline(always)]
+pub unsafe fn rdseed32(e: &mut u32) -> bool {
+ _rdseed32_step(e) == 1
+}
+
+/// Generates a 64-bit random value and stores it in `e`.
+///
+/// # Unsafe
+/// Will crash if RDSEED instructions are not supported.
+#[inline(always)]
+pub unsafe fn rdseed64(e: &mut u64) -> bool {
+ _rdseed64_step(e) == 1
+}
+
+/// RdSeed trait to implement the generic rdseed_slice function.
+pub trait RdSeed {
+ /// Fills `self` with random bits. Returns true on success or false otherwise
+ ///
+ /// # Unsafe
+ /// RDSEED is not supported on all architctures, so using this may crash you.
+ unsafe fn fill_random(&mut self) -> bool;
+}
+
+impl RdSeed for u16 {
+ /// Fills the 16-bit value with a random bit string
+ ///
+ /// # Unsafe
+ /// Will crash if RDSEED instructions are not supported.
+ unsafe fn fill_random(&mut self) -> bool {
+ rdseed16(self)
+ }
+}
+
+impl RdSeed for u32 {
+ /// Fills the 32-bit value with a random bit string
+ ///
+ /// # Unsafe
+ /// Will crash if RDSEED instructions are not supported.
+ unsafe fn fill_random(&mut self) -> bool {
+ rdseed32(self)
+ }
+}
+
+impl RdSeed for u64 {
+ /// Fills the 64-bit value with a random bit string
+ ///
+ /// # Unsafe
+ /// Will crash if RDSEED instructions are not supported.
+ unsafe fn fill_random(&mut self) -> bool {
+ rdseed64(self)
+ }
+}
+
+/// Fill a slice with random values.
+///
+/// Returns true if the iterator was successfully filled with
+/// random values, otherwise false.
+pub unsafe fn rdseed_slice<T: RdSeed>(buffer: &mut [T]) -> bool {
+ let mut worked = true;
+ for element in buffer {
+ worked &= element.fill_random();
+ }
+ worked
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn rdrand64_test() {
+ unsafe {
+ let mut buf: [u64; 4] = [0, 0, 0, 0];
+ rdrand_slice(&mut buf);
+
+ assert_ne!(buf[0], 0);
+ assert_ne!(buf[1], 0);
+ assert_ne!(buf[2], 0);
+ assert_ne!(buf[3], 0);
+ }
+ }
+
+
+ #[test]
+ fn rdrand32_test() {
+ unsafe {
+ let mut buf: [u32; 4] = [0, 0, 0, 0];
+ rdrand_slice(&mut buf);
+
+ assert_ne!(buf[0], 0);
+ assert_ne!(buf[1], 0);
+ assert_ne!(buf[2], 0);
+ assert_ne!(buf[3], 0);
+ }
+ }
+
+
+ #[test]
+ fn rdrand16_test() {
+ unsafe {
+ let mut buf: [u16; 4] = [0, 0, 0, 0];
+ rdrand_slice(&mut buf);
+ assert_ne!(buf[0], 0);
+ assert_ne!(buf[1], 0);
+ assert_ne!(buf[2], 0);
+ assert_ne!(buf[3], 0);
+ }
+ }
+
+
+ #[test]
+ fn rdseed64_test() {
+ unsafe {
+ let mut buf: [u64; 4] = [0, 0, 0, 0];
+ rdseed_slice(&mut buf);
+
+ assert_ne!(buf[0], 0);
+ assert_ne!(buf[1], 0);
+ assert_ne!(buf[2], 0);
+ assert_ne!(buf[3], 0);
+ }
+ }
+
+
+ #[test]
+ fn rdseed32_test() {
+ unsafe {
+ let mut buf: [u32; 4] = [0, 0, 0, 0];
+ rdseed_slice(&mut buf);
+
+ assert_ne!(buf[0], 0);
+ assert_ne!(buf[1], 0);
+ assert_ne!(buf[2], 0);
+ assert_ne!(buf[3], 0);
+ }
+ }
+
+
+ #[test]
+ fn rdseed16_test() {
+ unsafe {
+ let mut buf: [u16; 4] = [0, 0, 0, 0];
+ rdseed_slice(&mut buf);
+ assert_ne!(buf[0], 0);
+ assert_ne!(buf[1], 0);
+ assert_ne!(buf[2], 0);
+ assert_ne!(buf[3], 0);
+ }
+ }
+
+} \ No newline at end of file