primitives/random/
derive_rng.rs

1use rand::SeedableRng;
2use rand_chacha::ChaCha12Rng;
3
4use crate::{
5    hashing::{self, hash_into, Digest},
6    random::CryptoRngCore,
7};
8
9pub trait DeriveRng: AsRef<[u8]> + From<Digest> {
10    /// Derive new Seed from the current object
11    fn derive_new(&self, tag: &[u8]) -> Self {
12        hashing::hash(&[self.as_ref(), tag]).into()
13    }
14
15    /// Initializes a ChaCha12 RNG with the session ID as a seed.
16    fn derive_new_rng(&self, tag: &[u8]) -> ChaCha12Rng {
17        self.derive_new_custom_rng(tag)
18    }
19
20    /// Derive a new seed using the tag and initialize a Rng
21    fn derive_new_custom_rng<Rng>(&self, tag: &[u8]) -> Rng
22    where
23        Rng: CryptoRngCore + SeedableRng,
24    {
25        let mut seed = Rng::Seed::default();
26        hash_into([self.derive_new(tag)], seed.as_mut());
27        Rng::from_seed(seed)
28    }
29
30    /// Initializes a ChaCha12 RNG with the session ID as a seed.
31    fn derive_rng(&self) -> ChaCha12Rng {
32        self.derive_custom_rng::<ChaCha12Rng>()
33    }
34
35    /// Initializes an RNG with the current seed.
36    /// This is useful for generating random values that are consistent across protocol runs.
37    fn derive_custom_rng<Rng>(&self) -> Rng
38    where
39        Rng: CryptoRngCore + SeedableRng,
40    {
41        self.derive_new_custom_rng(b"")
42    }
43}