Skip to content

Commit

Permalink
feat: add support for rand (#282)
Browse files Browse the repository at this point in the history
  • Loading branch information
DaniPopes authored Sep 20, 2023
1 parent bf93324 commit 3fd6c90
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 5 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ itoa = "1"
once_cell = "1"
proptest = "1"
proptest-derive = "0.4"
rand = { version = "0.8", default-feature = false }
ruint = { version = "1.10.1", default-features = false, features = ["alloc"] }
ruint-macro = { version = "1", default-features = false }
tiny-keccak = "2.0"
6 changes: 5 additions & 1 deletion crates/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ serde = { workspace = true, optional = true }
# getrandom
getrandom = { workspace = true, optional = true }

# rand
rand = { workspace = true, optional = true, features = ["getrandom"] }

# arbitrary
arbitrary = { workspace = true, optional = true }
derive_arbitrary = { workspace = true, optional = true }
Expand All @@ -51,10 +54,11 @@ serde = { workspace = true, features = ["derive"] }

[features]
default = ["std"]
std = ["bytes/std", "hex/std", "alloy-rlp?/std", "proptest?/std", "serde?/std"]
std = ["bytes/std", "hex/std", "alloy-rlp?/std", "proptest?/std", "rand?/std", "serde?/std"]
tiny-keccak = []
native-keccak = []
getrandom = ["dep:getrandom"]
rand = ["dep:rand", "getrandom"]
rlp = ["dep:alloy-rlp", "ruint/alloy-rlp"]
serde = ["dep:serde", "bytes/serde", "hex/serde", "ruint/serde"]
arbitrary = [
Expand Down
61 changes: 57 additions & 4 deletions crates/primitives/src/bits/fixed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,16 @@ impl<const N: usize> str::FromStr for FixedBytes<N> {
}
}

#[cfg(feature = "rand")]
impl<const N: usize> rand::distributions::Distribution<FixedBytes<N>>
for rand::distributions::Standard
{
#[inline]
fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> FixedBytes<N> {
FixedBytes::random_with(rng)
}
}

impl<const N: usize> FixedBytes<N> {
/// Array of Zero bytes.
pub const ZERO: Self = Self([0u8; N]);
Expand Down Expand Up @@ -338,6 +348,7 @@ impl<const N: usize> FixedBytes<N> {
/// [`getrandom_uninit`](getrandom::getrandom_uninit) fails.
#[cfg(feature = "getrandom")]
#[inline]
#[track_caller]
pub fn random() -> Self {
Self::try_random().unwrap()
}
Expand All @@ -350,11 +361,53 @@ impl<const N: usize> FixedBytes<N> {
/// This function only propagates the error from the underlying call to
/// [`getrandom_uninit`](getrandom::getrandom_uninit).
#[cfg(feature = "getrandom")]
#[inline]
pub fn try_random() -> Result<Self, getrandom::Error> {
let mut bytes: [_; N] = crate::impl_core::uninit_array();
getrandom::getrandom_uninit(&mut bytes)?;
// SAFETY: The array is initialized by getrandom_uninit.
Ok(Self(unsafe { crate::impl_core::array_assume_init(bytes) }))
let mut bytes = Self::ZERO;
bytes.try_randomize()?;
Ok(bytes)
}

/// Creates a new [`FixedBytes`] with the given random number generator.
#[cfg(feature = "rand")]
#[inline]
#[doc(alias = "random_using")]
pub fn random_with<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
let mut bytes = Self::ZERO;
bytes.randomize_with(rng);
bytes
}

/// Fills this [`FixedBytes`] with cryptographically random content.
///
/// # Panics
///
/// This function panics if the underlying call to
/// [`getrandom_uninit`](getrandom::getrandom_uninit) fails.
#[inline]
#[cfg(feature = "getrandom")]
#[track_caller]
pub fn randomize(&mut self) {
self.try_randomize().unwrap()
}

/// Tries to fill this [`FixedBytes`] with cryptographically random content.
///
/// # Errors
///
/// This function only propagates the error from the underlying call to
/// [`getrandom_uninit`](getrandom::getrandom_uninit).
#[inline]
#[cfg(feature = "getrandom")]
pub fn try_randomize(&mut self) -> Result<(), getrandom::Error> {
getrandom::getrandom(&mut self.0)
}

/// Fills this [`FixedBytes`] with the given random number generator.
#[cfg(feature = "rand")]
#[doc(alias = "randomize_using")]
pub fn randomize_with<R: rand::Rng + ?Sized>(&mut self, rng: &mut R) {
rng.fill_bytes(&mut self.0);
}

/// Concatenate two `FixedBytes`.
Expand Down
66 changes: 66 additions & 0 deletions crates/primitives/src/bits/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ macro_rules! wrap_fixed_bytes {
$crate::impl_rlp!($name, $n);
$crate::impl_serde!($name);
$crate::impl_arbitrary!($name, $n);
$crate::impl_rand!($name);

impl $name {
/// Array of Zero bytes.
Expand Down Expand Up @@ -207,6 +208,7 @@ macro_rules! wrap_fixed_bytes {
}

$crate::impl_getrandom!();
$crate::impl_rand!();

/// Create a new fixed-hash from the given slice `src`.
///
Expand Down Expand Up @@ -397,6 +399,7 @@ macro_rules! impl_getrandom {
/// This function panics if the underlying call to `getrandom_uninit`
/// fails.
#[inline]
#[track_caller]
pub fn random() -> Self {
Self($crate::FixedBytes::random())
}
Expand All @@ -412,6 +415,30 @@ macro_rules! impl_getrandom {
pub fn try_random() -> $crate::private::Result<Self, $crate::private::getrandom::Error> {
$crate::FixedBytes::try_random().map(Self)
}

/// Fills this fixed byte array with cryptographically random content.
///
/// # Panics
///
/// This function panics if the underlying call to `getrandom_uninit` fails.
#[inline]
#[track_caller]
pub fn randomize(&mut self) {
self.try_randomize().unwrap()
}

/// Tries to fill this fixed byte array with cryptographically random content.
///
/// # Errors
///
/// This function only propagates the error from the underlying call to
/// `getrandom_uninit`.
#[inline]
pub fn try_randomize(
&mut self,
) -> $crate::private::Result<(), $crate::private::getrandom::Error> {
self.0.try_randomize()
}
};
}

Expand All @@ -422,6 +449,45 @@ macro_rules! impl_getrandom {
() => {};
}

#[doc(hidden)]
#[macro_export]
#[cfg(feature = "rand")]
macro_rules! impl_rand {
() => {
/// Creates a new fixed byte array with the given random number generator.
#[inline]
#[doc(alias = "random_using")]
pub fn random_with<R: $crate::private::rand::Rng + ?Sized>(rng: &mut R) -> Self {
Self($crate::FixedBytes::random_with(rng))
}

/// Fills this fixed byte array with the given random number generator.
#[inline]
#[doc(alias = "randomize_using")]
pub fn randomize_with<R: $crate::private::rand::Rng + ?Sized>(&mut self, rng: &mut R) {
self.0.randomize_with(rng);
}
};

($t:ty) => {
impl $crate::private::rand::distributions::Distribution<$t>
for $crate::private::rand::distributions::Standard
{
#[inline]
fn sample<R: $crate::private::rand::Rng + ?Sized>(&self, rng: &mut R) -> $t {
<$t>::random_with(rng)
}
}
};
}

#[doc(hidden)]
#[macro_export]
#[cfg(not(feature = "rand"))]
macro_rules! impl_rand {
($($t:tt)*) => {};
}

#[doc(hidden)]
#[macro_export]
#[cfg(feature = "rlp")]
Expand Down
3 changes: 3 additions & 0 deletions crates/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ pub mod private {
#[cfg(feature = "getrandom")]
pub use getrandom;

#[cfg(feature = "rand")]
pub use rand;

#[cfg(feature = "rlp")]
pub use alloy_rlp;

Expand Down

0 comments on commit 3fd6c90

Please sign in to comment.