Skip to content

Commit

Permalink
rand_seeder: add Seeder type
Browse files Browse the repository at this point in the history
  • Loading branch information
dhardy committed Jul 27, 2018
1 parent 9b1fafa commit b37c70d
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 0 deletions.
25 changes: 25 additions & 0 deletions rand_seeder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,31 @@

A universal seeder based on [`SipHash`](https://131002.net/siphash/).

This crate provides three things:

- a portable implementation of SipHash-2-4, `SipHasher`
- `SipRng`, based around the `SipHash` state and mixing operations
- `Seeder`, a convenience wrapper

`Seeder` can be used to seed any `SeedableRng` from any hashable value. It is
portable and reproducible, and should turn any input into a good RNG seed.
It is intended for use in simulations and games where reproducibility is
important.

We do not recommend using `Seeder` for cryptographic applications and
strongly advise against usage for authentication (password hashing).

Example:

```rust
use rand_core::RngCore; // for next_u32
use rand::prng::XorShiftRng; // or whatever you like
use rand_seeder::Seeder;

let mut rng: XorShiftRng = Seeder::from("stripy zebra").make_rng();
println!("First value: {}", rng.next_u32());
```

Documentation:
[master branch](https://rust-lang-nursery.github.io/rand/rand_seeder/index.html),
[by release](https://docs.rs/rand_seeder)
Expand Down
72 changes: 72 additions & 0 deletions rand_seeder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,75 @@ extern crate rand_core;
mod sip;

pub use sip::{SipHasher, SipRng};

use core::hash::Hash;
use rand_core::{RngCore, SeedableRng};

/// A universal seeder.
///
/// `Seeder` can be used to seed any `SeedableRng` from any hashable value. It
/// is portable and reproducible, and should turn any input into a good RNG
/// seed. It is intended for use in simulations and games where reproducibility
/// is important.
///
/// We do not recommend using `Seeder` for cryptographic applications and
/// strongly advise against usage for authentication (password hashing).
///
/// Example:
///
/// ```rust
/// # extern crate rand_core;
/// # extern crate rand_seeder;
/// use rand_core::RngCore;
/// use rand_seeder::{Seeder, SipRng};
///
/// // Use any SeedableRng you like in place of SipRng:
/// let mut rng: SipRng = Seeder::from("stripy zebra").make_rng();
/// println!("First value: {}", rng.next_u32());
/// ```
#[derive(Debug, Clone)]
pub struct Seeder {
rng: SipRng,
}

impl Seeder {
/// Construct an RNG (of type `R: SeedableRng`), seeded from the internal
/// `SipRng`.
///
/// Mutliple RNGs may be constructed using the same `Seeder`.
pub fn make_rng<R: SeedableRng>(&mut self) -> R {
let mut seed = R::Seed::default();
self.rng.fill_bytes(seed.as_mut());
R::from_seed(seed)
}
}

impl<H: Hash> From<H> for Seeder {
#[inline]
fn from(h: H) -> Seeder {
let hasher = SipHasher::from(h);
Seeder {
rng: hasher.make_rng()
}
}
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn make_seeder() {
let _ = Seeder::from(0u64);
let _ = Seeder::from("a static string");
let _ = Seeder::from([1u8, 2, 3]);
}

#[test]
fn make_rng() {
let mut seeder = Seeder::from("test string");
let mut rng = seeder.make_rng::<SipRng>();
assert_eq!(rng.next_u64(), 7267854722795183454);
assert_eq!(rng.next_u64(), 602994585684902144);
}
}

0 comments on commit b37c70d

Please sign in to comment.