diff options
Diffstat (limited to 'rand/rand_jitter')
-rw-r--r-- | rand/rand_jitter/CHANGELOG.md | 32 | ||||
-rw-r--r-- | rand/rand_jitter/COPYRIGHT | 12 | ||||
-rw-r--r-- | rand/rand_jitter/Cargo.toml | 30 | ||||
-rw-r--r-- | rand/rand_jitter/LICENSE-APACHE | 201 | ||||
-rw-r--r-- | rand/rand_jitter/LICENSE-MIT | 26 | ||||
-rw-r--r-- | rand/rand_jitter/README.md | 119 | ||||
-rw-r--r-- | rand/rand_jitter/benches/mod.rs | 17 | ||||
-rw-r--r-- | rand/rand_jitter/src/error.rs | 77 | ||||
-rw-r--r-- | rand/rand_jitter/src/lib.rs | 750 | ||||
-rw-r--r-- | rand/rand_jitter/src/platform.rs | 44 | ||||
-rw-r--r-- | rand/rand_jitter/tests/mod.rs | 28 |
11 files changed, 0 insertions, 1336 deletions
diff --git a/rand/rand_jitter/CHANGELOG.md b/rand/rand_jitter/CHANGELOG.md deleted file mode 100644 index 9f4bb7e..0000000 --- a/rand/rand_jitter/CHANGELOG.md +++ /dev/null @@ -1,32 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [0.2.1] - 2019-08-16 -### Changed -- `TimerError` changed to `repr(u32)` (#864) -- `TimerError` enum values all increased by `1<<30` to match new `rand_core::Error` range (#864) - -## [0.2.0] - 2019-06-06 -- Bump `rand_core` version -- Support new `Error` type in `rand_core` 0.5 -- Remove CryptoRng trait bound (#699, #814) -- Enable doc-testing of README - -## [0.1.4] - 2019-05-02 -- Change error conversion code to partially fix #738 - -## [0.1.3] - 2019-02-05 -- Use libc in `no_std` mode to fix #723 - -## [0.1.2] - 2019-01-31 -- Fix for older rustc compilers on Windows (#722) - -## [0.1.1] - 2019-01-29 -- Fix for older rustc compilers on Mac OSX / iOS (#720) -- Misc. doc fixes - -## [0.1.0] - 2019-01-24 -Initial release. diff --git a/rand/rand_jitter/COPYRIGHT b/rand/rand_jitter/COPYRIGHT deleted file mode 100644 index 468d907..0000000 --- a/rand/rand_jitter/COPYRIGHT +++ /dev/null @@ -1,12 +0,0 @@ -Copyrights in the Rand project are retained by their contributors. No -copyright assignment is required to contribute to the Rand project. - -For full authorship information, see the version control history. - -Except as otherwise noted (below and/or in individual files), Rand is -licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or -<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option. - -The Rand project includes code from the Rust project -published under these same licenses. diff --git a/rand/rand_jitter/Cargo.toml b/rand/rand_jitter/Cargo.toml deleted file mode 100644 index 5b7e3c3..0000000 --- a/rand/rand_jitter/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "rand_jitter" -version = "0.2.1" -authors = ["The Rand Project Developers"] -license = "MIT OR Apache-2.0" -readme = "README.md" -repository = "https://github.com/rust-random/rand" -documentation = "https://docs.rs/rand_jitter" -description = "Random number generator based on timing jitter" -keywords = ["random", "rng", "os"] -edition = "2018" - -[badges] -travis-ci = { repository = "rust-random/rand" } -appveyor = { repository = "rust-random/rand" } - -[dependencies] -rand_core = { path = "../rand_core", version = "0.5" } -log = { version = "0.4", optional = true } - -[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] -# We don't need the 'use_std' feature and depending on it causes -# issues due to: https://github.com/rust-lang/cargo/issues/1197 -libc = { version = "0.2", default_features = false } - -[target.'cfg(target_os = "windows")'.dependencies] -winapi = { version = "0.3", features = ["profileapi"] } - -[features] -std = ["rand_core/std"] diff --git a/rand/rand_jitter/LICENSE-APACHE b/rand/rand_jitter/LICENSE-APACHE deleted file mode 100644 index 17d7468..0000000 --- a/rand/rand_jitter/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/rand/rand_jitter/LICENSE-MIT b/rand/rand_jitter/LICENSE-MIT deleted file mode 100644 index d93b5ba..0000000 --- a/rand/rand_jitter/LICENSE-MIT +++ /dev/null @@ -1,26 +0,0 @@ -Copyright 2018 Developers of the Rand project -Copyright (c) 2014 The Rust Project Developers - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/rand/rand_jitter/README.md b/rand/rand_jitter/README.md deleted file mode 100644 index 2091d6c..0000000 --- a/rand/rand_jitter/README.md +++ /dev/null @@ -1,119 +0,0 @@ -# rand_jitter -[![Build Status](https://travis-ci.org/rust-random/rand.svg?branch=master)](https://travis-ci.org/rust-random/rand) -[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) -[![Latest version](https://img.shields.io/crates/v/rand_jitter.svg)](https://crates.io/crates/rand_jitter) -[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) -[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_jitter) -[![API](https://docs.rs/rand_jitter/badge.svg)](https://docs.rs/rand_jitter) -[![Minimum rustc version](https://img.shields.io/badge/rustc-1.32+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) - -Non-physical true random number generator based on timing jitter. - -Note that this RNG is not suited for use cases where cryptographic security is -required (also see [this -discussion](https://github.com/rust-random/rand/issues/699)). - -This crate depends on [rand_core](https://crates.io/crates/rand_core) and is -part of the [Rand project](https://github.com/rust-random/rand). - -This crate aims to support all of Rust's `std` platforms with a system-provided -entropy source. Unlike other Rand crates, this crate does not support `no_std` -(handling this gracefully is a current discussion topic). - -Links: - -- [API documentation (master)](https://rust-random.github.io/rand/rand_jitter) -- [API documentation (docs.rs)](https://docs.rs/rand_jitter) -- [Changelog](https://github.com/rust-random/rand/blob/master/rand_jitter/CHANGELOG.md) - -## Features - -This crate has optional `std` support which is *disabled by default*; -this feature is required to provide the `JitterRng::new` function; -without `std` support a timer must be supplied via `JitterRng::new_with_timer`. - -## 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: - -```rust,no_run -use rand_jitter::JitterRng; - -use std::error::Error; -use std::fs::File; -use std::io::Write; - -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 -} - -fn main() -> Result<(), Box<dyn Error>> { - let mut rng = JitterRng::new_with_timer(get_nstime); - - // 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(()) -} -``` - -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 noise 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> - ``` - -## License - -`rand_jitter` is distributed under the terms of both the MIT license and the -Apache License (Version 2.0). - -See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and -[COPYRIGHT](COPYRIGHT) for details. diff --git a/rand/rand_jitter/benches/mod.rs b/rand/rand_jitter/benches/mod.rs deleted file mode 100644 index bf7c8a2..0000000 --- a/rand/rand_jitter/benches/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![feature(test)] -#![cfg(std)] - -use test::Bencher; -use rand_jitter::rand_core::RngCore; - -#[bench] -fn bench_add_two(b: &mut Bencher) { - let mut rng = rand_jitter::JitterRng::new().unwrap(); - let mut buf = [0u8; 1024]; - b.iter(|| { - rng.fill_bytes(&mut buf[..]); - test::black_box(&buf); - }); - b.bytes = buf.len() as u64; -} - diff --git a/rand/rand_jitter/src/error.rs b/rand/rand_jitter/src/error.rs deleted file mode 100644 index b54fffa..0000000 --- a/rand/rand_jitter/src/error.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// Copyright 2013-2015 The Rust Project Developers. -// -// 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. - -use rand_core::Error; -use core::fmt; - -/// Base code for all `JitterRng` errors -const ERROR_BASE: u32 = 0xAE53_0400; - -/// An error that can occur when [`JitterRng::test_timer`] fails. -/// -/// All variants have a value of 0xAE530400 = 2924676096 plus a small -/// increment (1 through 5). -/// -/// [`JitterRng::test_timer`]: crate::JitterRng::test_timer -#[derive(Debug, Clone, PartialEq, Eq)] -#[repr(u32)] -pub enum TimerError { - /// No timer available. - NoTimer = ERROR_BASE + 1, - /// Timer too coarse to use as an entropy source. - CoarseTimer = ERROR_BASE + 2, - /// Timer is not monotonically increasing. - NotMonotonic = ERROR_BASE + 3, - /// Variations of deltas of time too small. - TinyVariantions = ERROR_BASE + 4, - /// Too many stuck results (indicating no added entropy). - TooManyStuck = ERROR_BASE + 5, - #[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. - #[cfg(feature = "std")] { - Error::new(err) - } - #[cfg(not(feature = "std"))] { - Error::from(core::num::NonZeroU32::new(err as u32).unwrap()) - } - } -} - diff --git a/rand/rand_jitter/src/lib.rs b/rand/rand_jitter/src/lib.rs deleted file mode 100644 index 49c53e6..0000000 --- a/rand/rand_jitter/src/lib.rs +++ /dev/null @@ -1,750 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// 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 that this RNG is not suited for use cases where cryptographic security is -//! required (also see this [discussion]). -//! -//! 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 it 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. -//! -//! `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 [`JitterRng::new_with_timer`]. -//! -//! This implementation is based on [Jitterentropy] 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. It is also unavailable -//! with disabled `std` feature. -//! -//! [Jitterentropy]: http://www.chronox.de/jent.html -//! [discussion]: https://github.com/rust-random/rand/issues/699 - -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", - html_favicon_url = "https://www.rust-lang.org/favicon.ico", - html_root_url = "https://rust-random.github.io/rand/")] - -#![deny(missing_docs)] -#![deny(missing_debug_implementations)] -#![doc(test(attr(allow(unused_variables), deny(warnings))))] - -// 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. -#![no_std] -#[cfg(feature = "std")] -extern crate std; - -pub use rand_core; - -// Coming from https://crates.io/crates/doc-comment -#[cfg(test)] -macro_rules! doc_comment { - ($x:expr) => { - #[doc = $x] - extern {} - }; -} - -#[cfg(test)] -doc_comment!(include_str!("../README.md")); - -#[allow(unused)] -macro_rules! trace { ($($x:tt)*) => ( - #[cfg(feature = "log")] { - log::trace!($($x)*) - } -) } -#[allow(unused)] -macro_rules! debug { ($($x:tt)*) => ( - #[cfg(feature = "log")] { - log::debug!($($x)*) - } -) } -#[allow(unused)] -macro_rules! info { ($($x:tt)*) => ( - #[cfg(feature = "log")] { - log::info!($($x)*) - } -) } -#[allow(unused)] -macro_rules! warn { ($($x:tt)*) => ( - #[cfg(feature = "log")] { - log::warn!($($x)*) - } -) } -#[allow(unused)] -macro_rules! error { ($($x:tt)*) => ( - #[cfg(feature = "log")] { - log::error!($($x)*) - } -) } - -#[cfg(feature = "std")] -mod platform; -mod error; - -use rand_core::{RngCore, Error, impls}; -pub use crate::error::TimerError; - -use core::{fmt, mem, ptr}; -#[cfg(feature = "std")] -use std::sync::atomic::{AtomicUsize, 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. -/// -/// Note that this RNG is not suitable for use cases where cryptographic -/// security is required. -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, - } - } -} - -// Initialise to zero; must be positive -#[cfg(all(feature = "std", not(target_arch = "wasm32")))] -static JITTER_ROUNDS: AtomicUsize = AtomicUsize::new(0); - -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> { - if cfg!(target_arch = "wasm32") { - return Err(TimerError::NoTimer); - } - 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_jitter::rand_core::{RngCore, 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.next_u64(); - /// - /// // Ready for use - /// let v: u64 = rng.next_u64(); - /// # Ok(()) - /// # } - /// - /// # let _ = try_inner(); - /// ``` - /// - /// [`test_timer`]: JitterRng::test_timer - /// [`set_rounds`]: JitterRng::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`]: JitterRng::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 successful, 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. - 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 this crate's README 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 - } -} - -// 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)) - } -} diff --git a/rand/rand_jitter/src/platform.rs b/rand/rand_jitter/src/platform.rs deleted file mode 100644 index 8e3d0fb..0000000 --- a/rand/rand_jitter/src/platform.rs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// Copyright 2013-2015 The Rust Project Developers. -// -// 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. - -#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))] -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 { - use 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 { - use winapi; - - unsafe { - let mut t = super::mem::zeroed(); - winapi::um::profileapi::QueryPerformanceCounter(&mut t); - *t.QuadPart() as u64 - } -} diff --git a/rand/rand_jitter/tests/mod.rs b/rand/rand_jitter/tests/mod.rs deleted file mode 100644 index 961dc27..0000000 --- a/rand/rand_jitter/tests/mod.rs +++ /dev/null @@ -1,28 +0,0 @@ -use rand_jitter::JitterRng; -#[cfg(feature = "std")] -use rand_core::RngCore; - -#[cfg(feature = "std")] -#[test] -fn test_jitter_init() { - // 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()); -} - |