primitives/transcripts/
mod.rs

1use rand::RngCore;
2use serde::Serialize;
3
4use crate::types::SessionId;
5
6pub mod folklore;
7pub mod merlin;
8
9pub use folklore::FolkloreTranscript;
10pub use merlin::MerlinTranscript;
11pub trait Transcript {
12    // Required methods
13    fn new(label: &'static [u8]) -> Self;
14    fn new_with_session_id(label: &'static [u8], session_id: &SessionId) -> Self;
15    fn append<T: AsRef<[u8]>>(&mut self, label: &'static [u8], message: &T);
16    fn append_many<T: AsRef<[u8]>>(&mut self, label: &'static [u8], values: &[T]);
17    fn extract<T: AsMut<[u8]>>(&mut self, label: &'static [u8], dest: &mut T);
18
19    // Provided methods
20    fn append_serializable<T: Serialize>(&mut self, label: &'static [u8], value: &T) {
21        let serialized = bincode::serialize(value).unwrap();
22        self.append(label, &serialized);
23    }
24}
25
26pub trait TranscriptRng {
27    type Rng: RngCore;
28    fn derive_rng(&mut self, label: &'static [u8]) -> Self::Rng;
29}
30
31#[cfg(test)]
32mod tests {
33    use rand::RngCore;
34
35    use super::{Transcript, TranscriptRng};
36
37    // Appending a message and extracting it in two identical transcripts should
38    // yield the same result.
39    pub fn test_happypath_same_transcripts_yield_same_extracts<T: Transcript + TranscriptRng>() {
40        let message = b"hello world";
41
42        let mut t1 = T::new(b"my_protocol");
43        let mut t2 = T::new(b"my_protocol");
44
45        t1.append(b"message_1", &message);
46        t2.append(b"message_1", &message);
47
48        let mut dest1 = [0u8; 32];
49        let mut dest2 = [0u8; 32];
50
51        t1.extract(b"value_1", &mut dest1);
52        t2.extract(b"value_1", &mut dest2);
53
54        assert_eq!(dest1, dest2);
55
56        let mut rng1 = t1.derive_rng(b"stream");
57        let mut rng2 = t2.derive_rng(b"stream");
58
59        let mut bytes1 = [0u8; 100];
60        let mut bytes2 = [0u8; 100];
61
62        rng1.fill_bytes(&mut bytes1);
63        rng2.fill_bytes(&mut bytes2);
64
65        assert_eq!(bytes1, bytes2);
66    }
67
68    // Appending a message and extracting it in two different transcripts should
69    // yield different results.
70    pub fn test_unhappypath_different_transcripts_yield_different_extracts<
71        T: Transcript + TranscriptRng,
72    >() {
73        // Two transcripts that differ only in their init labels.
74        let message = b"hello world";
75
76        let mut t1 = T::new(b"protocol1");
77        let mut t2 = T::new(b"protocol2");
78
79        t1.append(b"message_1", &message);
80        t2.append(b"message_1", &message);
81
82        let mut dest1 = [0u8; 32];
83        let mut dest2 = [0u8; 32];
84
85        t1.extract(b"value_1", &mut dest1);
86        t2.extract(b"value_1", &mut dest2);
87
88        assert_ne!(dest1, dest2);
89
90        let mut rng1 = t1.derive_rng(b"stream");
91        let mut rng2 = t2.derive_rng(b"stream");
92
93        let mut bytes1 = [0u8; 100];
94        let mut bytes2 = [0u8; 100];
95
96        rng1.fill_bytes(&mut bytes1);
97        rng2.fill_bytes(&mut bytes2);
98
99        assert_ne!(bytes1, bytes2);
100
101        // Two transcripts that differ in their message ordering.
102        let mut t1 = T::new(b"protocol");
103        let mut t2 = T::new(b"protocol");
104
105        let message1 = b"hello world";
106        let message2 = b"goodbye world";
107
108        t1.append(b"message_1", &message1);
109        t1.append(b"message_2", &message2);
110        t2.append(b"message_2", &message2);
111        t2.append(b"message_1", &message1);
112
113        let mut dest1 = [0u8; 32];
114        let mut dest2 = [0u8; 32];
115
116        t1.extract(b"value_1", &mut dest1);
117        t2.extract(b"value_1", &mut dest2);
118
119        assert_ne!(dest1, dest2);
120
121        let mut rng1 = t1.derive_rng(b"stream");
122        let mut rng2 = t2.derive_rng(b"stream");
123
124        let mut bytes1 = [0u8; 100];
125        let mut bytes2 = [0u8; 100];
126
127        rng1.fill_bytes(&mut bytes1);
128        rng2.fill_bytes(&mut bytes2);
129
130        assert_ne!(bytes1, bytes2);
131    }
132
133    #[test]
134    fn test_folklore_transcript() {
135        test_happypath_same_transcripts_yield_same_extracts::<super::folklore::FolkloreTranscript>(
136        );
137        test_unhappypath_different_transcripts_yield_different_extracts::<
138            super::folklore::FolkloreTranscript,
139        >();
140    }
141
142    #[test]
143    fn test_merlin_transcript() {
144        test_happypath_same_transcripts_yield_same_extracts::<super::merlin::MerlinTranscript>();
145        test_unhappypath_different_transcripts_yield_different_extracts::<
146            super::merlin::MerlinTranscript,
147        >();
148    }
149}