Make BlockRng{64} fields private

This commit is contained in:
Paul Dicker 2018-04-04 17:26:04 +02:00
parent 6f6431043c
commit 204b9e48b2
5 changed files with 133 additions and 118 deletions

View File

@ -191,9 +191,9 @@ pub struct BlockRng<R: BlockRngCore + ?Sized> {
#[cfg_attr(feature="serde-1", serde(bound(
serialize = "R::Results: Serialize",
deserialize = "R::Results: Deserialize<'de>")))]
pub results: R::Results,
pub index: usize,
pub core: R,
results: R::Results,
index: usize,
core: R,
}
// Custom Debug implementation that does not expose the contents of `results`.
@ -207,6 +207,35 @@ impl<R: BlockRngCore + fmt::Debug> fmt::Debug for BlockRng<R> {
}
}
impl<R: BlockRngCore> BlockRng<R> {
/// Create a new `BlockRng` from an existing RNG implementing
/// `BlockRngCore`. Results will be generated on first use.
pub fn new(core: R) -> BlockRng<R>{
let results_empty = R::Results::default();
BlockRng {
core,
index: results_empty.as_ref().len(),
results: results_empty,
}
}
/// Return a reference the wrapped `BlockRngCore`.
pub fn inner(&self) -> &R {
&self.core
}
/// Return a mutable reference the wrapped `BlockRngCore`.
pub fn inner_mut(&mut self) -> &mut R {
&mut self.core
}
// Reset the number of available results.
// This will force a new set of results to be generated on next use.
pub fn reset(&mut self) {
self.index = self.results.as_ref().len();
}
}
impl<R: BlockRngCore<Item=u32>> RngCore for BlockRng<R>
where <R as BlockRngCore>::Results: AsRef<[u32]>
{
@ -323,21 +352,11 @@ impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng<R> {
type Seed = R::Seed;
fn from_seed(seed: Self::Seed) -> Self {
let results_empty = R::Results::default();
Self {
core: R::from_seed(seed),
index: results_empty.as_ref().len(), // generate on first use
results: results_empty,
}
Self::new(R::from_seed(seed))
}
fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
let results_empty = R::Results::default();
Ok(Self {
core: R::from_rng(rng)?,
index: results_empty.as_ref().len(), // generate on first use
results: results_empty,
})
Ok(Self::new(R::from_rng(rng)?))
}
}
@ -358,10 +377,10 @@ pub struct BlockRng64<R: BlockRngCore + ?Sized> {
#[cfg_attr(feature="serde-1", serde(bound(
serialize = "R::Results: Serialize",
deserialize = "R::Results: Deserialize<'de>")))]
pub results: R::Results,
pub index: usize,
pub half_used: bool, // true if only half of the previous result is used
pub core: R,
results: R::Results,
index: usize,
half_used: bool, // true if only half of the previous result is used
core: R,
}
// Custom Debug implementation that does not expose the contents of `results`.
@ -376,6 +395,31 @@ impl<R: BlockRngCore + fmt::Debug> fmt::Debug for BlockRng64<R> {
}
}
impl<R: BlockRngCore> BlockRng64<R> {
/// Create a new `BlockRng` from an existing RNG implementing
/// `BlockRngCore`. Results will be generated on first use.
pub fn new(core: R) -> BlockRng64<R>{
let results_empty = R::Results::default();
BlockRng64 {
core,
index: results_empty.as_ref().len(),
half_used: false,
results: results_empty,
}
}
/// Return a mutable reference the wrapped `BlockRngCore`.
pub fn inner(&mut self) -> &mut R {
&mut self.core
}
// Reset the number of available results.
// This will force a new set of results to be generated on next use.
pub fn reset(&mut self) {
self.index = self.results.as_ref().len();
}
}
impl<R: BlockRngCore<Item=u64>> RngCore for BlockRng64<R>
where <R as BlockRngCore>::Results: AsRef<[u64]>
{
@ -424,6 +468,7 @@ where <R as BlockRngCore>::Results: AsRef<[u64]>
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn fill_bytes(&mut self, dest: &mut [u8]) {
let mut filled = 0;
self.half_used = false;
// Continue filling from the current set of results
if self.index < self.results.as_ref().len() {
@ -461,11 +506,11 @@ where <R as BlockRngCore>::Results: AsRef<[u64]>
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn fill_bytes(&mut self, dest: &mut [u8]) {
let mut read_len = 0;
self.half_used = false;
while read_len < dest.len() {
if self.index as usize >= self.results.as_ref().len() {
self.core.generate(&mut self.results);
self.index = 0;
self.half_used = false;
}
let (consumed_u64, filled_u8) =
@ -486,23 +531,11 @@ impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng64<R> {
type Seed = R::Seed;
fn from_seed(seed: Self::Seed) -> Self {
let results_empty = R::Results::default();
Self {
core: R::from_seed(seed),
index: results_empty.as_ref().len(), // generate on first use
half_used: false,
results: results_empty,
}
Self::new(R::from_seed(seed))
}
fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
let results_empty = R::Results::default();
Ok(Self {
core: R::from_rng(rng)?,
index: results_empty.as_ref().len(), // generate on first use
half_used: false,
results: results_empty,
})
Ok(Self::new(R::from_rng(rng)?))
}
}

View File

@ -156,8 +156,8 @@ impl ChaChaRng {
/// assert_eq!(rng1.next_u32(), rng2.next_u32());
/// ```
pub fn set_counter(&mut self, counter_low: u64, counter_high: u64) {
self.0.core.set_counter(counter_low, counter_high);
self.0.index = STATE_WORDS; // force recomputation on next use
self.0.inner_mut().set_counter(counter_low, counter_high);
self.0.reset(); // force recomputation on next use
}
/// Sets the number of rounds to run the ChaCha core algorithm per block to
@ -179,8 +179,8 @@ impl ChaChaRng {
/// assert_eq!(rng.next_u32(), 0x2fef003e);
/// ```
pub fn set_rounds(&mut self, rounds: usize) {
self.0.core.set_rounds(rounds);
self.0.index = STATE_WORDS; // force recomputation on next use
self.0.inner_mut().set_rounds(rounds);
self.0.reset(); // force recomputation on next use
}
}

View File

@ -128,28 +128,15 @@ impl IsaacRng {
///
/// DEPRECATED. `IsaacRng::new_from_u64(0)` will produce identical results.
#[deprecated(since="0.5.0", note="use the NewRng or SeedableRng trait")]
pub fn new_unseeded() -> IsaacRng {
pub fn new_unseeded() -> Self {
Self::new_from_u64(0)
}
/// Create an ISAAC random number generator using an u64 as 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.
pub fn new_from_u64(seed: u64) -> IsaacRng {
let mut key = [w(0); RAND_SIZE];
key[0] = w(seed as u32);
key[1] = w((seed >> 32) as u32);
IsaacRng(BlockRng {
// Initialize with only one pass.
// A second pass does not improve the quality here, because all of
// the seed was already available in the first round.
// Not doing the second pass has the small advantage that if
// `seed == 0` this method produces exactly the same state as the
// reference implementation when used unseeded.
core: IsaacCore::init(key, 1),
results: IsaacArray::default(),
index: RAND_SIZE, // generate on first use
})
pub fn new_from_u64(seed: u64) -> Self {
IsaacRng(BlockRng::new(IsaacCore::new_from_u64(seed)))
}
}
@ -318,6 +305,22 @@ impl IsaacCore {
Self { mem, a: w(0), b: w(0), c: w(0) }
}
/// 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.
fn new_from_u64(seed: u64) -> Self {
let mut key = [w(0); RAND_SIZE];
key[0] = w(seed as u32);
key[1] = w((seed >> 32) as u32);
// Initialize with only one pass.
// A second pass does not improve the quality here, because all of the
// seed was already available in the first round.
// Not doing the second pass has the small advantage that if
// `seed == 0` this method produces exactly the same state as the
// reference implementation when used unseeded.
Self::init(key, 1)
}
}
impl SeedableRng for IsaacCore {
@ -470,20 +473,8 @@ mod test {
let mut read = BufReader::new(&buf[..]);
let mut deserialized: IsaacRng = bincode::deserialize_from(&mut read).expect("Could not deserialize");
assert_eq!(rng.0.index, deserialized.0.index);
/* Can't assert directly because of the array size */
for (orig,deser) in rng.0.results.iter().zip(deserialized.0.results.iter()) {
assert_eq!(orig, deser);
}
for (orig,deser) in rng.0.core.mem.iter().zip(deserialized.0.core.mem.iter()) {
assert_eq!(orig, deser);
}
assert_eq!(rng.0.core.a, deserialized.0.core.a);
assert_eq!(rng.0.core.b, deserialized.0.core.b);
assert_eq!(rng.0.core.c, deserialized.0.core.c);
for _ in 0..16 {
assert_eq!(rng.next_u64(), deserialized.next_u64());
for _ in 0..300 { // more than the 256 buffered results
assert_eq!(rng.next_u32(), deserialized.next_u32());
}
}
}

View File

@ -118,28 +118,15 @@ impl Isaac64Rng {
///
/// DEPRECATED. `Isaac64Rng::new_from_u64(0)` will produce identical results.
#[deprecated(since="0.5.0", note="use the NewRng or SeedableRng trait")]
pub fn new_unseeded() -> Isaac64Rng {
pub fn new_unseeded() -> Self {
Self::new_from_u64(0)
}
/// Create an ISAAC-64 random number generator using an u64 as seed.
/// Create an ISAAC-64 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.
pub fn new_from_u64(seed: u64) -> Isaac64Rng {
let mut key = [w(0); RAND_SIZE];
key[0] = w(seed);
Isaac64Rng(BlockRng64 {
// Initialize with only one pass.
// A second pass does not improve the quality here, because all of
// the seed was already available in the first round.
// Not doing the second pass has the small advantage that if
// `seed == 0` this method produces exactly the same state as the
// reference implementation when used unseeded.
core: Isaac64Core::init(key, 1),
results: IsaacArray::default(),
index: RAND_SIZE, // generate on first use
half_used: false,
})
pub fn new_from_u64(seed: u64) -> Self {
Isaac64Rng(BlockRng64::new(Isaac64Core::new_from_u64(seed)))
}
}
@ -283,6 +270,21 @@ impl Isaac64Core {
Self { mem, a: w(0), b: w(0), c: w(0) }
}
/// Create an ISAAC-64 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.
pub fn new_from_u64(seed: u64) -> Self {
let mut key = [w(0); RAND_SIZE];
key[0] = w(seed);
// Initialize with only one pass.
// A second pass does not improve the quality here, because all of the
// seed was already available in the first round.
// Not doing the second pass has the small advantage that if
// `seed == 0` this method produces exactly the same state as the
// reference implementation when used unseeded.
Self::init(key, 1)
}
}
impl SeedableRng for Isaac64Core {
@ -463,20 +465,7 @@ mod test {
let mut read = BufReader::new(&buf[..]);
let mut deserialized: Isaac64Rng = bincode::deserialize_from(&mut read).expect("Could not deserialize");
assert_eq!(rng.0.index, deserialized.0.index);
assert_eq!(rng.0.half_used, deserialized.0.half_used);
/* Can't assert directly because of the array size */
for (orig,deser) in rng.0.results.iter().zip(deserialized.0.results.iter()) {
assert_eq!(orig, deser);
}
for (orig,deser) in rng.0.core.mem.iter().zip(deserialized.0.core.mem.iter()) {
assert_eq!(orig, deser);
}
assert_eq!(rng.0.core.a, deserialized.0.core.a);
assert_eq!(rng.0.core.b, deserialized.0.core.b);
assert_eq!(rng.0.core.c, deserialized.0.core.c);
for _ in 0..16 {
for _ in 0..300 { // more than the 256 buffered results
assert_eq!(rng.next_u64(), deserialized.next_u64());
}
}

View File

@ -68,28 +68,13 @@ where R: BlockRngCore + SeedableRng,
/// * `rng`: the random number generator to use.
/// * `threshold`: the number of generated bytes after which to reseed the RNG.
/// * `reseeder`: the RNG to use for reseeding.
pub fn new(rng: R, threshold: u64, reseeder: Rsdr)
-> ReseedingRng<R, Rsdr>
{
assert!(threshold <= ::core::i64::MAX as u64);
let results_empty = R::Results::default();
ReseedingRng(
BlockRng {
core: ReseedingCore {
inner: rng,
reseeder,
threshold: threshold as i64,
bytes_until_reseed: threshold as i64,
},
index: results_empty.as_ref().len(), // generate on first use
results: results_empty,
}
)
pub fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self {
ReseedingRng(BlockRng::new(ReseedingCore::new(rng, threshold, reseeder)))
}
/// Reseed the internal PRNG.
pub fn reseed(&mut self) -> Result<(), Error> {
self.0.core.reseed()
self.0.inner_mut().reseed()
}
}
@ -154,6 +139,23 @@ impl<R, Rsdr> ReseedingCore<R, Rsdr>
where R: BlockRngCore + SeedableRng,
Rsdr: RngCore
{
/// Create a new `ReseedingCore` with the given parameters.
///
/// # Arguments
///
/// * `rng`: the random number generator to use.
/// * `threshold`: the number of generated bytes after which to reseed the RNG.
/// * `reseeder`: the RNG to use for reseeding.
pub fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self {
assert!(threshold <= ::core::i64::MAX as u64);
ReseedingCore {
inner: rng,
reseeder,
threshold: threshold as i64,
bytes_until_reseed: threshold as i64,
}
}
/// Reseed the internal PRNG.
fn reseed(&mut self) -> Result<(), Error> {
R::from_rng(&mut self.reseeder).map(|result| {