ark_marlin/
rng.rs

1use crate::Vec;
2use ark_ff::{FromBytes, ToBytes};
3use ark_std::marker::PhantomData;
4use ark_std::rand::{RngCore, SeedableRng};
5use digest::{generic_array::GenericArray, Digest};
6use rand_chacha::ChaChaRng;
7
8/// A `SeedableRng` that refreshes its seed by hashing together the previous seed
9/// and the new seed material.
10// TODO: later: re-evaluate decision about ChaChaRng
11pub struct FiatShamirRng<D: Digest> {
12    r: ChaChaRng,
13    seed: GenericArray<u8, D::OutputSize>,
14    #[doc(hidden)]
15    digest: PhantomData<D>,
16}
17
18impl<D: Digest> RngCore for FiatShamirRng<D> {
19    #[inline]
20    fn next_u32(&mut self) -> u32 {
21        self.r.next_u32()
22    }
23
24    #[inline]
25    fn next_u64(&mut self) -> u64 {
26        self.r.next_u64()
27    }
28
29    #[inline]
30    fn fill_bytes(&mut self, dest: &mut [u8]) {
31        self.r.fill_bytes(dest);
32    }
33
34    #[inline]
35    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), ark_std::rand::Error> {
36        Ok(self.r.fill_bytes(dest))
37    }
38}
39
40impl<D: Digest> FiatShamirRng<D> {
41    /// Create a new `Self` by initializing with a fresh seed.
42    /// `self.seed = H(self.seed || new_seed)`.
43    #[inline]
44    pub fn from_seed<'a, T: 'a + ToBytes>(seed: &'a T) -> Self {
45        let mut bytes = Vec::new();
46        seed.write(&mut bytes).expect("failed to convert to bytes");
47        let seed = D::digest(&bytes);
48        let r_seed: [u8; 32] = FromBytes::read(seed.as_ref()).expect("failed to get [u32; 8]");
49        let r = ChaChaRng::from_seed(r_seed);
50        Self {
51            r,
52            seed,
53            digest: PhantomData,
54        }
55    }
56
57    /// Refresh `self.seed` with new material. Achieved by setting
58    /// `self.seed = H(self.seed || new_seed)`.
59    #[inline]
60    pub fn absorb<'a, T: 'a + ToBytes>(&mut self, seed: &'a T) {
61        let mut bytes = Vec::new();
62        seed.write(&mut bytes).expect("failed to convert to bytes");
63        bytes.extend_from_slice(&self.seed);
64        self.seed = D::digest(&bytes);
65        let seed: [u8; 32] = FromBytes::read(self.seed.as_ref()).expect("failed to get [u32; 8]");
66        self.r = ChaChaRng::from_seed(seed);
67    }
68}