]> git.proxmox.com Git - cargo.git/blob - vendor/rdrand/src/lib.rs
New upstream version 0.33.0
[cargo.git] / vendor / rdrand / src / lib.rs
1 // Copyright © 2014, Simonas Kazlauskas <rdrand@kazlauskas.me>
2 //
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.
6 //
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
12 // OF THIS SOFTWARE.
13 //! An implementation of random number generators based on `rdrand` and `rdseed` instructions.
14 //!
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.
18 //!
19 //! Unless you know what you are doing, use the random number generators provided by the `rand`
20 //! crate (such as `OsRng`) instead.
21 //!
22 //! Here are a measurements for select processor architectures. Check [Agner’s instruction tables]
23 //! for up-to-date listings.
24 //!
25 //! <table>
26 //! <tr>
27 //! <th>Architecture</th>
28 //! <th colspan="3">Latency (cycles)</th>
29 //! <th>Maximum throughput (per core)</th>
30 //! </tr>
31 //! <tr>
32 //! <td></td>
33 //! <td>u16</td>
34 //! <td>u32</td>
35 //! <td>u64</td>
36 //! <td></td>
37 //! </tr>
38 //! <tr>
39 //! <td>AMD Ryzen</td>
40 //! <td>~1200</td>
41 //! <td>~1200</td>
42 //! <td>~2500</td>
43 //! <td>~12MB/s @ 3.7GHz</td>
44 //! </tr>
45 //! <tr>
46 //! <td>Intel Skylake</td>
47 //! <td>460</td>
48 //! <td>460</td>
49 //! <td>460</td>
50 //! <td>~72MB/s @ 4.2GHz</td>
51 //! </tr>
52 //! <tr>
53 //! <td>Intel Haswell</td>
54 //! <td>320</td>
55 //! <td>320</td>
56 //! <td>320</td>
57 //! <td>~110MB/s @ 4.4GHz</td>
58 //! </tr>
59 //! </table>
60 //!
61 //! [Agner’s instruction tables]: http://agner.org/optimize/
62 #![cfg_attr(not(feature = "std"), no_std)]
63
64 extern crate rand_core;
65
66 #[cfg(feature = "std")]
67 extern crate core;
68
69 pub mod changelog;
70
71 use rand_core::{RngCore, CryptoRng, Error, ErrorKind};
72 use core::slice;
73
74 const RETRY_LIMIT: u8 = 127;
75
76 #[cold]
77 #[inline(never)]
78 pub(crate) fn busy_loop_fail() -> ! {
79 panic!("hardware generator failure");
80 }
81
82 /// A cryptographically secure statistically uniform, non-periodic and non-deterministic random bit
83 /// generator.
84 ///
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.
87 ///
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.
90 ///
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(());
95
96 /// A cryptographically secure non-deterministic random bit generator.
97 ///
98 /// This generator produces high-entropy output and is suited to seed other pseudo-random
99 /// generators.
100 ///
101 /// This instruction currently is only available in Intel Broadwell (and later) and AMD Ryzen
102 /// processors.
103 ///
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(());
108
109 impl CryptoRng for RdRand {}
110 impl CryptoRng for RdSeed {}
111
112 mod arch {
113 #[cfg(target_arch = "x86_64")]
114 pub use core::arch::x86_64::*;
115 #[cfg(target_arch = "x86")]
116 pub use core::arch::x86::*;
117
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);
124 1
125 } else {
126 0
127 }
128 }
129
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);
136 1
137 } else {
138 0
139 }
140 }
141 }
142
143 #[cfg(not(feature = "std"))]
144 macro_rules! is_x86_feature_detected {
145 ("rdrand") => {{
146 if cfg!(target_feature="rdrand") {
147 true
148 } else if cfg!(target_env = "sgx") {
149 false
150 } else {
151 const FLAG : u32 = 1 << 30;
152 unsafe { ::arch::__cpuid(1).ecx & FLAG == FLAG }
153 }
154 }};
155 ("rdseed") => {{
156 if cfg!(target_feature = "rdseed") {
157 true
158 } else if cfg!(target_env = "sgx") {
159 false
160 } else {
161 const FLAG : u32 = 1 << 18;
162 unsafe { ::arch::__cpuid(7).ebx & FLAG == FLAG }
163 }
164 }};
165 }
166
167 macro_rules! loop_rand {
168 ($el: ty, $step: path) => { {
169 let mut idx = 0;
170 loop {
171 let mut el: $el = ::core::mem::uninitialized();
172 if $step(&mut el) != 0 {
173 break Some(el);
174 } else if idx == RETRY_LIMIT {
175 break None;
176 }
177 idx += 1;
178 }
179 } }
180 }
181
182 macro_rules! impl_rand {
183 ($gen:ident, $feat:tt, $step16: path, $step32:path, $step64:path,
184 maxstep = $maxstep:path, maxty = $maxty: ty) => {
185 impl $gen {
186 /// Create a new instance of the random number generator.
187 ///
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) {
193 Ok($gen(()))
194 } else {
195 Err(Error::new(rand_core::ErrorKind::Unavailable,
196 "the instruction is not supported"))
197 }
198 }
199
200 /// Generate a single random `u16` value.
201 ///
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
204 /// usually exposed.
205 ///
206 /// This method will retry calling the instruction a few times, however if all the
207 /// attempts fail, it will return `None`.
208 ///
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.
211 #[inline(always)]
212 pub fn try_next_u16(&self) -> Option<u16> {
213 #[target_feature(enable = $feat)]
214 unsafe fn imp()
215 -> Option<u16> {
216 loop_rand!(u16, $step16)
217 }
218 unsafe { imp() }
219 }
220
221 /// Generate a single random `u32` value.
222 ///
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
225 /// usually exposed.
226 ///
227 /// This method will retry calling the instruction a few times, however if all the
228 /// attempts fail, it will return `None`.
229 ///
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.
232 #[inline(always)]
233 pub fn try_next_u32(&self) -> Option<u32> {
234 #[target_feature(enable = $feat)]
235 unsafe fn imp()
236 -> Option<u32> {
237 loop_rand!(u32, $step32)
238 }
239 unsafe { imp() }
240 }
241
242 /// Generate a single random `u64` value.
243 ///
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
246 /// usually exposed.
247 ///
248 /// This method will retry calling the instruction a few times, however if all the
249 /// attempts fail, it will return `None`.
250 ///
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.
253 ///
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.
256 #[inline(always)]
257 pub fn try_next_u64(&self) -> Option<u64> {
258 #[target_feature(enable = $feat)]
259 unsafe fn imp()
260 -> Option<u64> {
261 loop_rand!(u64, $step64)
262 }
263 unsafe { imp() }
264 }
265 }
266
267 impl RngCore for $gen {
268 /// Generate a single random `u32` value.
269 ///
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
272 /// usually exposed.
273 ///
274 /// # Panic
275 ///
276 /// This method will retry calling the instruction a few times, however if all the
277 /// attempts fail, it will `panic`.
278 ///
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.
281 #[inline(always)]
282 fn next_u32(&mut self) -> u32 {
283 if let Some(result) = self.try_next_u32() {
284 result
285 } else {
286 busy_loop_fail()
287 }
288 }
289
290 /// Generate a single random `u64` value.
291 ///
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
294 /// usually exposed.
295 ///
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.
298 ///
299 /// # Panic
300 ///
301 /// This method will retry calling the instruction a few times, however if all the
302 /// attempts fail, it will `panic`.
303 ///
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.
306 #[inline(always)]
307 fn next_u64(&mut self) -> u64 {
308 if let Some(result) = self.try_next_u64() {
309 result
310 } else {
311 busy_loop_fail()
312 }
313 }
314
315 /// Fill a buffer `dest` with random data.
316 ///
317 /// See `try_fill_bytes` for a more extensive documentation.
318 ///
319 /// # Panic
320 ///
321 /// This method will panic any time `try_fill_bytes` would return an error.
322 #[inline(always)]
323 fn fill_bytes(&mut self, dest: &mut [u8]) {
324 if let Err(_) = self.try_fill_bytes(dest) {
325 busy_loop_fail()
326 }
327 }
328
329 /// Fill a buffer `dest` with random data.
330 ///
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.
334 ///
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
337 /// usually exposed.
338 ///
339 /// This method will retry calling the instruction a few times, however if all the
340 /// attempts fail, it will return an error.
341 ///
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.
344 #[inline(always)]
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])
349 -> Result<(), Error>
350 {
351 unsafe fn imp_less_fast(mut dest: &mut [u8], word: &mut $maxty,
352 buffer: &mut &[u8])
353 -> Result<(), Error>
354 {
355 while !dest.is_empty() {
356 if buffer.is_empty() {
357 if let Some(w) = loop_rand!($maxty, $maxstep) {
358 *word = w;
359 *buffer = slice::from_raw_parts(
360 word as *const _ as *const u8,
361 ::core::mem::size_of::<$maxty>()
362 );
363 } else {
364 return Err(Error::new(ErrorKind::Unexpected,
365 "hardware generator failure"));
366 }
367 }
368
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);
372 *buffer = leftover;
373 dest = dest_leftover;
374 ::core::ptr::copy_nonoverlapping(
375 copy_src.as_ptr(), copy_dest.as_mut_ptr(), len
376 );
377 }
378 Ok(())
379 }
380
381 let destlen = dest.len();
382 if destlen > ::core::mem::size_of::<$maxty>() {
383 let (left, mid, right) = dest.align_to_mut();
384 let mut word = 0;
385 let mut buffer: &[u8] = &[];
386
387 for el in mid {
388 if let Some(val) = loop_rand!($maxty, $maxstep) {
389 *el = val;
390 } else {
391 return Err(Error::new(ErrorKind::Unexpected,
392 "hardware generator failure"));
393 }
394 }
395
396 imp_less_fast(left, &mut word, &mut buffer)?;
397 imp_less_fast(right, &mut word, &mut buffer)
398 } else {
399 let mut word = 0;
400 let mut buffer: &[u8] = &[];
401 imp_less_fast(dest, &mut word, &mut buffer)
402 }
403 }
404 unsafe { imp(dest) }
405 }
406 }
407 }
408 }
409
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);
426
427 #[test]
428 fn rdrand_works() {
429 let _ = RdRand::new().map(|mut r| {
430 r.next_u32();
431 r.next_u64();
432 });
433 }
434
435 #[test]
436 fn fill_fills_all_bytes() {
437 let _ = RdRand::new().map(|mut r| {
438 let mut peach;
439 let mut banana;
440 let mut start = 0;
441 let mut end = 128;
442 'outer: while start < end {
443 banana = [0; 128];
444 for _ in 0..512 {
445 peach = [0; 128];
446 r.fill_bytes(&mut peach[start..end]);
447 for (b, p) in banana.iter_mut().zip(peach.iter()) {
448 *b = *b | *p;
449 }
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");
453 if start < 17 {
454 start += 1;
455 } else {
456 end -= 3;
457 }
458 continue 'outer;
459 }
460 }
461 panic!("wow, we broke it? {} {} {:?}", start, end, &banana[..])
462 }
463 });
464 }
465
466 #[test]
467 fn rdseed_works() {
468 let _ = RdSeed::new().map(|mut r| {
469 r.next_u32();
470 r.next_u64();
471 });
472 }