Ibraheem Ahmed

Hidden inside std::collections::hash_map is a struct called RandomState. It's job is to initialize a DefaultHasher with a random seed for use in a HashMap. It turns out that if you create a random DefaultHasher and extract the final hash without actually hashing anything, you get a random number:

fn rand() -> u64 {
    RandomState::new().build_hasher().finish()
}

fn main() {
    for _ in 0..5 {
        println!("{}", rand());
    }
}
13850751674286760248
45510352149189357
6403375774259711286
1678796842412519869
12232603414372688969

Under the hood RandomState::new doesn't actually fetch entropy every time it's called. Instead, it caches a key per thread and increments it:

impl RandomState {
    /// Constructs a new `RandomState` that is initialized with random keys.
    pub fn new() -> RandomState {
        thread_local!(static KEYS: Cell<(u64, u64)> = {
            Cell::new(sys::hashmap_random_keys()) // e.g getrandom()
        });

        KEYS.with(|keys| {
            let (k0, k1) = keys.get();
            keys.set((k0.wrapping_add(1), k1));
            RandomState { k0, k1 }
        })
    }
}

This seed is then hashed with SipHash13, Rust's default hasher, and a decent psuedo random number generator:

impl hash::Hasher for SipHasher {
    // ...
    fn finish(&self) -> u64 {
        let mut state = self.state;

        let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;

        state.v3 ^= b;
        Sip13Rounds::c_rounds(&mut state);
        state.v0 ^= b;

        state.v2 ^= 0xff;
        Sip13Rounds::d_rounds(&mut state);

        state.v0 ^ state.v1 ^ state.v2 ^ state.v3
    }
}

Of course everything above is an implementation detail that you can't rely on... so use it at your own risk.