primitives/transcripts/
folklore.rs

1use hybrid_array::Array;
2use rand::SeedableRng;
3use rand_chacha::ChaCha12Rng as ChachaRng;
4use serde::{Deserialize, Serialize};
5use zeroize::Zeroize;
6
7use super::{Transcript, TranscriptRng};
8use crate::{constants::CollisionResistanceBytes, hashing::hash, types::SessionId};
9
10#[derive(Clone, Default, Debug, Serialize, Deserialize, Zeroize)]
11pub struct FolkloreTranscript {
12    state: Array<u8, CollisionResistanceBytes>,
13}
14
15impl Transcript for FolkloreTranscript {
16    fn new(label: &'static [u8]) -> Self {
17        let state = hash(&[label]);
18        Self { state }
19    }
20
21    fn new_with_session_id(label: &'static [u8], session_id: &SessionId) -> Self {
22        let state = hash(&[label, session_id.as_ref()]);
23        Self { state }
24    }
25
26    fn append<T: AsRef<[u8]>>(&mut self, label: &'static [u8], value: &T) {
27        self.state = hash(&[label, value.as_ref(), self.state.as_ref()]);
28    }
29
30    fn append_many<T: AsRef<[u8]>>(&mut self, label: &'static [u8], values: &[T]) {
31        // Create a vector of references to pass to hash
32        let mut elements: Vec<&[u8]> = Vec::with_capacity(2 + values.len());
33        elements.push(label);
34        elements.extend(values.iter().map(AsRef::as_ref));
35        elements.push(self.state.as_ref());
36
37        let values_len = values.len().to_be_bytes();
38        elements.push(&values_len);
39
40        self.state = hash(&elements);
41    }
42
43    fn extract<T: AsMut<[u8]>>(&mut self, label: &'static [u8], dest: &mut T) {
44        self.state = hash(&[label, self.state.as_ref()]);
45        dest.as_mut().clone_from_slice(&self.state);
46    }
47}
48
49impl TranscriptRng for FolkloreTranscript {
50    type Rng = ChachaRng;
51    fn rng(&mut self, label: &'static [u8]) -> Self::Rng {
52        self.state = hash(&[label, self.state.as_ref()]);
53        ChachaRng::from_seed(self.state.into())
54    }
55}