primitives/transcripts/
mod.rs1use crate::{
2 random::{CryptoRngCore, Seed},
3 types::{identifiers::ProtocolInfo, SessionId},
4};
5
6pub mod folklore;
7pub mod merlin;
8pub mod protocol_transcript;
9
10pub use folklore::FolkloreTranscript;
11pub use merlin::MerlinTranscript;
12pub use protocol_transcript::ProtocolTranscript;
13
14pub trait Transcript: Clone {
20 type Rng: CryptoRngCore;
22
23 fn new(protocol_info: &'static ProtocolInfo, session_id: &SessionId) -> Self;
25
26 fn append_with<S: AsRef<[u8]>>(&mut self, label: &'static [u8], message: &S);
28
29 fn append_many_with<S: AsRef<[u8]>>(&mut self, label: &'static [u8], messages: &[S]);
31
32 fn extract(&mut self, label: &'static [u8]) -> Seed;
35
36 fn extract_rng(&mut self, label: &'static [u8]) -> Self::Rng;
39}
40
41pub trait AutoTranscript: Transcript + Sized {
45 type Label: AsRef<[u8]>;
47
48 #[inline]
49 fn new(protocol_info: &'static ProtocolInfo, session_id: &SessionId) -> Self {
51 Transcript::new(protocol_info, session_id)
52 }
53
54 fn get_current_label(&self) -> Self::Label;
57
58 fn next_label(&mut self) -> Self::Label;
60
61 fn append<S: AsRef<[u8]>>(&mut self, message: &S);
63
64 fn append_many<S: AsRef<[u8]>>(&mut self, values: &[S]);
66
67 #[inline]
68 fn extract(&mut self, label: &'static [u8]) -> Seed {
71 Transcript::extract(self, label)
72 }
73
74 #[inline]
75 fn extract_rng(&mut self, label: &'static [u8]) -> Self::Rng {
78 Transcript::extract_rng(self, label)
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use rand::RngCore;
85
86 use crate::{
87 random::{test_rng, Random},
88 transcripts::Transcript,
89 types::{identifiers::ProtocolInfo, SessionId},
90 };
91
92 pub fn test_happypath_same_transcripts_yield_same_extracts<T: Transcript>() {
95 let message = b"hello world";
96 let session_id = SessionId::random(&mut test_rng());
97
98 static TEST_PROTOCOL_INFO: ProtocolInfo = ProtocolInfo::new("test_protocol", 42);
99 let mut t1 = T::new(&TEST_PROTOCOL_INFO, &session_id);
100 t1.append_with(b"message_1", &message);
101 let mut t2 = T::new(&TEST_PROTOCOL_INFO, &session_id);
102 t2.append_with(b"message_1", &message);
103
104 let dest1 = t1.extract(b"value_1");
105 let dest2 = t2.extract(b"value_1");
106 assert_eq!(dest1, dest2);
107
108 let mut bytes1 = [0u8; 100];
109 let mut bytes2 = [0u8; 100];
110 t1.extract_rng(b"stream").fill_bytes(&mut bytes1);
111 t2.extract_rng(b"stream").fill_bytes(&mut bytes2);
112 assert_eq!(bytes1, bytes2);
113 }
114
115 pub fn test_unhappypath_different_transcripts_yield_different_extracts<T: Transcript>() {
118 let message = b"hello world";
120 let session_id = SessionId::random(&mut test_rng());
121
122 static PROTOCOL_1: ProtocolInfo = ProtocolInfo::new("test_protocol_1", 42);
123 let mut t1 = T::new(&PROTOCOL_1, &session_id);
124 t1.append_with(b"message_1", &message);
125
126 static PROTOCOL_2: ProtocolInfo = ProtocolInfo::new("test_protocol_2", 43);
127 let mut t2 = T::new(&PROTOCOL_2, &session_id);
128 t2.append_with(b"message_1", &message);
129
130 let dest1 = t1.extract(b"value_1");
131 let dest2 = t2.extract(b"value_1");
132 assert_ne!(dest1, dest2);
133
134 let mut bytes1 = [0u8; 100];
135 let mut bytes2 = [0u8; 100];
136 t1.extract_rng(b"stream").fill_bytes(&mut bytes1);
137 t2.extract_rng(b"stream").fill_bytes(&mut bytes2);
138 assert_ne!(bytes1, bytes2);
139
140 let message1 = b"hello world";
142 let message2 = b"goodbye world";
143
144 let mut t1 = T::new(&PROTOCOL_1, &session_id);
145 t1.append_with(b"message_1", &message1);
146 t1.append_with(b"message_2", &message2);
147 let mut t2 = T::new(&PROTOCOL_1, &session_id);
148 t2.append_with(b"message_2", &message2);
149 t2.append_with(b"message_1", &message1);
150
151 let dest1 = t1.extract(b"value_1");
152 let dest2 = t2.extract(b"value_1");
153 assert_ne!(dest1, dest2);
154
155 let mut bytes1 = [0u8; 100];
156 let mut bytes2 = [0u8; 100];
157 t1.extract_rng(b"stream").fill_bytes(&mut bytes1);
158 t2.extract_rng(b"stream").fill_bytes(&mut bytes2);
159 assert_ne!(bytes1, bytes2);
160 }
161
162 #[test]
163 fn test_folklore_transcript() {
164 test_happypath_same_transcripts_yield_same_extracts::<super::folklore::FolkloreTranscript>(
165 );
166 test_unhappypath_different_transcripts_yield_different_extracts::<
167 super::folklore::FolkloreTranscript,
168 >();
169 }
170
171 #[test]
172 fn test_merlin_transcript() {
173 test_happypath_same_transcripts_yield_same_extracts::<super::merlin::MerlinTranscript>();
174 test_unhappypath_different_transcripts_yield_different_extracts::<
175 super::merlin::MerlinTranscript,
176 >();
177 }
178}