1 // Copyright © 2014, Simonas Kazlauskas <rdrand@kazlauskas.me>
3 // Permission to use, copy, modify, and/or distribute this software for any purpose with or without
4 // fee is hereby granted, provided that the above copyright notice and this permission notice
5 // appear in all copies.
7 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
8 // SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
9 // AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
10 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
11 // NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
13 //! An implementation of random number generators based on `rdrand` and `rdseed` instructions.
15 //! The random number generators provided by this crate are fairly slow (the latency for these
16 //! instructions is pretty high), but provide high quality random bits. Caveat is: neither AMD’s
17 //! nor Intel’s designs are public and therefore are not verifiable for lack of backdoors.
19 //! Unless you know what you are doing, use the random number generators provided by the `rand`
20 //! crate (such as `OsRng`) instead.
22 //! Here are a measurements for select processor architectures. Check [Agner’s instruction tables]
23 //! for up-to-date listings.
27 //! <th>Architecture</th>
28 //! <th colspan="3">Latency (cycles)</th>
29 //! <th>Maximum throughput (per core)</th>
39 //! <td>AMD Ryzen</td>
43 //! <td>~12MB/s @ 3.7GHz</td>
46 //! <td>Intel Skylake</td>
50 //! <td>~72MB/s @ 4.2GHz</td>
53 //! <td>Intel Haswell</td>
57 //! <td>~110MB/s @ 4.4GHz</td>
61 //! [Agner’s instruction tables]: http://agner.org/optimize/
62 #![cfg_attr(not(feature = "std"), no_std)]
64 extern crate rand_core
;
66 #[cfg(feature = "std")]
71 use rand_core
::{RngCore, CryptoRng, Error, ErrorKind}
;
74 const RETRY_LIMIT
: u8 = 127;
78 pub(crate) fn busy_loop_fail() -> ! {
79 panic
!("hardware generator failure");
82 /// A cryptographically secure statistically uniform, non-periodic and non-deterministic random bit
85 /// Note that this generator may be implemented using a deterministic algorithm that is reseeded
86 /// routinely from a non-deterministic entropy source to achieve the desirable properties.
88 /// This generator is a viable replacement to any generator, however, since nobody has audited
89 /// Intel or AMD hardware yet, the usual disclaimers as to their suitability apply.
91 /// It is potentially faster than `OsRng`, but is only supported on more recent Intel (Ivy Bridge
92 /// and later) and AMD (Ryzen and later) processors.
93 #[derive(Clone, Copy)]
94 pub struct RdRand(());
96 /// A cryptographically secure non-deterministic random bit generator.
98 /// This generator produces high-entropy output and is suited to seed other pseudo-random
101 /// This instruction currently is only available in Intel Broadwell (and later) and AMD Ryzen
104 /// This generator is not intended for general random number generation purposes and should be used
105 /// to seed other generators implementing [rand_core::SeedableRng].
106 #[derive(Clone, Copy)]
107 pub struct RdSeed(());
109 impl CryptoRng
for RdRand {}
110 impl CryptoRng
for RdSeed {}
113 #[cfg(target_arch = "x86_64")]
114 pub use core
::arch
::x86_64
::*;
115 #[cfg(target_arch = "x86")]
116 pub use core
::arch
::x86
::*;
118 #[cfg(target_arch = "x86")]
119 pub(crate) unsafe fn _rdrand64_step(dest
: &mut u64) -> i32 {
120 let mut ret1
: u32 = ::core
::mem
::uninitialized();
121 let mut ret2
: u32 = ::core
::mem
::uninitialized();
122 if _rdrand32_step(&mut ret1
) != 0 && _rdrand32_step(&mut ret2
) != 0 {
123 *dest
= (ret1
as u64) << 32 | (ret2
as u64);
130 #[cfg(target_arch = "x86")]
131 pub(crate) unsafe fn _rdseed64_step(dest
: &mut u64) -> i32 {
132 let mut ret1
: u32 = ::core
::mem
::uninitialized();
133 let mut ret2
: u32 = ::core
::mem
::uninitialized();
134 if _rdseed32_step(&mut ret1
) != 0 && _rdseed32_step(&mut ret2
) != 0 {
135 *dest
= (ret1
as u64) << 32 | (ret2
as u64);
143 #[cfg(not(feature = "std"))]
144 macro_rules
! is_x86_feature_detected
{
146 if cfg
!(target_feature
="rdrand") {
148 } else if cfg
!(target_env
= "sgx") {
151 const FLAG
: u32 = 1 << 30;
152 unsafe { ::arch::__cpuid(1).ecx & FLAG == FLAG }
156 if cfg
!(target_feature
= "rdseed") {
158 } else if cfg
!(target_env
= "sgx") {
161 const FLAG
: u32 = 1 << 18;
162 unsafe { ::arch::__cpuid(7).ebx & FLAG == FLAG }
167 macro_rules
! loop_rand
{
168 ($el
: ty
, $step
: path
) => { {
171 let mut el
: $el
= ::core
::mem
::uninitialized();
172 if $
step(&mut el
) != 0 {
174 } else if idx
== RETRY_LIMIT
{
182 macro_rules
! impl_rand
{
183 ($gen
:ident
, $feat
:tt
, $step16
: path
, $step32
:path
, $step64
:path
,
184 maxstep
= $maxstep
:path
, maxty
= $maxty
: ty
) => {
186 /// Create a new instance of the random number generator.
188 /// This constructor checks whether the CPU the program is running on supports the
189 /// instruction necessary for this generator to operate. If the instruction is not
190 /// supported, an error is returned.
191 pub fn new() -> Result
<Self, Error
> {
192 if is_x86_feature_detected
!($feat
) {
195 Err(Error
::new(rand_core
::ErrorKind
::Unavailable
,
196 "the instruction is not supported"))
200 /// Generate a single random `u16` value.
202 /// The underlying instruction may fail for variety reasons (such as actual hardware
203 /// failure or exhausted entropy), however the exact reason for the failure is not
206 /// This method will retry calling the instruction a few times, however if all the
207 /// attempts fail, it will return `None`.
209 /// In case `None` is returned, the caller should assume that an non-recoverable
210 /// hardware failure has occured and use another random number genrator instead.
212 pub fn try_next_u16(&self) -> Option
<u16> {
213 #[target_feature(enable = $feat)]
216 loop_rand
!(u16, $step16
)
221 /// Generate a single random `u32` value.
223 /// The underlying instruction may fail for variety reasons (such as actual hardware
224 /// failure or exhausted entropy), however the exact reason for the failure is not
227 /// This method will retry calling the instruction a few times, however if all the
228 /// attempts fail, it will return `None`.
230 /// In case `None` is returned, the caller should assume that an non-recoverable
231 /// hardware failure has occured and use another random number genrator instead.
233 pub fn try_next_u32(&self) -> Option
<u32> {
234 #[target_feature(enable = $feat)]
237 loop_rand
!(u32, $step32
)
242 /// Generate a single random `u64` value.
244 /// The underlying instruction may fail for variety reasons (such as actual hardware
245 /// failure or exhausted entropy), however the exact reason for the failure is not
248 /// This method will retry calling the instruction a few times, however if all the
249 /// attempts fail, it will return `None`.
251 /// In case `None` is returned, the caller should assume that an non-recoverable
252 /// hardware failure has occured and use another random number genrator instead.
254 /// Note, that on 32-bit targets, there’s no underlying instruction to generate a
255 /// 64-bit number, so it is emulated with the 32-bit version of the instruction.
257 pub fn try_next_u64(&self) -> Option
<u64> {
258 #[target_feature(enable = $feat)]
261 loop_rand
!(u64, $step64
)
267 impl RngCore
for $gen
{
268 /// Generate a single random `u32` value.
270 /// The underlying instruction may fail for variety reasons (such as actual hardware
271 /// failure or exhausted entropy), however the exact reason for the failure is not
276 /// This method will retry calling the instruction a few times, however if all the
277 /// attempts fail, it will `panic`.
279 /// In case `panic` occurs, the caller should assume that an non-recoverable
280 /// hardware failure has occured and use another random number genrator instead.
282 fn next_u32(&mut self) -> u32 {
283 if let Some(result
) = self.try_next_u32() {
290 /// Generate a single random `u64` value.
292 /// The underlying instruction may fail for variety reasons (such as actual hardware
293 /// failure or exhausted entropy), however the exact reason for the failure is not
296 /// Note, that on 32-bit targets, there’s no underlying instruction to generate a
297 /// 64-bit number, so it is emulated with the 32-bit version of the instruction.
301 /// This method will retry calling the instruction a few times, however if all the
302 /// attempts fail, it will `panic`.
304 /// In case `panic` occurs, the caller should assume that an non-recoverable
305 /// hardware failure has occured and use another random number genrator instead.
307 fn next_u64(&mut self) -> u64 {
308 if let Some(result
) = self.try_next_u64() {
315 /// Fill a buffer `dest` with random data.
317 /// See `try_fill_bytes` for a more extensive documentation.
321 /// This method will panic any time `try_fill_bytes` would return an error.
323 fn fill_bytes(&mut self, dest
: &mut [u8]) {
324 if let Err(_
) = self.try_fill_bytes(dest
) {
329 /// Fill a buffer `dest` with random data.
331 /// This method will use the most appropriate variant of the instruction available on
332 /// the machine to achieve the greatest single-core throughput, however it has a
333 /// slightly higher setup cost than the plain `next_u32` or `next_u64` methods.
335 /// The underlying instruction may fail for variety reasons (such as actual hardware
336 /// failure or exhausted entropy), however the exact reason for the failure is not
339 /// This method will retry calling the instruction a few times, however if all the
340 /// attempts fail, it will return an error.
342 /// If an error is returned, the caller should assume that an non-recoverable hardware
343 /// failure has occured and use another random number genrator instead.
345 fn try_fill_bytes(&mut self, dest
: &mut [u8])
346 -> Result
<(), Error
> {
347 #[target_feature(enable = $feat)]
348 unsafe fn imp(dest
: &mut [u8])
351 unsafe fn imp_less_fast(mut dest
: &mut [u8], word
: &mut $maxty
,
355 while !dest
.is_empty() {
356 if buffer
.is_empty() {
357 if let Some(w
) = loop_rand
!($maxty
, $maxstep
) {
359 *buffer
= slice
::from_raw_parts(
360 word
as *const _
as *const u8,
361 ::core
::mem
::size_of
::<$maxty
>()
364 return Err(Error
::new(ErrorKind
::Unexpected
,
365 "hardware generator failure"));
369 let len
= dest
.len().min(buffer
.len());
370 let (copy_src
, leftover
) = buffer
.split_at(len
);
371 let (copy_dest
, dest_leftover
) = { dest }
.split_at_mut(len
);
373 dest
= dest_leftover
;
374 ::core
::ptr
::copy_nonoverlapping(
375 copy_src
.as_ptr(), copy_dest
.as_mut_ptr(), len
381 let destlen
= dest
.len();
382 if destlen
> ::core
::mem
::size_of
::<$maxty
>() {
383 let (left
, mid
, right
) = dest
.align_to_mut();
385 let mut buffer
: &[u8] = &[];
388 if let Some(val
) = loop_rand
!($maxty
, $maxstep
) {
391 return Err(Error
::new(ErrorKind
::Unexpected
,
392 "hardware generator failure"));
396 imp_less_fast(left
, &mut word
, &mut buffer
)?
;
397 imp_less_fast(right
, &mut word
, &mut buffer
)
400 let mut buffer
: &[u8] = &[];
401 imp_less_fast(dest
, &mut word
, &mut buffer
)
410 #[cfg(target_arch = "x86_64")]
411 impl_rand
!(RdRand
, "rdrand",
412 ::arch
::_rdrand16_step
, ::arch
::_rdrand32_step
, ::arch
::_rdrand64_step
,
413 maxstep
= ::arch
::_rdrand64_step
, maxty
= u64);
414 #[cfg(target_arch = "x86_64")]
415 impl_rand
!(RdSeed
, "rdseed",
416 ::arch
::_rdseed16_step
, ::arch
::_rdseed32_step
, ::arch
::_rdseed64_step
,
417 maxstep
= ::arch
::_rdseed64_step
, maxty
= u64);
418 #[cfg(target_arch = "x86")]
419 impl_rand
!(RdRand
, "rdrand",
420 ::arch
::_rdrand16_step
, ::arch
::_rdrand32_step
, ::arch
::_rdrand64_step
,
421 maxstep
= ::arch
::_rdrand32_step
, maxty
= u32);
422 #[cfg(target_arch = "x86")]
423 impl_rand
!(RdSeed
, "rdseed",
424 ::arch
::_rdseed16_step
, ::arch
::_rdseed32_step
, ::arch
::_rdseed64_step
,
425 maxstep
= ::arch
::_rdseed32_step
, maxty
= u32);
429 let _
= RdRand
::new().map(|mut r
| {
436 fn fill_fills_all_bytes() {
437 let _
= RdRand
::new().map(|mut r
| {
442 'outer
: while start
< end
{
446 r
.fill_bytes(&mut peach
[start
..end
]);
447 for (b
, p
) in banana
.iter_mut().zip(peach
.iter()) {
450 if (&banana
[start
..end
]).iter().all(|x
| *x
!= 0) {
451 assert
!(banana
[..start
].iter().all(|x
| *x
== 0), "all other values must be 0");
452 assert
!(banana
[end
..].iter().all(|x
| *x
== 0), "all other values must be 0");
461 panic
!("wow, we broke it? {} {} {:?}", start
, end
, &banana
[..])
468 let _
= RdSeed
::new().map(|mut r
| {