aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-03-25 12:32:30 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-03-25 12:32:30 +0000
commit18ad126d0d50bf948b63ed5c1d91905752400508 (patch)
treed9ccef6def8def89a2570e9f3e3a7e944d61f16b
parent04cf306a95531e641cba1918c7559af682be1939 (diff)
parent3eaac1d03750a3fede31fa0cbbf6d41214638bc6 (diff)
downloadrand_chacha-android13-mainline-go-ipsec-release.tar.gz
Snap for 8358640 from 3eaac1d03750a3fede31fa0cbbf6d41214638bc6 to mainline-go-ipsec-releaseaml_go_ips_330911000android13-mainline-go-ipsec-release
Change-Id: If87c4a8fe4b518379cbe324313aac98d8d8e94d2
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--Android.bp35
-rw-r--r--CHANGELOG.md5
-rw-r--r--Cargo.toml14
-rw-r--r--Cargo.toml.orig12
-rw-r--r--METADATA10
-rw-r--r--TEST_MAPPING99
-rw-r--r--cargo2android.json10
-rw-r--r--src/chacha.rs145
-rw-r--r--src/guts.rs41
10 files changed, 336 insertions, 37 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 0db4f9b..e097925 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
{
"git": {
- "sha1": "98e220c30234370fb04ba928799ebd9727fc049a"
+ "sha1": "98a0339f99ecfe0467b2829c329bd8b7525a1c21"
}
}
diff --git a/Android.bp b/Android.bp
index 4fa5058..0e15608 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,4 +1,5 @@
-// This file is generated by cargo2android.py --device --run --dependencies.
+// This file is generated by cargo2android.py --config cargo2android.json.
+// Do not modify this file as changes will be overridden on upgrade.
package {
default_applicable_licenses: ["external_rust_crates_rand_chacha_license"],
@@ -41,6 +42,8 @@ rust_library {
name: "librand_chacha",
host_supported: true,
crate_name: "rand_chacha",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.3.1",
srcs: ["src/lib.rs"],
edition: "2018",
features: [
@@ -51,8 +54,32 @@ rust_library {
"libppv_lite86",
"librand_core",
],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.virt",
+ ],
}
-// dependent_library ["feature_list"]
-// ppv-lite86-0.2.10 "simd,std"
-// rand_core-0.6.0
+rust_test {
+ name: "rand_chacha_test_src_lib",
+ host_supported: true,
+ crate_name: "rand_chacha",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.3.1",
+ srcs: ["src/lib.rs"],
+ test_suites: ["general-tests"],
+ auto_gen_config: true,
+ test_options: {
+ unit_test: true,
+ },
+ edition: "2018",
+ features: [
+ "default",
+ "std",
+ ],
+ rustlibs: [
+ "libppv_lite86",
+ "librand_core",
+ "libserde_json",
+ ],
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8a07390..a598bb7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,11 @@ 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.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)
diff --git a/Cargo.toml b/Cargo.toml
index 0f371b3..c907ae9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,11 +13,11 @@
[package]
edition = "2018"
name = "rand_chacha"
-version = "0.3.0"
+version = "0.3.1"
authors = ["The Rand Project Developers", "The Rust Project Developers", "The CryptoCorrosion Contributors"]
description = "ChaCha random number generator\n"
-homepage = "https://crates.io/crates/rand_chacha"
-documentation = "https://rust-random.github.io/rand/rand_chacha/"
+homepage = "https://rust-random.github.io/book"
+documentation = "https://docs.rs/rand_chacha"
readme = "README.md"
keywords = ["random", "rng", "chacha"]
categories = ["algorithms", "no-std"]
@@ -31,7 +31,15 @@ default-features = false
[dependencies.rand_core]
version = "0.6.0"
+[dependencies.serde]
+version = "1.0"
+features = ["derive"]
+optional = true
+[dev-dependencies.serde_json]
+version = "1.0"
+
[features]
default = ["std"]
+serde1 = ["serde"]
simd = []
std = ["ppv-lite86/std"]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 8d7dcd7..53f9f59 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,12 +1,12 @@
[package]
name = "rand_chacha"
-version = "0.3.0"
+version = "0.3.1"
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://rust-random.github.io/rand/rand_chacha/"
-homepage = "https://crates.io/crates/rand_chacha"
+documentation = "https://docs.rs/rand_chacha"
+homepage = "https://rust-random.github.io/book"
description = """
ChaCha random number generator
"""
@@ -17,8 +17,14 @@ edition = "2018"
[dependencies]
rand_core = { path = "../rand_core", version = "0.6.0" }
ppv-lite86 = { version = "0.2.8", default-features = false, features = ["simd"] }
+serde = { version = "1.0", features = ["derive"], optional = true }
+
+[dev-dependencies]
+# Only to test serde1
+serde_json = "1.0"
[features]
default = ["std"]
std = ["ppv-lite86/std"]
simd = [] # deprecated
+serde1 = ["serde"]
diff --git a/METADATA b/METADATA
index ba8e6ec..72cd107 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/rand_chacha/rand_chacha-0.3.0.crate"
+ value: "https://static.crates.io/crates/rand_chacha/rand_chacha-0.3.1.crate"
}
- version: "0.3.0"
+ version: "0.3.1"
license_type: NOTICE
last_upgrade_date {
- year: 2020
- month: 12
- day: 15
+ year: 2021
+ month: 6
+ day: 21
}
}
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..3f99cb1
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,99 @@
+// Generated by update_crate_tests.py for tests that depend on this crate.
+{
+ "imports": [
+ {
+ "path": "external/rust/crates/base64"
+ },
+ {
+ "path": "external/rust/crates/cast"
+ },
+ {
+ "path": "external/rust/crates/crc32fast"
+ },
+ {
+ "path": "external/rust/crates/crossbeam-deque"
+ },
+ {
+ "path": "external/rust/crates/crossbeam-epoch"
+ },
+ {
+ "path": "external/rust/crates/crossbeam-queue"
+ },
+ {
+ "path": "external/rust/crates/crossbeam-utils"
+ },
+ {
+ "path": "external/rust/crates/mio"
+ },
+ {
+ "path": "external/rust/crates/quickcheck"
+ },
+ {
+ "path": "external/rust/crates/regex"
+ },
+ {
+ "path": "external/rust/crates/ryu"
+ },
+ {
+ "path": "external/rust/crates/tokio"
+ }
+ ],
+ "presubmit": [
+ {
+ "name": "ZipFuseTest"
+ },
+ {
+ "name": "apkdmverity.test"
+ },
+ {
+ "name": "authfs_device_test_src_lib"
+ },
+ {
+ "name": "keystore2_test"
+ },
+ {
+ "name": "keystore2_test_utils_test"
+ },
+ {
+ "name": "legacykeystore_test"
+ },
+ {
+ "name": "microdroid_manager_test"
+ },
+ {
+ "name": "rand_chacha_test_src_lib"
+ },
+ {
+ "name": "virtualizationservice_device_test"
+ }
+ ],
+ "presubmit-rust": [
+ {
+ "name": "ZipFuseTest"
+ },
+ {
+ "name": "apkdmverity.test"
+ },
+ {
+ "name": "authfs_device_test_src_lib"
+ },
+ {
+ "name": "keystore2_test"
+ },
+ {
+ "name": "keystore2_test_utils_test"
+ },
+ {
+ "name": "legacykeystore_test"
+ },
+ {
+ "name": "microdroid_manager_test"
+ },
+ {
+ "name": "rand_chacha_test_src_lib"
+ },
+ {
+ "name": "virtualizationservice_device_test"
+ }
+ ]
+}
diff --git a/cargo2android.json b/cargo2android.json
new file mode 100644
index 0000000..ac56e26
--- /dev/null
+++ b/cargo2android.json
@@ -0,0 +1,10 @@
+{
+ "apex-available": [
+ "//apex_available:platform",
+ "com.android.virt"
+ ],
+ "dependencies": true,
+ "device": true,
+ "run": true,
+ "tests": true
+} \ No newline at end of file
diff --git a/src/chacha.rs b/src/chacha.rs
index 17bcc55..50da81b 100644
--- a/src/chacha.rs
+++ b/src/chacha.rs
@@ -16,14 +16,14 @@ use crate::guts::ChaCha;
use rand_core::block::{BlockRng, BlockRngCore};
use rand_core::{CryptoRng, Error, RngCore, SeedableRng};
-const STREAM_PARAM_NONCE: u32 = 1;
-const STREAM_PARAM_BLOCK: u32 = 0;
+#[cfg(feature = "serde1")] use serde::{Serialize, Deserialize, Serializer, Deserializer};
// 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>([T; 64]);
impl<T> Default for Array64<T>
where T: Default
@@ -68,7 +68,7 @@ impl<T> fmt::Debug for Array64<T> {
}
macro_rules! chacha_impl {
- ($ChaChaXCore:ident, $ChaChaXRng:ident, $rounds:expr, $doc:expr) => {
+ ($ChaChaXCore:ident, $ChaChaXRng:ident, $rounds:expr, $doc:expr, $abst:ident) => {
#[doc=$doc]
#[derive(Clone, PartialEq, Eq)]
pub struct $ChaChaXCore {
@@ -193,7 +193,7 @@ macro_rules! chacha_impl {
#[inline]
pub fn get_word_pos(&self) -> u128 {
let buf_start_block = {
- let buf_end_block = self.rng.core.state.get_stream_param(STREAM_PARAM_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) = {
@@ -218,7 +218,7 @@ macro_rules! chacha_impl {
self.rng
.core
.state
- .set_stream_param(STREAM_PARAM_BLOCK, block);
+ .set_block_pos(block);
self.rng.generate_and_set((word_offset % u128::from(BLOCK_WORDS)) as usize);
}
@@ -238,12 +238,30 @@ macro_rules! chacha_impl {
self.rng
.core
.state
- .set_stream_param(STREAM_PARAM_NONCE, stream);
+ .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 {}
@@ -258,24 +276,129 @@ macro_rules! chacha_impl {
impl PartialEq<$ChaChaXRng> for $ChaChaXRng {
fn eq(&self, rhs: &$ChaChaXRng) -> bool {
- self.rng.core.state.stream64_eq(&rhs.rng.core.state)
- && self.get_word_pos() == rhs.get_word_pos()
+ let a: $abst::$ChaChaXRng = self.into();
+ let b: $abst::$ChaChaXRng = rhs.into();
+ a == b
}
}
impl Eq for $ChaChaXRng {}
+
+ #[cfg(feature = "serde1")]
+ impl Serialize for $ChaChaXRng {
+ fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
+ where S: Serializer {
+ $abst::$ChaChaXRng::from(self).serialize(s)
+ }
+ }
+ #[cfg(feature = "serde1")]
+ impl<'de> Deserialize<'de> for $ChaChaXRng {
+ fn deserialize<D>(d: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
+ $abst::$ChaChaXRng::deserialize(d).map(|x| Self::from(&x))
+ }
+ }
+
+ mod $abst {
+ #[cfg(feature = "serde1")] use serde::{Serialize, Deserialize};
+
+ // 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 = "serde1",
+ 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");
-chacha_impl!(ChaCha12Core, ChaCha12Rng, 6, "ChaCha with 12 rounds");
-chacha_impl!(ChaCha8Core, ChaCha8Rng, 4, "ChaCha with 8 rounds");
+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 = "serde1")] use super::{ChaCha20Rng, ChaCha12Rng, ChaCha8Rng};
+
type ChaChaRng = super::ChaCha20Rng;
+ #[cfg(feature = "serde1")]
+ #[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 = "serde1")]
+ #[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 = [
diff --git a/src/guts.rs b/src/guts.rs
index 27ff957..cee8cf7 100644
--- a/src/guts.rs
+++ b/src/guts.rs
@@ -21,6 +21,9 @@ 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,
@@ -83,21 +86,28 @@ impl ChaCha {
}
#[inline(always)]
- pub fn set_stream_param(&mut self, param: u32, value: u64) {
- set_stream_param(self, param, value)
+ 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_stream_param(&self, param: u32) -> u64 {
- get_stream_param(self, param)
+ pub fn get_nonce(&self) -> u64 {
+ get_stream_param(self, STREAM_PARAM_NONCE)
}
- /// Return whether rhs is equal in all parameters except current 64-bit position.
- #[inline]
- pub fn stream64_eq(&self, rhs: &Self) -> bool {
- let self_d: [u32; 4] = self.d.into();
- let rhs_d: [u32; 4] = rhs.d.into();
- self.b == rhs.b && self.c == rhs.c && self_d[3] == rhs_d[3] && self_d[2] == rhs_d[2]
+ #[inline(always)]
+ pub fn get_seed(&self) -> [u8; 32] {
+ get_seed(self)
}
}
@@ -205,6 +215,17 @@ dispatch_light128!(m, Mach, {
}
});
+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)