Skip to content

Commit

Permalink
Rework CryptoRng
Browse files Browse the repository at this point in the history
  • Loading branch information
newpavlov committed Dec 6, 2022
1 parent 7aa25d5 commit 81f3b15
Show file tree
Hide file tree
Showing 63 changed files with 981 additions and 841 deletions.
3 changes: 1 addition & 2 deletions benches/generators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use rand::prelude::*;
use rand::rngs::adapter::ReseedingRng;
use rand::rngs::{mock::StepRng, OsRng};
use rand_chacha::{ChaCha12Rng, ChaCha20Core, ChaCha20Rng, ChaCha8Rng};
use rand_pcg::{Pcg32, Pcg64, Pcg64Mcg, Pcg64Dxsm};
use rand_pcg::{Pcg32, Pcg64, Pcg64Dxsm, Pcg64Mcg};

macro_rules! gen_bytes {
($fnn:ident, $gen:expr) => {
Expand Down Expand Up @@ -142,7 +142,6 @@ reseeding_bytes!(reseeding_chacha20_64k, 64);
reseeding_bytes!(reseeding_chacha20_256k, 256);
reseeding_bytes!(reseeding_chacha20_1M, 1024);


macro_rules! threadrng_uint {
($fnn:ident, $ty:ty) => {
#[bench]
Expand Down
2 changes: 1 addition & 1 deletion benches/seq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ extern crate test;

use test::Bencher;

use core::mem::size_of;
use rand::prelude::*;
use rand::seq::*;
use core::mem::size_of;

// We force use of 32-bit RNG since seq code is optimised for use with 32-bit
// generators on all platforms.
Expand Down
102 changes: 56 additions & 46 deletions rand_chacha/src/chacha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@

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

#[cfg(feature = "serde1")] use serde::{Serialize, Deserialize, Serializer, Deserializer};
#[cfg(feature = "serde1")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};

// NB. this must remain consistent with some currently hard-coded numbers in this module
const BUF_BLOCKS: u8 = 4;
Expand Down Expand Up @@ -85,6 +86,7 @@ macro_rules! chacha_impl {
impl BlockRngCore for $ChaChaXCore {
type Item = u32;
type Results = Array64<u32>;

#[inline]
fn generate(&mut self, r: &mut Self::Results) {
self.state.refill4($rounds, &mut r.0);
Expand All @@ -93,13 +95,16 @@ macro_rules! chacha_impl {

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

#[inline]
fn from_seed(seed: Self::Seed) -> Self {
$ChaChaXCore { state: ChaCha::new(&seed, &[0u8; 8]) }
$ChaChaXCore {
state: ChaCha::new(&seed, &[0u8; 8]),
}
}
}

impl CryptoRng for $ChaChaXCore {}
impl CryptoBlockRng for $ChaChaXCore {}

/// A cryptographically secure random number generator that uses the ChaCha algorithm.
///
Expand Down Expand Up @@ -146,6 +151,7 @@ macro_rules! chacha_impl {

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

#[inline]
fn from_seed(seed: Self::Seed) -> Self {
let core = $ChaChaXCore::from_seed(seed);
Expand All @@ -160,18 +166,16 @@ macro_rules! chacha_impl {
fn next_u32(&mut self) -> u32 {
self.rng.next_u32()
}

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

#[inline]
fn fill_bytes(&mut self, bytes: &mut [u8]) {
self.rng.fill_bytes(bytes)
}
#[inline]
fn try_fill_bytes(&mut self, bytes: &mut [u8]) -> Result<(), Error> {
self.rng.try_fill_bytes(bytes)
}
}

impl $ChaChaXRng {
Expand Down Expand Up @@ -209,11 +213,9 @@ 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
.core
.state
.set_block_pos(block);
self.rng.generate_and_set((word_offset % u128::from(BLOCK_WORDS)) as usize);
.generate_and_set((word_offset % u128::from(BLOCK_WORDS)) as usize);
}

/// Set the stream number.
Expand All @@ -229,10 +231,7 @@ 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);
self.rng.core.state.set_nonce(stream);
if self.rng.index() != 64 {
let wp = self.get_word_pos();
self.set_word_pos(wp);
Expand All @@ -242,19 +241,13 @@ macro_rules! chacha_impl {
/// Get the stream number.
#[inline]
pub fn get_stream(&self) -> u64 {
self.rng
.core
.state
.get_nonce()
self.rng.core.state.get_nonce()
}

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

Expand Down Expand Up @@ -286,22 +279,20 @@ macro_rules! chacha_impl {
}
#[cfg(feature = "serde1")]
impl<'de> Deserialize<'de> for $ChaChaXRng {
fn deserialize<D>(d: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
where D: Deserializer<'de> {
$abst::$ChaChaXRng::deserialize(d).map(|x| Self::from(&x))
}
}

mod $abst {
#[cfg(feature = "serde1")] use serde::{Serialize, Deserialize};
#[cfg(feature = "serde1")] use serde::{Deserialize, Serialize};

// 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
// the API.
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(
feature = "serde1",
derive(Serialize, Deserialize),
)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub(crate) struct $ChaChaXRng {
seed: [u8; 32],
stream: u64,
Expand Down Expand Up @@ -331,27 +322,45 @@ macro_rules! chacha_impl {
}
}
}
}
};
}

chacha_impl!(ChaCha20Core, ChaCha20Rng, 10, "ChaCha with 20 rounds", abstract20);
chacha_impl!(ChaCha12Core, ChaCha12Rng, 6, "ChaCha with 12 rounds", abstract12);
chacha_impl!(ChaCha8Core, ChaCha8Rng, 4, "ChaCha with 8 rounds", abstract8);
chacha_impl!(
ChaCha20Core,
ChaCha20Rng,
10,
"ChaCha with 20 rounds",
abstract20
);
chacha_impl!(
ChaCha12Core,
ChaCha12Rng,
6,
"ChaCha with 12 rounds",
abstract12
);
chacha_impl!(
ChaCha8Core,
ChaCha8Rng,
4,
"ChaCha with 8 rounds",
abstract8
);

#[cfg(test)]
mod test {
use rand_core::{RngCore, SeedableRng};

#[cfg(feature = "serde1")] use super::{ChaCha20Rng, ChaCha12Rng, ChaCha8Rng};
#[cfg(feature = "serde1")] use super::{ChaCha12Rng, ChaCha20Rng, ChaCha8Rng};

type ChaChaRng = super::ChaCha20Rng;

#[cfg(feature = "serde1")]
#[test]
fn test_chacha_serde_roundtrip() {
let seed = [
1, 0, 52, 0, 0, 0, 0, 0, 1, 0, 10, 0, 22, 32, 0, 0, 2, 0, 55, 49, 0, 11, 0, 0, 3, 0, 0, 0, 0,
0, 2, 92,
1, 0, 52, 0, 0, 0, 0, 0, 1, 0, 10, 0, 22, 32, 0, 0, 2, 0, 55, 49, 0, 11, 0, 0, 3, 0, 0,
0, 0, 0, 2, 92,
];
let mut rng1 = ChaCha20Rng::from_seed(seed);
let mut rng2 = ChaCha12Rng::from_seed(seed);
Expand Down Expand Up @@ -402,7 +411,7 @@ mod test {
let mut rng1 = ChaChaRng::from_seed(seed);
assert_eq!(rng1.next_u32(), 137206642);

let mut rng2 = ChaChaRng::from_rng(rng1).unwrap();
let mut rng2 = ChaChaRng::from_rng(rng1);
assert_eq!(rng2.next_u32(), 1325750369);
}

Expand Down Expand Up @@ -598,7 +607,7 @@ mod test {

#[test]
fn test_chacha_word_pos_wrap_exact() {
use super::{BUF_BLOCKS, BLOCK_WORDS};
use super::{BLOCK_WORDS, BUF_BLOCKS};
let mut rng = ChaChaRng::from_seed(Default::default());
// refilling the buffer in set_word_pos will wrap the block counter to 0
let last_block = (1 << 68) - u128::from(BUF_BLOCKS * BLOCK_WORDS);
Expand Down Expand Up @@ -626,12 +635,13 @@ mod test {

#[test]
fn test_trait_objects() {
use rand_core::CryptoRngCore;
use rand_core::CryptoRng;

let rng = &mut ChaChaRng::from_seed(Default::default()) as &mut dyn CryptoRngCore;
let r1 = rng.next_u64();
let rng: &mut dyn RngCore = rng.as_rngcore();
let r2 = rng.next_u64();
assert_ne!(r1, r2);
let mut rng = ChaChaRng::from_seed(Default::default());
let dyn_rng = &mut rng.clone() as &mut dyn CryptoRng;
let mut box_rng = Box::new(rng.clone());
let exp = rng.next_u64();
assert_ne!(exp, dyn_rng.next_u64());
assert_ne!(exp, box_rng.next_u64());
}
}
7 changes: 5 additions & 2 deletions rand_chacha/src/guts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
use ppv_lite86::{dispatch, dispatch_light128};

pub use ppv_lite86::Machine;
use ppv_lite86::{vec128_storage, ArithOps, BitOps32, LaneWords4, MultiLane, StoreBytes, Vec4, Vec4Ext, Vector};
use ppv_lite86::{
vec128_storage, ArithOps, BitOps32, LaneWords4, MultiLane, StoreBytes, Vec4, Vec4Ext, Vector,
};

pub(crate) const BLOCK: usize = 16;
pub(crate) const BLOCK64: u64 = BLOCK as u64;
Expand Down Expand Up @@ -140,7 +142,8 @@ fn add_pos<Mach: Machine>(m: Mach, d: Mach::u32x4, i: u64) -> Mach::u32x4 {
#[cfg(target_endian = "little")]
fn d0123<Mach: Machine>(m: Mach, d: vec128_storage) -> Mach::u32x4x4 {
let d0: Mach::u64x2 = m.unpack(d);
let incr = Mach::u64x2x4::from_lanes([m.vec([0, 0]), m.vec([1, 0]), m.vec([2, 0]), m.vec([3, 0])]);
let incr =
Mach::u64x2x4::from_lanes([m.vec([0, 0]), m.vec([1, 0]), m.vec([2, 0]), m.vec([3, 0])]);
m.unpack((Mach::u64x2x4::from_lanes([d0, d0, d0, d0]) + incr).into())
}

Expand Down
Loading

0 comments on commit 81f3b15

Please sign in to comment.