Skip to content

Add next_bool method to RngCore and counter levels to BlockRng #1031

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
76 changes: 27 additions & 49 deletions rand_chacha/src/chacha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

//! The ChaCha random number generator.

// TODO: remove
#[cfg(not(feature = "std"))] use core;
#[cfg(feature = "std")] use std as core;

Expand All @@ -24,46 +25,23 @@ const BUF_BLOCKS: u8 = 4;
// number of 32-bit words per ChaCha block (fixed by algorithm definition)
const BLOCK_WORDS: u8 = 16;

pub struct Array64<T>([T; 64]);
impl<T> Default for Array64<T>
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<T> AsRef<[T]> for Array64<T> {
fn as_ref(&self) -> &[T] {
/// Type representing result of the ChaCha core iteration
#[derive(Eq, PartialEq, Default, Clone, Copy, Debug)]
pub struct Results([u64; 32]);

impl AsRef<[u64]> for Results {
#[inline(always)]
fn as_ref(&self) -> &[u64] {
&self.0
}
}
impl<T> AsMut<[T]> for Array64<T> {
fn as_mut(&mut self) -> &mut [T] {
&mut self.0
}
}
impl<T> Clone for Array64<T>
where T: Copy + Default
{
fn clone(&self) -> Self {
let mut new = Self::default();
new.0.copy_from_slice(&self.0);
new
}
}
impl<T> fmt::Debug for Array64<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Array64 {{}}")

impl AsMut<[u8; 256]> for Results {
#[inline(always)]
fn as_mut(&mut self) -> &mut [u8; 256] {
unsafe {
&mut *(self.0.as_mut_ptr() as *mut [u8; 256])
}
}
}

Expand All @@ -83,17 +61,11 @@ macro_rules! chacha_impl {
}

impl BlockRngCore for $ChaChaXCore {
type Item = u32;
type Results = Array64<u32>;
type Results = Results;
#[inline]
fn generate(&mut self, r: &mut Self::Results) {
// Fill slice of words by writing to equivalent slice of bytes, then fixing endianness.
self.state.refill4($rounds, unsafe {
&mut *(&mut *r as *mut Array64<u32> as *mut [u8; 256])
});
for x in r.as_mut() {
*x = x.to_le();
}
let r: &mut [u8; 256] = r.as_mut();
self.state.refill4($rounds, r);
}
}

Expand Down Expand Up @@ -162,6 +134,10 @@ macro_rules! chacha_impl {
}

impl RngCore for $ChaChaXRng {
#[inline]
fn next_bool(&mut self) -> bool {
self.rng.next_bool()
}
#[inline]
fn next_u32(&mut self) -> u32 {
self.rng.next_u32()
Expand All @@ -180,6 +156,7 @@ macro_rules! chacha_impl {
}
}

/*
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 seeked it may not be self-aligned.
Expand Down Expand Up @@ -245,6 +222,7 @@ macro_rules! chacha_impl {
}
}
}
*/

impl CryptoRng for $ChaChaXRng {}

Expand All @@ -258,8 +236,7 @@ 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()
self.rng.eq(&rhs.rng)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure this is correct.

Copy link
Contributor

Choose a reason for hiding this comment

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

Good catch @vks.

@newpavlov There is a reason BlockRng doesn't derive PartialEq. (This probably deserves a comment in the source, because it's subtle.) Two BlockRngs can be logically equivalent without being bitwise equivalent if: their buffers correspond to different positions in the stream (equivalently: their underlying RNGs have different block counters), and the indexes into their buffers are at different positions, and these differences offset each other. This situation happens with Seekable RNGs like ChaCha.

}
}
impl Eq for $ChaChaXRng {}
Expand Down Expand Up @@ -344,7 +321,7 @@ mod test {
];
assert_eq!(results, expected);
}

/*
#[test]
fn test_chacha_true_values_c() {
// Test vector 4 from
Expand Down Expand Up @@ -506,4 +483,5 @@ mod test {
rng.set_word_pos(0);
assert_eq!(rng.get_word_pos(), 0);
}
*/
}
2 changes: 1 addition & 1 deletion rand_chacha/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![doc(test(attr(allow(unused_variables), deny(warnings))))]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), no_std)] // TODO: use `#![no_std]`

pub use rand_core;

Expand Down
Loading