primitives/transcripts/
merlin.rs

1use hybrid_array::Array;
2pub use merlin::Transcript as MerlinTranscript;
3use rand::SeedableRng;
4use rand_chacha::ChaCha12Rng as ChachaRng;
5use typenum::Unsigned;
6
7use super::Transcript;
8use crate::{constants::CollisionResistanceBytes, hashing::flatten_slices, types::SessionId};
9
10impl Transcript for MerlinTranscript {
11    type Rng = merlin::TranscriptRng;
12
13    fn new(label: &'static [u8]) -> Self {
14        merlin::Transcript::new(label)
15    }
16
17    fn new_with_session_id(label: &'static [u8], session_id: &SessionId) -> Self {
18        let mut t = merlin::Transcript::new(label);
19        t.append_message(b"session_id", session_id.as_ref());
20        t
21    }
22
23    fn append<T: AsRef<[u8]>>(&mut self, label: &'static [u8], message: &T) {
24        self.append_message(label, message.as_ref());
25    }
26
27    fn append_many<T: AsRef<[u8]>>(&mut self, label: &'static [u8], values: &[T]) {
28        let concatenated = flatten_slices(values);
29        self.append_message(label, &concatenated);
30    }
31
32    fn extract<T: AsMut<[u8]>>(&mut self, label: &'static [u8], dest: &mut T) {
33        self.challenge_bytes(label, dest.as_mut());
34    }
35
36    fn derive_rng(&mut self, label: &'static [u8]) -> Self::Rng {
37        let mut seed: Array<u8, CollisionResistanceBytes> =
38            Array([0u8; CollisionResistanceBytes::USIZE]);
39        self.extract(label, &mut seed);
40        self.build_rng()
41            .finalize(&mut ChachaRng::from_seed(seed.into()))
42    }
43}