Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion chacha20/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
59 changes: 27 additions & 32 deletions chacha20/src/rng.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ impl<R: Rounds, V: Variant> ChaChaCore<R, V> {
}

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
Expand Down Expand Up @@ -225,8 +225,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`
///
Expand Down Expand Up @@ -267,18 +268,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>,
pub core: BlockRng<ChaChaCore<$rounds, Legacy>>,
Comment thread
dhardy marked this conversation as resolved.
Outdated
}

/// 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 {
Expand All @@ -287,7 +285,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())),
}
}
}
Expand All @@ -308,12 +306,9 @@ macro_rules! impl_chacha_rng {
Ok(())
}
}
impl CryptoGenerator for $ChaChaXCore {}
impl CryptoGenerator for ChaChaCore<$rounds, Legacy> {}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the field will be private this impl can be removed.

Copy link
Copy Markdown
Contributor Author

@dhardy dhardy Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point being that we don't need trait CryptoGenerator at all. The trait is (I believe) only used by ReseedingRng, so lets start with that. (Another PR will be needed to update to the new rand_core soon anyway.)

impl TryCryptoRng for $ChaChaXRng {}

#[cfg(feature = "zeroize")]
impl ZeroizeOnDrop for $ChaChaXCore {}

#[cfg(feature = "zeroize")]
impl ZeroizeOnDrop for $ChaChaXRng {}

Expand All @@ -336,8 +331,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);
}
Expand All @@ -360,8 +355,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);
}

Expand All @@ -383,16 +378,16 @@ macro_rules! impl_chacha_rng {
pub fn set_block_pos<B: Into<BlockPos>>(&mut self, block_pos: B) {
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.core.state[12] = block_pos[0];
self.core.core.state[13] = block_pos[1]
}

/// 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);
self.core.core.state[12] as u64 | ((self.core.core.state[13] as u64) << 32);
if self.core.word_offset() != 0 {
counter - BUF_BLOCKS as u64 + self.core.word_offset() as u64 / 16
} else {
Expand Down Expand Up @@ -440,15 +435,15 @@ macro_rules! impl_chacha_rng {
#[inline]
pub fn set_stream<S: Into<StreamId>>(&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);
}

/// Get the stream number.
#[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()
{
Expand All @@ -465,7 +460,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;
Expand All @@ -486,8 +481,8 @@ macro_rules! impl_chacha_rng {

impl Eq for $ChaChaXRng {}

impl From<$ChaChaXCore> for $ChaChaXRng {
fn from(core: $ChaChaXCore) -> Self {
impl From<ChaChaCore<$rounds, Legacy>> for $ChaChaXRng {
Comment thread
dhardy marked this conversation as resolved.
Outdated
fn from(core: ChaChaCore<$rounds, Legacy>) -> Self {
$ChaChaXRng {
core: BlockRng::new(core),
}
Expand Down Expand Up @@ -529,12 +524,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")]
Expand All @@ -545,11 +540,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 {
Expand Down Expand Up @@ -920,7 +915,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);
Expand Down