From 894edd4b2553377106b2c628b020a2aba0bfe773 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 13 Jan 2020 17:59:32 +0000 Subject: [PATCH 1/5] rand_chacha: integrate c2-chacha dependency --- rand_chacha/Cargo.toml | 4 +- rand_chacha/src/chacha.rs | 2 +- rand_chacha/src/guts.rs | 312 ++++++++++++++++++++++++++++++++++++++ rand_chacha/src/lib.rs | 1 + 4 files changed, 316 insertions(+), 3 deletions(-) create mode 100644 rand_chacha/src/guts.rs diff --git a/rand_chacha/Cargo.toml b/rand_chacha/Cargo.toml index 6a47b863417..3f90384e8c9 100644 --- a/rand_chacha/Cargo.toml +++ b/rand_chacha/Cargo.toml @@ -20,9 +20,9 @@ appveyor = { repository = "rust-random/rand" } [dependencies] rand_core = { path = "../rand_core", version = "0.5" } -c2-chacha = { version = "0.2.2", default-features = false, features = ["simd"] } +ppv-lite86 = { version = "0.2.6", default-features = false, features = ["simd"] } [features] default = ["std", "simd"] -std = ["c2-chacha/std"] +std = ["ppv-lite86/std"] simd = [] # deprecated diff --git a/rand_chacha/src/chacha.rs b/rand_chacha/src/chacha.rs index a40a7d38059..1865495d17e 100644 --- a/rand_chacha/src/chacha.rs +++ b/rand_chacha/src/chacha.rs @@ -12,7 +12,7 @@ #[cfg(feature = "std")] use std as core; use self::core::fmt; -use c2_chacha::guts::ChaCha; +use crate::guts::ChaCha; use rand_core::block::{BlockRng, BlockRngCore}; use rand_core::{CryptoRng, Error, RngCore, SeedableRng}; diff --git a/rand_chacha/src/guts.rs b/rand_chacha/src/guts.rs new file mode 100644 index 00000000000..b3216777713 --- /dev/null +++ b/rand_chacha/src/guts.rs @@ -0,0 +1,312 @@ +// 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}; + +#[cfg(feature = "rustcrypto_api")] +pub use stream_cipher::generic_array; + +pub use ppv_lite86::Machine; +use ppv_lite86::{vec128_storage, ArithOps, BitOps32, LaneWords4, MultiLane, StoreBytes, Vec4}; + +pub(crate) const BLOCK: usize = 64; +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; + +#[derive(Clone)] +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) + } + + #[inline(always)] + fn pos64(&self, m: M) -> u64 { + let d: M::u32x4 = m.unpack(self.d); + ((d.extract(1) as u64) << 32) | d.extract(0) as u64 + } + + /// Set 64-bit block count, affecting next refill. + #[inline(always)] + pub(crate) fn seek64(&mut self, m: M, blockct: u64) { + let d: M::u32x4 = m.unpack(self.d); + self.d = d + .insert((blockct >> 32) as u32, 1) + .insert(blockct as u32, 0) + .into(); + } + + /// Set 32-bit block count, affecting next refill. + #[inline(always)] + pub(crate) fn seek32(&mut self, m: M, blockct: u32) { + let d: M::u32x4 = m.unpack(self.d); + self.d = d.insert(blockct, 0).into(); + } + + /// Produce output from the current state. + #[inline(always)] + fn output_narrow(&mut self, m: M, x: State, out: &mut [u8; BLOCK]) { + let k = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]); + (x.a + k).write_le(&mut out[0..16]); + (x.b + m.unpack(self.b)).write_le(&mut out[16..32]); + (x.c + m.unpack(self.c)).write_le(&mut out[32..48]); + (x.d + m.unpack(self.d)).write_le(&mut out[48..64]); + } + + /// Add one to the block counter (no overflow check). + #[inline(always)] + fn inc_block_ct(&mut self, m: M) { + let mut pos = self.pos64(m); + let d0: M::u32x4 = m.unpack(self.d); + pos += 1; + let d1 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0); + self.d = d1.into(); + } + + /// Produce 4 blocks of output, advancing the state + #[inline(always)] + pub fn refill4(&mut self, drounds: u32, out: &mut [u8; BUFSZ]) { + refill_wide(self, drounds, out) + } + + /// Produce a block of output, advancing the state + #[inline(always)] + pub fn refill(&mut self, drounds: u32, out: &mut [u8; BLOCK]) { + refill_narrow(self, drounds, out) + } + + #[inline(always)] + pub(crate) fn refill_rounds(&mut self, drounds: u32) -> State { + refill_narrow_rounds(self, drounds) + } + + #[inline(always)] + pub fn set_stream_param(&mut self, param: u32, value: u64) { + set_stream_param(self, param, value) + } + + #[inline(always)] + pub fn get_stream_param(&self, param: u32) -> u64 { + get_stream_param(self, param) + } +} + +#[inline(always)] +fn refill_wide_impl( + m: Mach, + state: &mut ChaCha, + drounds: u32, + out: &mut [u8; BUFSZ], +) { + let k = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]); + let mut pos = state.pos64(m); + let d0: Mach::u32x4 = m.unpack(state.d); + pos += 1; + let d1 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0); + pos += 1; + let d2 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0); + pos += 1; + let d3 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0); + + 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: m.unpack(Mach::u32x4x4::from_lanes([d0, d1, d2, d3]).into()), + }; + for _ in 0..drounds { + x = round(x); + x = undiagonalize(round(diagonalize(x))); + } + let mut pos = state.pos64(m); + let d0: Mach::u32x4 = m.unpack(state.d); + pos += 1; + let d1 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0); + pos += 1; + let d2 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0); + pos += 1; + let d3 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0); + pos += 1; + let d4 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0); + + let (a, b, c, d) = ( + x.a.to_lanes(), + x.b.to_lanes(), + x.c.to_lanes(), + x.d.to_lanes(), + ); + let sb = m.unpack(state.b); + let sc = m.unpack(state.c); + let sd = [m.unpack(state.d), d1, d2, d3]; + state.d = d4.into(); + let mut words = out.chunks_exact_mut(16); + for ((((&a, &b), &c), &d), &sd) in a.iter().zip(&b).zip(&c).zip(&d).zip(&sd) { + (a + k).write_le(words.next().unwrap()); + (b + sb).write_le(words.next().unwrap()); + (c + sc).write_le(words.next().unwrap()); + (d + sd).write_le(words.next().unwrap()); + } +} + +dispatch!(m, Mach, { + fn refill_wide(state: &mut ChaCha, drounds: u32, out: &mut [u8; BUFSZ]) { + refill_wide_impl(m, state, drounds, out); + } +}); + +/// Refill the buffer from a single-block round, updating the block count. +dispatch_light128!(m, Mach, { + fn refill_narrow(state: &mut ChaCha, drounds: u32, out: &mut [u8; BLOCK]) { + let x = refill_narrow_rounds(state, drounds); + let x = State { + a: m.unpack(x.a), + b: m.unpack(x.b), + c: m.unpack(x.c), + d: m.unpack(x.d), + }; + state.output_narrow(m, x, out); + state.inc_block_ct(m); + } +}); + +/// 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 + } +}); + +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 index 63f7e2484b5..24125b45e10 100644 --- a/rand_chacha/src/lib.rs +++ b/rand_chacha/src/lib.rs @@ -21,6 +21,7 @@ pub use rand_core; mod chacha; +mod guts; pub use crate::chacha::{ ChaCha12Core, ChaCha12Rng, ChaCha20Core, ChaCha20Rng, ChaCha8Core, ChaCha8Rng, From de0c625be6bbcda203333eda0b4ec30684ec11d4 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 13 Jan 2020 18:02:59 +0000 Subject: [PATCH 2/5] rand_chacha: remove unused code / eliminate warnings --- rand_chacha/src/guts.rs | 67 ++--------------------------------------- 1 file changed, 2 insertions(+), 65 deletions(-) diff --git a/rand_chacha/src/guts.rs b/rand_chacha/src/guts.rs index b3216777713..cafd8f64620 100644 --- a/rand_chacha/src/guts.rs +++ b/rand_chacha/src/guts.rs @@ -79,60 +79,12 @@ impl ChaCha { ((d.extract(1) as u64) << 32) | d.extract(0) as u64 } - /// Set 64-bit block count, affecting next refill. - #[inline(always)] - pub(crate) fn seek64(&mut self, m: M, blockct: u64) { - let d: M::u32x4 = m.unpack(self.d); - self.d = d - .insert((blockct >> 32) as u32, 1) - .insert(blockct as u32, 0) - .into(); - } - - /// Set 32-bit block count, affecting next refill. - #[inline(always)] - pub(crate) fn seek32(&mut self, m: M, blockct: u32) { - let d: M::u32x4 = m.unpack(self.d); - self.d = d.insert(blockct, 0).into(); - } - - /// Produce output from the current state. - #[inline(always)] - fn output_narrow(&mut self, m: M, x: State, out: &mut [u8; BLOCK]) { - let k = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]); - (x.a + k).write_le(&mut out[0..16]); - (x.b + m.unpack(self.b)).write_le(&mut out[16..32]); - (x.c + m.unpack(self.c)).write_le(&mut out[32..48]); - (x.d + m.unpack(self.d)).write_le(&mut out[48..64]); - } - - /// Add one to the block counter (no overflow check). - #[inline(always)] - fn inc_block_ct(&mut self, m: M) { - let mut pos = self.pos64(m); - let d0: M::u32x4 = m.unpack(self.d); - pos += 1; - let d1 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0); - self.d = d1.into(); - } - /// Produce 4 blocks of output, advancing the state #[inline(always)] pub fn refill4(&mut self, drounds: u32, out: &mut [u8; BUFSZ]) { refill_wide(self, drounds, out) } - /// Produce a block of output, advancing the state - #[inline(always)] - pub fn refill(&mut self, drounds: u32, out: &mut [u8; BLOCK]) { - refill_narrow(self, drounds, out) - } - - #[inline(always)] - pub(crate) fn refill_rounds(&mut self, drounds: u32) -> State { - refill_narrow_rounds(self, drounds) - } - #[inline(always)] pub fn set_stream_param(&mut self, param: u32, value: u64) { set_stream_param(self, param, value) @@ -209,23 +161,8 @@ dispatch!(m, Mach, { } }); -/// Refill the buffer from a single-block round, updating the block count. -dispatch_light128!(m, Mach, { - fn refill_narrow(state: &mut ChaCha, drounds: u32, out: &mut [u8; BLOCK]) { - let x = refill_narrow_rounds(state, drounds); - let x = State { - a: m.unpack(x.a), - b: m.unpack(x.b), - c: m.unpack(x.c), - d: m.unpack(x.d), - }; - state.output_narrow(m, x, out); - state.inc_block_ct(m); - } -}); - -/// Single-block, rounds-only; shared by try_apply_keystream for tails shorter than BUFSZ -/// and XChaCha's setup step. +// 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]); From f1b7c0fcaec4fc4cb9c6142e01cd74b6b3dc90a3 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 13 Jan 2020 18:03:35 +0000 Subject: [PATCH 3/5] rand_chacha: cargo fmt --- rand_chacha/src/guts.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/rand_chacha/src/guts.rs b/rand_chacha/src/guts.rs index cafd8f64620..95c4c15b6ea 100644 --- a/rand_chacha/src/guts.rs +++ b/rand_chacha/src/guts.rs @@ -11,8 +11,7 @@ use ppv_lite86::{dispatch, dispatch_light128}; -#[cfg(feature = "rustcrypto_api")] -pub use stream_cipher::generic_array; +#[cfg(feature = "rustcrypto_api")] pub use stream_cipher::generic_array; pub use ppv_lite86::Machine; use ppv_lite86::{vec128_storage, ArithOps, BitOps32, LaneWords4, MultiLane, StoreBytes, Vec4}; @@ -98,10 +97,7 @@ impl ChaCha { #[inline(always)] fn refill_wide_impl( - m: Mach, - state: &mut ChaCha, - drounds: u32, - out: &mut [u8; BUFSZ], + m: Mach, state: &mut ChaCha, drounds: u32, out: &mut [u8; BUFSZ], ) { let k = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]); let mut pos = state.pos64(m); From c7f6c48d433b57b68a6db28df9377963e12bfd87 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 13 Jan 2020 18:04:59 +0000 Subject: [PATCH 4/5] rand_chacha: version bump & changelog --- rand_chacha/CHANGELOG.md | 3 +++ rand_chacha/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/rand_chacha/CHANGELOG.md b/rand_chacha/CHANGELOG.md index d242f972606..80007f531bd 100644 --- a/rand_chacha/CHANGELOG.md +++ b/rand_chacha/CHANGELOG.md @@ -4,6 +4,9 @@ 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.2] - 2020-01-20 +- Integrate `c2-chacha`, reducing dependency count (#931) + ## [0.2.1] - 2019-07-22 - Force enable the `simd` feature of `c2-chacha` (#845) diff --git a/rand_chacha/Cargo.toml b/rand_chacha/Cargo.toml index 3f90384e8c9..601fef9169b 100644 --- a/rand_chacha/Cargo.toml +++ b/rand_chacha/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rand_chacha" -version = "0.2.1" +version = "0.2.2" authors = ["The Rand Project Developers", "The Rust Project Developers", "The CryptoCorrosion Contributors"] license = "MIT OR Apache-2.0" readme = "README.md" From 145e5ff0b8e512e38b4f326474794150fcf838d7 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Mon, 13 Jan 2020 21:13:29 +0000 Subject: [PATCH 5/5] rand_chacha: remove another line of dead code --- rand_chacha/src/guts.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/rand_chacha/src/guts.rs b/rand_chacha/src/guts.rs index 95c4c15b6ea..7561c1bcd11 100644 --- a/rand_chacha/src/guts.rs +++ b/rand_chacha/src/guts.rs @@ -11,8 +11,6 @@ use ppv_lite86::{dispatch, dispatch_light128}; -#[cfg(feature = "rustcrypto_api")] pub use stream_cipher::generic_array; - pub use ppv_lite86::Machine; use ppv_lite86::{vec128_storage, ArithOps, BitOps32, LaneWords4, MultiLane, StoreBytes, Vec4};