rand_jitter/lib.rs
1// Copyright 2018 Developers of the Rand project.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8//
9// Based on jitterentropy-library, http://www.chronox.de/jent.html.
10// Copyright Stephan Mueller <smueller@chronox.de>, 2014 - 2017.
11//
12// With permission from Stephan Mueller to relicense the Rust translation under
13// the MIT license.
14
15//! Non-physical true random number generator based on timing jitter.
16//!
17//! Note that this RNG is not suited for use cases where cryptographic security is
18//! required (also see this [discussion]).
19//!
20//! This is a true random number generator, as opposed to pseudo-random
21//! generators. Random numbers generated by `JitterRng` can be seen as fresh
22//! entropy. A consequence is that it is orders of magnitude slower than `OsRng`
23//! and PRNGs (about 10<sup>3</sup>..10<sup>6</sup> slower).
24//!
25//! There are very few situations where using this RNG is appropriate. Only very
26//! few applications require true entropy. A normal PRNG can be statistically
27//! indistinguishable, and a cryptographic PRNG should also be as impossible to
28//! predict.
29//!
30//! `JitterRng` can be used without the standard library, but not conveniently,
31//! you must provide a high-precision timer and carefully have to follow the
32//! instructions of [`JitterRng::new_with_timer`].
33//!
34//! This implementation is based on [Jitterentropy] version 2.1.0.
35//!
36//! Note: There is no accurate timer available on WASM platforms, to help
37//! prevent fingerprinting or timing side-channel attacks. Therefore
38//! [`JitterRng::new()`] is not available on WASM. It is also unavailable
39//! with disabled `std` feature.
40//!
41//! [Jitterentropy]: http://www.chronox.de/jent.html
42//! [discussion]: https://github.com/rust-random/rand/issues/699
43
44#![doc(
45 html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
46 html_favicon_url = "https://www.rust-lang.org/favicon.ico",
47 html_root_url = "https://rust-random.github.io/rand/"
48)]
49#![deny(missing_docs)]
50#![deny(missing_debug_implementations)]
51#![doc(test(attr(allow(unused_variables), deny(warnings))))]
52// Note: the C implementation of `Jitterentropy` relies on being compiled
53// without optimizations. This implementation goes through lengths to make the
54// compiler not optimize out code which does influence timing jitter, but is
55// technically dead code.
56#![no_std]
57#[cfg(feature = "std")]
58extern crate std;
59
60pub use rand_core;
61
62// Coming from https://crates.io/crates/doc-comment
63#[cfg(test)]
64macro_rules! doc_comment {
65 ($x:expr) => {
66 #[doc = $x]
67 fn _doc_comment() {}
68 };
69}
70
71#[cfg(test)]
72doc_comment!(include_str!("../README.md"));
73
74#[allow(unused)]
75macro_rules! trace { ($($x:tt)*) => (
76 #[cfg(feature = "log")] {
77 log::trace!($($x)*)
78 }
79) }
80#[allow(unused)]
81macro_rules! debug { ($($x:tt)*) => (
82 #[cfg(feature = "log")] {
83 log::debug!($($x)*)
84 }
85) }
86#[allow(unused)]
87macro_rules! info { ($($x:tt)*) => (
88 #[cfg(feature = "log")] {
89 log::info!($($x)*)
90 }
91) }
92#[allow(unused)]
93macro_rules! warn { ($($x:tt)*) => (
94 #[cfg(feature = "log")] {
95 log::warn!($($x)*)
96 }
97) }
98#[allow(unused)]
99macro_rules! error { ($($x:tt)*) => (
100 #[cfg(feature = "log")] {
101 log::error!($($x)*)
102 }
103) }
104
105mod error;
106#[cfg(feature = "std")]
107mod platform;
108
109pub use crate::error::TimerError;
110use rand_core::{impls, RngCore};
111
112use core::{fmt, mem, ptr};
113#[cfg(feature = "std")]
114use std::sync::atomic::{AtomicUsize, Ordering};
115
116const MEMORY_BLOCKS: usize = 64;
117const MEMORY_BLOCKSIZE: usize = 32;
118const MEMORY_SIZE: usize = MEMORY_BLOCKS * MEMORY_BLOCKSIZE;
119
120/// A true random number generator based on jitter in the CPU execution time,
121/// and jitter in memory access time.
122///
123/// Note that this RNG is not suitable for use cases where cryptographic
124/// security is required.
125pub struct JitterRng<F> {
126 data: u64, // Actual random number
127 // Number of rounds to run the entropy collector per 64 bits
128 rounds: u8,
129 // Timer used by `measure_jitter`
130 timer: F,
131 // Memory for the Memory Access noise source
132 mem_prev_index: u16,
133 // Make `next_u32` not waste 32 bits
134 data_half_used: bool,
135}
136
137// Note: `JitterRng` maintains a small 64-bit entropy pool. With every
138// `generate` 64 new bits should be integrated in the pool. If a round of
139// `generate` were to collect less than the expected 64 bit, then the returned
140// value, and the new state of the entropy pool, would be in some way related to
141// the initial state. It is therefore better if the initial state of the entropy
142// pool is different on each call to `generate`. This has a few implications:
143// - `generate` should be called once before using `JitterRng` to produce the
144// first usable value (this is done by default in `new`);
145// - We do not zero the entropy pool after generating a result. The reference
146// implementation also does not support zeroing, but recommends generating a
147// new value without using it if you want to protect a previously generated
148// 'secret' value from someone inspecting the memory;
149// - Implementing `Clone` seems acceptable, as it would not cause the systematic
150// bias a constant might cause. Only instead of one value that could be
151// potentially related to the same initial state, there are now two.
152
153// Entropy collector state.
154// These values are not necessary to preserve across runs.
155struct EcState {
156 // Previous time stamp to determine the timer delta
157 prev_time: u64,
158 // Deltas used for the stuck test
159 last_delta: i32,
160 last_delta2: i32,
161 // Memory for the Memory Access noise source
162 mem: [u8; MEMORY_SIZE],
163}
164
165impl EcState {
166 // Stuck test by checking the:
167 // - 1st derivation of the jitter measurement (time delta)
168 // - 2nd derivation of the jitter measurement (delta of time deltas)
169 // - 3rd derivation of the jitter measurement (delta of delta of time
170 // deltas)
171 //
172 // All values must always be non-zero.
173 // This test is a heuristic to see whether the last measurement holds
174 // entropy.
175 fn stuck(&mut self, current_delta: i32) -> bool {
176 let delta2 = self.last_delta - current_delta;
177 let delta3 = delta2 - self.last_delta2;
178
179 self.last_delta = current_delta;
180 self.last_delta2 = delta2;
181
182 current_delta == 0 || delta2 == 0 || delta3 == 0
183 }
184}
185
186// Custom Debug implementation that does not expose the internal state
187impl<F> fmt::Debug for JitterRng<F> {
188 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
189 write!(f, "JitterRng {{}}")
190 }
191}
192
193impl<F> Clone for JitterRng<F>
194where
195 F: Clone,
196{
197 fn clone(&self) -> JitterRng<F> {
198 JitterRng {
199 data: self.data,
200 rounds: self.rounds,
201 timer: self.timer.clone(),
202 mem_prev_index: self.mem_prev_index,
203 // The 32 bits that may still be unused from the previous round are
204 // for the original to use, not for the clone.
205 data_half_used: false,
206 }
207 }
208}
209
210// Initialise to zero; must be positive
211#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
212static JITTER_ROUNDS: AtomicUsize = AtomicUsize::new(0);
213
214impl JitterRng<()> {
215 /// Create a new `JitterRng`. Makes use of `std::time` for a timer, or a
216 /// platform-specific function with higher accuracy if necessary and
217 /// available.
218 ///
219 /// During initialization CPU execution timing jitter is measured a few
220 /// hundred times. If this does not pass basic quality tests, an error is
221 /// returned. The test result is cached to make subsequent calls faster.
222 #[cfg(all(feature = "std", not(target_arch = "wasm32")))]
223 pub fn new() -> Result<JitterRng<impl Fn() -> u64 + Send + Sync>, TimerError> {
224 if cfg!(target_arch = "wasm32") {
225 return Err(TimerError::NoTimer);
226 }
227 let mut state = JitterRng::new_with_timer(platform::get_nstime);
228 let mut rounds = JITTER_ROUNDS.load(Ordering::Relaxed) as u8;
229 if rounds == 0 {
230 // No result yet: run test.
231 // This allows the timer test to run multiple times; we don't care.
232 rounds = state.test_timer()?;
233 JITTER_ROUNDS.store(rounds as usize, Ordering::Relaxed);
234 info!("JitterRng: using {} rounds per u64 output", rounds);
235 }
236 state.set_rounds(rounds);
237
238 // Fill `data` with a non-zero value.
239 state.gen_entropy();
240 Ok(state)
241 }
242}
243
244impl<F> JitterRng<F>
245where
246 F: Fn() -> u64 + Send + Sync,
247{
248 /// Create a new `JitterRng`.
249 /// A custom timer can be supplied, making it possible to use `JitterRng` in
250 /// `no_std` environments.
251 ///
252 /// The timer must have nanosecond precision.
253 ///
254 /// This method is more low-level than `new()`. It is the responsibility of
255 /// the caller to run [`test_timer`] before using any numbers generated with
256 /// `JitterRng`, and optionally call [`set_rounds`]. Also it is important to
257 /// consume at least one `u64` before using the first result to initialize
258 /// the entropy collection pool.
259 ///
260 /// # Example
261 ///
262 /// ```
263 /// use rand_jitter::{JitterRng, TimerError};
264 ///
265 /// fn make_jitter_rng() -> Result<JitterRng<impl Fn() -> u64 + Send + Sync>, TimerError> {
266 /// fn get_nstime() -> u64 {
267 /// use std::time::{SystemTime, UNIX_EPOCH};
268 ///
269 /// let dur = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
270 /// // The correct way to calculate the current time is
271 /// // `dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64`
272 /// // But this is faster, and the difference in terms of entropy is
273 /// // negligible (log2(10^9) == 29.9).
274 /// dur.as_secs() << 30 | dur.subsec_nanos() as u64
275 /// }
276 ///
277 /// let mut rng = JitterRng::new_with_timer(get_nstime);
278 /// let rounds = rng.test_timer()?;
279 /// rng.set_rounds(rounds); // optional
280 /// Ok(rng)
281 /// }
282 /// # let _rng = make_jitter_rng();
283 /// ```
284 ///
285 /// [`test_timer`]: JitterRng::test_timer
286 /// [`set_rounds`]: JitterRng::set_rounds
287 pub fn new_with_timer(timer: F) -> JitterRng<F> {
288 JitterRng {
289 data: 0,
290 rounds: 64,
291 timer,
292 mem_prev_index: 0,
293 data_half_used: false,
294 }
295 }
296
297 /// Configures how many rounds are used to generate each 64-bit value.
298 /// This must be greater than zero, and has a big impact on performance
299 /// and output quality.
300 ///
301 /// [`new_with_timer`] conservatively uses 64 rounds, but often less rounds
302 /// can be used. The `test_timer()` function returns the minimum number of
303 /// rounds required for full strength (platform dependent), so one may use
304 /// `rng.set_rounds(rng.test_timer()?);` or cache the value.
305 ///
306 /// [`new_with_timer`]: JitterRng::new_with_timer
307 pub fn set_rounds(&mut self, rounds: u8) {
308 assert!(rounds > 0);
309 self.rounds = rounds;
310 }
311
312 // Calculate a random loop count used for the next round of an entropy
313 // collection, based on bits from a fresh value from the timer.
314 //
315 // The timer is folded to produce a number that contains at most `n_bits`
316 // bits.
317 //
318 // Note: A constant should be added to the resulting random loop count to
319 // prevent loops that run 0 times.
320 #[inline(never)]
321 fn random_loop_cnt(&mut self, n_bits: u32) -> u32 {
322 let mut rounds = 0;
323
324 let mut time = (self.timer)();
325 // Mix with the current state of the random number balance the random
326 // loop counter a bit more.
327 time ^= self.data;
328
329 // We fold the time value as much as possible to ensure that as many
330 // bits of the time stamp are included as possible.
331 let folds = (64 + n_bits - 1) / n_bits;
332 let mask = (1 << n_bits) - 1;
333 for _ in 0..folds {
334 rounds ^= time & mask;
335 time >>= n_bits;
336 }
337
338 rounds as u32
339 }
340
341 // CPU jitter noise source
342 // Noise source based on the CPU execution time jitter
343 //
344 // This function injects the individual bits of the time value into the
345 // entropy pool using an LFSR.
346 //
347 // The code is deliberately inefficient with respect to the bit shifting.
348 // This function not only acts as folding operation, but this function's
349 // execution is used to measure the CPU execution time jitter. Any change to
350 // the loop in this function implies that careful retesting must be done.
351 #[inline(never)]
352 fn lfsr_time(&mut self, time: u64, var_rounds: bool) {
353 fn lfsr(mut data: u64, time: u64) -> u64 {
354 for i in 1..65 {
355 let mut tmp = time << (64 - i);
356 tmp >>= 64 - 1;
357
358 // Fibonacci LSFR with polynomial of
359 // x^64 + x^61 + x^56 + x^31 + x^28 + x^23 + 1 which is
360 // primitive according to
361 // http://poincare.matf.bg.ac.rs/~ezivkovm/publications/primpol1.pdf
362 // (the shift values are the polynomial values minus one
363 // due to counting bits from 0 to 63). As the current
364 // position is always the LSB, the polynomial only needs
365 // to shift data in from the left without wrap.
366 data ^= tmp;
367 data ^= (data >> 63) & 1;
368 data ^= (data >> 60) & 1;
369 data ^= (data >> 55) & 1;
370 data ^= (data >> 30) & 1;
371 data ^= (data >> 27) & 1;
372 data ^= (data >> 22) & 1;
373 data = data.rotate_left(1);
374 }
375 data
376 }
377
378 // Note: in the reference implementation only the last round effects
379 // `self.data`, all the other results are ignored. To make sure the
380 // other rounds are not optimised out, we first run all but the last
381 // round on a throw-away value instead of the real `self.data`.
382 let mut lfsr_loop_cnt = 0;
383 if var_rounds {
384 lfsr_loop_cnt = self.random_loop_cnt(4)
385 };
386
387 let mut throw_away: u64 = 0;
388 for _ in 0..lfsr_loop_cnt {
389 throw_away = lfsr(throw_away, time);
390 }
391 black_box(throw_away);
392
393 self.data = lfsr(self.data, time);
394 }
395
396 // Memory Access noise source
397 // This is a noise source based on variations in memory access times
398 //
399 // This function performs memory accesses which will add to the timing
400 // variations due to an unknown amount of CPU wait states that need to be
401 // added when accessing memory. The memory size should be larger than the L1
402 // caches as outlined in the documentation and the associated testing.
403 //
404 // The L1 cache has a very high bandwidth, albeit its access rate is usually
405 // slower than accessing CPU registers. Therefore, L1 accesses only add
406 // minimal variations as the CPU has hardly to wait. Starting with L2,
407 // significant variations are added because L2 typically does not belong to
408 // the CPU any more and therefore a wider range of CPU wait states is
409 // necessary for accesses. L3 and real memory accesses have even a wider
410 // range of wait states. However, to reliably access either L3 or memory,
411 // the `self.mem` memory must be quite large which is usually not desirable.
412 #[inline(never)]
413 fn memaccess(&mut self, mem: &mut [u8; MEMORY_SIZE], var_rounds: bool) {
414 let mut acc_loop_cnt = 128;
415 if var_rounds {
416 acc_loop_cnt += self.random_loop_cnt(4)
417 };
418
419 let mut index = self.mem_prev_index as usize;
420 for _ in 0..acc_loop_cnt {
421 // Addition of memblocksize - 1 to index with wrap around logic to
422 // ensure that every memory location is hit evenly.
423 // The modulus also allows the compiler to remove the indexing
424 // bounds check.
425 index = (index + MEMORY_BLOCKSIZE - 1) % MEMORY_SIZE;
426
427 // memory access: just add 1 to one byte
428 // memory access implies read from and write to memory location
429 mem[index] = mem[index].wrapping_add(1);
430 }
431 self.mem_prev_index = index as u16;
432 }
433
434 // This is the heart of the entropy generation: calculate time deltas and
435 // use the CPU jitter in the time deltas. The jitter is injected into the
436 // entropy pool.
437 //
438 // Ensure that `ec.prev_time` is primed before using the output of this
439 // function. This can be done by calling this function and not using its
440 // result.
441 fn measure_jitter(&mut self, ec: &mut EcState) -> Option<()> {
442 // Invoke one noise source before time measurement to add variations
443 self.memaccess(&mut ec.mem, true);
444
445 // Get time stamp and calculate time delta to previous
446 // invocation to measure the timing variations
447 let time = (self.timer)();
448 // Note: wrapping_sub combined with a cast to `i64` generates a correct
449 // delta, even in the unlikely case this is a timer that is not strictly
450 // monotonic.
451 let current_delta = time.wrapping_sub(ec.prev_time) as i64 as i32;
452 ec.prev_time = time;
453
454 // Call the next noise source which also injects the data
455 self.lfsr_time(current_delta as u64, true);
456
457 // Check whether we have a stuck measurement (i.e. does the last
458 // measurement holds entropy?).
459 if ec.stuck(current_delta) {
460 return None;
461 };
462
463 // Rotate the data buffer by a prime number (any odd number would
464 // do) to ensure that every bit position of the input time stamp
465 // has an even chance of being merged with a bit position in the
466 // entropy pool. We do not use one here as the adjacent bits in
467 // successive time deltas may have some form of dependency. The
468 // chosen value of 7 implies that the low 7 bits of the next
469 // time delta value is concatenated with the current time delta.
470 self.data = self.data.rotate_left(7);
471
472 Some(())
473 }
474
475 // Shuffle the pool a bit by mixing some value with a bijective function
476 // (XOR) into the pool.
477 //
478 // The function generates a mixer value that depends on the bits set and
479 // the location of the set bits in the random number generated by the
480 // entropy source. Therefore, based on the generated random number, this
481 // mixer value can have 2^64 different values. That mixer value is
482 // initialized with the first two SHA-1 constants. After obtaining the
483 // mixer value, it is XORed into the random number.
484 //
485 // The mixer value is not assumed to contain any entropy. But due to the
486 // XOR operation, it can also not destroy any entropy present in the
487 // entropy pool.
488 #[inline(never)]
489 fn stir_pool(&mut self) {
490 // This constant is derived from the first two 32 bit initialization
491 // vectors of SHA-1 as defined in FIPS 180-4 section 5.3.1
492 // The order does not really matter as we do not rely on the specific
493 // numbers. We just pick the SHA-1 constants as they have a good mix of
494 // bit set and unset.
495 const CONSTANT: u64 = 0x67452301efcdab89;
496
497 // The start value of the mixer variable is derived from the third
498 // and fourth 32 bit initialization vector of SHA-1 as defined in
499 // FIPS 180-4 section 5.3.1
500 let mut mixer = 0x98badcfe10325476;
501
502 // This is a constant time function to prevent leaking timing
503 // information about the random number.
504 // The normal code is:
505 // ```
506 // for i in 0..64 {
507 // if ((self.data >> i) & 1) == 1 { mixer ^= CONSTANT; }
508 // }
509 // ```
510 // This is a bit fragile, as LLVM really wants to use branches here, and
511 // we rely on it to not recognise the opportunity.
512 for i in 0..64 {
513 let apply = (self.data >> i) & 1;
514 let mask = !apply.wrapping_sub(1);
515 mixer ^= CONSTANT & mask;
516 mixer = mixer.rotate_left(1);
517 }
518
519 self.data ^= mixer;
520 }
521
522 fn gen_entropy(&mut self) -> u64 {
523 trace!("JitterRng: collecting entropy");
524
525 // Prime `ec.prev_time`, and run the noise sources to make sure the
526 // first loop round collects the expected entropy.
527 let mut ec = EcState {
528 prev_time: (self.timer)(),
529 last_delta: 0,
530 last_delta2: 0,
531 mem: [0; MEMORY_SIZE],
532 };
533 let _ = self.measure_jitter(&mut ec);
534
535 for _ in 0..self.rounds {
536 // If a stuck measurement is received, repeat measurement
537 // Note: we do not guard against an infinite loop, that would mean
538 // the timer suddenly became broken.
539 while self.measure_jitter(&mut ec).is_none() {}
540 }
541
542 // Do a single read from `self.mem` to make sure the Memory Access noise
543 // source is not optimised out.
544 black_box(ec.mem[0]);
545
546 self.stir_pool();
547 self.data
548 }
549
550 /// Basic quality tests on the timer, by measuring CPU timing jitter a few
551 /// hundred times.
552 ///
553 /// If successful, this will return the estimated number of rounds necessary
554 /// to collect 64 bits of entropy. Otherwise a [`TimerError`] with the cause
555 /// of the failure will be returned.
556 pub fn test_timer(&mut self) -> Result<u8, TimerError> {
557 debug!("JitterRng: testing timer ...");
558 // We could add a check for system capabilities such as `clock_getres`
559 // or check for `CONFIG_X86_TSC`, but it does not make much sense as the
560 // following sanity checks verify that we have a high-resolution timer.
561
562 let mut delta_sum = 0;
563 let mut old_delta = 0;
564
565 let mut time_backwards = 0;
566 let mut count_mod = 0;
567 let mut count_stuck = 0;
568
569 let mut ec = EcState {
570 prev_time: (self.timer)(),
571 last_delta: 0,
572 last_delta2: 0,
573 mem: [0; MEMORY_SIZE],
574 };
575
576 // TESTLOOPCOUNT needs some loops to identify edge systems.
577 // 100 is definitely too little.
578 const TESTLOOPCOUNT: u64 = 300;
579 const CLEARCACHE: u64 = 100;
580
581 for i in 0..(CLEARCACHE + TESTLOOPCOUNT) {
582 // Measure time delta of core entropy collection logic
583 let time = (self.timer)();
584 self.memaccess(&mut ec.mem, true);
585 self.lfsr_time(time, true);
586 let time2 = (self.timer)();
587
588 // Test whether timer works
589 if time == 0 || time2 == 0 {
590 return Err(TimerError::NoTimer);
591 }
592 let delta = time2.wrapping_sub(time) as i64 as i32;
593
594 // Test whether timer is fine grained enough to provide delta even
595 // when called shortly after each other -- this implies that we also
596 // have a high resolution timer
597 if delta == 0 {
598 return Err(TimerError::CoarseTimer);
599 }
600
601 // Up to here we did not modify any variable that will be
602 // evaluated later, but we already performed some work. Thus we
603 // already have had an impact on the caches, branch prediction,
604 // etc. with the goal to clear it to get the worst case
605 // measurements.
606 if i < CLEARCACHE {
607 continue;
608 }
609
610 if ec.stuck(delta) {
611 count_stuck += 1;
612 }
613
614 // Test whether we have an increasing timer.
615 if time2 <= time {
616 time_backwards += 1;
617 }
618
619 // Count the number of times the counter increases in steps of 100ns
620 // or greater.
621 if (delta % 100) == 0 {
622 count_mod += 1;
623 }
624
625 // Ensure that we have a varying delta timer which is necessary for
626 // the calculation of entropy -- perform this check only after the
627 // first loop is executed as we need to prime the old_delta value
628 delta_sum += (delta - old_delta).unsigned_abs() as u64;
629 old_delta = delta;
630 }
631
632 // Do a single read from `self.mem` to make sure the Memory Access noise
633 // source is not optimised out.
634 black_box(ec.mem[0]);
635
636 // We allow the time to run backwards for up to three times.
637 // This can happen if the clock is being adjusted by NTP operations.
638 // If such an operation just happens to interfere with our test, it
639 // should not fail. The value of 3 should cover the NTP case being
640 // performed during our test run.
641 if time_backwards > 3 {
642 return Err(TimerError::NotMonotonic);
643 }
644
645 // Test that the available amount of entropy per round does not get to
646 // low. We expect 1 bit of entropy per round as a reasonable minimum
647 // (although less is possible, it means the collector loop has to run
648 // much more often).
649 // `assert!(delta_average >= log2(1))`
650 // `assert!(delta_sum / TESTLOOPCOUNT >= 1)`
651 // `assert!(delta_sum >= TESTLOOPCOUNT)`
652 if delta_sum < TESTLOOPCOUNT {
653 return Err(TimerError::TinyVariations);
654 }
655
656 // Ensure that we have variations in the time stamp below 100 for at
657 // least 10% of all checks -- on some platforms, the counter increments
658 // in multiples of 100, but not always
659 if count_mod > (TESTLOOPCOUNT * 9 / 10) {
660 return Err(TimerError::CoarseTimer);
661 }
662
663 // If we have more than 90% stuck results, then this Jitter RNG is
664 // likely to not work well.
665 if count_stuck > (TESTLOOPCOUNT * 9 / 10) {
666 return Err(TimerError::TooManyStuck);
667 }
668
669 // Estimate the number of `measure_jitter` rounds necessary for 64 bits
670 // of entropy.
671 //
672 // We don't try very hard to come up with a good estimate of the
673 // available bits of entropy per round here for two reasons:
674 // 1. Simple estimates of the available bits (like Shannon entropy) are
675 // too optimistic.
676 // 2. Unless we want to waste a lot of time during initialization, there
677 // only a small number of samples are available.
678 //
679 // Therefore we use a very simple and conservative estimate:
680 // `let bits_of_entropy = log2(delta_average) / 2`.
681 //
682 // The number of rounds `measure_jitter` should run to collect 64 bits
683 // of entropy is `64 / bits_of_entropy`.
684 let delta_average = delta_sum / TESTLOOPCOUNT;
685
686 if delta_average >= 16 {
687 let log2 = 64 - delta_average.leading_zeros();
688 // Do something similar to roundup(64/(log2/2)):
689 Ok(((64u32 * 2 + log2 - 1) / log2) as u8)
690 } else {
691 // For values < 16 the rounding error becomes too large, use a
692 // lookup table.
693 // Values 0 and 1 are invalid, and filtered out by the
694 // `delta_sum < TESTLOOPCOUNT` test above.
695 let log2_lookup = [
696 0, 0, 128, 81, 64, 56, 50, 46, 43, 41, 39, 38, 36, 35, 34, 33,
697 ];
698 Ok(log2_lookup[delta_average as usize])
699 }
700 }
701
702 /// Statistical test: return the timer delta of one normal run of the
703 /// `JitterRng` entropy collector.
704 ///
705 /// Setting `var_rounds` to `true` will execute the memory access and the
706 /// CPU jitter noise sources a variable amount of times (just like a real
707 /// `JitterRng` round).
708 ///
709 /// Setting `var_rounds` to `false` will execute the noise sources the
710 /// minimal number of times. This can be used to measure the minimum amount
711 /// of entropy one round of the entropy collector can collect in the worst
712 /// case.
713 ///
714 /// See this crate's README on how to use `timer_stats` to test the quality
715 /// of `JitterRng`.
716 pub fn timer_stats(&mut self, var_rounds: bool) -> i64 {
717 let mut mem = [0; MEMORY_SIZE];
718
719 let time = (self.timer)();
720 self.memaccess(&mut mem, var_rounds);
721 self.lfsr_time(time, var_rounds);
722 let time2 = (self.timer)();
723 time2.wrapping_sub(time) as i64
724 }
725}
726
727// A function that is opaque to the optimizer to assist in avoiding dead-code
728// elimination. Taken from `bencher`.
729fn black_box<T>(dummy: T) -> T {
730 unsafe {
731 let ret = ptr::read_volatile(&dummy);
732 mem::forget(dummy);
733 ret
734 }
735}
736
737impl<F> RngCore for JitterRng<F>
738where
739 F: Fn() -> u64 + Send + Sync,
740{
741 fn next_u32(&mut self) -> u32 {
742 // We want to use both parts of the generated entropy
743 if self.data_half_used {
744 self.data_half_used = false;
745 (self.data >> 32) as u32
746 } else {
747 self.data = self.next_u64();
748 self.data_half_used = true;
749 self.data as u32
750 }
751 }
752
753 fn next_u64(&mut self) -> u64 {
754 self.data_half_used = false;
755 self.gen_entropy()
756 }
757
758 fn fill_bytes(&mut self, dest: &mut [u8]) {
759 // Fill using `next_u32`. This is faster for filling small slices (four
760 // bytes or less), while the overhead is negligible.
761 //
762 // This is done especially for wrappers that implement `next_u32`
763 // themselves via `fill_bytes`.
764 impls::fill_bytes_via_next(self, dest)
765 }
766}