x86_64/instructions/
random.rs

1//! Support for build-in RNGs
2
3#[derive(Copy, Clone, Debug)]
4/// Used to obtain random numbers using x86_64's RDRAND opcode
5pub struct RdRand(());
6
7impl RdRand {
8    /// Creates Some(RdRand) if RDRAND is supported, None otherwise
9    #[inline]
10    pub fn new() -> Option<Self> {
11        // RDRAND support indicated by CPUID page 01h, ecx bit 30
12        // https://en.wikipedia.org/wiki/RdRand#Overview
13        let cpuid = unsafe { core::arch::x86_64::__cpuid(0x1) };
14        if cpuid.ecx & (1 << 30) != 0 {
15            Some(RdRand(()))
16        } else {
17            None
18        }
19    }
20
21    /// Uniformly sampled u64.
22    /// May fail in rare circumstances or heavy load.
23    #[inline]
24    pub fn get_u64(self) -> Option<u64> {
25        let mut res: u64 = 0;
26        unsafe {
27            match core::arch::x86_64::_rdrand64_step(&mut res) {
28                1 => Some(res),
29                x => {
30                    debug_assert_eq!(x, 0, "rdrand64 returned non-binary value");
31                    None
32                }
33            }
34        }
35    }
36    /// Uniformly sampled u32.
37    /// May fail in rare circumstances or heavy load.
38    #[inline]
39    pub fn get_u32(self) -> Option<u32> {
40        let mut res: u32 = 0;
41        unsafe {
42            match core::arch::x86_64::_rdrand32_step(&mut res) {
43                1 => Some(res),
44                x => {
45                    debug_assert_eq!(x, 0, "rdrand32 returned non-binary value");
46                    None
47                }
48            }
49        }
50    }
51    /// Uniformly sampled u16.
52    /// May fail in rare circumstances or heavy load.
53    #[inline]
54    pub fn get_u16(self) -> Option<u16> {
55        let mut res: u16 = 0;
56        unsafe {
57            match core::arch::x86_64::_rdrand16_step(&mut res) {
58                1 => Some(res),
59                x => {
60                    debug_assert_eq!(x, 0, "rdrand16 returned non-binary value");
61                    None
62                }
63            }
64        }
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71
72    #[test]
73    pub fn test_rdrand() {
74        let rand = RdRand::new();
75        if is_x86_feature_detected!("rdrand") {
76            let rand = rand.unwrap();
77            assert!(rand.get_u16().is_some());
78            assert!(rand.get_u32().is_some());
79            assert!(rand.get_u64().is_some());
80        } else {
81            assert!(rand.is_none());
82        }
83    }
84}