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