Skip to content
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
78 changes: 17 additions & 61 deletions rand_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@ pub mod block;
pub mod le;
#[cfg(feature = "os_rng")]
mod os;
mod seed;

#[cfg(feature = "os_rng")]
pub use os::{OsError, OsRng};
pub use seed::Seed;

/// Implementation-level interface for RNGs
///
Expand Down Expand Up @@ -344,50 +346,7 @@ pub trait SeedableRng: Sized {
/// partially overlapping periods.
///
/// For cryptographic RNG's a seed of 256 bits is recommended, `[u8; 32]`.
///
///
/// # Implementing `SeedableRng` for RNGs with large seeds
///
/// Note that [`Default`] is not implemented for large arrays `[u8; N]` with
/// `N` > 32. To be able to implement the traits required by `SeedableRng`
/// for RNGs with such large seeds, the newtype pattern can be used:
///
/// ```
/// use rand_core::SeedableRng;
///
/// const N: usize = 64;
/// #[derive(Clone)]
/// pub struct MyRngSeed(pub [u8; N]);
/// # #[allow(dead_code)]
/// pub struct MyRng(MyRngSeed);
///
/// impl Default for MyRngSeed {
/// fn default() -> MyRngSeed {
/// MyRngSeed([0; N])
/// }
/// }
///
/// impl AsRef<[u8]> for MyRngSeed {
/// fn as_ref(&self) -> &[u8] {
/// &self.0
/// }
/// }
///
/// impl AsMut<[u8]> for MyRngSeed {
/// fn as_mut(&mut self) -> &mut [u8] {
/// &mut self.0
/// }
/// }
///
/// impl SeedableRng for MyRng {
/// type Seed = MyRngSeed;
///
/// fn from_seed(seed: MyRngSeed) -> MyRng {
/// MyRng(seed)
/// }
/// }
/// ```
type Seed: Clone + Default + AsRef<[u8]> + AsMut<[u8]>;
type Seed: Seed;

/// Create a new PRNG using the given seed.
///
Expand Down Expand Up @@ -448,15 +407,16 @@ pub trait SeedableRng: Sized {
x.to_le_bytes()
}

let mut seed = Self::Seed::default();
let mut iter = seed.as_mut().chunks_exact_mut(4);
for chunk in &mut iter {
chunk.copy_from_slice(&pcg32(&mut state));
}
let rem = iter.into_remainder();
if !rem.is_empty() {
rem.copy_from_slice(&pcg32(&mut state)[..rem.len()]);
}
let seed = Self::Seed::from_fill(|buf| {
let mut iter = buf.chunks_exact_mut(4);
for chunk in &mut iter {
chunk.copy_from_slice(&pcg32(&mut state));
}
let rem = iter.into_remainder();
if !rem.is_empty() {
rem.copy_from_slice(&pcg32(&mut state)[..rem.len()]);
}
});

Self::from_seed(seed)
}
Expand Down Expand Up @@ -486,17 +446,15 @@ pub trait SeedableRng: Sized {
///
/// [`rand`]: https://docs.rs/rand
fn from_rng<R: RngCore + ?Sized>(rng: &mut R) -> Self {
let mut seed = Self::Seed::default();
rng.fill_bytes(seed.as_mut());
let Ok(seed) = Self::Seed::try_from_fill(|buf| rng.try_fill_bytes(buf));
Self::from_seed(seed)
}

/// Create a new PRNG seeded from a potentially fallible `Rng`.
///
/// See [`from_rng`][SeedableRng::from_rng] docs for more information.
fn try_from_rng<R: TryRngCore + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
let mut seed = Self::Seed::default();
rng.try_fill_bytes(seed.as_mut())?;
let seed = Self::Seed::try_from_fill(|buf| rng.try_fill_bytes(buf))?;
Ok(Self::from_seed(seed))
}

Expand Down Expand Up @@ -536,10 +494,8 @@ pub trait SeedableRng: Sized {
/// [`getrandom`]: https://docs.rs/getrandom
#[cfg(feature = "os_rng")]
fn try_from_os_rng() -> Result<Self, getrandom::Error> {
let mut seed = Self::Seed::default();
getrandom::fill(seed.as_mut())?;
let res = Self::from_seed(seed);
Ok(res)
let seed = Self::Seed::try_from_fill(getrandom::fill)?;
Ok(Self::from_seed(seed))
}
}

Expand Down
73 changes: 73 additions & 0 deletions rand_core/src/seed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/// Trait implemented by types used for seeding PRNG.
///
/// This crate provides implementations for `[u8; N]`, `u32`, `u64`, and `u128`.
pub trait Seed: Sized {
/// Create seed from a fallible closure which fills the provided buffer.
fn try_from_fill<E>(fill: impl FnOnce(&mut [u8]) -> Result<(), E>) -> Result<Self, E>;

/// Create seed from an infallible closure which fills the provided buffer.
fn from_fill(fill: impl FnOnce(&mut [u8])) -> Self {
let Ok(seed) = Self::try_from_fill::<core::convert::Infallible>(|buf| {
fill(buf);
Ok(())
});
seed
}
}

impl<const N: usize> Seed for [u8; N] {
fn try_from_fill<E>(fill: impl FnOnce(&mut [u8]) -> Result<(), E>) -> Result<Self, E> {
let mut buf = [0u8; N];
fill(&mut buf)?;
Ok(buf)
}
}

macro_rules! impl_un {
($($t:ty)*) => {
$(
impl Seed for $t {
fn try_from_fill<E>(fill: impl FnOnce(&mut [u8]) -> Result<(), E>) -> Result<Self, E> {
let mut buf = [0u8; size_of::<$t>()];
fill(&mut buf)?;
Ok(<$t>::from_le_bytes(buf))
}
}
)*
};
}

impl_un!(u8 u16 u32 u64 u128);

macro_rules! impl_array_un {
($($t:ty)*) => {
$(
impl<const N: usize> Seed for [$t; N] {
fn try_from_fill<E>(fill: impl FnOnce(&mut [u8]) -> Result<(), E>) -> Result<Self, E> {
let mut buf: [$t; N] = [0; N];

{
let byte_size = size_of_val(&buf);
// SAFETY: it's safe to case `&mut [uM; N]` to `&mut [u8]`
// with size equal to `size_of_val`
let bytes_buf: &mut [u8] = unsafe {
core::slice::from_raw_parts_mut(
buf.as_mut_ptr().cast(),
byte_size,
)
};
fill(bytes_buf)?;
}

for val in &mut buf {
*val = val.to_le();
}

Ok(buf)
}
}
)*
};
}

impl_array_un!(u16 u32 u64 u128);
Loading