Skip to main content

relay_crypto/
rng.rs

1use rand_core::{CryptoRng, OsRng, RngCore, SeedableRng as _};
2
3/// Hashes an os ranadom seed with the nonce provided. Provices a sense of security against OS RNG failures.
4pub fn os_rng_hkdf(
5    nonce: Option<&[u8]>,
6    context: &[u8],
7) -> Result<impl RngCore + CryptoRng, hkdf::InvalidLength> {
8    let mut ikm = [0u8; 32];
9    OsRng.fill_bytes(&mut ikm);
10
11    let hk = hkdf::Hkdf::<sha2::Sha256>::new(nonce, &ikm);
12
13    let mut seed = [0u8; 32];
14    hk.expand(context, &mut seed)?;
15
16    Ok(rand_chacha::ChaCha20Rng::from_seed(seed))
17}
18
19#[cfg(test)]
20mod tests {
21    use super::*;
22
23    #[test]
24    fn test_os_rng_hkdf() {
25        let mut rng1 = os_rng_hkdf(None, b"test-context").unwrap();
26        let mut rng2 = os_rng_hkdf(Some(b"hey there!"), b"test-context").unwrap();
27
28        let mut buf1 = [0u8; 256];
29        let mut buf2 = [0u8; 256];
30
31        rng1.fill_bytes(&mut buf1);
32        rng2.fill_bytes(&mut buf2);
33
34        // There is a very small chance this could fail if both RNGs produce the same output :DDD
35        assert_ne!(buf1, buf2);
36    }
37}