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