Skip to content
Draft
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
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ exclude = ["benches", "distr_test"]
rand_core = { version = "0.10.0-rc-2", default-features = false }
log = { version = "0.4.4", optional = true }
serde = { version = "1.0.103", features = ["derive"], optional = true }
chacha20 = { version = "=0.10.0-rc.5", default-features = false, features = ["rng"], optional = true }
chacha20 = { path = "rand_chacha", optional = true, package = "rand_chacha" }
getrandom = { version = "0.3.0", optional = true }

[dev-dependencies]
Expand All @@ -85,3 +85,6 @@ rand_pcg = { path = "rand_pcg", version = "0.10.0-rc.1" }
bincode = "1.2.1"
rayon = "1.7"
serde_json = "1.0.140"

[patch.crates-io]
rand_core = { git = "https://github.com/rust-random/rand_core.git", branch = "reduce-block-code" }
3 changes: 3 additions & 0 deletions benches/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,6 @@ harness = false
[[bench]]
name = "weighted"
harness = false

[patch.crates-io]
rand_core = { git = "https://github.com/rust-random/rand_core.git", branch = "reduce-block-code" }
63 changes: 8 additions & 55 deletions rand_chacha/src/chacha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

use crate::guts::ChaCha;
use core::fmt;
use rand_core::block::{BlockRng, BlockRngCore, CryptoBlockRng};
use rand_core::block::{BlockRng, CryptoGenerator, Generator};
use rand_core::{CryptoRng, RngCore, SeedableRng};

#[cfg(feature = "serde")]
Expand All @@ -21,52 +21,6 @@ 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,
{
#[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] {
&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 {{}}")
}
}

macro_rules! chacha_impl {
($ChaChaXCore:ident, $ChaChaXRng:ident, $rounds:expr, $doc:expr, $abst:ident,) => {
#[doc=$doc]
Expand All @@ -82,13 +36,12 @@ macro_rules! chacha_impl {
}
}

impl BlockRngCore for $ChaChaXCore {
type Item = u32;
type Results = Array64<u32>;
impl Generator for $ChaChaXCore {
type Output = [u32; 64];

#[inline]
fn generate(&mut self, r: &mut Self::Results) {
self.state.refill4($rounds, &mut r.0);
fn generate(&mut self, output: &mut Self::Output) {
self.state.refill4($rounds, output);
}
}

Expand All @@ -103,7 +56,7 @@ macro_rules! chacha_impl {
}
}

impl CryptoBlockRng for $ChaChaXCore {}
impl CryptoGenerator for $ChaChaXCore {}

/// A cryptographically secure random number generator that uses the ChaCha algorithm.
///
Expand Down Expand Up @@ -163,12 +116,12 @@ macro_rules! chacha_impl {
impl RngCore for $ChaChaXRng {
#[inline]
fn next_u32(&mut self) -> u32 {
self.rng.next_u32()
self.rng.next_word()
}

#[inline]
fn next_u64(&mut self) -> u64 {
self.rng.next_u64()
self.rng.next_u64_from_u32()
}

#[inline]
Expand Down
61 changes: 30 additions & 31 deletions src/rngs/reseeding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@

use core::mem::size_of_val;

use rand_core::block::{BlockRng, BlockRngCore, CryptoBlockRng};
use rand_core::block::{BlockRng, CryptoGenerator, Generator};
use rand_core::{CryptoRng, RngCore, SeedableRng, TryCryptoRng, TryRngCore};

/// A wrapper around any PRNG that implements [`BlockRngCore`], that adds the
/// A wrapper around any PRNG that implements [`Generator`], that adds the
/// ability to reseed it.
///
/// `ReseedingRng` reseeds the underlying PRNG in the following cases:
Expand Down Expand Up @@ -53,7 +53,7 @@ use rand_core::{CryptoRng, RngCore, SeedableRng, TryCryptoRng, TryRngCore};
///
/// ```
/// use chacha20::ChaCha20Core; // Internal part of ChaChaRng that
/// // implements BlockRngCore
/// // implements Generator
/// use rand::prelude::*;
/// use rand::rngs::OsRng;
/// use rand::rngs::ReseedingRng;
Expand All @@ -63,18 +63,18 @@ use rand_core::{CryptoRng, RngCore, SeedableRng, TryCryptoRng, TryRngCore};
/// println!("{}", reseeding_rng.random::<u64>());
/// ```
///
/// [`BlockRngCore`]: rand_core::block::BlockRngCore
/// [`Generator`]: rand_core::block::Generator
/// [`ReseedingRng::new`]: ReseedingRng::new
/// [`reseed()`]: ReseedingRng::reseed
#[derive(Debug)]
pub struct ReseedingRng<R, Rsdr>(BlockRng<ReseedingCore<R, Rsdr>>)
pub struct ReseedingRng<G, Rsdr>(BlockRng<ReseedingCore<G, Rsdr>>)
where
R: BlockRngCore + SeedableRng,
G: Generator + SeedableRng,
Rsdr: TryRngCore;

impl<R, Rsdr> ReseedingRng<R, Rsdr>
impl<const N: usize, G, Rsdr> ReseedingRng<G, Rsdr>
where
R: BlockRngCore + SeedableRng,
G: Generator<Output = [u32; N]> + SeedableRng,
Rsdr: TryRngCore,
{
/// Create a new `ReseedingRng` from an existing PRNG, combined with a RNG
Expand All @@ -100,71 +100,70 @@ where

// TODO: this should be implemented for any type where the inner type
// implements RngCore, but we can't specify that because ReseedingCore is private
impl<R, Rsdr> RngCore for ReseedingRng<R, Rsdr>
impl<const N: usize, G, Rsdr> RngCore for ReseedingRng<G, Rsdr>
where
R: BlockRngCore<Item = u32> + SeedableRng,
G: Generator<Output = [u32; N]> + SeedableRng,
Rsdr: TryRngCore,
{
#[inline(always)]
fn next_u32(&mut self) -> u32 {
self.0.next_u32()
self.0.next_word()
}

#[inline(always)]
fn next_u64(&mut self) -> u64 {
self.0.next_u64()
self.0.next_u64_from_u32()
}

fn fill_bytes(&mut self, dest: &mut [u8]) {
self.0.fill_bytes(dest)
}
}

impl<R, Rsdr> CryptoRng for ReseedingRng<R, Rsdr>
impl<const N: usize, G, Rsdr> CryptoRng for ReseedingRng<G, Rsdr>
where
R: BlockRngCore<Item = u32> + SeedableRng + CryptoBlockRng,
G: Generator<Output = [u32; N]> + SeedableRng + CryptoGenerator,
Rsdr: TryCryptoRng,
{
}

#[derive(Debug)]
struct ReseedingCore<R, Rsdr> {
inner: R,
struct ReseedingCore<G, Rsdr> {
inner: G,
reseeder: Rsdr,
threshold: i64,
bytes_until_reseed: i64,
}

impl<R, Rsdr> BlockRngCore for ReseedingCore<R, Rsdr>
impl<G, Rsdr> Generator for ReseedingCore<G, Rsdr>
where
R: BlockRngCore + SeedableRng,
G: Generator + SeedableRng,
Rsdr: TryRngCore,
{
type Item = <R as BlockRngCore>::Item;
type Results = <R as BlockRngCore>::Results;
type Output = <G as Generator>::Output;

fn generate(&mut self, results: &mut Self::Results) {
fn generate(&mut self, results: &mut Self::Output) {
if self.bytes_until_reseed <= 0 {
// We get better performance by not calling only `reseed` here
// and continuing with the rest of the function, but by directly
// returning from a non-inlined function.
return self.reseed_and_generate(results);
}
let num_bytes = size_of_val(results.as_ref());
let num_bytes = size_of_val(results);
self.bytes_until_reseed -= num_bytes as i64;
self.inner.generate(results);
}
}

impl<R, Rsdr> ReseedingCore<R, Rsdr>
impl<G, Rsdr> ReseedingCore<G, Rsdr>
where
R: BlockRngCore + SeedableRng,
G: Generator + SeedableRng,
Rsdr: TryRngCore,
{
/// Create a new `ReseedingCore`.
///
/// `threshold` is the maximum number of bytes produced by
/// [`BlockRngCore::generate`] before attempting reseeding.
/// [`Generator::generate`] before attempting reseeding.
fn new(threshold: u64, mut reseeder: Rsdr) -> Result<Self, Rsdr::Error> {
// Because generating more values than `i64::MAX` takes centuries on
// current hardware, we just clamp to that value.
Expand All @@ -178,7 +177,7 @@ where
i64::MAX
};

let inner = R::try_from_rng(&mut reseeder)?;
let inner = G::try_from_rng(&mut reseeder)?;

Ok(ReseedingCore {
inner,
Expand All @@ -190,17 +189,17 @@ where

/// Reseed the internal PRNG.
fn reseed(&mut self) -> Result<(), Rsdr::Error> {
R::try_from_rng(&mut self.reseeder).map(|result| {
G::try_from_rng(&mut self.reseeder).map(|result| {
self.bytes_until_reseed = self.threshold;
self.inner = result
})
}

#[inline(never)]
fn reseed_and_generate(&mut self, results: &mut <Self as BlockRngCore>::Results) {
fn reseed_and_generate(&mut self, results: &mut G::Output) {
trace!("Reseeding RNG (periodic reseed)");

let num_bytes = size_of_val(results.as_ref());
let num_bytes = size_of_val(results);

if let Err(e) = self.reseed() {
warn!("Reseeding RNG failed: {}", e);
Expand All @@ -212,9 +211,9 @@ where
}
}

impl<R, Rsdr> CryptoBlockRng for ReseedingCore<R, Rsdr>
impl<G, Rsdr> CryptoGenerator for ReseedingCore<G, Rsdr>
where
R: BlockRngCore<Item = u32> + SeedableRng + CryptoBlockRng,
G: Generator + SeedableRng + CryptoGenerator,
Rsdr: TryCryptoRng,
{
}
Expand Down
Loading