Skip to content

Commit

Permalink
Rework fallability
Browse files Browse the repository at this point in the history
  • Loading branch information
newpavlov committed May 7, 2024
1 parent 0e626c7 commit 515ad2c
Show file tree
Hide file tree
Showing 56 changed files with 824 additions and 784 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/gh-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
rm target/doc/.lock
- name: Setup Pages
uses: actions/configure-pages@v4
uses: actions/configure-pages@v5

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ A [separate changelog is kept for rand_core](rand_core/CHANGELOG.md).
You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.html) useful.

## [Unreleased]
- Add `rand::distributions::WeightedIndex::{weight, weights, total_weight}` (#1420)
- Bump the MSRV to 1.61.0

## [0.9.0-alpha.1] - 2024-03-18
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ compiler versions will be compatible. This is especially true of Rand's
experimental `simd_support` feature.

Rand supports limited functionality in `no_std` mode (enabled via
`default-features = false`). In this case, `OsRng` and `from_entropy` are
`default-features = false`). In this case, `OsRng` and `from_os_rng` are
unavailable (unless `getrandom` is enabled), large parts of `seq` are
unavailable (unless `alloc` is enabled), and `thread_rng` and `random` are
unavailable.
Expand Down
2 changes: 1 addition & 1 deletion rand_chacha/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Links:
`rand_chacha` is `no_std` compatible when disabling default features; the `std`
feature can be explicitly required to re-enable `std` support. Using `std`
allows detection of CPU features and thus better optimisation. Using `std`
also enables `getrandom` functionality, such as `ChaCha20Rng::from_entropy()`.
also enables `getrandom` functionality, such as `ChaCha20Rng::from_os_rng()`.


# License
Expand Down
91 changes: 51 additions & 40 deletions rand_chacha/src/chacha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
use self::core::fmt;
use crate::guts::ChaCha;
use rand_core::block::{BlockRng, BlockRngCore, CryptoBlockRng};
use rand_core::{CryptoRng, Error, RngCore, SeedableRng};
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 @@ -68,7 +69,7 @@ impl<T> fmt::Debug for Array64<T> {
}

macro_rules! chacha_impl {
($ChaChaXCore:ident, $ChaChaXRng:ident, $rounds:expr, $doc:expr, $abst:ident) => {
($ChaChaXCore:ident, $ChaChaXRng:ident, $rounds:expr, $doc:expr, $abst:ident,) => {
#[doc=$doc]
#[derive(Clone, PartialEq, Eq)]
pub struct $ChaChaXCore {
Expand All @@ -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,9 +95,12 @@ 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]),
}
}
}

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,24 +241,20 @@ 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()
}
}

impl CryptoRng for $ChaChaXRng {}

rand_core::impl_try_crypto_rng_from_crypto_rng!($ChaChaXRng);

impl From<$ChaChaXCore> for $ChaChaXRng {
fn from(core: $ChaChaXCore) -> Self {
$ChaChaXRng {
Expand All @@ -286,22 +281,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 +324,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 @@ -388,7 +399,7 @@ mod test {
#[test]
fn test_chacha_serde_format_stability() {
let j = r#"{"seed":[4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8,15,16,23,42,4,8],"stream":27182818284,"word_pos":314159265359}"#;
let r: ChaChaRng = serde_json::from_str(&j).unwrap();
let r: ChaChaRng = serde_json::from_str(j).unwrap();
let j1 = serde_json::to_string(&r).unwrap();
assert_eq!(j, j1);
}
Expand All @@ -402,7 +413,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(&mut rng1);
assert_eq!(rng2.next_u32(), 1325750369);
}

Expand Down Expand Up @@ -598,7 +609,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
91 changes: 91 additions & 0 deletions rand_core/src/blanket_impls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#[cfg(feature = "alloc")] use alloc::boxed::Box;

use crate::{CryptoRng, RngCore, TryCryptoRng, TryRngCore};

impl<'a, R: RngCore + ?Sized> RngCore for &'a mut R {
#[inline(always)]
fn next_u32(&mut self) -> u32 {
R::next_u32(self)
}

#[inline(always)]
fn next_u64(&mut self) -> u64 {
R::next_u64(self)
}

#[inline(always)]
fn fill_bytes(&mut self, dst: &mut [u8]) {
R::fill_bytes(self, dst)
}
}

impl<'a, R: CryptoRng + ?Sized> CryptoRng for &'a mut R {}

impl<'a, R: TryRngCore + ?Sized> TryRngCore for &'a mut R {
type Error = R::Error;

#[inline(always)]
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
R::try_next_u32(self)
}

#[inline(always)]
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
R::try_next_u64(self)
}

#[inline(always)]
fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
R::try_fill_bytes(self, dst)
}
}

impl<'a, R: TryCryptoRng + ?Sized> TryCryptoRng for &'a mut R {}

#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
impl<R: RngCore + ?Sized> RngCore for Box<R> {
#[inline(always)]
fn next_u32(&mut self) -> u32 {
R::next_u32(self)
}

#[inline(always)]
fn next_u64(&mut self) -> u64 {
R::next_u64(self)
}

#[inline(always)]
fn fill_bytes(&mut self, dest: &mut [u8]) {
R::fill_bytes(self, dest)
}
}

#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
impl<R: CryptoRng + ?Sized> CryptoRng for Box<R> {}

#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
impl<R: TryRngCore + ?Sized> TryRngCore for Box<R> {
type Error = R::Error;

#[inline(always)]
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
R::try_next_u32(self)
}

#[inline(always)]
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
R::try_next_u64(self)
}

#[inline(always)]
fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
R::try_fill_bytes(self, dst)
}
}

#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
impl<R: TryCryptoRng + ?Sized> TryCryptoRng for Box<R> {}
Loading

0 comments on commit 515ad2c

Please sign in to comment.