diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 46d265490d7..38788a04501 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -45,8 +45,6 @@ jobs: run: cargo doc --all-features --no-deps - name: rand_core run: cargo doc --all-features --package rand_core --no-deps - - name: rand_chacha - run: cargo doc --all-features --package rand_chacha --no-deps - name: rand_pcg run: cargo doc --all-features --package rand_pcg --no-deps @@ -139,8 +137,6 @@ jobs: cargo test --target ${{ matrix.target }} --manifest-path rand_core/Cargo.toml --no-default-features --features=os_rng - name: Test rand_pcg run: cargo test --target ${{ matrix.target }} --manifest-path rand_pcg/Cargo.toml --features=serde - - name: Test rand_chacha - run: cargo test --target ${{ matrix.target }} --manifest-path rand_chacha/Cargo.toml --features=serde test-cross: runs-on: ${{ matrix.os }} @@ -173,7 +169,6 @@ jobs: cross test --no-fail-fast --target ${{ matrix.target }} --examples cross test --no-fail-fast --target ${{ matrix.target }} --manifest-path rand_core/Cargo.toml cross test --no-fail-fast --target ${{ matrix.target }} --manifest-path rand_pcg/Cargo.toml --features=serde - cross test --no-fail-fast --target ${{ matrix.target }} --manifest-path rand_chacha/Cargo.toml test-miri: runs-on: ubuntu-latest @@ -192,7 +187,6 @@ jobs: cargo miri test --manifest-path rand_core/Cargo.toml --features=serde cargo miri test --manifest-path rand_core/Cargo.toml --no-default-features cargo miri test --manifest-path rand_pcg/Cargo.toml --features=serde - cargo miri test --manifest-path rand_chacha/Cargo.toml --no-default-features test-no-std: runs-on: ubuntu-latest diff --git a/Cargo.toml b/Cargo.toml index 8630d701569..bcf3231524d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,7 +68,6 @@ log = ["dep:log"] [workspace] members = [ "rand_core", - "rand_chacha", "rand_pcg", ] exclude = ["benches", "distr_test"] diff --git a/SECURITY.md b/SECURITY.md index f1a61b0d208..a12d09232ca 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -77,7 +77,7 @@ distribution. We aim to provide security fixes in the form of a new patch version for the latest release version of `rand` and its dependencies `rand_core` and -`rand_chacha`, as well as for prior major and minor releases which were, at some +`chacha20`, as well as for prior major and minor releases which were, at some time during the previous 12 months, the latest release version. ## Reporting a Vulnerability diff --git a/benches/Cargo.toml b/benches/Cargo.toml index f5f585cc9bd..80acf8ad4f2 100644 --- a/benches/Cargo.toml +++ b/benches/Cargo.toml @@ -18,7 +18,7 @@ rand_core = { path = "../rand_core" } [dev-dependencies] rand = { path = "..", features = ["small_rng", "nightly"] } rand_pcg = { path = "../rand_pcg" } -rand_chacha = { path = "../rand_chacha" } +chacha20 = { version = "=0.10.0-rc.2", default-features = false, features = ["rng"] } criterion = "0.5" criterion-cycles-per-byte = "0.6" diff --git a/benches/benches/generators.rs b/benches/benches/generators.rs index 1d22b1aa6c7..39bc616321b 100644 --- a/benches/benches/generators.rs +++ b/benches/benches/generators.rs @@ -6,14 +6,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use chacha20::rand_core::UnwrapErr; +use chacha20::{ChaCha8Rng, ChaCha12Rng, ChaCha20Core, ChaCha20Rng}; use core::time::Duration; use criterion::measurement::WallTime; use criterion::{BenchmarkGroup, Criterion, black_box, criterion_group, criterion_main}; use rand::prelude::*; use rand::rngs::OsRng; use rand::rngs::ReseedingRng; -use rand_chacha::rand_core::UnwrapErr; -use rand_chacha::{ChaCha8Rng, ChaCha12Rng, ChaCha20Core, ChaCha20Rng}; use rand_pcg::{Pcg32, Pcg64, Pcg64Dxsm, Pcg64Mcg}; criterion_group!( diff --git a/benches/benches/seq_choose.rs b/benches/benches/seq_choose.rs index a3560a158e1..3822d372dc2 100644 --- a/benches/benches/seq_choose.rs +++ b/benches/benches/seq_choose.rs @@ -94,7 +94,7 @@ pub fn bench(c: &mut Criterion) { b.iter(|| x.iter().cloned().sample_fill(&mut rng, &mut buf)) }); - bench_rng::(c, "ChaCha20"); + bench_rng::(c, "ChaCha20"); bench_rng::(c, "Pcg32"); bench_rng::(c, "Pcg64"); } diff --git a/benches/benches/shuffle.rs b/benches/benches/shuffle.rs index f2ccff2e877..c9ba3598716 100644 --- a/benches/benches/shuffle.rs +++ b/benches/benches/shuffle.rs @@ -30,7 +30,7 @@ pub fn bench(c: &mut Criterion) { }) }); - bench_rng::(c, "ChaCha12"); + bench_rng::(c, "ChaCha12"); bench_rng::(c, "Pcg32"); bench_rng::(c, "Pcg64"); } diff --git a/benches/benches/uniform.rs b/benches/benches/uniform.rs index f995b934e8d..1309a9a5183 100644 --- a/benches/benches/uniform.rs +++ b/benches/benches/uniform.rs @@ -10,11 +10,11 @@ #![cfg_attr(feature = "simd_support", feature(portable_simd))] +use chacha20::ChaCha8Rng; use core::time::Duration; use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main}; use rand::distr::uniform::{SampleRange, Uniform}; use rand::prelude::*; -use rand_chacha::ChaCha8Rng; use rand_pcg::{Pcg32, Pcg64}; #[cfg(feature = "simd_support")] use std::simd::{Simd, num::SimdUint}; diff --git a/benches/benches/uniform_float.rs b/benches/benches/uniform_float.rs index ee9441627e8..e3ff079f88e 100644 --- a/benches/benches/uniform_float.rs +++ b/benches/benches/uniform_float.rs @@ -12,11 +12,11 @@ //! //! - sample: current method: (x12 - 1.0) * (b - a) + a +use chacha20::ChaCha8Rng; use core::time::Duration; use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main}; use rand::distr::uniform::{SampleUniform, Uniform, UniformSampler}; use rand::prelude::*; -use rand_chacha::ChaCha8Rng; use rand_pcg::{Pcg32, Pcg64}; const WARM_UP_TIME: Duration = Duration::from_millis(1000); diff --git a/rand_chacha/CHANGELOG.md b/rand_chacha/CHANGELOG.md deleted file mode 100644 index 7965cf7640e..00000000000 --- a/rand_chacha/CHANGELOG.md +++ /dev/null @@ -1,46 +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.9.0] - 2025-01-27 -### Dependencies and features -- Update to `rand_core` v0.9.0 (#1558) -- Feature `std` now implies feature `rand_core/std` (#1153) -- Rename feature `serde1` to `serde` (#1477) -- Rename feature `getrandom` to `os_rng` (#1537) - -### Other changes -- Remove usage of `unsafe` in `fn generate` (#1181) then optimise for AVX2 (~4-7%) (#1192) -- Revise crate docs (#1454) - -## [0.3.1] - 2021-06-09 -- add getters corresponding to existing setters: `get_seed`, `get_stream` (#1124) -- add serde support, gated by the `serde1` feature (#1124) -- ensure expected layout via `repr(transparent)` (#1120) - -## [0.3.0] - 2020-12-08 -- Bump `rand_core` version to 0.6.0 -- Bump MSRV to 1.36 (#1011) -- Remove usage of deprecated feature "simd" of `ppv-lite86` (#979), then revert - this change (#1023) since SIMD is only enabled by default from `ppv-lite86 v0.2.10` -- impl PartialEq+Eq for ChaChaXRng and ChaChaXCore (#979) -- Fix panic on block counter wrap that was occurring in debug builds (#980) - -## [0.2.2] - 2020-03-09 -- Integrate `c2-chacha`, reducing dependency count (#931) -- Add CryptoRng to ChaChaXCore (#944) - -## [0.2.1] - 2019-07-22 -- Force enable the `simd` feature of `c2-chacha` (#845) - -## [0.2.0] - 2019-06-06 -- Rewrite based on the much faster `c2-chacha` crate (#789) - -## [0.1.1] - 2019-01-04 -- Disable `i128` and `u128` if the `target_os` is `emscripten` (#671: work-around Emscripten limitation) -- Update readme and doc links - -## [0.1.0] - 2018-10-17 -- Pulled out of the Rand crate diff --git a/rand_chacha/COPYRIGHT b/rand_chacha/COPYRIGHT deleted file mode 100644 index 468d907caf9..00000000000 --- a/rand_chacha/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 or - or the MIT license - or , at your option. - -The Rand project includes code from the Rust project -published under these same licenses. diff --git a/rand_chacha/Cargo.toml b/rand_chacha/Cargo.toml deleted file mode 100644 index e2f313d2e8e..00000000000 --- a/rand_chacha/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -[package] -name = "rand_chacha" -version = "0.9.0" -authors = ["The Rand Project Developers", "The Rust Project Developers", "The CryptoCorrosion Contributors"] -license = "MIT OR Apache-2.0" -readme = "README.md" -repository = "https://github.com/rust-random/rand" -documentation = "https://docs.rs/rand_chacha" -homepage = "https://rust-random.github.io/book" -description = """ -ChaCha random number generator -""" -keywords = ["random", "rng", "chacha"] -categories = ["algorithms", "no-std"] -edition = "2021" -rust-version = "1.63" - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--generate-link-to-definition"] - -[dependencies] -rand_core = { path = "../rand_core", version = "0.9.0" } -ppv-lite86 = { version = "0.2.14", default-features = false, features = ["simd"] } -serde = { version = "1.0", features = ["derive"], optional = true } - -[dev-dependencies] -# Only to test serde -serde_json = "1.0.120" -rand_core = { path = "../rand_core", version = "0.9.0", features = ["os_rng"] } - -[features] -default = ["std"] -os_rng = ["rand_core/os_rng"] -std = ["ppv-lite86/std", "rand_core/std"] -serde = ["dep:serde"] diff --git a/rand_chacha/LICENSE-APACHE b/rand_chacha/LICENSE-APACHE deleted file mode 100644 index 494ad3bfdfe..00000000000 --- a/rand_chacha/LICENSE-APACHE +++ /dev/null @@ -1,176 +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 diff --git a/rand_chacha/LICENSE-MIT b/rand_chacha/LICENSE-MIT deleted file mode 100644 index d93b5baf341..00000000000 --- a/rand_chacha/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_chacha/README.md b/rand_chacha/README.md deleted file mode 100644 index 167417f85c8..00000000000 --- a/rand_chacha/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# rand_chacha - -[![Test Status](https://github.com/rust-random/rand/actions/workflows/test.yml/badge.svg?event=push)](https://github.com/rust-random/rand/actions) -[![Latest version](https://img.shields.io/crates/v/rand_chacha.svg)](https://crates.io/crates/rand_chacha) -[![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_chacha) -[![API](https://docs.rs/rand_chacha/badge.svg)](https://docs.rs/rand_chacha) - -A cryptographically secure random number generator that uses the ChaCha -algorithm. - -ChaCha is a stream cipher designed by Daniel J. Bernstein[^1], that we use -as an RNG. It is an improved variant of the Salsa20 cipher family, which was -selected as one of the "stream ciphers suitable for widespread adoption" by -eSTREAM[^2]. - -The RNGs provided by this crate are implemented via the fast stream ciphers of -the [`c2-chacha`](https://crates.io/crates/c2-chacha) crate. - -Links: - -- [API documentation (master)](https://rust-random.github.io/rand/rand_chacha) -- [API documentation (docs.rs)](https://docs.rs/rand_chacha) -- [Changelog](https://github.com/rust-random/rand/blob/master/rand_chacha/CHANGELOG.md) - -[rand]: https://crates.io/crates/rand -[^1]: D. J. Bernstein, [*ChaCha, a variant of Salsa20*]( - https://cr.yp.to/chacha.html) - -[^2]: [eSTREAM: the ECRYPT Stream Cipher Project]( - http://www.ecrypt.eu.org/stream/) - - -## Crate Features - -`rand_chacha` is `no_std` compatible when disabling default features; the `std` -feature can be explicitly required to re-enable `std` support. Using `std` -allows detection of CPU features and thus better optimisation. Using `std` -also enables `os_rng` functionality, such as `ChaCha20Rng::from_os_rng()`. - - -# License - -`rand_chacha` 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_chacha/src/chacha.rs b/rand_chacha/src/chacha.rs deleted file mode 100644 index 91d3cd628d2..00000000000 --- a/rand_chacha/src/chacha.rs +++ /dev/null @@ -1,651 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The ChaCha random number generator. - -use crate::guts::ChaCha; -use core::fmt; -use rand_core::block::{BlockRng, BlockRngCore, CryptoBlockRng}; -use rand_core::{CryptoRng, RngCore, SeedableRng}; - -#[cfg(feature = "serde")] -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -// NB. this must remain consistent with some currently hard-coded numbers in this module -const BUF_BLOCKS: u8 = 4; -// number of 32-bit words per ChaCha block (fixed by algorithm definition) -const BLOCK_WORDS: u8 = 16; - -#[repr(transparent)] -pub struct Array64([T; 64]); -impl Default for Array64 -where - T: Default, -{ - #[rustfmt::skip] - fn default() -> Self { - Self([ - T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), - T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), - T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), - T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), - T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), - T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), - T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), - T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), - ]) - } -} -impl AsRef<[T]> for Array64 { - fn as_ref(&self) -> &[T] { - &self.0 - } -} -impl AsMut<[T]> for Array64 { - fn as_mut(&mut self) -> &mut [T] { - &mut self.0 - } -} -impl Clone for Array64 -where - T: Copy + Default, -{ - fn clone(&self) -> Self { - let mut new = Self::default(); - new.0.copy_from_slice(&self.0); - new - } -} -impl fmt::Debug for Array64 { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Array64 {{}}") - } -} - -macro_rules! chacha_impl { - ($ChaChaXCore:ident, $ChaChaXRng:ident, $rounds:expr, $doc:expr, $abst:ident,) => { - #[doc=$doc] - #[derive(Clone, PartialEq, Eq)] - pub struct $ChaChaXCore { - state: ChaCha, - } - - // Custom Debug implementation that does not expose the internal state - impl fmt::Debug for $ChaChaXCore { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "ChaChaXCore {{}}") - } - } - - impl BlockRngCore for $ChaChaXCore { - type Item = u32; - type Results = Array64; - - #[inline] - fn generate(&mut self, r: &mut Self::Results) { - self.state.refill4($rounds, &mut r.0); - } - } - - impl SeedableRng for $ChaChaXCore { - type Seed = [u8; 32]; - - #[inline] - fn from_seed(seed: Self::Seed) -> Self { - $ChaChaXCore { - state: ChaCha::new(&seed, &[0u8; 8]), - } - } - } - - impl CryptoBlockRng for $ChaChaXCore {} - - /// A cryptographically secure random number generator that uses the ChaCha algorithm. - /// - /// ChaCha is a stream cipher designed by Daniel J. Bernstein[^1], that we use as an RNG. It is - /// an improved variant of the Salsa20 cipher family, which was selected as one of the "stream - /// ciphers suitable for widespread adoption" by eSTREAM[^2]. - /// - /// ChaCha uses add-rotate-xor (ARX) operations as its basis. These are safe against timing - /// attacks, although that is mostly a concern for ciphers and not for RNGs. We provide a SIMD - /// implementation to support high throughput on a variety of common hardware platforms. - /// - /// With the ChaCha algorithm it is possible to choose the number of rounds the core algorithm - /// should run. The number of rounds is a tradeoff between performance and security, where 8 - /// rounds is the minimum potentially secure configuration, and 20 rounds is widely used as a - /// conservative choice. - /// - /// We use a 64-bit counter and 64-bit stream identifier as in Bernstein's implementation[^1] - /// except that we use a stream identifier in place of a nonce. A 64-bit counter over 64-byte - /// (16 word) blocks allows 1 ZiB of output before cycling, and the stream identifier allows - /// 264 unique streams of output per seed. Both counter and stream are initialized - /// to zero but may be set via the `set_word_pos` and `set_stream` methods. - /// - /// The word layout is: - /// - /// ```text - /// constant constant constant constant - /// seed seed seed seed - /// seed seed seed seed - /// counter counter stream_id stream_id - /// ``` - /// - /// This implementation uses an output buffer of sixteen `u32` words, and uses - /// [`BlockRng`] to implement the [`RngCore`] methods. - /// - /// [^1]: D. J. Bernstein, [*ChaCha, a variant of Salsa20*]( - /// https://cr.yp.to/chacha.html) - /// - /// [^2]: [eSTREAM: the ECRYPT Stream Cipher Project]( - /// http://www.ecrypt.eu.org/stream/) - #[derive(Clone, Debug)] - pub struct $ChaChaXRng { - rng: BlockRng<$ChaChaXCore>, - } - - impl SeedableRng for $ChaChaXRng { - type Seed = [u8; 32]; - - #[inline] - fn from_seed(seed: Self::Seed) -> Self { - let core = $ChaChaXCore::from_seed(seed); - Self { - rng: BlockRng::new(core), - } - } - } - - impl RngCore for $ChaChaXRng { - #[inline] - fn next_u32(&mut self) -> u32 { - self.rng.next_u32() - } - - #[inline] - fn next_u64(&mut self) -> u64 { - self.rng.next_u64() - } - - #[inline] - fn fill_bytes(&mut self, bytes: &mut [u8]) { - self.rng.fill_bytes(bytes) - } - } - - impl $ChaChaXRng { - // The buffer is a 4-block window, i.e. it is always at a block-aligned position in the - // stream but if the stream has been sought it may not be self-aligned. - - /// Get the offset from the start of the stream, in 32-bit words. - /// - /// Since the generated blocks are 16 words (24) long and the - /// counter is 64-bits, the offset is a 68-bit number. Sub-word offsets are - /// not supported, hence the result can simply be multiplied by 4 to get a - /// byte-offset. - #[inline] - pub fn get_word_pos(&self) -> u128 { - let buf_start_block = { - let buf_end_block = self.rng.core.state.get_block_pos(); - u64::wrapping_sub(buf_end_block, BUF_BLOCKS.into()) - }; - let (buf_offset_blocks, block_offset_words) = { - let buf_offset_words = self.rng.index() as u64; - let blocks_part = buf_offset_words / u64::from(BLOCK_WORDS); - let words_part = buf_offset_words % u64::from(BLOCK_WORDS); - (blocks_part, words_part) - }; - let pos_block = u64::wrapping_add(buf_start_block, buf_offset_blocks); - let pos_block_words = u128::from(pos_block) * u128::from(BLOCK_WORDS); - pos_block_words + u128::from(block_offset_words) - } - - /// Set the offset from the start of the stream, in 32-bit words. - /// - /// As with `get_word_pos`, we use a 68-bit number. Since the generator - /// simply cycles at the end of its period (1 ZiB), we ignore the upper - /// 60 bits. - #[inline] - pub fn set_word_pos(&mut self, word_offset: u128) { - let block = (word_offset / u128::from(BLOCK_WORDS)) as u64; - self.rng.core.state.set_block_pos(block); - self.rng - .generate_and_set((word_offset % u128::from(BLOCK_WORDS)) as usize); - } - - /// Set the stream number. - /// - /// This is initialized to zero; 264 unique streams of output - /// are available per seed/key. - /// - /// Note that in order to reproduce ChaCha output with a specific 64-bit - /// nonce, one can convert that nonce to a `u64` in little-endian fashion - /// and pass to this function. In theory a 96-bit nonce can be used by - /// passing the last 64-bits to this function and using the first 32-bits as - /// the most significant half of the 64-bit counter (which may be set - /// indirectly via `set_word_pos`), but this is not directly supported. - #[inline] - pub fn set_stream(&mut self, stream: u64) { - self.rng.core.state.set_nonce(stream); - if self.rng.index() != 64 { - let wp = self.get_word_pos(); - self.set_word_pos(wp); - } - } - - /// Get the stream number. - #[inline] - pub fn get_stream(&self) -> u64 { - self.rng.core.state.get_nonce() - } - - /// Get the seed. - #[inline] - pub fn get_seed(&self) -> [u8; 32] { - self.rng.core.state.get_seed() - } - } - - impl CryptoRng for $ChaChaXRng {} - - impl From<$ChaChaXCore> for $ChaChaXRng { - fn from(core: $ChaChaXCore) -> Self { - $ChaChaXRng { - rng: BlockRng::new(core), - } - } - } - - impl PartialEq<$ChaChaXRng> for $ChaChaXRng { - fn eq(&self, rhs: &$ChaChaXRng) -> bool { - let a: $abst::$ChaChaXRng = self.into(); - let b: $abst::$ChaChaXRng = rhs.into(); - a == b - } - } - impl Eq for $ChaChaXRng {} - - #[cfg(feature = "serde")] - impl Serialize for $ChaChaXRng { - fn serialize(&self, s: S) -> Result - where - S: Serializer, - { - $abst::$ChaChaXRng::from(self).serialize(s) - } - } - #[cfg(feature = "serde")] - impl<'de> Deserialize<'de> for $ChaChaXRng { - fn deserialize(d: D) -> Result - where - D: Deserializer<'de>, - { - $abst::$ChaChaXRng::deserialize(d).map(|x| Self::from(&x)) - } - } - - mod $abst { - #[cfg(feature = "serde")] - use serde::{Deserialize, Serialize}; - - // The abstract state of a ChaCha stream, independent of implementation choices. The - // comparison and serialization of this object is considered a semver-covered part of - // the API. - #[derive(Debug, PartialEq, Eq)] - #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] - pub(crate) struct $ChaChaXRng { - seed: [u8; 32], - stream: u64, - word_pos: u128, - } - - impl From<&super::$ChaChaXRng> for $ChaChaXRng { - // Forget all information about the input except what is necessary to determine the - // outputs of any sequence of pub API calls. - fn from(r: &super::$ChaChaXRng) -> Self { - Self { - seed: r.get_seed(), - stream: r.get_stream(), - word_pos: r.get_word_pos(), - } - } - } - - impl From<&$ChaChaXRng> for super::$ChaChaXRng { - // Construct one of the possible concrete RNGs realizing an abstract state. - fn from(a: &$ChaChaXRng) -> Self { - use rand_core::SeedableRng; - let mut r = Self::from_seed(a.seed); - r.set_stream(a.stream); - r.set_word_pos(a.word_pos); - r - } - } - } - }; -} - -chacha_impl!( - ChaCha20Core, - ChaCha20Rng, - 10, - "ChaCha with 20 rounds", - abstract20, -); -chacha_impl!( - ChaCha12Core, - ChaCha12Rng, - 6, - "ChaCha with 12 rounds", - abstract12, -); -chacha_impl!( - ChaCha8Core, - ChaCha8Rng, - 4, - "ChaCha with 8 rounds", - abstract8, -); - -#[cfg(test)] -mod test { - use rand_core::{RngCore, SeedableRng}; - - #[cfg(feature = "serde")] - use super::{ChaCha12Rng, ChaCha20Rng, ChaCha8Rng}; - - type ChaChaRng = super::ChaCha20Rng; - - #[cfg(feature = "serde")] - #[test] - fn test_chacha_serde_roundtrip() { - let seed = [ - 1, 0, 52, 0, 0, 0, 0, 0, 1, 0, 10, 0, 22, 32, 0, 0, 2, 0, 55, 49, 0, 11, 0, 0, 3, 0, 0, - 0, 0, 0, 2, 92, - ]; - let mut rng1 = ChaCha20Rng::from_seed(seed); - let mut rng2 = ChaCha12Rng::from_seed(seed); - let mut rng3 = ChaCha8Rng::from_seed(seed); - - let encoded1 = serde_json::to_string(&rng1).unwrap(); - let encoded2 = serde_json::to_string(&rng2).unwrap(); - let encoded3 = serde_json::to_string(&rng3).unwrap(); - - let mut decoded1: ChaCha20Rng = serde_json::from_str(&encoded1).unwrap(); - let mut decoded2: ChaCha12Rng = serde_json::from_str(&encoded2).unwrap(); - let mut decoded3: ChaCha8Rng = serde_json::from_str(&encoded3).unwrap(); - - assert_eq!(rng1, decoded1); - assert_eq!(rng2, decoded2); - assert_eq!(rng3, decoded3); - - assert_eq!(rng1.next_u32(), decoded1.next_u32()); - assert_eq!(rng2.next_u32(), decoded2.next_u32()); - assert_eq!(rng3.next_u32(), decoded3.next_u32()); - } - - // This test validates that: - // 1. a hard-coded serialization demonstrating the format at time of initial release can still - // be deserialized to a ChaChaRng - // 2. re-serializing the resultant object produces exactly the original string - // - // Condition 2 is stronger than necessary: an equivalent serialization (e.g. with field order - // permuted, or whitespace differences) would also be admissible, but would fail this test. - // However testing for equivalence of serialized data is difficult, and there shouldn't be any - // reason we need to violate the stronger-than-needed condition, e.g. by changing the field - // definition order. - #[cfg(feature = "serde")] - #[test] - fn test_chacha_serde_format_stability() { - let j = r#"{"seed":[4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8],"stream":27182818284,"word_pos":314159265359}"#; - let r: ChaChaRng = serde_json::from_str(j).unwrap(); - let j1 = serde_json::to_string(&r).unwrap(); - assert_eq!(j, j1); - } - - #[test] - fn test_chacha_construction() { - let seed = [ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, - 0, 0, 0, - ]; - let mut rng1 = ChaChaRng::from_seed(seed); - assert_eq!(rng1.next_u32(), 137206642); - - let mut rng2 = ChaChaRng::from_rng(&mut rng1); - assert_eq!(rng2.next_u32(), 1325750369); - } - - #[test] - fn test_chacha_true_values_a() { - // Test vectors 1 and 2 from - // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 - let seed = [0u8; 32]; - let mut rng = ChaChaRng::from_seed(seed); - - let mut results = [0u32; 16]; - for i in results.iter_mut() { - *i = rng.next_u32(); - } - let expected = [ - 0xade0b876, 0x903df1a0, 0xe56a5d40, 0x28bd8653, 0xb819d2bd, 0x1aed8da0, 0xccef36a8, - 0xc70d778b, 0x7c5941da, 0x8d485751, 0x3fe02477, 0x374ad8b8, 0xf4b8436a, 0x1ca11815, - 0x69b687c3, 0x8665eeb2, - ]; - assert_eq!(results, expected); - - for i in results.iter_mut() { - *i = rng.next_u32(); - } - let expected = [ - 0xbee7079f, 0x7a385155, 0x7c97ba98, 0x0d082d73, 0xa0290fcb, 0x6965e348, 0x3e53c612, - 0xed7aee32, 0x7621b729, 0x434ee69c, 0xb03371d5, 0xd539d874, 0x281fed31, 0x45fb0a51, - 0x1f0ae1ac, 0x6f4d794b, - ]; - assert_eq!(results, expected); - } - - #[test] - fn test_chacha_true_values_b() { - // Test vector 3 from - // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 - let seed = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, - ]; - let mut rng = ChaChaRng::from_seed(seed); - - // Skip block 0 - for _ in 0..16 { - rng.next_u32(); - } - - let mut results = [0u32; 16]; - for i in results.iter_mut() { - *i = rng.next_u32(); - } - let expected = [ - 0x2452eb3a, 0x9249f8ec, 0x8d829d9b, 0xddd4ceb1, 0xe8252083, 0x60818b01, 0xf38422b8, - 0x5aaa49c9, 0xbb00ca8e, 0xda3ba7b4, 0xc4b592d1, 0xfdf2732f, 0x4436274e, 0x2561b3c8, - 0xebdd4aa6, 0xa0136c00, - ]; - assert_eq!(results, expected); - } - - #[test] - fn test_chacha_true_values_c() { - // Test vector 4 from - // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 - let seed = [ - 0, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, - ]; - let expected = [ - 0xfb4dd572, 0x4bc42ef1, 0xdf922636, 0x327f1394, 0xa78dea8f, 0x5e269039, 0xa1bebbc1, - 0xcaf09aae, 0xa25ab213, 0x48a6b46c, 0x1b9d9bcb, 0x092c5be6, 0x546ca624, 0x1bec45d5, - 0x87f47473, 0x96f0992e, - ]; - let expected_end = 3 * 16; - let mut results = [0u32; 16]; - - // Test block 2 by skipping block 0 and 1 - let mut rng1 = ChaChaRng::from_seed(seed); - for _ in 0..32 { - rng1.next_u32(); - } - for i in results.iter_mut() { - *i = rng1.next_u32(); - } - assert_eq!(results, expected); - assert_eq!(rng1.get_word_pos(), expected_end); - - // Test block 2 by using `set_word_pos` - let mut rng2 = ChaChaRng::from_seed(seed); - rng2.set_word_pos(2 * 16); - for i in results.iter_mut() { - *i = rng2.next_u32(); - } - assert_eq!(results, expected); - assert_eq!(rng2.get_word_pos(), expected_end); - - // Test skipping behaviour with other types - let mut buf = [0u8; 32]; - rng2.fill_bytes(&mut buf[..]); - assert_eq!(rng2.get_word_pos(), expected_end + 8); - rng2.fill_bytes(&mut buf[0..25]); - assert_eq!(rng2.get_word_pos(), expected_end + 15); - rng2.next_u64(); - assert_eq!(rng2.get_word_pos(), expected_end + 17); - rng2.next_u32(); - rng2.next_u64(); - assert_eq!(rng2.get_word_pos(), expected_end + 20); - rng2.fill_bytes(&mut buf[0..1]); - assert_eq!(rng2.get_word_pos(), expected_end + 21); - } - - #[test] - fn test_chacha_multiple_blocks() { - let seed = [ - 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 7, - 0, 0, 0, - ]; - let mut rng = ChaChaRng::from_seed(seed); - - // Store the 17*i-th 32-bit word, - // i.e., the i-th word of the i-th 16-word block - let mut results = [0u32; 16]; - for i in results.iter_mut() { - *i = rng.next_u32(); - for _ in 0..16 { - rng.next_u32(); - } - } - let expected = [ - 0xf225c81a, 0x6ab1be57, 0x04d42951, 0x70858036, 0x49884684, 0x64efec72, 0x4be2d186, - 0x3615b384, 0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530, 0x2c5bad8f, 0x898881dc, - 0x5f1c86d9, 0xc1f8e7f4, - ]; - assert_eq!(results, expected); - } - - #[test] - fn test_chacha_true_bytes() { - let seed = [0u8; 32]; - let mut rng = ChaChaRng::from_seed(seed); - let mut results = [0u8; 32]; - rng.fill_bytes(&mut results); - let expected = [ - 118, 184, 224, 173, 160, 241, 61, 144, 64, 93, 106, 229, 83, 134, 189, 40, 189, 210, - 25, 184, 160, 141, 237, 26, 168, 54, 239, 204, 139, 119, 13, 199, - ]; - assert_eq!(results, expected); - } - - #[test] - fn test_chacha_nonce() { - // Test vector 5 from - // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 - // Although we do not support setting a nonce, we try it here anyway so - // we can use this test vector. - let seed = [0u8; 32]; - let mut rng = ChaChaRng::from_seed(seed); - // 96-bit nonce in LE order is: 0,0,0,0, 0,0,0,0, 0,0,0,2 - rng.set_stream(2u64 << (24 + 32)); - - let mut results = [0u32; 16]; - for i in results.iter_mut() { - *i = rng.next_u32(); - } - let expected = [ - 0x374dc6c2, 0x3736d58c, 0xb904e24a, 0xcd3f93ef, 0x88228b1a, 0x96a4dfb3, 0x5b76ab72, - 0xc727ee54, 0x0e0e978a, 0xf3145c95, 0x1b748ea8, 0xf786c297, 0x99c28f5f, 0x628314e8, - 0x398a19fa, 0x6ded1b53, - ]; - assert_eq!(results, expected); - } - - #[test] - fn test_chacha_clone_streams() { - let seed = [ - 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 7, - 0, 0, 0, - ]; - let mut rng = ChaChaRng::from_seed(seed); - let mut clone = rng.clone(); - for _ in 0..16 { - assert_eq!(rng.next_u64(), clone.next_u64()); - } - - rng.set_stream(51); - for _ in 0..7 { - assert!(rng.next_u32() != clone.next_u32()); - } - clone.set_stream(51); // switch part way through block - for _ in 7..16 { - assert_eq!(rng.next_u32(), clone.next_u32()); - } - } - - #[test] - fn test_chacha_word_pos_wrap_exact() { - use super::{BLOCK_WORDS, BUF_BLOCKS}; - let mut rng = ChaChaRng::from_seed(Default::default()); - // refilling the buffer in set_word_pos will wrap the block counter to 0 - let last_block = (1 << 68) - u128::from(BUF_BLOCKS * BLOCK_WORDS); - rng.set_word_pos(last_block); - assert_eq!(rng.get_word_pos(), last_block); - } - - #[test] - fn test_chacha_word_pos_wrap_excess() { - use super::BLOCK_WORDS; - let mut rng = ChaChaRng::from_seed(Default::default()); - // refilling the buffer in set_word_pos will wrap the block counter past 0 - let last_block = (1 << 68) - u128::from(BLOCK_WORDS); - rng.set_word_pos(last_block); - assert_eq!(rng.get_word_pos(), last_block); - } - - #[test] - fn test_chacha_word_pos_zero() { - let mut rng = ChaChaRng::from_seed(Default::default()); - assert_eq!(rng.get_word_pos(), 0); - rng.set_word_pos(0); - assert_eq!(rng.get_word_pos(), 0); - } - - #[test] - fn test_trait_objects() { - use rand_core::CryptoRng; - - let mut rng1 = ChaChaRng::from_seed(Default::default()); - let rng2 = &mut rng1.clone() as &mut dyn CryptoRng; - for _ in 0..1000 { - assert_eq!(rng1.next_u64(), rng2.next_u64()); - } - } -} diff --git a/rand_chacha/src/guts.rs b/rand_chacha/src/guts.rs deleted file mode 100644 index d077225c625..00000000000 --- a/rand_chacha/src/guts.rs +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright 2019 The CryptoCorrosion Contributors -// Copyright 2020 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The ChaCha random number generator. - -use ppv_lite86::{dispatch, dispatch_light128}; - -pub use ppv_lite86::Machine; -use ppv_lite86::{ - vec128_storage, ArithOps, BitOps32, LaneWords4, MultiLane, StoreBytes, Vec4, Vec4Ext, Vector, -}; - -pub(crate) const BLOCK: usize = 16; -pub(crate) const BLOCK64: u64 = BLOCK as u64; -const LOG2_BUFBLOCKS: u64 = 2; -const BUFBLOCKS: u64 = 1 << LOG2_BUFBLOCKS; -pub(crate) const BUFSZ64: u64 = BLOCK64 * BUFBLOCKS; -pub(crate) const BUFSZ: usize = BUFSZ64 as usize; - -const STREAM_PARAM_NONCE: u32 = 1; -const STREAM_PARAM_BLOCK: u32 = 0; - -#[derive(Clone, PartialEq, Eq)] -pub struct ChaCha { - pub(crate) b: vec128_storage, - pub(crate) c: vec128_storage, - pub(crate) d: vec128_storage, -} - -#[derive(Clone)] -pub struct State { - pub(crate) a: V, - pub(crate) b: V, - pub(crate) c: V, - pub(crate) d: V, -} - -#[inline(always)] -pub(crate) fn round(mut x: State) -> State { - x.a += x.b; - x.d = (x.d ^ x.a).rotate_each_word_right16(); - x.c += x.d; - x.b = (x.b ^ x.c).rotate_each_word_right20(); - x.a += x.b; - x.d = (x.d ^ x.a).rotate_each_word_right24(); - x.c += x.d; - x.b = (x.b ^ x.c).rotate_each_word_right25(); - x -} - -#[inline(always)] -pub(crate) fn diagonalize(mut x: State) -> State { - x.b = x.b.shuffle_lane_words3012(); - x.c = x.c.shuffle_lane_words2301(); - x.d = x.d.shuffle_lane_words1230(); - x -} -#[inline(always)] -pub(crate) fn undiagonalize(mut x: State) -> State { - x.b = x.b.shuffle_lane_words1230(); - x.c = x.c.shuffle_lane_words2301(); - x.d = x.d.shuffle_lane_words3012(); - x -} - -impl ChaCha { - #[inline(always)] - pub fn new(key: &[u8; 32], nonce: &[u8]) -> Self { - init_chacha(key, nonce) - } - - /// Produce 4 blocks of output, advancing the state - #[inline(always)] - pub fn refill4(&mut self, drounds: u32, out: &mut [u32; BUFSZ]) { - refill_wide(self, drounds, out) - } - - #[inline(always)] - pub fn set_block_pos(&mut self, value: u64) { - set_stream_param(self, STREAM_PARAM_BLOCK, value) - } - - #[inline(always)] - pub fn get_block_pos(&self) -> u64 { - get_stream_param(self, STREAM_PARAM_BLOCK) - } - - #[inline(always)] - pub fn set_nonce(&mut self, value: u64) { - set_stream_param(self, STREAM_PARAM_NONCE, value) - } - - #[inline(always)] - pub fn get_nonce(&self) -> u64 { - get_stream_param(self, STREAM_PARAM_NONCE) - } - - #[inline(always)] - pub fn get_seed(&self) -> [u8; 32] { - get_seed(self) - } -} - -// This implementation is platform-independent. -#[inline(always)] -#[cfg(target_endian = "big")] -fn add_pos(_m: Mach, d0: Mach::u32x4, i: u64) -> Mach::u32x4 { - let pos0 = ((d0.extract(1) as u64) << 32) | d0.extract(0) as u64; - let pos = pos0.wrapping_add(i); - d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0) -} -#[inline(always)] -#[cfg(target_endian = "big")] -fn d0123(m: Mach, d: vec128_storage) -> Mach::u32x4x4 { - let d0: Mach::u32x4 = m.unpack(d); - let mut pos = ((d0.extract(1) as u64) << 32) | d0.extract(0) as u64; - pos = pos.wrapping_add(1); - let d1 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0); - pos = pos.wrapping_add(1); - let d2 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0); - pos = pos.wrapping_add(1); - let d3 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0); - Mach::u32x4x4::from_lanes([d0, d1, d2, d3]) -} - -// Pos is packed into the state vectors as a little-endian u64, -// so on LE platforms we can use native vector ops to increment it. -#[inline(always)] -#[cfg(target_endian = "little")] -fn add_pos(m: Mach, d: Mach::u32x4, i: u64) -> Mach::u32x4 { - let d0: Mach::u64x2 = m.unpack(d.into()); - let incr = m.vec([i, 0]); - m.unpack((d0 + incr).into()) -} -#[inline(always)] -#[cfg(target_endian = "little")] -fn d0123(m: Mach, d: vec128_storage) -> Mach::u32x4x4 { - let d0: Mach::u64x2 = m.unpack(d); - let incr = - Mach::u64x2x4::from_lanes([m.vec([0, 0]), m.vec([1, 0]), m.vec([2, 0]), m.vec([3, 0])]); - m.unpack((Mach::u64x2x4::from_lanes([d0, d0, d0, d0]) + incr).into()) -} - -#[allow(clippy::many_single_char_names)] -#[inline(always)] -fn refill_wide_impl( - m: Mach, - state: &mut ChaCha, - drounds: u32, - out: &mut [u32; BUFSZ], -) { - let k = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]); - let b = m.unpack(state.b); - let c = m.unpack(state.c); - let mut x = State { - a: Mach::u32x4x4::from_lanes([k, k, k, k]), - b: Mach::u32x4x4::from_lanes([b, b, b, b]), - c: Mach::u32x4x4::from_lanes([c, c, c, c]), - d: d0123(m, state.d), - }; - for _ in 0..drounds { - x = round(x); - x = undiagonalize(round(diagonalize(x))); - } - let kk = Mach::u32x4x4::from_lanes([k, k, k, k]); - let sb = m.unpack(state.b); - let sb = Mach::u32x4x4::from_lanes([sb, sb, sb, sb]); - let sc = m.unpack(state.c); - let sc = Mach::u32x4x4::from_lanes([sc, sc, sc, sc]); - let sd = d0123(m, state.d); - let results = Mach::u32x4x4::transpose4(x.a + kk, x.b + sb, x.c + sc, x.d + sd); - out[0..16].copy_from_slice(&results.0.to_scalars()); - out[16..32].copy_from_slice(&results.1.to_scalars()); - out[32..48].copy_from_slice(&results.2.to_scalars()); - out[48..64].copy_from_slice(&results.3.to_scalars()); - state.d = add_pos(m, sd.to_lanes()[0], 4).into(); -} - -dispatch!(m, Mach, { - fn refill_wide(state: &mut ChaCha, drounds: u32, out: &mut [u32; BUFSZ]) { - refill_wide_impl(m, state, drounds, out); - } -}); - -// Single-block, rounds-only; shared by try_apply_keystream for tails shorter than BUFSZ -// and XChaCha's setup step. -dispatch!(m, Mach, { - fn refill_narrow_rounds(state: &mut ChaCha, drounds: u32) -> State { - let k: Mach::u32x4 = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]); - let mut x = State { - a: k, - b: m.unpack(state.b), - c: m.unpack(state.c), - d: m.unpack(state.d), - }; - for _ in 0..drounds { - x = round(x); - x = undiagonalize(round(diagonalize(x))); - } - State { - a: x.a.into(), - b: x.b.into(), - c: x.c.into(), - d: x.d.into(), - } - } -}); - -dispatch_light128!(m, Mach, { - fn set_stream_param(state: &mut ChaCha, param: u32, value: u64) { - let d: Mach::u32x4 = m.unpack(state.d); - state.d = d - .insert((value >> 32) as u32, (param << 1) | 1) - .insert(value as u32, param << 1) - .into(); - } -}); - -dispatch_light128!(m, Mach, { - fn get_stream_param(state: &ChaCha, param: u32) -> u64 { - let d: Mach::u32x4 = m.unpack(state.d); - ((d.extract((param << 1) | 1) as u64) << 32) | d.extract(param << 1) as u64 - } -}); - -dispatch_light128!(m, Mach, { - fn get_seed(state: &ChaCha) -> [u8; 32] { - let b: Mach::u32x4 = m.unpack(state.b); - let c: Mach::u32x4 = m.unpack(state.c); - let mut key = [0u8; 32]; - b.write_le(&mut key[..16]); - c.write_le(&mut key[16..]); - key - } -}); - -fn read_u32le(xs: &[u8]) -> u32 { - assert_eq!(xs.len(), 4); - u32::from(xs[0]) | (u32::from(xs[1]) << 8) | (u32::from(xs[2]) << 16) | (u32::from(xs[3]) << 24) -} - -dispatch_light128!(m, Mach, { - fn init_chacha(key: &[u8; 32], nonce: &[u8]) -> ChaCha { - let ctr_nonce = [ - 0, - if nonce.len() == 12 { - read_u32le(&nonce[0..4]) - } else { - 0 - }, - read_u32le(&nonce[nonce.len() - 8..nonce.len() - 4]), - read_u32le(&nonce[nonce.len() - 4..]), - ]; - let key0: Mach::u32x4 = m.read_le(&key[..16]); - let key1: Mach::u32x4 = m.read_le(&key[16..]); - ChaCha { - b: key0.into(), - c: key1.into(), - d: ctr_nonce.into(), - } - } -}); - -dispatch_light128!(m, Mach, { - fn init_chacha_x(key: &[u8; 32], nonce: &[u8; 24], rounds: u32) -> ChaCha { - let key0: Mach::u32x4 = m.read_le(&key[..16]); - let key1: Mach::u32x4 = m.read_le(&key[16..]); - let nonce0: Mach::u32x4 = m.read_le(&nonce[..16]); - let mut state = ChaCha { - b: key0.into(), - c: key1.into(), - d: nonce0.into(), - }; - let x = refill_narrow_rounds(&mut state, rounds); - let ctr_nonce1 = [0, 0, read_u32le(&nonce[16..20]), read_u32le(&nonce[20..24])]; - state.b = x.a; - state.c = x.d; - state.d = ctr_nonce1.into(); - state - } -}); diff --git a/rand_chacha/src/lib.rs b/rand_chacha/src/lib.rs deleted file mode 100644 index 24ddd601d27..00000000000 --- a/rand_chacha/src/lib.rs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2018 Developers of the Rand project. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The ChaCha random number generators. -//! -//! These are native Rust implementations of RNGs derived from the -//! [ChaCha stream ciphers] by D J Bernstein. -//! -//! ## Generators -//! -//! This crate provides 8-, 12- and 20-round variants of generators via a "core" -//! implementation (of [`BlockRngCore`]), each with an associated "RNG" type -//! (implementing [`RngCore`]). -//! -//! These generators are all deterministic and portable (see [Reproducibility] -//! in the book), with testing against reference vectors. -//! -//! ## Cryptographic (secure) usage -//! -//! Where secure unpredictable generators are required, it is suggested to use -//! [`ChaCha12Rng`] or [`ChaCha20Rng`] and to seed via -//! [`SeedableRng::from_os_rng`]. -//! -//! See also the [Security] chapter in the rand book. The crate is provided -//! "as is", without any form of guarantee, and without a security audit. -//! -//! ## Seeding (construction) -//! -//! Generators implement the [`SeedableRng`] trait. Any method may be used, -//! but note that `seed_from_u64` is not suitable for usage where security is -//! important. Some suggestions: -//! -//! 1. With a fresh seed, **direct from the OS** (implies a syscall): -//! ``` -//! # use {rand_core::SeedableRng, rand_chacha::ChaCha12Rng}; -//! let rng = ChaCha12Rng::from_os_rng(); -//! # let _: ChaCha12Rng = rng; -//! ``` -//! 2. **From a master generator.** This could be [`rand::rng`] -//! (effectively a fresh seed without the need for a syscall on each usage) -//! or a deterministic generator such as [`ChaCha20Rng`]. -//! Beware that should a weak master generator be used, correlations may be -//! detectable between the outputs of its child generators. -//! ```ignore -//! let rng = ChaCha12Rng::from_rng(&mut rand::rng()); -//! ``` -//! -//! See also [Seeding RNGs] in the book. -//! -//! ## Generation -//! -//! Generators implement [`RngCore`], whose methods may be used directly to -//! generate unbounded integer or byte values. -//! ``` -//! use rand_core::{SeedableRng, RngCore}; -//! use rand_chacha::ChaCha12Rng; -//! -//! let mut rng = ChaCha12Rng::from_seed(Default::default()); -//! let x = rng.next_u64(); -//! assert_eq!(x, 0x53f955076a9af49b); -//! ``` -//! -//! It is often more convenient to use the [`rand::Rng`] trait, which provides -//! further functionality. See also the [Random Values] chapter in the book. -//! -//! [ChaCha stream ciphers]: https://cr.yp.to/chacha.html -//! [Reproducibility]: https://rust-random.github.io/book/crate-reprod.html -//! [Seeding RNGs]: https://rust-random.github.io/book/guide-seeding.html -//! [Security]: https://rust-random.github.io/book/guide-rngs.html#security -//! [Random Values]: https://rust-random.github.io/book/guide-values.html -//! [`BlockRngCore`]: rand_core::block::BlockRngCore -//! [`RngCore`]: rand_core::RngCore -//! [`SeedableRng`]: rand_core::SeedableRng -//! [`SeedableRng::from_os_rng`]: rand_core::SeedableRng::from_os_rng -//! [`rand::rng`]: https://docs.rs/rand/latest/rand/fn.rng.html -//! [`rand::Rng`]: https://docs.rs/rand/latest/rand/trait.Rng.html - -#![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/" -)] -#![forbid(unsafe_code)] -#![deny(missing_docs)] -#![deny(missing_debug_implementations)] -#![doc(test(attr(allow(unused_variables), deny(warnings))))] -#![cfg_attr(not(feature = "std"), no_std)] - -pub use rand_core; - -mod chacha; -mod guts; - -pub use crate::chacha::{ - ChaCha12Core, ChaCha12Rng, ChaCha20Core, ChaCha20Rng, ChaCha8Core, ChaCha8Rng, -}; - -/// ChaCha with 20 rounds -pub type ChaChaRng = ChaCha20Rng; -/// ChaCha with 20 rounds, low-level interface -pub type ChaChaCore = ChaCha20Core; diff --git a/rand_pcg/src/lib.rs b/rand_pcg/src/lib.rs index 300d6bbc404..8e723e8e527 100644 --- a/rand_pcg/src/lib.rs +++ b/rand_pcg/src/lib.rs @@ -77,7 +77,6 @@ //! [`SeedableRng::from_rng`]: rand_core::SeedableRng#method.from_rng //! [`rand::rng`]: https://docs.rs/rand/latest/rand/fn.rng.html //! [`rand::Rng`]: https://docs.rs/rand/latest/rand/trait.Rng.html -//! [`rand_chacha::ChaCha8Rng`]: https://docs.rs/rand_chacha/latest/rand_chacha/struct.ChaCha8Rng.html #![doc( html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", diff --git a/src/rngs/mod.rs b/src/rngs/mod.rs index b4b4440b251..8be09be7e88 100644 --- a/src/rngs/mod.rs +++ b/src/rngs/mod.rs @@ -57,8 +57,6 @@ //! - The [`rand_jitter`] crate provides a user-space implementation of //! entropy harvesting from CPU timer jitter, but is very slow and has //! [security issues](https://github.com/rust-random/rand/issues/699). -//! - The [`rand_chacha`] crate provides portable implementations of -//! generators derived from the [ChaCha] family of stream ciphers //! - The [`rand_pcg`] crate provides portable implementations of a subset //! of the [PCG] family of small, insecure generators //! - The [`rand_xoshiro`] crate provides portable implementations of the @@ -87,7 +85,6 @@ //! [`SeedableRng`]: crate::SeedableRng //! [`rdrand`]: https://crates.io/crates/rdrand //! [`rand_jitter`]: https://crates.io/crates/rand_jitter -//! [`rand_chacha`]: https://crates.io/crates/rand_chacha //! [`rand_pcg`]: https://crates.io/crates/rand_pcg //! [`rand_xoshiro`]: https://crates.io/crates/rand_xoshiro //! [crates with the `rng` tag]: https://crates.io/keywords/rng diff --git a/src/rngs/small.rs b/src/rngs/small.rs index 67e0d0544f4..53ce71b0359 100644 --- a/src/rngs/small.rs +++ b/src/rngs/small.rs @@ -78,7 +78,6 @@ type Rng = super::xoshiro256plusplus::Xoshiro256PlusPlus; /// [`StdRng`]: crate::rngs::StdRng /// [rand_pcg]: https://crates.io/crates/rand_pcg /// [rand_xoshiro]: https://crates.io/crates/rand_xoshiro -/// [`rand_chacha::ChaCha8Rng`]: https://docs.rs/rand_chacha/latest/rand_chacha/struct.ChaCha8Rng.html /// [`rand_seeder`]: https://docs.rs/rand_seeder/latest/rand_seeder/ #[derive(Clone, Debug, PartialEq, Eq)] pub struct SmallRng(Rng); diff --git a/src/rngs/std.rs b/src/rngs/std.rs index 29e7219ff29..1f3d99f74f8 100644 --- a/src/rngs/std.rs +++ b/src/rngs/std.rs @@ -21,7 +21,7 @@ use chacha20::ChaCha12Rng as Rng; /// /// - Non-[portable]: any future library version may replace the algorithm /// and results may be platform-dependent. -/// (For a portable version, use the [rand_chacha] crate directly.) +/// (For a portable version, use the [chacha20] crate directly.) /// - [CSPRNG]: statistically good quality of randomness and [unpredictable] /// - Fast ([amortized](https://en.wikipedia.org/wiki/Amortized_analysis)): /// the RNG is fast for bulk generation, but the cost of method calls is not @@ -64,7 +64,7 @@ use chacha20::ChaCha12Rng as Rng; /// [unpredictable]: https://rust-random.github.io/book/guide-rngs.html#security /// [Random Values]: https://rust-random.github.io/book/guide-values.html /// [CSPRNG]: https://rust-random.github.io/book/guide-gen.html#cryptographically-secure-pseudo-random-number-generator -/// [rand_chacha]: https://crates.io/crates/rand_chacha +/// [chacha20]: https://crates.io/crates/chacha20 /// [rand issue]: https://github.com/rust-random/rand/issues/932 #[derive(Clone, Debug, PartialEq, Eq)] pub struct StdRng(Rng);