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;
8use crate::{
9    constants::CollisionResistanceBytes,
10    hashing::hash,
11    random::Seed,
12    types::{identifiers::ProtocolInfo, SessionId},
13};
14
15#[derive(Clone, Default, Debug, Serialize, Deserialize, Zeroize)]
16pub struct FolkloreTranscript {
17    state: Array<u8, CollisionResistanceBytes>,
18}
19
20impl Transcript for FolkloreTranscript {
21    type Rng = ChachaRng;
22
23    fn new(protocol_info: &'static ProtocolInfo, session_id: &SessionId) -> Self {
24        let state = hash(&[protocol_info.tag(), session_id.as_ref()]);
25        Self { state }
26    }
27
28    fn append_with<T: AsRef<[u8]>>(&mut self, label: &'static [u8], value: &T) {
29        self.state = hash(&[label, value.as_ref(), self.state.as_ref()]);
30    }
31
32    fn append_many_with<T: AsRef<[u8]>>(&mut self, label: &'static [u8], values: &[T]) {
33        // Create a vector of references to pass to hash
34        let mut elements: Vec<&[u8]> = Vec::with_capacity(2 + values.len());
35        elements.push(label);
36        elements.extend(values.iter().map(AsRef::as_ref));
37        elements.push(self.state.as_ref());
38
39        let values_len = values.len().to_be_bytes();
40        elements.push(&values_len);
41
42        self.state = hash(&elements);
43    }
44
45    fn extract(&mut self, label: &'static [u8]) -> Seed {
46        self.state = hash(&[label, self.state.as_ref()]);
47        *self.state.as_ref()
48    }
49
50    fn derive_rng(&mut self, label: &'static [u8]) -> Self::Rng {
51        self.state = hash(&[label, self.state.as_ref()]);
52        ChachaRng::from_seed(self.state.into())
53    }
54}