### rdrand changelog module source Source: https://docs.rs/rdrand/latest/src/rdrand/changelog.rs.html The complete source of the changelog.rs file, containing documentation comments and empty module declarations for each version. It includes a TOML example for disabling default features in version 0.4.0. ```rust 1//! Project changelog 2 3/// ## Breaking changes 4/// 5/// * Upgrade to `rand_core = ^0.10.0`. 6/// * Increase MSRV to 1.86.0. 7/// * Implemented support for aarch64 RNDR and RNDRRS instructions. 8pub mod r0_9_0 {} 9 10/// Fix the implementation of `try_fill_bytes` when the buffer is aligned but the size is not a 11/// multiple of a word size. 12pub mod r0_8_2 {} 13 14/// Disallow use of `rdrand`/`rdseed` on known-broken AMD systems. 15pub mod r0_8_1 {} 16 17/// ## Breaking changes 18/// /// * Upgrade to `rand_core = ^0.6.0`. 19pub mod r0_8_0 {} 20 /// ## Breaking changes /// /// Upgrade to `rand_core = ^0.5.1`. This involves a major change to how errors are handled. See /// [`ErrorCode`](crate::ErrorCode). /// /// rustc version 1.42 is now required to build the library (up from 1.32). 28pub mod r0_7_0 {} 29 /// Fix unsound mutable reference aliasing in the implementation of `try_fill_bytes`. /// /// The affected code has been replaced with safer one where the scope of `unsafe` is reduced to /// the loop which obtains a random word via a native instruction. /// /// ## Breaking changes /// /// rustc version 1.32 is now required to build the library (up from 1.30). 38pub mod r0_6_0 {} 39 /// Replaced likely unsound use of `core::mem::uninitialized()`. 41pub mod r0_5_1 {} 42 /// ## Breaking changes /// /// Updated rand_core dependency from `0.3` to `0.4`. 46pub mod r0_5_0 {} 47 /// ## 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. 63pub mod r0_4_0 {} 64 /// Crate now works on stable! /// /// ## Breaking changes /// /// * Updated to `rand_core = ^0.3`. 70pub mod r0_3_0 {} ``` ```toml rdrand = { version = "0.4", default-features = false } ``` -------------------------------- ### new() -> Result Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html Creates a new instance of the random number generator. Checks CPU support for the required instruction and returns an error if unsupported. ```APIDOC ## new() -> Result ### Description Creates a new instance of the random number generator. This constructor checks whether the CPU supports the necessary instruction and returns an error if not supported. ### Method Constructor ### Parameters None ### Returns - **Result** - Ok with a new generator instance, or Err with ErrorCode::UnsupportedInstruction if the instruction is not supported. ### Error Handling - **ErrorCode::UnsupportedInstruction** - Returned when the CPU does not support the required instruction. ``` -------------------------------- ### RdRand::new Source: https://docs.rs/rdrand/latest/rdrand/struct.RdRand.html Creates a new instance of the RdRand random number generator. Checks CPU support for the required instruction and returns an error if not supported. ```APIDOC ## RdRand::new ### Description Creates a new instance of the random number generator. This constructor checks whether the CPU supports the necessary instruction and returns an error if not supported. ### Method new ### Signature pub fn new() -> Result ### Parameters None ### Returns - **Result** - Ok(RdRand) if the CPU supports the instruction, otherwise Err(ErrorCode). ### Errors Returns an error if the CPU does not support the required instruction. ``` -------------------------------- ### RdSeed::new Source: https://docs.rs/rdrand/latest/rdrand/struct.RdSeed.html Creates a new instance of the RdSeed random number generator. It checks CPU support for the required instruction and returns an error if not supported. ```APIDOC ## RdSeed::new ### Description Creates a new instance of the RdSeed random number generator. This constructor checks whether the CPU supports the necessary instruction and returns an error if not supported. ### Method new ### Signature pub fn new() -> Result ### Parameters None ### Returns - Result - Ok(RdSeed) on success, Err(ErrorCode) if the instruction is not supported. ### Example ```rust let rng = RdSeed::new()?; ``` ``` -------------------------------- ### Crate-level documentation and module declarations Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html The crate-level documentation and module declarations for the rdrand crate. It includes the license header, crate-level doc comments, and the module declarations for changelog and errors. ```rust // 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. //! 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. //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //!
ArchitectureLatency (cycles)Maximum throughput (per core)
u16u32u64
AMD Ryzen~1200~1200~2500~12MB/s @ 3.7GHz
Intel Skylake460460460~72MB/s @ 4.2GHz
Intel Haswell320320320~110MB/s @ 4.4GHz
//! //! [Agner’s instruction tables]: http://agner.org/optimize/ #![no_std] pub mod changelog; mod errors; use core::hint::spin_loop; pub use errors::ErrorCode; use rand_core::{TryCryptoRng, TryRng}; ``` -------------------------------- ### TryRng::try_fill_bytes Source: https://docs.rs/rdrand/latest/rdrand/struct.RdRand.html Fills a buffer with random data. Uses the most appropriate instruction variant for best throughput. Retries a few times and returns an error if all attempts fail. ```APIDOC ## TryRng::try_fill_bytes ### Description Fills a buffer `dest` with random data. This method uses the most appropriate variant of the instruction available on the machine to achieve the greatest single-core throughput, but has a slightly higher setup cost than `next_u32` or `next_u64`. The underlying instruction may fail for various reasons. This method retries a few times, but if all attempts fail, it returns an error. ### Method try_fill_bytes ### Signature fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), ErrorCode> ### Parameters - **dest** (&mut [u8]) - Required - The buffer to fill with random data. ### Returns - **Result<(), ErrorCode>** - Ok(()) on success, or Err(ErrorCode) if a non-recoverable failure occurs. ### Errors Returns an error if the underlying instruction fails after retries. ``` -------------------------------- ### try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), ErrorCode> Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html Fills a buffer with random data using the most appropriate instruction variant for maximum throughput. ```APIDOC ## try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), ErrorCode> ### Description Fills a buffer `dest` with random data. Uses the most appropriate instruction variant for the machine to achieve the greatest single-core throughput, with a slightly higher setup cost than the plain next_u32 or next_u64 methods. ### Method Method ### Parameters - **dest** (&mut [u8]) - Required - The buffer to fill with random data. ### Returns - **Result<(), ErrorCode>** - Ok if the buffer was filled successfully, or Err if all attempts fail. ### Error Handling - **ErrorCode** - Returned when the instruction fails after retries. Caller should assume a non-recoverable hardware failure. ``` -------------------------------- ### try_next_u32(&mut self) -> Result Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html Generates a single random u32 value. Retries the instruction a few times and returns an error if all attempts fail. ```APIDOC ## try_next_u32(&mut self) -> Result ### Description Generates a single random u32 value. The underlying instruction may fail for various reasons, and this method retries a few times before returning an error. ### Method Method ### Parameters None ### Returns - **Result** - Ok with a random u32 value, or Err if all attempts fail. ### Error Handling - **ErrorCode** - Returned when the instruction fails after retries. Caller should assume a non-recoverable failure. ``` -------------------------------- ### try_next_u64(&mut self) -> Result Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html Generates a single random u64 value. On 32-bit targets, it is emulated using the 32-bit instruction. ```APIDOC ## try_next_u64(&mut self) -> Result ### Description Generates a single random u64 value. The underlying instruction may fail, and this method retries a few times before returning an error. On 32-bit targets, the 64-bit value is emulated with the 32-bit instruction. ### Method Method ### Parameters None ### Returns - **Result** - Ok with a random u64 value, or Err if all attempts fail. ### Error Handling - **ErrorCode** - Returned when the instruction fails after retries. Caller should assume a non-recoverable failure. ``` -------------------------------- ### TryRng::try_next_u64 Source: https://docs.rs/rdrand/latest/rdrand/struct.RdRand.html Generates a single random u64 value. On 32-bit targets, it is emulated using the 32-bit instruction. Retries a few times and returns an error if all attempts fail. ```APIDOC ## TryRng::try_next_u64 ### Description Generates a single random u64 value. The underlying instruction may fail for various reasons. This method retries a few times, but if all attempts fail, it returns an error. On 32-bit targets, it is emulated with the 32-bit instruction. ### Method try_next_u64 ### Signature fn try_next_u64(&mut self) -> Result ### Parameters None ### Returns - **Result** - Ok(u64) with a random value, or Err(ErrorCode) if a non-recoverable failure occurs. ### Errors Returns an error if the underlying instruction fails after retries. ``` -------------------------------- ### Verify RdSeed functionality Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html This test ensures that RdSeed can be initialized and can successfully generate both u32 and u64 random values. ```rust #[test] fn rdseed_works() { let _status = RdSeed::new().map(|mut r| { r.try_next_u32().unwrap(); r.try_next_u64().unwrap(); }); #[cfg(any( all(target_feature = "rand", target_arch = "aarch64"), target_arch = "x86_64", target_arch = "x86" ))] _status.unwrap(); } ``` -------------------------------- ### Architecture-specific implementations for x86, x86_64, and aarch64 Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html The arch module provides architecture-specific implementations for the rdrand and rdseed instructions. For x86, it defines fallback implementations of _rdrand64_step and _rdseed64_step using 32-bit steps. For aarch64, it defines a rand function. ```rust mod arch { #[cfg(target_arch = "x86")] pub use core::arch::x86::*; #[cfg(target_arch = "x86_64")] pub use core::arch::x86_64::*; #[cfg(target_arch = "x86")] pub(crate) unsafe fn _rdrand64_step(dest: &mut u64) -> i32 { let mut ret1: u32 = 0; let mut ret2: u32 = 0; let ok = _rdrand32_step(&mut ret1) & _rdrand32_step(&mut ret2); *dest = (ret1 as u64) << 32 | (ret2 as u64); ok } #[cfg(target_arch = "x86")] pub(crate) unsafe fn _rdseed64_step(dest: &mut u64) -> i32 { let mut ret1: u32 = 0; let mut ret2: u32 = 0; let ok = _rdseed32_step(&mut ret1) & _rdseed32_step(&mut ret2); *dest = (ret1 as u64) << 32 | (ret2 as u64); ok } #[cfg(target_arch = "aarch64")] pub(crate) unsafe fn rand(out: &mut u64) -> i32 { let value: u64; ``` -------------------------------- ### Unsupported architecture fallback for RdRand Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html Fallback implementation for RdRand on architectures where hardware instructions are not available. ```rust #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))) impl RdRand { fn new() -> Result { Err(ErrorCode::UnsupportedInstruction) } } #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))) impl TryRng for RdRand { type Error = ErrorCode; fn try_next_u32(&mut self) -> Result { Err(ErrorCode::UnsupportedInstruction) } fn try_next_u64(&mut self) -> Result { Err(ErrorCode::UnsupportedInstruction) } fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), ErrorCode> { Err(ErrorCode::UnsupportedInstruction) } } ``` -------------------------------- ### TryRng::try_next_u32 Source: https://docs.rs/rdrand/latest/rdrand/struct.RdRand.html Generates a single random u32 value. Retries the underlying instruction a few times and returns an error if all attempts fail. ```APIDOC ## TryRng::try_next_u32 ### Description Generates a single random u32 value. The underlying instruction may fail for various reasons (such as hardware failure or exhausted entropy). This method retries a few times, but if all attempts fail, it returns an error. ### Method try_next_u32 ### Signature fn try_next_u32(&mut self) -> Result ### Parameters None ### Returns - **Result** - Ok(u32) with a random value, or Err(ErrorCode) if a non-recoverable failure occurs. ### Errors Returns an error if the underlying instruction fails after retries. ``` -------------------------------- ### Unsupported architecture fallback for RdSeed Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html Fallback implementation for RdSeed on architectures where hardware instructions are not available. ```rust #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))) impl RdSeed { fn new() -> Result { Err(ErrorCode::UnsupportedInstruction) } } #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))) impl TryRng for RdSeed { type Error = ErrorCode; fn try_next_u32(&mut self) -> Result { Err(ErrorCode::UnsupportedInstruction) } fn try_next_u64(&mut self) -> Result { Err(ErrorCode::UnsupportedInstruction) } ``` -------------------------------- ### RdSeed::try_fill_bytes Source: https://docs.rs/rdrand/latest/rdrand/struct.RdSeed.html Fills a buffer with random data. Uses the most appropriate instruction variant for throughput. Retries a few times and returns an error if all attempts fail. ```APIDOC ## RdSeed::try_fill_bytes ### Description Fills a buffer with random data. Uses the most appropriate instruction variant for throughput. Retries a few times and returns an error if all attempts fail. ### Method try_fill_bytes ### Signature pub fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), ErrorCode> ### Parameters - dest (&mut [u8]) - Required - The buffer to fill with random data. ### Returns - Result<(), ErrorCode> - Ok(()) on success, Err(ErrorCode) on failure. ### Example ```rust let mut buffer = [0u8; 32]; g.try_fill_bytes(&mut buffer)?; ``` ``` -------------------------------- ### Architecture-specific impl_rand macro invocations Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html Macro invocations to implement RdRand and RdSeed for x86_64, x86, and aarch64 architectures. ```rust #[cfg(target_arch = "x86_64")] impl_rand!( RdRand, "rdrand", "rdrand", arch::_rdrand32_step, arch::_rdrand64_step, maxstep = arch::_rdrand64_step, maxty = u64 ); #[cfg(target_arch = "x86_64")] impl_rand!( RdSeed, "rdseed", "rdseed", arch::_rdseed32_step, arch::_rdseed64_step, maxstep = arch::_rdseed64_step, maxty = u64 ); #[cfg(target_arch = "x86")] impl_rand!( RdRand, "rdrand", "rdrand", arch::_rdrand32_step, arch::_rdrand64_step, maxstep = arch::_rdrand32_step, maxty = u32 ); #[cfg(target_arch = "x86")] impl_rand!( RdSeed, "rdseed", "rdseed", arch::_rdseed32_step, arch::_rdseed64_step, maxstep = arch::_rdseed32_step, maxty = u32 ); #[cfg(target_arch = "aarch64")] impl_rand!( RdRand, "rand", "rdrand", arch::rand32, arch::rand, maxstep = arch::rand, maxty = u64 ); #[cfg(target_arch = "aarch64")] impl_rand!( RdSeed, "rand", "rdseed", arch::seed32, arch::seed, maxstep = arch::seed, maxty = u64 ); ``` -------------------------------- ### RdSeed::try_next_u64 Source: https://docs.rs/rdrand/latest/rdrand/struct.RdSeed.html Generates a single random u64 value. On 32-bit targets, it is emulated with the 32-bit instruction. Retries a few times and returns an error if all attempts fail. ```APIDOC ## RdSeed::try_next_u64 ### Description Generates a single random u64 value. The underlying instruction may fail for various reasons; this method retries a few times and returns an error if all attempts fail. On 32-bit targets, it is emulated with the 32-bit instruction. ### Method try_next_u64 ### Signature pub fn try_next_u64(&mut self) -> Result ### Parameters None ### Returns - Result - Ok(u64) on success, Err(ErrorCode) on failure. ### Example ```rust let value = rng.try_next_u64()?; ``` ``` -------------------------------- ### RdSeed::try_next_u32 Source: https://docs.rs/rdrand/latest/rdrand/struct.RdSeed.html Generates a single random u32 value. Retries the underlying instruction a few times and returns an error if all attempts fail. ```APIDOC ## RdSeed::try_next_u32 ### Description Generates a single random u32 value. The underlying instruction may fail for various reasons; this method retries a few times and returns an error if all attempts fail. ### Method try_next_u32 ### Signature pub fn try_next_u32(&mut self) -> Result ### Parameters None ### Returns - Result - Ok(u32) on success, Err(ErrorCode) on failure. ### Example ```rust let value = rng.try_next_u32()?; ``` ``` -------------------------------- ### Verify RdRand functionality Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html This test checks if RdRand can be initialized and if it can successfully generate a random u32 value. ```rust #[test] fn rdrand_works() { extern crate std; use std::eprintln; eprintln!("Checking RdRand::new()..."); match RdRand::new() { Ok(mut r) => { eprintln!("RdRand created successfully, calling try_next_u32()"); match r.try_next_u32() { Ok(val) => eprintln!("Got random value: {}", val), Err(e) => eprintln!("try_next_u32 failed: {:?}", e), } } Err(e) => { eprintln!("RdRand::new() failed with: {:?}", e); eprintln!("This is expected on CPUs without RDRAND support"); } } } ``` -------------------------------- ### RDRAND Generator Implementation Macro Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html This macro defines the structure and implementation for an RDRAND-based random number generator, including safe and unsafe constructors and trait implementations for random number generation. ```rust 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 { if cfg!(target_env = "sgx") { if cfg!(target_feature = $feat) { Ok($gen(())) } else { Err(ErrorCode::UnsupportedInstruction) } } else if is_available!($feat) { Ok($gen(())) } else { Err(ErrorCode::UnsupportedInstruction) } } /// Create a new instance of the random number generator. /// /// # Safety /// /// This constructor is unsafe because it doesn't check that the CPU supports the /// instruction, but devolves this responsibility to the caller. pub unsafe fn new_unchecked() -> Self { $gen(()) } } impl TryRng for $gen { type Error = ErrorCode; /// 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 `Err` is returned, the caller should assume that a non-recoverable failure /// has occured and use another random number genrator instead. #[inline(always)] #[allow(unused_unsafe)] fn try_next_u32(&mut self) -> Result { #[target_feature(enable = $feat)] #[allow(unused_unsafe)] unsafe fn imp() -> Result { loop_rand!($loop_mode, 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 `Err` is returned, the caller should assume that a non-recoverable 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)] fn try_next_u64(&mut self) -> Result { #[target_feature(enable = $feat)] #[allow(unused_unsafe)] unsafe fn imp() -> Result { loop_rand!($loop_mode, u64, $step64) } unsafe { imp() } } /// 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)] ``` -------------------------------- ### Internal try_fill_bytes implementation Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html The internal logic for filling a byte slice using hardware random number generation instructions, including handling of alignment and buffer management. ```rust fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), ErrorCode> { #[target_feature(enable = $feat)] #[allow(unused_unsafe)] unsafe fn imp(dest: &mut [u8]) -> Result<(), ErrorCode> { fn slow_fill_bytes<'a>( mut left: &'a mut [u8], mut right: &'a mut [u8], ) -> Result<(), ErrorCode> { let mut word; let mut buffer: &[u8] = &[]; loop { if left.is_empty() { if right.is_empty() { break; } ::core::mem::swap(&mut left, &mut right); } #[allow(unused_unsafe)] if buffer.is_empty() { word = unsafe { loop_rand!($loop_mode, $maxty, $maxstep) }? .to_ne_bytes(); buffer = &word[..]; } let len = left.len().min(buffer.len()); let (copy_src, leftover) = buffer.split_at(len); let (copy_dest, dest_leftover) = { left }.split_at_mut(len); buffer = leftover; left = dest_leftover; copy_dest.copy_from_slice(copy_src); } Ok(()) } let destlen = dest.len(); if destlen > ::core::mem::size_of::<$maxty>() { let (left, mid, right) = unsafe { dest.align_to_mut() }; for el in mid { *el = loop_rand!($loop_mode, $maxty, $maxstep)?; } slow_fill_bytes(left, right) } else { slow_fill_bytes(dest, &mut []) } } unsafe { imp(dest) } } } }; ``` -------------------------------- ### Configure rdrand dependency for core-only usage Source: https://docs.rs/rdrand/latest/rdrand/changelog/r0_4_0/index.html Use this configuration in your Cargo.toml to disable the default 'std' feature if your project is constrained to 'core'. ```toml rdrand = { version = "0.4", default-features = false } ``` -------------------------------- ### loop_rand! macro for RDRAND and RDSEED retry loops Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html Defines a macro that retries the given hardware RNG step until success or a maximum number of attempts. For "rdrand" it retries up to 10 times without a spin loop; for "rdseed" it retries up to 127 times with a spin_loop() between attempts. Returns Ok(el) on success or Err(ErrorCode::HardwareFailure) after exhausting retries. ```rust macro_rules! loop_rand { ("rdrand", $el: ty, $step: path) => {{ let mut idx = 0; #[allow(unused_unsafe)] loop { let mut el: $el = 0; if unsafe { $step(&mut el) } != 0 { break Ok(el); } else if idx == 10 { break Err(ErrorCode::HardwareFailure); } idx += 1; } }}; ("rdseed", $el: ty, $step: path) => {{ let mut idx = 0; #[allow(unused_unsafe)] loop { let mut el: $el = 0; if unsafe { $step(&mut el) } != 0 { break Ok(el); } else if idx == 127 { break Err(ErrorCode::HardwareFailure); } idx += 1; spin_loop(); } }}; } ``` -------------------------------- ### Rust: AArch64 RNG detection via sysctl, MRS, and fallbacks Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html Defines `has_rand()` for AArch64 with cfg-specific detection: macOS sysctl, Linux/Android/FreeBSD/NetBSD/UEFI MRS, and fallbacks for other OSes (including OpenBSD sysctl). Contains platform-specific code and FIXMEs. ```rust oldlenp: *mut usize, newp: *const core::ffi::c_void, newlen: usize, ) -> core::ffi::c_int; } unsafe { sysctlbyname(name.as_ptr(), &mut value, &mut size, core::ptr::null(), 0) == 0 && value != 0 } } #[cfg(any( target_os = "linux", target_os = "android", target_os = "freebsd", target_os = "netbsd", target_os = "none", target_os = "uefi"))] { let value: u64; unsafe { // MRS is a privileged instruction (EL1), // but it's emulated on Linux, FreeBSD and NetBSD. core::arch::asm!( "mrs {0}, ID_AA64ISAR0_EL1", // feature register out(reg) value, options(nostack) ); } (value & 0xF000_0000_0000_0000) != 0 } #[cfg(not(any( target_os = "linux", target_os = "android", target_os = "windows", target_os = "macos", target_os = "freebsd", target_os = "netbsd", target_os = "uefi", target_os = "none" )))] { #[cfg(feature = "std")] { extern crate std; std::arch::is_aarch64_feature_detected!("rand") } #[cfg(not(feature = "std"))] { #[cfg(target_os = "openbsd")] { // FIXME: Not tested. const CTL_MACHDEP: c_int = 7; const CPU_ID_AA64ISAR0: c_int = 2; let mib = [CTL_MACHDEP, CPU_ID_AA64ISAR0]; let mut isar0: u64 = 0; let mut len = core::mem::size_of_val(&isar0); let result = unsafe { libc::sysctl( mib.as_ptr(), mib.len() as u32, &mut isar0 as *mut _ as *mut c_void, &mut len, core::ptr::null_mut(), 0, ) }; if result == 0 { // Extract the RND field (bits 60-63) ((isar0 >> 60) & 0xF) >= 1 } else { false } } #[cfg(not(target_os = "openbsd"))] { // When we can't detect the feature, assume it's unavailable unless compiling with // `-Ctarget-feature=+rand` (in which case `has_rand` is bypassed altogether). // FIXME: Detection on iOS should be possible, but no known method is future-proof. false } } } ``` -------------------------------- ### Unit tests for ErrorCode trait implementations Source: https://docs.rs/rdrand/latest/src/rdrand/errors.rs.html Contains unit tests that verify ErrorCode implements Send, Sync, Copy, Clone, and Error traits at compile time. ```rust #[cfg(test)] mod test { use super::ErrorCode; use core::error::Error; #[test] fn error_code_send() { fn assert_send() {} assert_send::(); } #[test] fn error_code_sync() { fn assert_sync() {} assert_sync::(); } #[test] fn error_code_copy() { fn assert_copy() {} assert_copy::(); } #[test] fn error_code_clone() { fn assert_clone() {} assert_clone::(); } #[test] fn error_code_error() { fn assert_error() {} assert_error::(); } } ``` -------------------------------- ### Rust macro: is_available! for RDRAND, RAND, RDSEED Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html `is_available!` determines instruction availability for RDRAND/RAND/RDSEED. For RDRAND/RDSEED, it checks AMD family restrictions; for RAND, it only compiles on AArch64, using `has_rand()` or target features. Note that on non-AArch64 the `"rand"` arm is unreachable. ```rust macro_rules! is_available { ("rdrand") => {{ #[allow(unused_unsafe)] if authentic_amd() { let cpuid1 = unsafe { arch::__cpuid(1) }; has_rdrand(&cpuid1) && amd_family(&cpuid1) >= FIRST_GOOD_AMD_FAMILY } else { cfg!(target_feature = "rdrand") || has_rdrand(&unsafe { arch::__cpuid(1) }) } }}; ("rand") => {{ #[cfg(target_arch = "aarch64")] { cfg!(target_feature = "rand") || has_rand() } #[cfg(not(target_arch = "aarch64"))] { unreachable!() } }}; ("rdseed") => {{ #[allow(unused_unsafe)] if authentic_amd() { amd_family(&unsafe { arch::__cpuid(1) }) >= FIRST_GOOD_AMD_FAMILY && has_rdseed() } else { cfg!(target_feature = "rdrand") || has_rdseed() } }}; } ``` -------------------------------- ### RdRand::new_unchecked Source: https://docs.rs/rdrand/latest/rdrand/struct.RdRand.html Creates a new instance of the RdRand random number generator without checking CPU support. This is unsafe and the caller must ensure the CPU supports the instruction. ```APIDOC ## RdRand::new_unchecked ### Description Creates a new instance of the random number generator without checking CPU support. This constructor is unsafe because it does not check that the CPU supports the instruction, devolving this responsibility to the caller. ### Method new_unchecked ### Signature pub unsafe fn new_unchecked() -> Self ### Parameters None ### Returns - **Self** - A new RdRand instance. ### Safety This function is unsafe because it does not verify CPU support for the required instruction. ``` -------------------------------- ### RdSeed::new_unchecked Source: https://docs.rs/rdrand/latest/rdrand/struct.RdSeed.html Creates a new instance of the RdSeed random number generator without checking CPU support. This is unsafe and the caller must ensure the instruction is supported. ```APIDOC ## RdSeed::new_unchecked ### Description Creates a new instance of the RdSeed random number generator without checking CPU support. This is unsafe and the caller must ensure the instruction is supported. ### Method new_unchecked ### Signature pub unsafe fn new_unchecked() -> Self ### Parameters None ### Returns - Self - A new RdSeed instance. ### Safety This constructor is unsafe because it does not check that the CPU supports the instruction; the caller is responsible for ensuring support. ### Example ```rust let rng = unsafe { RdSeed::new_unchecked() }; ``` ``` -------------------------------- ### Rust: AMD family constant for RDRAND/RDSEED safety Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html Defines `FIRST_GOOD_AMD_FAMILY` as 0x17 and documents that older AMD processors (family < 0x17) can return non-random data from RDRAND/RDSEED. This constant is used to disable instructions on such hardware. ```rust #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] const FIRST_GOOD_AMD_FAMILY: u32 = 0x17; ``` -------------------------------- ### unsafe new_unchecked() -> Self Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html Creates a new instance of the random number generator without checking CPU support. The caller must ensure the instruction is available. ```APIDOC ## unsafe new_unchecked() -> Self ### Description Creates a new instance of the random number generator without checking CPU support. This is unsafe because it devolves the responsibility of checking instruction support to the caller. ### Method Constructor (unsafe) ### Parameters None ### Returns - **Self** - A new generator instance. ### Safety Caller must ensure the CPU supports the required instruction. ``` -------------------------------- ### Verify RdRand byte filling Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html This test verifies that RdRand correctly fills buffers of various sizes and alignments, ensuring that only the requested slice range is modified. ```rust #[repr(C, align(8))] struct FillBuffer([u8; 64]); #[test] fn fill_fills_all_bytes() { let _status = RdRand::new().map(|r| { let mut r = UnwrapErr(r); let mut test_buffer; let mut fill_buffer = FillBuffer([0; 64]); // make sure buffer is aligned to 8-bytes... let test_cases = [ (0, 64), // well aligned (8, 64), // well aligned (0, 64), // well aligned (5, 64), // left is non-empty, right is empty. (0, 63), // left is empty, right is non-empty. (5, 63), // left and right both are non-empty. (5, 61), // left and right both are non-empty. (0, 8), // 1 word-worth of data, aligned. (1, 9), // 1 word-worth of data, misaligned. (0, 7), // less than 1 word of data. (1, 7), // less than 1 word of data. ]; 'outer: for &(start, end) in &test_cases { test_buffer = [0; 64]; for _ in 0..512 { fill_buffer.0 = [0; 64]; r.fill_bytes(&mut fill_buffer.0[start..end]); for (b, p) in test_buffer.iter_mut().zip(fill_buffer.0.iter()) { *b = *b | *p; } if (&test_buffer[start..end]).iter().all(|x| *x != 0) { assert!( test_buffer[..start].iter().all(|x| *x == 0), "all other values must be 0" ); assert!( test_buffer[end..].iter().all(|x| *x == 0), "all other values must be 0" ); continue 'outer; } } panic!("wow, we broke it? {} {} {:?}", start, end, &test_buffer[..]) } }); #[cfg(any( all(target_feature = "rand", target_arch = "aarch64"), target_arch = "x86_64", target_arch = "x86" ))] _status.unwrap(); } ``` -------------------------------- ### ErrorCode enum and Display implementation Source: https://docs.rs/rdrand/latest/src/rdrand/errors.rs.html Defines the ErrorCode enum with UnsupportedInstruction and HardwareFailure variants, implements Display to provide human-readable messages, and implements the standard Error trait. ```rust use core::{ fmt::{self, Display, Formatter}, }; /// Errors in this library #[repr(u8)] #[derive(Debug, Copy, Clone)] pub enum ErrorCode { /// The hardware instruction is not supported UnsupportedInstruction, /// There was a hardware failure HardwareFailure, } impl core::error::Error for ErrorCode {} impl Display for ErrorCode { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.write_str(match self { ErrorCode::UnsupportedInstruction => "the hardware instruction is not supported", ErrorCode::HardwareFailure => "hardware generator failure", }) } } ``` -------------------------------- ### has_rand() on Windows using IsProcessorFeaturePresent Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html Detects RNDR support on aarch64 Windows by checking for ARMv8.1 atomic instructions via IsProcessorFeaturePresent with PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE. The comment warns this may falsely report availability on rare hardware because Windows lacks a specific RNDR check. ```rust #[cfg(target_arch = "aarch64")] #[inline(always)] fn has_rand() -> bool { #[cfg(target_os = "windows")] { // On Windows, use IsProcessorFeaturePresent use core::ffi::c_int; const PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE: c_int = 33; unsafe extern "C" { fn IsProcessorFeaturePresent(feature: c_int) -> i32; } // RNDR requires at least ARMv8.1, so check for atomic instructions // as a minimum. // FIXME: May falsely report available on rare hardware. Ideally Windows would have // a check specifically for RNDR. unsafe { IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE) != 0 } } #[cfg(any(target_os = "macos"))] { let mut value: u32 = 0; let mut size = core::mem::size_of::(); let name = b"hw.optional.arm.FEAT_RNG\0"; unsafe extern "C" { fn sysctlbyname( name: *const u8, oldp: *mut u32, ``` -------------------------------- ### aarch64 seed32() wrapper for RNDRRS Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html Calls the 64-bit seed() function and truncates the result to a 32-bit value. Returns the same status as seed(). ```rust #[cfg(target_arch = "aarch64")] pub(crate) unsafe fn seed32(out: &mut u32) -> i32 { let mut out64 = 0u64; let status = unsafe { seed(&mut out64) }; *out = out64 as u32; status } ``` -------------------------------- ### amd_family() CPUID family extraction Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html Extracts the AMD CPU family from a CPUID result by combining the base family (bits 8-11) and extended family (bits 20-27). Used to determine AMD-specific behavior. ```rust #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[inline(always)] fn amd_family(cpuid1: &arch::CpuidResult) -> u32 { ((cpuid1.eax >> 8) & 0xF) + ((cpuid1.eax >> 20) & 0xFF) } ``` -------------------------------- ### has_rdrand() CPUID flag check Source: https://docs.rs/rdrand/latest/src/rdrand/lib.rs.html Checks the CPUID ECX bit 30 to determine if the RDRAND instruction is available on x86/x86_64. ```rust #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[inline(always)] fn has_rdrand(cpuid1: &arch::CpuidResult) -> bool { const FLAG: u32 = 1 << 30; cpuid1.ecx & FLAG == FLAG } ```