primitives/transcripts/
mod.rs

1use rand::RngCore;
2use serde::Serialize;
3
4use crate::types::SessionId;
5
6pub mod folklore;
7pub mod merlin;
8pub mod protocol_transcript;
9
10pub use folklore::FolkloreTranscript;
11pub use merlin::MerlinTranscript;
12
13pub trait Transcript {
14    type Rng: RngCore;
15
16    // Required methods
17    fn new(label: &'static [u8]) -> Self;
18    fn new_with_session_id(label: &'static [u8], session_id: &SessionId) -> Self;
19    fn append<S: AsRef<[u8]>>(&mut self, label: &'static [u8], message: &S);
20    fn append_many<S: AsRef<[u8]>>(&mut self, label: &'static [u8], values: &[S]);
21    fn extract<S: AsMut<[u8]>>(&mut self, label: &'static [u8], dest: &mut S);
22    fn derive_rng(&mut self, label: &'static [u8]) -> Self::Rng;
23
24    // Provided methods
25    fn append_serializable<S: Serialize>(&mut self, label: &'static [u8], value: &S) {
26        let serialized = bincode::serialize(value).unwrap();
27        self.append(label, &serialized);
28    }
29}
30
31#[cfg(test)]
32mod tests {
33    use rand::RngCore;
34
35    use crate::transcripts::Transcript;
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>() {
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<T: Transcript>() {
71        // Two transcripts that differ only in their init labels.
72        let message = b"hello world";
73
74        let mut t1 = T::new(b"protocol1");
75        let mut t2 = T::new(b"protocol2");
76
77        t1.append(b"message_1", &message);
78        t2.append(b"message_1", &message);
79
80        let mut dest1 = [0u8; 32];
81        let mut dest2 = [0u8; 32];
82
83        t1.extract(b"value_1", &mut dest1);
84        t2.extract(b"value_1", &mut dest2);
85
86        assert_ne!(dest1, dest2);
87
88        let mut rng1 = t1.derive_rng(b"stream");
89        let mut rng2 = t2.derive_rng(b"stream");
90
91        let mut bytes1 = [0u8; 100];
92        let mut bytes2 = [0u8; 100];
93
94        rng1.fill_bytes(&mut bytes1);
95        rng2.fill_bytes(&mut bytes2);
96
97        assert_ne!(bytes1, bytes2);
98
99        // Two transcripts that differ in their message ordering.
100        let mut t1 = T::new(b"protocol");
101        let mut t2 = T::new(b"protocol");
102
103        let message1 = b"hello world";
104        let message2 = b"goodbye world";
105
106        t1.append(b"message_1", &message1);
107        t1.append(b"message_2", &message2);
108        t2.append(b"message_2", &message2);
109        t2.append(b"message_1", &message1);
110
111        let mut dest1 = [0u8; 32];
112        let mut dest2 = [0u8; 32];
113
114        t1.extract(b"value_1", &mut dest1);
115        t2.extract(b"value_1", &mut dest2);
116
117        assert_ne!(dest1, dest2);
118
119        let mut rng1 = t1.derive_rng(b"stream");
120        let mut rng2 = t2.derive_rng(b"stream");
121
122        let mut bytes1 = [0u8; 100];
123        let mut bytes2 = [0u8; 100];
124
125        rng1.fill_bytes(&mut bytes1);
126        rng2.fill_bytes(&mut bytes2);
127
128        assert_ne!(bytes1, bytes2);
129    }
130
131    #[test]
132    fn test_folklore_transcript() {
133        test_happypath_same_transcripts_yield_same_extracts::<super::folklore::FolkloreTranscript>(
134        );
135        test_unhappypath_different_transcripts_yield_different_extracts::<
136            super::folklore::FolkloreTranscript,
137        >();
138    }
139
140    #[test]
141    fn test_merlin_transcript() {
142        test_happypath_same_transcripts_yield_same_extracts::<super::merlin::MerlinTranscript>();
143        test_unhappypath_different_transcripts_yield_different_extracts::<
144            super::merlin::MerlinTranscript,
145        >();
146    }
147}