diff --git a/chacha20/src/lib.rs b/chacha20/src/lib.rs index 11fac731..5ed62d22 100644 --- a/chacha20/src/lib.rs +++ b/chacha20/src/lib.rs @@ -136,7 +136,7 @@ pub use chacha::{ChaCha8, ChaCha12, ChaCha20, Key, KeyIvInit}; #[cfg(feature = "rng")] pub use rand_core; #[cfg(feature = "rng")] -pub use rng::{ChaCha8Core, ChaCha8Rng, ChaCha12Core, ChaCha12Rng, ChaCha20Core, ChaCha20Rng}; +pub use rng::{ChaCha8Rng, ChaCha12Rng, ChaCha20Rng}; #[cfg(feature = "legacy")] pub use legacy::{ChaCha20Legacy, LegacyNonce}; @@ -265,6 +265,16 @@ impl ChaChaCore { _pd: PhantomData, } } + + #[inline(always)] + fn get_block_pos(&self) -> V::Counter { + V::get_block_pos(&self.state[12..]) + } + + #[inline(always)] + fn set_block_pos(&mut self, pos: V::Counter) { + V::set_block_pos(&mut self.state[12..], pos); + } } #[cfg(feature = "cipher")] @@ -273,12 +283,12 @@ impl StreamCipherSeekCore for ChaChaCore { #[inline(always)] fn get_block_pos(&self) -> Self::Counter { - V::get_block_pos(&self.state[12..]) + self.get_block_pos() } #[inline(always)] fn set_block_pos(&mut self, pos: Self::Counter) { - V::set_block_pos(&mut self.state[12..], pos); + self.set_block_pos(pos) } } diff --git a/chacha20/src/rng.rs b/chacha20/src/rng.rs index 0c7e7abc..0f4a1324 100644 --- a/chacha20/src/rng.rs +++ b/chacha20/src/rng.rs @@ -77,33 +77,32 @@ impl Debug for Seed { } } -/// A wrapper around 64 bits of data that can be constructed from any of the -/// following: +/// A wrapper for `stream_id` (64-bits). +/// +/// Can be constructed from any of the following: /// * `u64` /// * `[u32; 2]` /// * `[u8; 8]` /// -/// The arrays should be in little endian order. You should not need to use -/// this directly, as the methods in this crate that use this type call -/// `.into()` for you, so you only need to supply any of the above types. -pub struct U32x2([u32; Self::LEN]); +/// The arrays should be in little endian order. +pub struct StreamId([u32; Self::LEN]); -impl U32x2 { - /// Amount of raw bytes backing a `U32x2` instance. +impl StreamId { + /// Amount of raw bytes backing a `StreamId` instance. const BYTES: usize = size_of::(); - /// The length of the array contained within `U32x2`. + /// The length of the array contained within `StreamId`. const LEN: usize = 2; } -impl From<[u32; Self::LEN]> for U32x2 { +impl From<[u32; Self::LEN]> for StreamId { #[inline] fn from(value: [u32; Self::LEN]) -> Self { Self(value) } } -impl From<[u8; Self::BYTES]> for U32x2 { +impl From<[u8; Self::BYTES]> for StreamId { #[inline] fn from(value: [u8; Self::BYTES]) -> Self { let mut result = Self(Default::default()); @@ -118,7 +117,7 @@ impl From<[u8; Self::BYTES]> for U32x2 { } } -impl From for U32x2 { +impl From for StreamId { #[inline] fn from(value: u64) -> Self { let result: [u8; Self::BYTES] = value.to_le_bytes()[..Self::BYTES].try_into().unwrap(); @@ -126,26 +125,6 @@ impl From for U32x2 { } } -/// A wrapper for `stream_id`. -/// -/// Can be constructed from any of the following: -/// * `u64` -/// * `[u32; 2]` -/// * `[u8; 8]` -/// -/// The arrays should be in little endian order. -pub type StreamId = U32x2; - -/// A wrapper for `block_pos`. -/// -/// Can be constructed from any of the following: -/// * `u64` -/// * `[u32; 2]` -/// * `[u8; 8]` -/// -/// The arrays should be in little endian order. -pub type BlockPos = U32x2; - const BUFFER_SIZE: usize = 64; // NB. this must remain consistent with some currently hard-coded numbers in this module @@ -195,7 +174,7 @@ impl ChaChaCore { } macro_rules! impl_chacha_rng { - ($ChaChaXRng:ident, $ChaChaXCore:ident, $rounds:ident, $abst:ident) => { + ($ChaChaXRng:ident, $rounds:ident, $abst:ident) => { /// 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 @@ -225,8 +204,9 @@ macro_rules! impl_chacha_rng { /// 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 [`Rng`] methods. + /// This implementation uses an output buffer of sixteen `u32` words, using + /// [`rand_core::block::BlockRng`] over [`ChaChaCore`] to implement + /// [`rand_core::Rng`]. /// /// # Example for `ChaCha20Rng` /// @@ -266,19 +246,15 @@ macro_rules! impl_chacha_rng { /// /// [^2]: [eSTREAM: the ECRYPT Stream Cipher Project](http://www.ecrypt.eu.org/stream/) pub struct $ChaChaXRng { - /// The ChaChaCore struct - pub core: BlockRng<$ChaChaXCore>, + core: BlockRng>, } - /// The ChaCha core random number generator - pub struct $ChaChaXCore(ChaChaCore<$rounds, Legacy>); - - impl SeedableRng for $ChaChaXCore { + impl SeedableRng for ChaChaCore<$rounds, Legacy> { type Seed = Seed; #[inline] fn from_seed(seed: Self::Seed) -> Self { - Self(ChaChaCore::<$rounds, Legacy>::new(seed.as_ref(), &[0u8; 8])) + ChaChaCore::<$rounds, Legacy>::new(seed.as_ref(), &[0u8; 8]) } } impl SeedableRng for $ChaChaXRng { @@ -287,7 +263,7 @@ macro_rules! impl_chacha_rng { #[inline] fn from_seed(seed: Self::Seed) -> Self { Self { - core: BlockRng::new($ChaChaXCore::from_seed(seed.into())), + core: BlockRng::new(ChaChaCore::<$rounds, Legacy>::from_seed(seed.into())), } } } @@ -308,12 +284,9 @@ macro_rules! impl_chacha_rng { Ok(()) } } - impl CryptoGenerator for $ChaChaXCore {} + impl CryptoGenerator for ChaChaCore<$rounds, Legacy> {} impl TryCryptoRng for $ChaChaXRng {} - #[cfg(feature = "zeroize")] - impl ZeroizeOnDrop for $ChaChaXCore {} - #[cfg(feature = "zeroize")] impl ZeroizeOnDrop for $ChaChaXRng {} @@ -336,8 +309,8 @@ macro_rules! impl_chacha_rng { /// byte-offset. #[inline] pub fn get_word_pos(&self) -> u128 { - let mut block_counter = (u64::from(self.core.core.0.state[13]) << 32) - | u64::from(self.core.core.0.state[12]); + let mut block_counter = (u64::from(self.core.core.state[13]) << 32) + | u64::from(self.core.core.state[12]); if self.core.word_offset() != 0 { block_counter = block_counter.wrapping_sub(BUF_BLOCKS as u64); } @@ -360,8 +333,8 @@ macro_rules! impl_chacha_rng { let index = (word_offset % BLOCK_WORDS as u128) as usize; let counter = word_offset / BLOCK_WORDS as u128; //self.set_block_pos(counter as u64); - self.core.core.0.state[12] = counter as u32; - self.core.core.0.state[13] = (counter >> 32) as u32; + self.core.core.state[12] = counter as u32; + self.core.core.state[13] = (counter >> 32) as u32; self.core.reset_and_skip(index); } @@ -371,28 +344,18 @@ macro_rules! impl_chacha_rng { /// together. /// /// The word pos will be equal to `block_pos * 16 words per block`. - /// - /// This method takes any of the following: - /// * `u64` - /// * `[u32; 2]` - /// * `[u8; 8]` - /// - /// Note: the arrays should be in little endian order. #[inline] #[allow(unused)] - pub fn set_block_pos>(&mut self, block_pos: B) { + pub fn set_block_pos>(&mut self, block_pos: u64) { self.core.reset_and_skip(0); - let block_pos = block_pos.into().0; - self.core.core.0.state[12] = block_pos[0]; - self.core.core.0.state[13] = block_pos[1] + self.core.set_block_pos(block_pos); } /// Get the block pos. #[inline] #[allow(unused)] pub fn get_block_pos(&self) -> u64 { - let counter = - self.core.core.0.state[12] as u64 | ((self.core.core.0.state[13] as u64) << 32); + let counter = self.core.get_block_pos(); if self.core.word_offset() != 0 { counter - BUF_BLOCKS as u64 + self.core.word_offset() as u64 / 16 } else { @@ -440,7 +403,7 @@ macro_rules! impl_chacha_rng { #[inline] pub fn set_stream>(&mut self, stream: S) { let stream: StreamId = stream.into(); - self.core.core.0.state[14..].copy_from_slice(&stream.0); + self.core.core.state[14..].copy_from_slice(&stream.0); self.set_block_pos(0); } @@ -448,7 +411,7 @@ macro_rules! impl_chacha_rng { #[inline] pub fn get_stream(&self) -> u64 { let mut result = [0u8; 8]; - for (i, &big) in self.core.core.0.state[14..BLOCK_WORDS as usize] + for (i, &big) in self.core.core.state[14..BLOCK_WORDS as usize] .iter() .enumerate() { @@ -465,7 +428,7 @@ macro_rules! impl_chacha_rng { #[inline] pub fn get_seed(&self) -> [u8; 32] { let mut result = [0u8; 32]; - for (i, &big) in self.core.core.0.state[4..12].iter().enumerate() { + for (i, &big) in self.core.core.state[4..12].iter().enumerate() { let index = i * 4; result[index + 0] = big as u8; result[index + 1] = (big >> 8) as u8; @@ -486,14 +449,6 @@ macro_rules! impl_chacha_rng { impl Eq for $ChaChaXRng {} - impl From<$ChaChaXCore> for $ChaChaXRng { - fn from(core: $ChaChaXCore) -> Self { - $ChaChaXRng { - core: BlockRng::new(core), - } - } - } - mod $abst { // 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 @@ -529,12 +484,12 @@ macro_rules! impl_chacha_rng { } } - impl Generator for $ChaChaXCore { + impl Generator for ChaChaCore<$rounds, Legacy> { type Output = [u32; BUFFER_SIZE]; #[inline] fn generate(&mut self, r: &mut Self::Output) { - self.0.generate(r); + self.generate(r); } #[cfg(feature = "zeroize")] @@ -545,11 +500,11 @@ macro_rules! impl_chacha_rng { }; } -impl_chacha_rng!(ChaCha8Rng, ChaCha8Core, R8, abst8); +impl_chacha_rng!(ChaCha8Rng, R8, abst8); -impl_chacha_rng!(ChaCha12Rng, ChaCha12Core, R12, abst12); +impl_chacha_rng!(ChaCha12Rng, R12, abst12); -impl_chacha_rng!(ChaCha20Rng, ChaCha20Core, R20, abst20); +impl_chacha_rng!(ChaCha20Rng, R20, abst20); #[cfg(test)] pub(crate) mod tests { @@ -920,7 +875,7 @@ pub(crate) mod tests { #[test] fn test_chacha_word_pos_zero() { let mut rng = ChaChaRng::from_seed(Default::default()); - assert_eq!(rng.core.core.0.state[12], 0); + assert_eq!(rng.core.core.state[12], 0); assert_eq!(rng.core.word_offset(), 0); assert_eq!(rng.get_word_pos(), 0); rng.set_word_pos(0);