Skip to content
Draft
Show file tree
Hide file tree
Changes from 15 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
8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ features = ["small_rng", "serde"]
# Meta-features:
default = ["std", "std_rng", "os_rng", "small_rng", "thread_rng"]
nightly = [] # some additions requiring nightly Rust
serde = ["dep:serde", "rand_core/serde"]
serde = ["dep:serde"]

# Option (enabled by default): without "std" rand uses libcore; this option
# enables functionality expected to be available on a standard platform.
Expand Down Expand Up @@ -76,7 +76,8 @@ 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 = { 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 +86,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", branch = "push-wmrnlsxrmtrl" }
4 changes: 3 additions & 1 deletion benches/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ rand = { path = "..", features = ["small_rng", "nightly"] }
rand_pcg = { path = "../rand_pcg" }
rand_chacha = { path = "../rand_chacha" }
criterion = "0.5"
criterion-cycles-per-byte = "0.6"

[[bench]]
name = "array"
Expand Down Expand Up @@ -56,3 +55,6 @@ harness = false
[[bench]]
name = "weighted"
harness = false

[patch.crates-io]
rand_core = { git = "https://github.com/rust-random/rand_core", branch = "push-wmrnlsxrmtrl" }
4 changes: 2 additions & 2 deletions benches/benches/generators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use rand::prelude::*;
use rand::rngs::OsRng;
use rand::rngs::ReseedingRng;
use rand_chacha::rand_core::UnwrapErr;
use rand_chacha::{ChaCha8Rng, ChaCha12Rng, ChaCha20Core, ChaCha20Rng};
use rand_chacha::{ChaCha8Rng, ChaCha12Rng, ChaCha20Rng};
use rand_pcg::{Pcg32, Pcg64, Pcg64Dxsm, Pcg64Mcg};

criterion_group!(
Expand Down Expand Up @@ -198,7 +198,7 @@ pub fn reseeding_bytes(c: &mut Criterion) {
fn bench(g: &mut BenchmarkGroup<WallTime>, thresh: u64) {
let name = format!("chacha20_{thresh}k");
g.bench_function(name.as_str(), |b| {
let mut rng = ReseedingRng::<ChaCha20Core, _>::new(thresh * 1024, OsRng).unwrap();
let mut rng = ReseedingRng::<ChaCha20Rng, _>::new(thresh * 1024, OsRng).unwrap();
let mut buf = [0u8; 1024 * 1024];
b.iter(|| {
rng.fill_bytes(&mut buf);
Expand Down
114 changes: 43 additions & 71 deletions rand_chacha/src/chacha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@

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

#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
Expand All @@ -21,52 +20,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 +35,12 @@ macro_rules! chacha_impl {
}
}

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

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

Expand All @@ -103,7 +55,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 @@ -145,35 +97,55 @@ macro_rules! chacha_impl {
/// http://www.ecrypt.eu.org/stream/)
#[derive(Clone, Debug)]
pub struct $ChaChaXRng {
rng: BlockRng<$ChaChaXCore>,
core: $ChaChaXCore,
buffer: [u32; 64],
}

impl $ChaChaXRng {
fn buffer_index(&self) -> u32 {
self.buffer[0]
}

fn generate_and_set(&mut self, index: usize) {
assert!(index < self.buffer.len());
self.buffer[0] = if index != 0 {
self.core.generate(&mut self.buffer);
index as u32
} else {
self.buffer.len() as u32
}
}
}

impl SeedableRng for $ChaChaXRng {
type Seed = [u8; 32];

#[inline]
fn from_seed(seed: Self::Seed) -> Self {
let core = $ChaChaXCore::from_seed(seed);
Self {
rng: BlockRng::new(core),
core: $ChaChaXCore::from_seed(seed),
buffer: le::new_buffer(),
}
}
}

impl RngCore for $ChaChaXRng {
#[inline]
fn next_u32(&mut self) -> u32 {
self.rng.next_u32()
let Self { core, buffer } = self;
le::next_word_via_gen_block(buffer, |block| core.generate(block))
}

#[inline]
fn next_u64(&mut self) -> u64 {
self.rng.next_u64()
let Self { core, buffer } = self;
le::next_u64_via_gen_block(buffer, |block| core.generate(block))
}

#[inline]
fn fill_bytes(&mut self, bytes: &mut [u8]) {
self.rng.fill_bytes(bytes)
fn fill_bytes(&mut self, dst: &mut [u8]) {
let Self { core, buffer } = self;
le::fill_bytes_via_gen_block(dst, buffer, |block| core.generate(block));
}
}

Expand All @@ -190,11 +162,11 @@ macro_rules! chacha_impl {
#[inline]
pub fn get_word_pos(&self) -> u128 {
let buf_start_block = {
let buf_end_block = self.rng.core.state.get_block_pos();
let buf_end_block = self.core.state.get_block_pos();
u64::wrapping_sub(buf_end_block, BUF_BLOCKS.into())
};
let (buf_offset_blocks, block_offset_words) = {
let buf_offset_words = self.rng.index() as u64;
let buf_offset_words = self.buffer_index() as u64;
let blocks_part = buf_offset_words / u64::from(BLOCK_WORDS);
let words_part = buf_offset_words % u64::from(BLOCK_WORDS);
(blocks_part, words_part)
Expand All @@ -212,9 +184,8 @@ macro_rules! chacha_impl {
#[inline]
pub fn set_word_pos(&mut self, word_offset: u128) {
let block = (word_offset / u128::from(BLOCK_WORDS)) as u64;
self.rng.core.state.set_block_pos(block);
self.rng
.generate_and_set((word_offset % u128::from(BLOCK_WORDS)) as usize);
self.core.state.set_block_pos(block);
self.generate_and_set((word_offset % u128::from(BLOCK_WORDS)) as usize);
}

/// Set the stream number.
Expand All @@ -230,8 +201,8 @@ macro_rules! chacha_impl {
/// indirectly via `set_word_pos`), but this is not directly supported.
#[inline]
pub fn set_stream(&mut self, stream: u64) {
self.rng.core.state.set_nonce(stream);
if self.rng.index() != 64 {
self.core.state.set_nonce(stream);
if self.buffer_index() != 64 {
let wp = self.get_word_pos();
self.set_word_pos(wp);
}
Expand All @@ -240,13 +211,13 @@ macro_rules! chacha_impl {
/// Get the stream number.
#[inline]
pub fn get_stream(&self) -> u64 {
self.rng.core.state.get_nonce()
self.core.state.get_nonce()
}

/// Get the seed.
#[inline]
pub fn get_seed(&self) -> [u8; 32] {
self.rng.core.state.get_seed()
self.core.state.get_seed()
}
}

Expand All @@ -255,7 +226,8 @@ macro_rules! chacha_impl {
impl From<$ChaChaXCore> for $ChaChaXRng {
fn from(core: $ChaChaXCore) -> Self {
$ChaChaXRng {
rng: BlockRng::new(core),
core,
buffer: le::new_buffer(),
}
}
}
Expand Down
6 changes: 2 additions & 4 deletions rand_chacha/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@
//!
//! ## Generators
//!
//! This crate provides 8-, 12- and 20-round variants of generators via a "core"
//! implementation (of [`BlockRngCore`]), each with an associated "RNG" type
//! (implementing [`RngCore`]).
//! This crate provides 8-, 12- and 20-round variants of generators
//! implementing [`RngCore`].
//!
//! These generators are all deterministic and portable (see [Reproducibility]
//! in the book), with testing against reference vectors.
Expand Down Expand Up @@ -73,7 +72,6 @@
//! [Seeding RNGs]: https://rust-random.github.io/book/guide-seeding.html
//! [Security]: https://rust-random.github.io/book/guide-rngs.html#security
//! [Random Values]: https://rust-random.github.io/book/guide-values.html
//! [`BlockRngCore`]: rand_core::block::BlockRngCore
//! [`RngCore`]: rand_core::RngCore
//! [`SeedableRng`]: rand_core::SeedableRng
//! [`OsRng`]: https://docs.rs/rand/latest/rand/rngs/struct.OsRng.html
Expand Down
16 changes: 7 additions & 9 deletions rand_pcg/src/pcg128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,9 @@ impl SeedableRng for Lcg128Xsl64 {
/// We use a single 255-bit seed to initialise the state and select a stream.
/// One `seed` bit (lowest bit of `seed[8]`) is ignored.
fn from_seed(seed: Self::Seed) -> Self {
let mut seed_u64 = [0u64; 4];
le::read_u64_into(&seed, &mut seed_u64);
let state = u128::from(seed_u64[0]) | (u128::from(seed_u64[1]) << 64);
let incr = u128::from(seed_u64[2]) | (u128::from(seed_u64[3]) << 64);
let seed: [u64; 4] = le::read_words(&seed);
let state = u128::from(seed[0]) | (u128::from(seed[1]) << 64);
let incr = u128::from(seed[2]) | (u128::from(seed[3]) << 64);

// The increment must be odd, hence we discard one bit:
Lcg128Xsl64::from_state_incr(state, incr | 1)
Expand All @@ -150,7 +149,7 @@ impl RngCore for Lcg128Xsl64 {

#[inline]
fn fill_bytes(&mut self, dest: &mut [u8]) {
le::fill_bytes_via_next(self, dest)
le::fill_bytes_via_next_word(dest, || self.next_u64())
}
}

Expand Down Expand Up @@ -232,9 +231,8 @@ impl SeedableRng for Mcg128Xsl64 {

fn from_seed(seed: Self::Seed) -> Self {
// Read as if a little-endian u128 value:
let mut seed_u64 = [0u64; 2];
le::read_u64_into(&seed, &mut seed_u64);
let state = u128::from(seed_u64[0]) | (u128::from(seed_u64[1]) << 64);
let seed: [u64; 2] = le::read_words(&seed);
let state = u128::from(seed[0]) | (u128::from(seed[1]) << 64);
Mcg128Xsl64::new(state)
}
}
Expand All @@ -253,7 +251,7 @@ impl RngCore for Mcg128Xsl64 {

#[inline]
fn fill_bytes(&mut self, dest: &mut [u8]) {
le::fill_bytes_via_next(self, dest)
le::fill_bytes_via_next_word(dest, || self.next_u64())
}
}

Expand Down
9 changes: 4 additions & 5 deletions rand_pcg/src/pcg128cm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,9 @@ impl SeedableRng for Lcg128CmDxsm64 {
/// We use a single 255-bit seed to initialise the state and select a stream.
/// One `seed` bit (lowest bit of `seed[8]`) is ignored.
fn from_seed(seed: Self::Seed) -> Self {
let mut seed_u64 = [0u64; 4];
le::read_u64_into(&seed, &mut seed_u64);
let state = u128::from(seed_u64[0]) | (u128::from(seed_u64[1]) << 64);
let incr = u128::from(seed_u64[2]) | (u128::from(seed_u64[3]) << 64);
let seed: [u64; 4] = le::read_words(&seed);
let state = u128::from(seed[0]) | (u128::from(seed[1]) << 64);
let incr = u128::from(seed[2]) | (u128::from(seed[3]) << 64);

// The increment must be odd, hence we discard one bit:
Self::from_state_incr(state, incr | 1)
Expand All @@ -156,7 +155,7 @@ impl RngCore for Lcg128CmDxsm64 {

#[inline]
fn fill_bytes(&mut self, dest: &mut [u8]) {
le::fill_bytes_via_next(self, dest)
le::fill_bytes_via_next_word(dest, || self.next_u64())
}
}

Expand Down
8 changes: 3 additions & 5 deletions rand_pcg/src/pcg64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,9 @@ impl SeedableRng for Lcg64Xsh32 {
/// We use a single 127-bit seed to initialise the state and select a stream.
/// One `seed` bit (lowest bit of `seed[8]`) is ignored.
fn from_seed(seed: Self::Seed) -> Self {
let mut seed_u64 = [0u64; 2];
le::read_u64_into(&seed, &mut seed_u64);

let [state, increment] = le::read_words(&seed);
// The increment must be odd, hence we discard one bit:
Lcg64Xsh32::from_state_incr(seed_u64[0], seed_u64[1] | 1)
Lcg64Xsh32::from_state_incr(state, increment | 1)
}
}

Expand Down Expand Up @@ -159,6 +157,6 @@ impl RngCore for Lcg64Xsh32 {

#[inline]
fn fill_bytes(&mut self, dest: &mut [u8]) {
le::fill_bytes_via_next(self, dest)
le::fill_bytes_via_next_word(dest, || self.next_u32())
}
}
2 changes: 1 addition & 1 deletion src/distr/uniform_int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -882,7 +882,7 @@ mod tests {
use serde_json;
let serialized_on_32bit = r#"{"low":10,"range":91,"thresh":74}"#;
let deserialized: UniformUsize =
serde_json::from_str(&serialized_on_32bit).expect("deserialization");
serde_json::from_str(serialized_on_32bit).expect("deserialization");
assert_eq!(
deserialized,
UniformUsize::new_inclusive(10, 100).expect("creation")
Expand Down
Loading
Loading