Coverage Report

Created: 2026-04-01 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/x86-0.47.0/src/random.rs
Line
Count
Source
1
//! Instructions to generate random bits directly from the hardware (RDRAND and RDSEED).
2
//!
3
//! The decision process for which instruction to use is based on what
4
//! the output will be used for. If you wish to seed another pseudorandom
5
//! number generator (PRNG), use RDSEED. For all other purposes, use RDRAND
6
//!
7
//! See also: https://software.intel.com/en-us/blogs/2012/11/17/the-difference-between-rdrand-and-rdseed
8
//!
9
//! * RDRAND: Cryptographically secure pseudorandom number generator NIST:SP 800-90A
10
//! * RDSEED: Non-deterministic random bit generator NIST: SP 800-90B & C (drafts)
11
#[cfg(target_arch = "x86_64")]
12
use core::arch::x86_64::{
13
    _rdrand16_step, _rdrand32_step, _rdrand64_step, _rdseed16_step, _rdseed32_step, _rdseed64_step,
14
};
15
16
#[cfg(target_arch = "x86")]
17
use core::arch::x86::{_rdrand16_step, _rdrand32_step, _rdseed16_step, _rdseed32_step};
18
19
/// Generates a 16-bit random value and stores it in `e`.
20
///
21
/// # Safety
22
/// Will crash if RDRAND instructions are not supported.
23
#[inline(always)]
24
0
pub unsafe fn rdrand16(e: &mut u16) -> bool {
25
0
    _rdrand16_step(e) == 1
26
0
}
27
28
/// Generates a 32-bit random value and stores it in `e`.
29
///
30
/// # Safety
31
/// Will crash if RDRAND instructions are not supported.
32
#[inline(always)]
33
0
pub unsafe fn rdrand32(e: &mut u32) -> bool {
34
0
    _rdrand32_step(e) == 1
35
0
}
36
37
/// Generates a 64-bit random value and stores it in `e`.
38
///
39
/// # Safety
40
/// Will crash if RDRAND instructions are not supported.
41
#[cfg(target_arch = "x86_64")]
42
#[inline(always)]
43
0
pub unsafe fn rdrand64(e: &mut u64) -> bool {
44
0
    _rdrand64_step(e) == 1
45
0
}
46
47
/// RdRand trait to implement the generic rdrand_slice function.
48
pub trait RdRand {
49
    /// Fills `self` with random bits. Returns true on success or false otherwise
50
    ///
51
    /// # Safety
52
    /// RDRAND is not supported on all architctures, so using this may crash you.
53
    unsafe fn fill_random(&mut self) -> bool;
54
}
55
56
impl RdRand for u8 {
57
    /// Fills the 16-bit value with a random bit string
58
    ///
59
    /// # Safety
60
    /// Will crash if RDSEED instructions are not supported.
61
0
    unsafe fn fill_random(&mut self) -> bool {
62
0
        let mut r: u16 = 0;
63
0
        let ret = rdrand16(&mut r);
64
0
        *self = r as u8;
65
0
        ret
66
0
    }
67
}
68
69
impl RdRand for u16 {
70
    /// Fills the 16-bit value with a random bit string
71
    ///
72
    /// # Safety
73
    /// Will crash if RDRAND instructions are not supported.
74
0
    unsafe fn fill_random(&mut self) -> bool {
75
0
        rdrand16(self)
76
0
    }
77
}
78
79
impl RdRand for u32 {
80
    /// Fills the 32-bit value with a random bit string
81
    ///
82
    /// # Safety
83
    /// Will crash if RDRAND instructions are not supported.
84
0
    unsafe fn fill_random(&mut self) -> bool {
85
0
        rdrand32(self)
86
0
    }
87
}
88
89
#[cfg(target_arch = "x86_64")]
90
impl RdRand for u64 {
91
    /// Fills the 64-bit value with a random bit string
92
    ///
93
    /// # Safety
94
    /// Will crash if RDRAND instructions are not supported.
95
0
    unsafe fn fill_random(&mut self) -> bool {
96
0
        rdrand64(self)
97
0
    }
98
}
99
100
/// Fill a slice with random values.
101
///
102
/// Returns true if the iterator was successfully filled with
103
/// random values, otherwise false.
104
/// # Safety
105
/// Will crash if RDRAND instructions are not supported.
106
0
pub unsafe fn rdrand_slice<T: RdRand>(buffer: &mut [T]) -> bool {
107
0
    let mut worked = true;
108
0
    for element in buffer {
109
0
        worked &= element.fill_random();
110
0
    }
111
0
    worked
112
0
}
113
114
/// Generates a 16-bit random value and stores it in `e`.
115
///
116
/// # Safety
117
/// Will crash if RDSEED instructions are not supported.
118
#[inline(always)]
119
0
pub unsafe fn rdseed16(e: &mut u16) -> bool {
120
0
    _rdseed16_step(e) == 1
121
0
}
122
123
/// Generates a 32-bit random value and stores it in `e`.
124
///
125
/// # Safety
126
/// Will crash if RDSEED instructions are not supported.
127
#[inline(always)]
128
0
pub unsafe fn rdseed32(e: &mut u32) -> bool {
129
0
    _rdseed32_step(e) == 1
130
0
}
131
132
/// Generates a 64-bit random value and stores it in `e`.
133
///
134
/// # Safety
135
/// Will crash if RDSEED instructions are not supported.
136
#[cfg(target_arch = "x86_64")]
137
#[inline(always)]
138
0
pub unsafe fn rdseed64(e: &mut u64) -> bool {
139
0
    _rdseed64_step(e) == 1
140
0
}
141
142
/// RdSeed trait to implement the generic rdseed_slice function.
143
pub trait RdSeed {
144
    /// Fills `self` with random bits. Returns true on success or false otherwise
145
    ///
146
    /// # Safety
147
    /// RDSEED is not supported on all architctures, so using this may crash you.
148
    unsafe fn fill_random(&mut self) -> bool;
149
}
150
151
impl RdSeed for u8 {
152
    /// Fills the 16-bit value with a random bit string
153
    ///
154
    /// # Safety
155
    /// Will crash if RDSEED instructions are not supported.
156
0
    unsafe fn fill_random(&mut self) -> bool {
157
0
        let mut r: u16 = 0;
158
0
        let ret = rdseed16(&mut r);
159
0
        *self = r as u8;
160
0
        ret
161
0
    }
162
}
163
164
impl RdSeed for u16 {
165
    /// Fills the 16-bit value with a random bit string
166
    ///
167
    /// # Safety
168
    /// Will crash if RDSEED instructions are not supported.
169
0
    unsafe fn fill_random(&mut self) -> bool {
170
0
        rdseed16(self)
171
0
    }
172
}
173
174
impl RdSeed for u32 {
175
    /// Fills the 32-bit value with a random bit string
176
    ///
177
    /// # Safety
178
    /// Will crash if RDSEED instructions are not supported.
179
0
    unsafe fn fill_random(&mut self) -> bool {
180
0
        rdseed32(self)
181
0
    }
182
}
183
184
#[cfg(target_arch = "x86_64")]
185
impl RdSeed for u64 {
186
    /// Fills the 64-bit value with a random bit string
187
    ///
188
    /// # Safety
189
    /// Will crash if RDSEED instructions are not supported.
190
0
    unsafe fn fill_random(&mut self) -> bool {
191
0
        rdseed64(self)
192
0
    }
193
}
194
195
/// Fill a slice with random values.
196
///
197
/// Returns true if the iterator was successfully filled with
198
/// random values, otherwise false.
199
///
200
/// # Safety
201
/// Will crash if RDSEED instructions are not supported.
202
0
pub unsafe fn rdseed_slice<T: RdSeed>(buffer: &mut [T]) -> bool {
203
0
    let mut worked = true;
204
0
    for element in buffer {
205
0
        worked &= element.fill_random();
206
0
    }
207
0
    worked
208
0
}
209
210
#[cfg(all(test, feature = "utest"))]
211
mod test {
212
    use super::*;
213
214
    #[test]
215
    fn rdrand_u64() {
216
        let has_rdrand = crate::cpuid::CpuId::new()
217
            .get_feature_info()
218
            .map_or(false, |finfo| finfo.has_rdrand());
219
        if !has_rdrand {
220
            return;
221
        }
222
223
        unsafe {
224
            let mut buf: [u64; 4] = [0, 0, 0, 0];
225
            rdrand_slice(&mut buf);
226
227
            assert_ne!(buf[0], 0);
228
            assert_ne!(buf[1], 0);
229
            assert_ne!(buf[2], 0);
230
            assert_ne!(buf[3], 0);
231
        }
232
    }
233
234
    #[test]
235
    fn rdrand_u32() {
236
        let has_rdrand = crate::cpuid::CpuId::new()
237
            .get_feature_info()
238
            .map_or(false, |finfo| finfo.has_rdrand());
239
        if !has_rdrand {
240
            return;
241
        }
242
243
        unsafe {
244
            let mut buf: [u32; 4] = [0, 0, 0, 0];
245
            rdrand_slice(&mut buf);
246
247
            assert_ne!(buf[0], 0);
248
            assert_ne!(buf[1], 0);
249
            assert_ne!(buf[2], 0);
250
            assert_ne!(buf[3], 0);
251
        }
252
    }
253
254
    #[test]
255
    fn rdrand_u16() {
256
        let has_rdrand = crate::cpuid::CpuId::new()
257
            .get_feature_info()
258
            .map_or(false, |finfo| finfo.has_rdrand());
259
        if !has_rdrand {
260
            return;
261
        }
262
263
        unsafe {
264
            let mut buf: [u16; 4] = [0, 0, 0, 0];
265
            rdrand_slice(&mut buf);
266
            assert_ne!(buf[0], 0);
267
            assert_ne!(buf[1], 0);
268
            assert_ne!(buf[2], 0);
269
            assert_ne!(buf[3], 0);
270
        }
271
    }
272
273
    #[test]
274
    fn rdseed_u64() {
275
        let has_rdseed = crate::cpuid::CpuId::new()
276
            .get_extended_feature_info()
277
            .map_or(false, |efinfo| efinfo.has_rdseed());
278
        if !has_rdseed {
279
            return;
280
        }
281
282
        unsafe {
283
            let mut buf: [u64; 4] = [0, 0, 0, 0];
284
            rdseed_slice(&mut buf);
285
286
            assert_ne!(buf[0], 0);
287
            assert_ne!(buf[1], 0);
288
            assert_ne!(buf[2], 0);
289
            assert_ne!(buf[3], 0);
290
        }
291
    }
292
293
    #[test]
294
    fn rdseed_u32() {
295
        let has_rdseed = crate::cpuid::CpuId::new()
296
            .get_extended_feature_info()
297
            .map_or(false, |efinfo| efinfo.has_rdseed());
298
        if !has_rdseed {
299
            return;
300
        }
301
302
        unsafe {
303
            let mut buf: [u32; 4] = [0, 0, 0, 0];
304
            rdseed_slice(&mut buf);
305
306
            assert_ne!(buf[0], 0);
307
            assert_ne!(buf[1], 0);
308
            assert_ne!(buf[2], 0);
309
            assert_ne!(buf[3], 0);
310
        }
311
    }
312
313
    #[test]
314
    fn rdseed_u16() {
315
        let has_rdseed = crate::cpuid::CpuId::new()
316
            .get_extended_feature_info()
317
            .map_or(false, |efinfo| efinfo.has_rdseed());
318
        if !has_rdseed {
319
            return;
320
        }
321
322
        unsafe {
323
            let mut buf: [u16; 4] = [0, 0, 0, 0];
324
            rdseed_slice(&mut buf);
325
            // Not the best test in the world, but unlikely enough to fail...
326
            assert!(buf[0] > 0 || buf[1] > 0 || buf[2] > 0 || buf[3] > 0);
327
        }
328
    }
329
330
    #[test]
331
    fn rdrand_u8() {
332
        let has_rdseed = crate::cpuid::CpuId::new()
333
            .get_extended_feature_info()
334
            .map_or(false, |efinfo| efinfo.has_rdseed());
335
        if !has_rdseed {
336
            return;
337
        }
338
339
        unsafe {
340
            let mut buf: [u8; 4] = [0, 0, 0, 0];
341
            rdrand_slice(&mut buf);
342
            // Not the best test in the world, but unlikely enough to fail...
343
            assert!(buf[0] > 0 || buf[1] > 0 || buf[2] > 0 || buf[3] > 0);
344
        }
345
    }
346
347
    #[test]
348
    fn rdseed_u8() {
349
        let has_rdseed = crate::cpuid::CpuId::new()
350
            .get_extended_feature_info()
351
            .map_or(false, |efinfo| efinfo.has_rdseed());
352
        if !has_rdseed {
353
            return;
354
        }
355
356
        unsafe {
357
            let mut buf: [u8; 4] = [0, 0, 0, 0];
358
            rdseed_slice(&mut buf);
359
            // Not the best test in the world, but unlikely enough to fail...
360
            assert!(buf[0] > 0 || buf[1] > 0 || buf[2] > 0 || buf[3] > 0);
361
        }
362
    }
363
}