It annoyed me that I can't append a transcript to a transcript, nor can I fork a transcript which I can then append (or... not append).
Either way, here's how to forking append a transcript, seems like an oversight that something like this isn't part of the library.
TL;DR the current .clone semantics don't capture tree structures, which are very useful. Forking a transcript is transcribed in both transcripts, as is appending a transcript to another one.
Really, the challenge should be bi-directional, the code below doesn't acknowledge which transcript the fork is joining when it's appended. So don't use it...
use merlin::Transcript;
pub trait TranscriptExt {
// Proposed method to fork a transcript
fn fork_transcript(&mut self) -> Transcript;
// Proposed method to append another transcript
fn append_transcript(&mut self, other: &mut Transcript);
}
impl TranscriptExt for Transcript {
fn fork_transcript(&mut self) -> Transcript {
// Generate a challenge to use as a label for the fork
let mut fork_label = [0u8; 32];
self.challenge_bytes(b"fork_label", &mut fork_label);
// Create a new transcript with the fork label
let mut forked_transcript = self.clone();
forked_transcript.append_message(b"forked_from", &fork_label);
forked_transcript
}
fn append_transcript(&mut self, other: &mut Transcript) {
// Use the challenge from the previous fork as a label
let mut append_label = [0u8; 32];
other.challenge_bytes(b"fork_challenge", &mut append_label);
// Append the entire transcript with this label
self.append_message(b"appended_transcript", &append_label);
}
}
fn main() {
// Example usage
let mut original_transcript = Transcript::new(b"protocol_context");
original_transcript.append_message(b"initial_message", b"data");
// Fork the transcript
let mut forked_transcript = original_transcript.fork_transcript();
forked_transcript.append_message(b"fork_specific_message", b"fork_data");
// Append another transcript
original_transcript.append_transcript(&mut forked_transcript);
}
So you could use something like
fn append_transcript(&mut self, other: &mut Transcript) {
// Generate a challenge from the receiving transcript
let mut receiver_challenge = [0u8; 32];
self.challenge_bytes(b"append_receiver_challenge", &mut receiver_challenge);
// Generate a challenge from the appended transcript
let mut appended_challenge = [0u8; 32];
other.challenge_bytes(b"append_sender_challenge", &mut appended_challenge);
// Append both challenges to both transcripts
self.append_message(b"appended_transcript_receiver_challenge", &receiver_challenge);
other.append_message(b"appended_transcript_sender_challenge", &appended_challenge);
}
Additionally, it would be good if the challenge size was defined somewhere as a constant usize instead of hard-coding 32 everywhere
It annoyed me that I can't append a transcript to a transcript, nor can I fork a transcript which I can then append (or... not append).
Either way, here's how to forking append a transcript, seems like an oversight that something like this isn't part of the library.
TL;DR the current
.clonesemantics don't capture tree structures, which are very useful. Forking a transcript is transcribed in both transcripts, as is appending a transcript to another one.Really, the challenge should be bi-directional, the code below doesn't acknowledge which transcript the fork is joining when it's appended. So don't use it...
So you could use something like
Additionally, it would be good if the challenge size was defined somewhere as a constant
usizeinstead of hard-coding32everywhere