use crate::{
random::{CryptoRngCore, Seed},
types::{identifiers::ProtocolInfo, SessionId},
};
pub mod folklore;
pub mod merlin;
pub mod protocol_transcript;
pub use folklore::FolkloreTranscript;
pub use merlin::MerlinTranscript;
pub use protocol_transcript::ProtocolTranscript;
pub trait Transcript {
type Rng: CryptoRngCore;
fn new(protocol_info: &'static ProtocolInfo, session_id: &SessionId) -> Self;
fn append_with<S: AsRef<[u8]>>(&mut self, label: &'static [u8], message: &S);
fn append_many_with<S: AsRef<[u8]>>(&mut self, label: &'static [u8], messages: &[S]);
fn extract(&mut self, label: &'static [u8]) -> Seed;
fn extract_rng(&mut self, label: &'static [u8]) -> Self::Rng;
}
pub trait AutoTranscript: Transcript + Sized {
type Label: AsRef<[u8]>;
#[inline]
fn new(protocol_info: &'static ProtocolInfo, session_id: &SessionId) -> Self {
Transcript::new(protocol_info, session_id)
}
fn get_current_label(&self) -> Self::Label;
fn next_label(&mut self) -> Self::Label;
fn append<S: AsRef<[u8]>>(&mut self, message: &S);
fn append_many<S: AsRef<[u8]>>(&mut self, values: &[S]);
#[inline]
fn extract(&mut self, label: &'static [u8]) -> Seed {
Transcript::extract(self, label)
}
#[inline]
fn extract_rng(&mut self, label: &'static [u8]) -> Self::Rng {
Transcript::extract_rng(self, label)
}
}
#[cfg(test)]
mod tests {
use rand::RngCore;
use crate::{
random::{test_rng, Random},
transcripts::Transcript,
types::{identifiers::ProtocolInfo, SessionId},
};
pub fn test_happypath_same_transcripts_yield_same_extracts<T: Transcript>() {
let message = b"hello world";
let session_id = SessionId::random(&mut test_rng());
static TEST_PROTOCOL_INFO: ProtocolInfo = ProtocolInfo::new("test_protocol", 42);
let mut t1 = T::new(&TEST_PROTOCOL_INFO, &session_id);
t1.append_with(b"message_1", &message);
let mut t2 = T::new(&TEST_PROTOCOL_INFO, &session_id);
t2.append_with(b"message_1", &message);
let dest1 = t1.extract(b"value_1");
let dest2 = t2.extract(b"value_1");
assert_eq!(dest1, dest2);
let mut bytes1 = [0u8; 100];
let mut bytes2 = [0u8; 100];
t1.extract_rng(b"stream").fill_bytes(&mut bytes1);
t2.extract_rng(b"stream").fill_bytes(&mut bytes2);
assert_eq!(bytes1, bytes2);
}
pub fn test_unhappypath_different_transcripts_yield_different_extracts<T: Transcript>() {
let message = b"hello world";
let session_id = SessionId::random(&mut test_rng());
static PROTOCOL_1: ProtocolInfo = ProtocolInfo::new("test_protocol_1", 42);
let mut t1 = T::new(&PROTOCOL_1, &session_id);
t1.append_with(b"message_1", &message);
static PROTOCOL_2: ProtocolInfo = ProtocolInfo::new("test_protocol_2", 43);
let mut t2 = T::new(&PROTOCOL_2, &session_id);
t2.append_with(b"message_1", &message);
let dest1 = t1.extract(b"value_1");
let dest2 = t2.extract(b"value_1");
assert_ne!(dest1, dest2);
let mut bytes1 = [0u8; 100];
let mut bytes2 = [0u8; 100];
t1.extract_rng(b"stream").fill_bytes(&mut bytes1);
t2.extract_rng(b"stream").fill_bytes(&mut bytes2);
assert_ne!(bytes1, bytes2);
let message1 = b"hello world";
let message2 = b"goodbye world";
let mut t1 = T::new(&PROTOCOL_1, &session_id);
t1.append_with(b"message_1", &message1);
t1.append_with(b"message_2", &message2);
let mut t2 = T::new(&PROTOCOL_1, &session_id);
t2.append_with(b"message_2", &message2);
t2.append_with(b"message_1", &message1);
let dest1 = t1.extract(b"value_1");
let dest2 = t2.extract(b"value_1");
assert_ne!(dest1, dest2);
let mut bytes1 = [0u8; 100];
let mut bytes2 = [0u8; 100];
t1.extract_rng(b"stream").fill_bytes(&mut bytes1);
t2.extract_rng(b"stream").fill_bytes(&mut bytes2);
assert_ne!(bytes1, bytes2);
}
#[test]
fn test_folklore_transcript() {
test_happypath_same_transcripts_yield_same_extracts::<super::folklore::FolkloreTranscript>(
);
test_unhappypath_different_transcripts_yield_different_extracts::<
super::folklore::FolkloreTranscript,
>();
}
#[test]
fn test_merlin_transcript() {
test_happypath_same_transcripts_yield_same_extracts::<super::merlin::MerlinTranscript>();
test_unhappypath_different_transcripts_yield_different_extracts::<
super::merlin::MerlinTranscript,
>();
}
}