rapidhash/
random_state.rs

1use std::cell::Cell;
2use std::hash::BuildHasher;
3use crate::{rapidrng_fast, RapidHasher};
4
5/// A [std::collections::hash_map::RandomState] compatible hasher that initializes the [RapidHasher]
6/// algorithm with a random seed.
7///
8/// Note this is not sufficient to prevent HashDoS attacks. The rapidhash algorithm is not proven to
9/// be resistant, and the seed used is not wide enough.
10///
11/// # Example
12/// ```rust
13/// use std::collections::HashMap;
14/// use std::hash::Hasher;
15/// use rapidhash::RapidRandomState;
16///
17/// let mut map = HashMap::with_hasher(RapidRandomState::default());
18/// map.insert(42, "the answer");
19/// ```
20#[derive(Copy, Clone, Eq, PartialEq)]
21pub struct RapidRandomState {
22    seed: u64,
23}
24
25impl RapidRandomState {
26    /// Create a new random state with a random seed.
27    ///
28    /// With the `rand` feature enabled, this will use [rand::random] to initialise the seed.
29    ///
30    /// Without `rand` but with the `std` feature enabled, this will use [crate::rapidrng_time] to
31    /// initialise the seed.
32    pub fn new() -> Self {
33        #[cfg(feature = "rand")]
34        thread_local! {
35            static RANDOM_SEED: Cell<u64> = {
36                Cell::new(rand::random())
37            }
38        }
39
40        #[cfg(all(feature = "std", not(feature = "rand")))]
41        thread_local! {
42            static RANDOM_SEED: Cell<u64> = {
43                let mut seed = crate::RAPID_SEED;
44                Cell::new(crate::rapidrng_time(&mut seed))
45            }
46        }
47
48        let mut seed = RANDOM_SEED.with(|cell| {
49            let seed = cell.get();
50            cell.set(seed.wrapping_add(1));
51            seed
52        });
53
54        Self {
55            seed: rapidrng_fast(&mut seed),
56        }
57    }
58}
59
60impl Default for RapidRandomState {
61    fn default() -> Self {
62        Self::new()
63    }
64}
65
66impl BuildHasher for RapidRandomState {
67    type Hasher = RapidHasher;
68
69    fn build_hasher(&self) -> Self::Hasher {
70        RapidHasher::new(self.seed)
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use std::hash::{BuildHasher, Hasher, RandomState};
77
78    #[test]
79    fn test_random_state() {
80        // the same state should produce the equivalent hashes
81        let state1 = RandomState::new();
82        let mut hash1a = state1.build_hasher();
83        let mut hash1b = state1.build_hasher();
84
85        // different state should produce different hashes
86        let state2 = RandomState::new();
87        let mut hash2a = state2.build_hasher();
88
89        hash1a.write(b"hello");
90        hash1b.write(b"hello");
91        hash2a.write(b"hello");
92
93        let finish1a = hash1a.finish();
94        let finish1b = hash1b.finish();
95        let finish2a = hash2a.finish();
96
97        assert_eq!(finish1a, finish1b);
98        assert_ne!(finish1a, finish2a);
99    }
100}