1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A universal seeder based on [SipHash].
//!
//! This crate is designed for use with the [rand] crates, allowing any RNG
//! supporting [`SeedableRng`] to be seeded from any hashable value.
//! It provides the following:
//! 
//! -   [`SipHasher`], a portable implementation of the SipHash 2-4 hash function.
//!     According to the authors, [SipHash] is a secure, fast and simple keyed
//!     hash function.
//! -   [`SipRng`], a generator based on the SipHash state and mixing operations.
//!     It is statistically high-quality, passing practrand tests to at least 4 TiB.
//! -   A universal [`Seeder`] as a convenience wrapper around the above.
//!
//! Seeding is designed to be fast, robust, flexible and portable. This library
//! is intended for use in simulations and games, allowing e.g. any keyword to
//! reproduce a simulation or procedurally generated world.
//!
//! This library is not intended for cryptographic applications, and *definitely*
//! not for password hashing.
//!
//! [rand]: https://github.com/rust-random/rand
//! [SipHash]: https://131002.net/siphash/
//! [`SeedableRng`]: rand_core::SeedableRng

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
       html_favicon_url = "https://www.rust-lang.org/favicon.ico",
       html_root_url = "https://docs.rs/rand_seeder/0.2.0")]

#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![doc(test(attr(allow(unused_variables), deny(warnings))))]

#![no_std]

pub 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());
/// ```
///
/// [`SeedableRng`]: rand_core::SeedableRng
#[derive(Debug, Clone)]
pub struct Seeder {
    rng: SipRng,
}

impl Seeder {
    /// Construct and seed a generator of any type `R: SeedableRng`.
    ///
    /// This function seeds a new RNG using an internal [`SipRng`] generator.
    /// Because of this, multiple independent RNGs may safely be constructed
    /// from a single [`Seeder`].
    ///
    /// Alternatively, one can obtain a [`SipRng`] via
    /// `SipHasher::from(h).into_rng()`.
    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.into_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);
    }
}