Skip to content
Merged
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
1 change: 1 addition & 0 deletions rand_hc/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Changes
- Use Edition 2024 and MSRV 1.85 (#73)
- Update to `rand_core` v0.10 (#82)

## [0.4.0] - 2025-01-27
- Bump the MSRV to 1.63 (#58)
Expand Down
2 changes: 1 addition & 1 deletion rand_hc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ edition = "2024"
rust-version = "1.85"

[dependencies]
rand_core = "0.10.0-rc-2"
rand_core = "0.10.0-rc-3"
23 changes: 10 additions & 13 deletions rand_hc/src/hc128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
//! The HC-128 random number generator.

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

const SEED_WORDS: usize = 8; // 128 bit key followed by 128 bit iv

Expand Down Expand Up @@ -75,12 +75,12 @@ pub struct Hc128Rng(BlockRng<Hc128Core>);
impl RngCore for Hc128Rng {
#[inline]
fn next_u32(&mut self) -> u32 {
self.0.next_u32()
self.0.next_word()
}

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

#[inline]
Expand All @@ -94,7 +94,7 @@ impl SeedableRng for Hc128Rng {

#[inline]
fn from_seed(seed: Self::Seed) -> Self {
Hc128Rng(BlockRng::<Hc128Core>::from_seed(seed))
Hc128Rng(BlockRng::new(Hc128Core::from_seed(seed)))
}
}

Expand All @@ -121,11 +121,10 @@ impl fmt::Debug for Hc128Core {
}
}

impl BlockRngCore for Hc128Core {
type Item = u32;
type Results = [u32; 16];
impl Generator for Hc128Core {
type Output = [u32; 16];

fn generate(&mut self, results: &mut Self::Results) {
fn generate(&mut self, results: &mut Self::Output) {
assert!(self.counter1024 % 16 == 0);

let cc = self.counter1024 % 512;
Expand Down Expand Up @@ -336,13 +335,11 @@ impl SeedableRng for Hc128Core {
/// 256 bits in length, matching the 128 bit `key` followed by 128 bit `iv`
/// when HC-128 where to be used as a stream cipher.
fn from_seed(seed: Self::Seed) -> Self {
let mut seed_u32 = [0u32; SEED_WORDS];
le::read_u32_into(&seed, &mut seed_u32);
Self::init(seed_u32)
Self::init(utils::read_words(&seed))
}
}

impl CryptoBlockRng for Hc128Core {}
impl CryptoGenerator for Hc128Core {}

// Custom PartialEq implementation as it can't currently be derived from an array of size 1024
impl PartialEq for Hc128Core {
Expand Down
4 changes: 4 additions & 0 deletions rand_isaac/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Value-breaking changes
- Drop use of half-used words in `Isaac64Rng::next_u32` (#82)

### Changes
- Use Edition 2024 and MSRV 1.85 (#73)
- Update to `rand_core` v0.10 (#82)

## [0.4.0] - 2025-01-27
- Bump the MSRV to 1.63 (#58)
Expand Down
5 changes: 3 additions & 2 deletions rand_isaac/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ rust-version = "1.85"
all-features = true

[features]
serde = ["dep:serde", "rand_core/serde"]
serde = ["dep:serde", "dep:serde_arrays"]

[dependencies]
rand_core = "0.10.0-rc-2"
rand_core = "0.10.0-rc-3"
serde = { version = "1.0.104", features = ["derive"], optional = true }
serde_arrays = { version = "0.2.0", optional = true }

[dev-dependencies]
# This is for testing serde, unfortunately we can't specify feature-gated dev
Expand Down
163 changes: 143 additions & 20 deletions rand_isaac/src/isaac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@

//! The ISAAC random number generator.

use crate::isaac_array::IsaacArray;
use core::num::Wrapping as w;
use core::{fmt, slice};
use rand_core::block::{BlockRng, BlockRngCore};
use rand_core::{RngCore, SeedableRng, TryRngCore, le};
use rand_core::block::{BlockRng, Generator};
use rand_core::{RngCore, SeedableRng, TryRngCore, utils};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -90,18 +89,17 @@ const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;
///
/// [`rand_hc`]: https://docs.rs/rand_hc
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct IsaacRng(BlockRng<IsaacCore>);

impl RngCore for IsaacRng {
#[inline]
fn next_u32(&mut self) -> u32 {
self.0.next_u32()
self.0.next_word()
}

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

#[inline]
Expand All @@ -115,42 +113,165 @@ impl SeedableRng for IsaacRng {

#[inline]
fn from_seed(seed: Self::Seed) -> Self {
IsaacRng(BlockRng::<IsaacCore>::from_seed(seed))
IsaacRng(BlockRng::new(IsaacCore::from_seed(seed)))
}

/// Create an ISAAC random number generator using an `u64` as seed.
/// If `seed == 0` this will produce the same stream of random numbers as
/// the reference implementation when used unseeded.
#[inline]
fn seed_from_u64(seed: u64) -> Self {
IsaacRng(BlockRng::<IsaacCore>::seed_from_u64(seed))
IsaacRng(BlockRng::new(IsaacCore::seed_from_u64(seed)))
}

#[inline]
fn from_rng<R>(rng: &mut R) -> Self
where
R: RngCore + ?Sized,
{
IsaacRng(BlockRng::<IsaacCore>::from_rng(rng))
IsaacRng(BlockRng::new(IsaacCore::from_rng(rng)))
}

#[inline]
fn try_from_rng<S>(rng: &mut S) -> Result<Self, S::Error>
where
S: TryRngCore + ?Sized,
{
BlockRng::<IsaacCore>::try_from_rng(rng).map(IsaacRng)
IsaacCore::try_from_rng(rng).map(|core| IsaacRng(BlockRng::new(core)))
}
}

#[cfg(feature = "serde")]
mod serde_impls {
use super::{IsaacCore, IsaacRng, RAND_SIZE};
use core::fmt;
use rand_core::block::BlockRng;
use serde::de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
use serde::ser::{Serialize, SerializeStruct, Serializer};

impl Serialize for IsaacRng {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut state = serializer.serialize_struct("IsaacRng", 2)?;
state.serialize_field("core", &self.0.core)?;
state.serialize_field("results", self.0.remaining_results())?;
state.end()
}
}

struct Results {
results: [u32; RAND_SIZE],
len: usize,
}
impl Results {
fn to_rng(&self, core: IsaacCore) -> IsaacRng {
let results = &self.results[..self.len];
IsaacRng(BlockRng::reconstruct(core, results).unwrap())
}
}
struct ResultsVisitor;
impl<'de> Visitor<'de> for ResultsVisitor {
type Value = Results;

fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "") // TODO
}

fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut results = [0u32; RAND_SIZE];
let mut len = 0;
while let Some(value) = seq.next_element()? {
if len >= results.len() {
return Err(Error::invalid_length(
len + 1,
&("up to 256 elements" as &str),
));
}

results[len] = value;
len += 1;
}

Ok(Results { results, len })
}
}

impl<'de> Deserialize<'de> for Results {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_seq(ResultsVisitor)
}
}

#[derive(serde::Deserialize)]
#[serde(field_identifier, rename_all = "lowercase")]
enum Field {
Core,
Results,
}

struct IsaacVisitor;
impl<'de> Visitor<'de> for IsaacVisitor {
type Value = IsaacRng;

fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "") // TODO
}

fn visit_seq<V>(self, mut seq: V) -> Result<IsaacRng, V::Error>
where
V: SeqAccess<'de>,
{
let core = seq
.next_element()?
.ok_or_else(|| Error::invalid_length(0, &self))?;
let results: Results = seq
.next_element()?
.ok_or_else(|| Error::invalid_length(1, &self))?;

Ok(results.to_rng(core))
}

fn visit_map<V>(self, mut map: V) -> Result<IsaacRng, V::Error>
where
V: MapAccess<'de>,
{
let mut core = None;
let mut results: Option<Results> = None;
while let Some(key) = map.next_key()? {
match key {
Field::Core => {
if core.is_some() {
return Err(Error::duplicate_field("core"));
}
core = Some(map.next_value()?);
}
Field::Results => {
if results.is_some() {
return Err(Error::duplicate_field("results"));
}
results = Some(map.next_value()?);
}
}
}
let core = core.ok_or_else(|| Error::missing_field("core"))?;
let results = results.ok_or_else(|| Error::missing_field("results"))?;

Ok(results.to_rng(core))
}
}

impl<'de> Deserialize<'de> for IsaacRng {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
const FIELDS: &[&str] = &["core", "results"];
deserializer.deserialize_struct("IsaacRng", FIELDS, IsaacVisitor)
}
}
}

/// The core of [`IsaacRng`], used with [`BlockRng`].
#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct IsaacCore {
#[cfg_attr(
feature = "serde",
serde(with = "super::isaac_array::isaac_array_serde")
)]
#[cfg_attr(feature = "serde", serde(with = "serde_arrays"))]
mem: [w32; RAND_SIZE],
a: w32,
b: w32,
Expand All @@ -174,9 +295,8 @@ impl ::core::cmp::PartialEq for IsaacCore {
// Custom Eq implementation as it can't currently be derived from an array of size RAND_SIZE
impl ::core::cmp::Eq for IsaacCore {}

impl BlockRngCore for IsaacCore {
type Item = u32;
type Results = IsaacArray<Self::Item>;
impl Generator for IsaacCore {
type Output = [u32; RAND_SIZE];

/// Refills the output buffer, `results`. See also the pseudocode description
/// of the algorithm in the `IsaacRng` documentation.
Expand All @@ -198,7 +318,7 @@ impl BlockRngCore for IsaacCore {
/// make `fill_bytes` a memcopy. To maintain compatibility we fill in
/// reverse.
#[rustfmt::skip]
fn generate(&mut self, results: &mut IsaacArray<Self::Item>) {
fn generate(&mut self, results: &mut [u32; RAND_SIZE]) {
self.c += w(1);
// abbreviations
let mut a = self.a;
Expand Down Expand Up @@ -345,8 +465,7 @@ impl SeedableRng for IsaacCore {
type Seed = [u8; 32];

fn from_seed(seed: Self::Seed) -> Self {
let mut seed_u32 = [0u32; 8];
le::read_u32_into(&seed, &mut seed_u32);
let seed_u32: [u32; 8] = utils::read_words(&seed);
// Convert the seed to `Wrapping<u32>` and zero-extend to `RAND_SIZE`.
let mut seed_extended = [w(0); RAND_SIZE];
for (x, y) in seed_extended.iter_mut().zip(seed_u32.iter()) {
Expand Down Expand Up @@ -554,6 +673,10 @@ mod test {
];
let mut rng = IsaacRng::from_seed(seed);

// discard some results
let _ = rng.next_u64();
let _ = rng.next_u32();

let buf: Vec<u8> = Vec::new();
let mut buf = BufWriter::new(buf);
bincode::serialize_into(&mut buf, &rng).expect("Could not serialize");
Expand Down
Loading