// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// Based on jitterentropy-library, http://www.chronox.de/jent.html.
// Copyright Stephan Mueller <smueller@chronox.de>, 2014 - 2017.
//
// With permission from Stephan Mueller to relicense the Rust translation under
// the MIT license.

//! Non-physical true random number generator based on timing jitter.

// Note: the C implementation of `Jitterentropy` relies on being compiled
// without optimizations. This implementation goes through lengths to make the
// compiler not optimize out code which does influence timing jitter, but is
// technically dead code.

use rand_core::{RngCore, CryptoRng, Error, ErrorKind, impls};

use core::{fmt, mem, ptr};
#[cfg(all(feature="std", not(target_arch = "wasm32")))]
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

const MEMORY_BLOCKS: usize = 64;
const MEMORY_BLOCKSIZE: usize = 32;
const MEMORY_SIZE: usize = MEMORY_BLOCKS * MEMORY_BLOCKSIZE;

/// A true random number generator based on jitter in the CPU execution time,
/// and jitter in memory access time.
///
/// This is a true random number generator, as opposed to pseudo-random
/// generators. Random numbers generated by `JitterRng` can be seen as fresh
/// entropy. A consequence is that is orders of magnitude slower than [`OsRng`]
/// and PRNGs (about 10<sup>3</sup>..10<sup>6</sup> slower).
///
/// There are very few situations where using this RNG is appropriate. Only very
/// few applications require true entropy. A normal PRNG can be statistically
/// indistinguishable, and a cryptographic PRNG should also be as impossible to
/// predict.
///
/// Use of `JitterRng` is recommended for initializing cryptographic PRNGs when
/// [`OsRng`] is not available.
///
/// `JitterRng` can be used without the standard library, but not conveniently,
/// you must provide a high-precision timer and carefully have to follow the
/// instructions of [`new_with_timer`].
///
/// This implementation is based on
/// [Jitterentropy](http://www.chronox.de/jent.html) version 2.1.0.
///
/// Note: There is no accurate timer available on Wasm platforms, to help
/// prevent fingerprinting or timing side-channel attacks. Therefore
/// [`JitterRng::new()`] is not available on Wasm.
///
/// # Quality testing
///
/// [`JitterRng::new()`] has build-in, but limited, quality testing, however
/// before using `JitterRng` on untested hardware, or after changes that could
/// effect how the code is optimized (such as a new LLVM version), it is
/// recommend to run the much more stringent
/// [NIST SP 800-90B Entropy Estimation Suite](
/// https://github.com/usnistgov/SP800-90B_EntropyAssessment).
///
/// Use the following code using [`timer_stats`] to collect the data:
///
/// ```no_run
/// use rand::jitter::JitterRng;
/// #
/// # use std::error::Error;
/// # use std::fs::File;
/// # use std::io::Write;
/// #
/// # fn try_main() -> Result<(), Box<Error>> {
/// let mut rng = JitterRng::new()?;
///
/// // 1_000_000 results are required for the
/// // NIST SP 800-90B Entropy Estimation Suite
/// const ROUNDS: usize = 1_000_000;
/// let mut deltas_variable: Vec<u8> = Vec::with_capacity(ROUNDS);
/// let mut deltas_minimal: Vec<u8> = Vec::with_capacity(ROUNDS);
///
/// for _ in 0..ROUNDS {
///     deltas_variable.push(rng.timer_stats(true) as u8);
///     deltas_minimal.push(rng.timer_stats(false) as u8);
/// }
///
/// // Write out after the statistics collection loop, to not disturb the
/// // test results.
/// File::create("jitter_rng_var.bin")?.write(&deltas_variable)?;
/// File::create("jitter_rng_min.bin")?.write(&deltas_minimal)?;
/// #
/// # Ok(())
/// # }
/// #
/// # fn main() {
/// #     try_main().unwrap();
/// # }
/// ```
///
/// This will produce two files: `jitter_rng_var.bin` and `jitter_rng_min.bin`.
/// Run the Entropy Estimation Suite in three configurations, as outlined below.
/// Every run has two steps. One step to produce an estimation, another to
/// validate the estimation.
///
/// 1. Estimate the expected amount of entropy that is at least available with
///    each round of the entropy collector. This number should be greater than
///    the amount estimated with `64 / test_timer()`.
///    ```sh
///    python noniid_main.py -v jitter_rng_var.bin 8
///    restart.py -v jitter_rng_var.bin 8 <min-entropy>
///    ```
/// 2. Estimate the expected amount of entropy that is available in the last 4
///    bits of the timer delta after running noice sources. Note that a value of
///    `3.70` is the minimum estimated entropy for true randomness.
///    ```sh
///    python noniid_main.py -v -u 4 jitter_rng_var.bin 4
///    restart.py -v -u 4 jitter_rng_var.bin 4 <min-entropy>
///    ```
/// 3. Estimate the expected amount of entropy that is available to the entropy
///    collector if both noice sources only run their minimal number of times.
///    This measures the absolute worst-case, and gives a lower bound for the
///    available entropy.
///    ```sh
///    python noniid_main.py -v -u 4 jitter_rng_min.bin 4
///    restart.py -v -u 4 jitter_rng_min.bin 4 <min-entropy>
///    ```
///
/// [`OsRng`]: struct.OsRng.html
/// [`JitterRng::new()`]: struct.JitterRng.html#method.new
/// [`new_with_timer`]: struct.JitterRng.html#method.new_with_timer
/// [`timer_stats`]: struct.JitterRng.html#method.timer_stats
pub struct JitterRng {
    data: u64, // Actual random number
    // Number of rounds to run the entropy collector per 64 bits
    rounds: u8,
    // Timer used by `measure_jitter`
    timer: fn() -> u64,
    // Memory for the Memory Access noise source
    mem_prev_index: u16,
    // Make `next_u32` not waste 32 bits
    data_half_used: bool,
}

// Note: `JitterRng` maintains a small 64-bit entropy pool. With every
// `generate` 64 new bits should be integrated in the pool. If a round of
// `generate` were to collect less than the expected 64 bit, then the returned
// value, and the new state of the entropy pool, would be in some way related to
// the initial state. It is therefore better if the initial state of the entropy
// pool is different on each call to `generate`. This has a few implications:
// - `generate` should be called once before using `JitterRng` to produce the
//   first usable value (this is done by default in `new`);
// - We do not zero the entropy pool after generating a result. The reference
//   implementation also does not support zeroing, but recommends generating a
//   new value without using it if you want to protect a previously generated
//   'secret' value from someone inspecting the memory;
// - Implementing `Clone` seems acceptable, as it would not cause the systematic
//   bias a constant might cause. Only instead of one value that could be
//   potentially related to the same initial state, there are now two.

// Entropy collector state.
// These values are not necessary to preserve across runs.
struct EcState {
    // Previous time stamp to determine the timer delta
    prev_time: u64,
    // Deltas used for the stuck test
    last_delta: i32,
    last_delta2: i32,
    // Memory for the Memory Access noise source
    mem: [u8; MEMORY_SIZE],
}

impl EcState {
    // Stuck test by checking the:
    // - 1st derivation of the jitter measurement (time delta)
    // - 2nd derivation of the jitter measurement (delta of time deltas)
    // - 3rd derivation of the jitter measurement (delta of delta of time
    //   deltas)
    //
    // All values must always be non-zero.
    // This test is a heuristic to see whether the last measurement holds
    // entropy.
    fn stuck(&mut self, current_delta: i32) -> bool {
        let delta2 = self.last_delta - current_delta;
        let delta3 = delta2 - self.last_delta2;

        self.last_delta = current_delta;
        self.last_delta2 = delta2;

        current_delta == 0 || delta2 == 0 || delta3 == 0
    }
}

// Custom Debug implementation that does not expose the internal state
impl fmt::Debug for JitterRng {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "JitterRng {{}}")
    }
}

impl Clone for JitterRng {
    fn clone(&self) -> JitterRng {
        JitterRng {
            data: self.data,
            rounds: self.rounds,
            timer: self.timer,
            mem_prev_index: self.mem_prev_index,
            // The 32 bits that may still be unused from the previous round are
            // for the original to use, not for the clone.
            data_half_used: false,
        }
    }
}

/// An error that can occur when [`JitterRng::test_timer`] fails.
///
/// [`JitterRng::test_timer`]: struct.JitterRng.html#method.test_timer
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TimerError {
    /// No timer available.
    NoTimer,
    /// Timer too coarse to use as an entropy source.
    CoarseTimer,
    /// Timer is not monotonically increasing.
    NotMonotonic,
    /// Variations of deltas of time too small.
    TinyVariantions,
    /// Too many stuck results (indicating no added entropy).
    TooManyStuck,
    #[doc(hidden)]
    __Nonexhaustive,
}

impl TimerError {
    fn description(&self) -> &'static str {
        match *self {
            TimerError::NoTimer => "no timer available",
            TimerError::CoarseTimer => "coarse timer",
            TimerError::NotMonotonic => "timer not monotonic",
            TimerError::TinyVariantions => "time delta variations too small",
            TimerError::TooManyStuck => "too many stuck results",
            TimerError::__Nonexhaustive => unreachable!(),
        }
    }
}

impl fmt::Display for TimerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

#[cfg(feature="std")]
impl ::std::error::Error for TimerError {
    fn description(&self) -> &str {
        self.description()
    }
}

impl From<TimerError> for Error {
    fn from(err: TimerError) -> Error {
        // Timer check is already quite permissive of failures so we don't
        // expect false-positive failures, i.e. any error is irrecoverable.
        Error::with_cause(ErrorKind::Unavailable,
                              "timer jitter failed basic quality tests", err)
    }
}

// Initialise to zero; must be positive
#[cfg(all(feature="std", not(target_arch = "wasm32")))]
static JITTER_ROUNDS: AtomicUsize = ATOMIC_USIZE_INIT;

impl JitterRng {
    /// Create a new `JitterRng`. Makes use of `std::time` for a timer, or a
    /// platform-specific function with higher accuracy if necessary and
    /// available.
    ///
    /// During initialization CPU execution timing jitter is measured a few
    /// hundred times. If this does not pass basic quality tests, an error is
    /// returned. The test result is cached to make subsequent calls faster.
    #[cfg(all(feature="std", not(target_arch = "wasm32")))]
    pub fn new() -> Result<JitterRng, TimerError> {
        let mut state = JitterRng::new_with_timer(platform::get_nstime);
        let mut rounds = JITTER_ROUNDS.load(Ordering::Relaxed) as u8;
        if rounds == 0 {
            // No result yet: run test.
            // This allows the timer test to run multiple times; we don't care.
            rounds = state.test_timer()?;
            JITTER_ROUNDS.store(rounds as usize, Ordering::Relaxed);
            info!("JitterRng: using {} rounds per u64 output", rounds);
        }
        state.set_rounds(rounds);

        // Fill `data` with a non-zero value.
        state.gen_entropy();
        Ok(state)
    }

    /// Create a new `JitterRng`.
    /// A custom timer can be supplied, making it possible to use `JitterRng` in
    /// `no_std` environments.
    ///
    /// The timer must have nanosecond precision.
    ///
    /// This method is more low-level than `new()`. It is the responsibility of
    /// the caller to run [`test_timer`] before using any numbers generated with
    /// `JitterRng`, and optionally call [`set_rounds`]. Also it is important to
    /// consume at least one `u64` before using the first result to initialize
    /// the entropy collection pool.
    ///
    /// # Example
    ///
    /// ```
    /// # use rand::{Rng, Error};
    /// use rand::jitter::JitterRng;
    ///
    /// # fn try_inner() -> Result<(), Error> {
    /// fn get_nstime() -> u64 {
    ///     use std::time::{SystemTime, UNIX_EPOCH};
    ///
    ///     let dur = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
    ///     // The correct way to calculate the current time is
    ///     // `dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64`
    ///     // But this is faster, and the difference in terms of entropy is
    ///     // negligible (log2(10^9) == 29.9).
    ///     dur.as_secs() << 30 | dur.subsec_nanos() as u64
    /// }
    ///
    /// let mut rng = JitterRng::new_with_timer(get_nstime);
    /// let rounds = rng.test_timer()?;
    /// rng.set_rounds(rounds); // optional
    /// let _ = rng.gen::<u64>();
    ///
    /// // Ready for use
    /// let v: u64 = rng.gen();
    /// # Ok(())
    /// # }
    ///
    /// # let _ = try_inner();
    /// ```
    ///
    /// [`test_timer`]: struct.JitterRng.html#method.test_timer
    /// [`set_rounds`]: struct.JitterRng.html#method.set_rounds
    pub fn new_with_timer(timer: fn() -> u64) -> JitterRng {
        JitterRng {
            data: 0,
            rounds: 64,
            timer,
            mem_prev_index: 0,
            data_half_used: false,
        }
    }

    /// Configures how many rounds are used to generate each 64-bit value.
    /// This must be greater than zero, and has a big impact on performance
    /// and output quality.
    ///
    /// [`new_with_timer`] conservatively uses 64 rounds, but often less rounds
    /// can be used. The `test_timer()` function returns the minimum number of
    /// rounds required for full strength (platform dependent), so one may use
    /// `rng.set_rounds(rng.test_timer()?);` or cache the value.
    ///
    /// [`new_with_timer`]: struct.JitterRng.html#method.new_with_timer
    pub fn set_rounds(&mut self, rounds: u8) {
        assert!(rounds > 0);
        self.rounds = rounds;
    }

    // Calculate a random loop count used for the next round of an entropy
    // collection, based on bits from a fresh value from the timer.
    //
    // The timer is folded to produce a number that contains at most `n_bits`
    // bits.
    //
    // Note: A constant should be added to the resulting random loop count to
    // prevent loops that run 0 times.
    #[inline(never)]
    fn random_loop_cnt(&mut self, n_bits: u32) -> u32 {
        let mut rounds = 0;

        let mut time = (self.timer)();
        // Mix with the current state of the random number balance the random
        // loop counter a bit more.
        time ^= self.data;

        // We fold the time value as much as possible to ensure that as many
        // bits of the time stamp are included as possible.
        let folds = (64 + n_bits - 1) / n_bits;
        let mask = (1 << n_bits) - 1;
        for _ in 0..folds {
            rounds ^= time & mask;
            time >>= n_bits;
        }

        rounds as u32
    }

    // CPU jitter noise source
    // Noise source based on the CPU execution time jitter
    //
    // This function injects the individual bits of the time value into the
    // entropy pool using an LFSR.
    //
    // The code is deliberately inefficient with respect to the bit shifting.
    // This function not only acts as folding operation, but this function's
    // execution is used to measure the CPU execution time jitter. Any change to
    // the loop in this function implies that careful retesting must be done.
    #[inline(never)]
    fn lfsr_time(&mut self, time: u64, var_rounds: bool) {
        fn lfsr(mut data: u64, time: u64) -> u64{
            for i in 1..65 {
                let mut tmp = time << (64 - i);
                tmp >>= 64 - 1;

                // Fibonacci LSFR with polynomial of
                // x^64 + x^61 + x^56 + x^31 + x^28 + x^23 + 1 which is
                // primitive according to
                // http://poincare.matf.bg.ac.rs/~ezivkovm/publications/primpol1.pdf
                // (the shift values are the polynomial values minus one
                // due to counting bits from 0 to 63). As the current
                // position is always the LSB, the polynomial only needs
                // to shift data in from the left without wrap.
                data ^= tmp;
                data ^= (data >> 63) & 1;
                data ^= (data >> 60) & 1;
                data ^= (data >> 55) & 1;
                data ^= (data >> 30) & 1;
                data ^= (data >> 27) & 1;
                data ^= (data >> 22) & 1;
                data = data.rotate_left(1);
            }
            data
        }

        // Note: in the reference implementation only the last round effects
        // `self.data`, all the other results are ignored. To make sure the
        // other rounds are not optimised out, we first run all but the last
        // round on a throw-away value instead of the real `self.data`.
        let mut lfsr_loop_cnt = 0;
        if var_rounds { lfsr_loop_cnt = self.random_loop_cnt(4) };

        let mut throw_away: u64 = 0;
        for _ in 0..lfsr_loop_cnt {
            throw_away = lfsr(throw_away, time);
        }
        black_box(throw_away);

        self.data = lfsr(self.data, time);
    }

    // Memory Access noise source
    // This is a noise source based on variations in memory access times
    //
    // This function performs memory accesses which will add to the timing
    // variations due to an unknown amount of CPU wait states that need to be
    // added when accessing memory. The memory size should be larger than the L1
    // caches as outlined in the documentation and the associated testing.
    //
    // The L1 cache has a very high bandwidth, albeit its access rate is usually
    // slower than accessing CPU registers. Therefore, L1 accesses only add
    // minimal variations as the CPU has hardly to wait. Starting with L2,
    // significant variations are added because L2 typically does not belong to
    // the CPU any more and therefore a wider range of CPU wait states is
    // necessary for accesses. L3 and real memory accesses have even a wider
    // range of wait states. However, to reliably access either L3 or memory,
    // the `self.mem` memory must be quite large which is usually not desirable.
    #[inline(never)]
    fn memaccess(&mut self, mem: &mut [u8; MEMORY_SIZE], var_rounds: bool) {
        let mut acc_loop_cnt = 128;
        if var_rounds { acc_loop_cnt += self.random_loop_cnt(4) };

        let mut index = self.mem_prev_index as usize;
        for _ in 0..acc_loop_cnt {
            // Addition of memblocksize - 1 to index with wrap around logic to
            // ensure that every memory location is hit evenly.
            // The modulus also allows the compiler to remove the indexing
            // bounds check.
            index = (index + MEMORY_BLOCKSIZE - 1) % MEMORY_SIZE;

            // memory access: just add 1 to one byte
            // memory access implies read from and write to memory location
            mem[index] = mem[index].wrapping_add(1);
        }
        self.mem_prev_index = index as u16;
    }

    // This is the heart of the entropy generation: calculate time deltas and
    // use the CPU jitter in the time deltas. The jitter is injected into the
    // entropy pool.
    //
    // Ensure that `ec.prev_time` is primed before using the output of this
    // function. This can be done by calling this function and not using its
    // result.
    fn measure_jitter(&mut self, ec: &mut EcState) -> Option<()> {
        // Invoke one noise source before time measurement to add variations
        self.memaccess(&mut ec.mem, true);

        // Get time stamp and calculate time delta to previous
        // invocation to measure the timing variations
        let time = (self.timer)();
        // Note: wrapping_sub combined with a cast to `i64` generates a correct
        // delta, even in the unlikely case this is a timer that is not strictly
        // monotonic.
        let current_delta = time.wrapping_sub(ec.prev_time) as i64 as i32;
        ec.prev_time = time;

        // Call the next noise source which also injects the data
        self.lfsr_time(current_delta as u64, true);

        // Check whether we have a stuck measurement (i.e. does the last
        // measurement holds entropy?).
        if ec.stuck(current_delta) { return None };

        // Rotate the data buffer by a prime number (any odd number would
        // do) to ensure that every bit position of the input time stamp
        // has an even chance of being merged with a bit position in the
        // entropy pool. We do not use one here as the adjacent bits in
        // successive time deltas may have some form of dependency. The
        // chosen value of 7 implies that the low 7 bits of the next
        // time delta value is concatenated with the current time delta.
        self.data = self.data.rotate_left(7);

        Some(())
    }

    // Shuffle the pool a bit by mixing some value with a bijective function
    // (XOR) into the pool.
    //
    // The function generates a mixer value that depends on the bits set and
    // the location of the set bits in the random number generated by the
    // entropy source. Therefore, based on the generated random number, this
    // mixer value can have 2^64 different values. That mixer value is
    // initialized with the first two SHA-1 constants. After obtaining the
    // mixer value, it is XORed into the random number.
    //
    // The mixer value is not assumed to contain any entropy. But due to the
    // XOR operation, it can also not destroy any entropy present in the
    // entropy pool.
    #[inline(never)]
    fn stir_pool(&mut self) {
        // This constant is derived from the first two 32 bit initialization
        // vectors of SHA-1 as defined in FIPS 180-4 section 5.3.1
        // The order does not really matter as we do not rely on the specific
        // numbers. We just pick the SHA-1 constants as they have a good mix of
        // bit set and unset.
        const CONSTANT: u64 = 0x67452301efcdab89;

        // The start value of the mixer variable is derived from the third
        // and fourth 32 bit initialization vector of SHA-1 as defined in
        // FIPS 180-4 section 5.3.1
        let mut mixer = 0x98badcfe10325476;

        // This is a constant time function to prevent leaking timing
        // information about the random number.
        // The normal code is:
        // ```
        // for i in 0..64 {
        //     if ((self.data >> i) & 1) == 1 { mixer ^= CONSTANT; }
        // }
        // ```
        // This is a bit fragile, as LLVM really wants to use branches here, and
        // we rely on it to not recognise the opportunity.
        for i in 0..64 {
            let apply = (self.data >> i) & 1;
            let mask = !apply.wrapping_sub(1);
            mixer ^= CONSTANT & mask;
            mixer = mixer.rotate_left(1);
        }

        self.data ^= mixer;
    }

    fn gen_entropy(&mut self) -> u64 {
        trace!("JitterRng: collecting entropy");

        // Prime `ec.prev_time`, and run the noice sources to make sure the
        // first loop round collects the expected entropy.
        let mut ec = EcState {
            prev_time: (self.timer)(),
            last_delta: 0,
            last_delta2: 0,
            mem: [0; MEMORY_SIZE],
        };
        let _ = self.measure_jitter(&mut ec);

        for _ in 0..self.rounds {
            // If a stuck measurement is received, repeat measurement
            // Note: we do not guard against an infinite loop, that would mean
            // the timer suddenly became broken.
            while self.measure_jitter(&mut ec).is_none() {}
        }

        // Do a single read from `self.mem` to make sure the Memory Access noise
        // source is not optimised out.
        black_box(ec.mem[0]);

        self.stir_pool();
        self.data
    }
    
    /// Basic quality tests on the timer, by measuring CPU timing jitter a few
    /// hundred times.
    ///
    /// If succesful, this will return the estimated number of rounds necessary
    /// to collect 64 bits of entropy. Otherwise a [`TimerError`] with the cause
    /// of the failure will be returned.
    ///
    /// [`TimerError`]: enum.TimerError.html
    pub fn test_timer(&mut self) -> Result<u8, TimerError> {
        debug!("JitterRng: testing timer ...");
        // We could add a check for system capabilities such as `clock_getres`
        // or check for `CONFIG_X86_TSC`, but it does not make much sense as the
        // following sanity checks verify that we have a high-resolution timer.

        let mut delta_sum = 0;
        let mut old_delta = 0;

        let mut time_backwards = 0;
        let mut count_mod = 0;
        let mut count_stuck = 0;

        let mut ec = EcState {
            prev_time: (self.timer)(),
            last_delta: 0,
            last_delta2: 0,
            mem: [0; MEMORY_SIZE],
        };

        // TESTLOOPCOUNT needs some loops to identify edge systems.
        // 100 is definitely too little.
        const TESTLOOPCOUNT: u64 = 300;
        const CLEARCACHE: u64 = 100;

        for i in 0..(CLEARCACHE + TESTLOOPCOUNT) {
            // Measure time delta of core entropy collection logic
            let time = (self.timer)();
            self.memaccess(&mut ec.mem, true);
            self.lfsr_time(time, true);
            let time2 = (self.timer)();

            // Test whether timer works
            if time == 0 || time2 == 0 {
                return Err(TimerError::NoTimer);
            }
            let delta = time2.wrapping_sub(time) as i64 as i32;

            // Test whether timer is fine grained enough to provide delta even
            // when called shortly after each other -- this implies that we also
            // have a high resolution timer
            if delta == 0 {
                return Err(TimerError::CoarseTimer);
            }

            // Up to here we did not modify any variable that will be
            // evaluated later, but we already performed some work. Thus we
            // already have had an impact on the caches, branch prediction,
            // etc. with the goal to clear it to get the worst case
            // measurements.
            if i < CLEARCACHE { continue; }

            if ec.stuck(delta) { count_stuck += 1; }

            // Test whether we have an increasing timer.
            if !(time2 > time) { time_backwards += 1; }

            // Count the number of times the counter increases in steps of 100ns
            // or greater.
            if (delta % 100) == 0 { count_mod += 1; }

            // Ensure that we have a varying delta timer which is necessary for
            // the calculation of entropy -- perform this check only after the
            // first loop is executed as we need to prime the old_delta value
            delta_sum += (delta - old_delta).abs() as u64;
            old_delta = delta;
        }

        // Do a single read from `self.mem` to make sure the Memory Access noise
        // source is not optimised out.
        black_box(ec.mem[0]);

        // We allow the time to run backwards for up to three times.
        // This can happen if the clock is being adjusted by NTP operations.
        // If such an operation just happens to interfere with our test, it
        // should not fail. The value of 3 should cover the NTP case being
        // performed during our test run.
        if time_backwards > 3 {
            return Err(TimerError::NotMonotonic);
        }

        // Test that the available amount of entropy per round does not get to
        // low. We expect 1 bit of entropy per round as a reasonable minimum
        // (although less is possible, it means the collector loop has to run
        // much more often).
        // `assert!(delta_average >= log2(1))`
        // `assert!(delta_sum / TESTLOOPCOUNT >= 1)`
        // `assert!(delta_sum >= TESTLOOPCOUNT)`
        if delta_sum < TESTLOOPCOUNT {
            return Err(TimerError::TinyVariantions);
        }

        // Ensure that we have variations in the time stamp below 100 for at
        // least 10% of all checks -- on some platforms, the counter increments
        // in multiples of 100, but not always
        if count_mod > (TESTLOOPCOUNT * 9 / 10) {
            return Err(TimerError::CoarseTimer);
        }

        // If we have more than 90% stuck results, then this Jitter RNG is
        // likely to not work well.
        if count_stuck > (TESTLOOPCOUNT * 9 / 10) {
            return Err(TimerError::TooManyStuck);
        }

        // Estimate the number of `measure_jitter` rounds necessary for 64 bits
        // of entropy.
        //
        // We don't try very hard to come up with a good estimate of the
        // available bits of entropy per round here for two reasons:
        // 1. Simple estimates of the available bits (like Shannon entropy) are
        //    too optimistic.
        // 2. Unless we want to waste a lot of time during intialization, there
        //    only a small number of samples are available.
        //
        // Therefore we use a very simple and conservative estimate:
        // `let bits_of_entropy = log2(delta_average) / 2`.
        //
        // The number of rounds `measure_jitter` should run to collect 64 bits
        // of entropy is `64 / bits_of_entropy`.
        let delta_average = delta_sum / TESTLOOPCOUNT;

        if delta_average >= 16 {
            let log2 = 64 - delta_average.leading_zeros();
            // Do something similar to roundup(64/(log2/2)):
            Ok( ((64u32 * 2 + log2 - 1) / log2) as u8)
        } else {
            // For values < 16 the rounding error becomes too large, use a
            // lookup table.
            // Values 0 and 1 are invalid, and filtered out by the
            // `delta_sum < TESTLOOPCOUNT` test above.
            let log2_lookup = [0,  0, 128, 81, 64, 56, 50, 46,
                               43, 41, 39, 38, 36, 35, 34, 33];
            Ok(log2_lookup[delta_average as usize])
        }
    }

    /// Statistical test: return the timer delta of one normal run of the
    /// `JitterRng` entropy collector.
    ///
    /// Setting `var_rounds` to `true` will execute the memory access and the
    /// CPU jitter noice sources a variable amount of times (just like a real
    /// `JitterRng` round).
    ///
    /// Setting `var_rounds` to `false` will execute the noice sources the
    /// minimal number of times. This can be used to measure the minimum amount
    /// of entropy one round of the entropy collector can collect in the worst
    /// case.
    ///
    /// See [Quality testing](struct.JitterRng.html#quality-testing) on how to
    /// use `timer_stats` to test the quality of `JitterRng`.
    pub fn timer_stats(&mut self, var_rounds: bool) -> i64 {
        let mut mem = [0; MEMORY_SIZE];

        let time = (self.timer)();
        self.memaccess(&mut mem, var_rounds);
        self.lfsr_time(time, var_rounds);
        let time2 = (self.timer)();
        time2.wrapping_sub(time) as i64
    }
}

#[cfg(feature="std")]
mod platform {
    #[cfg(not(any(target_os = "macos", target_os = "ios",
                  target_os = "windows",
                  target_arch = "wasm32")))]
    pub fn get_nstime() -> u64 {
        use std::time::{SystemTime, UNIX_EPOCH};

        let dur = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
        // The correct way to calculate the current time is
        // `dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64`
        // But this is faster, and the difference in terms of entropy is
        // negligible (log2(10^9) == 29.9).
        dur.as_secs() << 30 | dur.subsec_nanos() as u64
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    pub fn get_nstime() -> u64 {
        extern crate libc;
        // On Mac OS and iOS std::time::SystemTime only has 1000ns resolution.
        // We use `mach_absolute_time` instead. This provides a CPU dependent
        // unit, to get real nanoseconds the result should by multiplied by
        // numer/denom from `mach_timebase_info`.
        // But we are not interested in the exact nanoseconds, just entropy. So
        // we use the raw result.
        unsafe { libc::mach_absolute_time() }
    }

    #[cfg(target_os = "windows")]
    pub fn get_nstime() -> u64 {
        extern crate winapi;
        unsafe {
            let mut t = super::mem::zeroed();
            winapi::um::profileapi::QueryPerformanceCounter(&mut t);
            *t.QuadPart() as u64
        }
    }
}

// A function that is opaque to the optimizer to assist in avoiding dead-code
// elimination. Taken from `bencher`.
fn black_box<T>(dummy: T) -> T {
    unsafe {
        let ret = ptr::read_volatile(&dummy);
        mem::forget(dummy);
        ret
    }
}

impl RngCore for JitterRng {
    fn next_u32(&mut self) -> u32 {
        // We want to use both parts of the generated entropy
        if self.data_half_used {
            self.data_half_used = false;
            (self.data >> 32) as u32
        } else {
            self.data = self.next_u64();
            self.data_half_used = true;
            self.data as u32
        }
    }

    fn next_u64(&mut self) -> u64 {
       self.data_half_used = false;
       self.gen_entropy()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        // Fill using `next_u32`. This is faster for filling small slices (four
        // bytes or less), while the overhead is negligible.
        //
        // This is done especially for wrappers that implement `next_u32`
        // themselves via `fill_bytes`.
        impls::fill_bytes_via_next(self, dest)
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        Ok(self.fill_bytes(dest))
    }
}

impl CryptoRng for JitterRng {}

#[cfg(test)]
mod test_jitter_init {
    use jitter::JitterRng;

    #[cfg(all(feature="std", not(target_arch = "wasm32")))]
    #[test]
    fn test_jitter_init() {
        use RngCore;
        // Because this is a debug build, measurements here are not representive
        // of the final release build.
        // Don't fail this test if initializing `JitterRng` fails because of a
        // bad timer (the timer from the standard library may not have enough
        // accuracy on all platforms).
        match JitterRng::new() {
            Ok(ref mut rng) => {
                // false positives are possible, but extremely unlikely
                assert!(rng.next_u32() | rng.next_u32() != 0);
            },
            Err(_) => {},
        }
    }

    #[test]
    fn test_jitter_bad_timer() {
        fn bad_timer() -> u64 { 0 }
        let mut rng = JitterRng::new_with_timer(bad_timer);
        assert!(rng.test_timer().is_err());
    }
}
