Skip to content

Instantly share code, notes, and snippets.

@HarryR
Last active December 23, 2024 01:46
Show Gist options
  • Save HarryR/a1217d3a2d929bde1aeace052500d670 to your computer and use it in GitHub Desktop.
Save HarryR/a1217d3a2d929bde1aeace052500d670 to your computer and use it in GitHub Desktop.
Forking Merlin transcripts
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);
}
use merlin::Transcript;
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
enum TranscriptState {
Original,
Forked { parent_label: Vec<u8> },
}
#[derive(Debug)]
struct RestrictedTranscript {
transcript: Transcript,
state: TranscriptState,
forks: RefCell<Vec<Rc<RestrictedTranscript>>>,
}
impl RestrictedTranscript {
// Create a new original transcript
pub fn new(context: &'static [u8]) -> Self {
Self {
transcript: Transcript::new(context),
state: TranscriptState::Original,
forks: RefCell::new(Vec::new()),
}
}
// Controlled forking method
pub fn fork(&mut self) -> Rc<RestrictedTranscript> {
// Generate a fork label
let mut fork_label = [0u8; 32];
self.transcript.clone_mut().challenge_bytes(b"fork_label", &mut fork_label);
// Create forked transcript
let forked = Rc::new(RestrictedTranscript {
transcript: self.transcript.clone(),
state: TranscriptState::Forked {
parent_label: fork_label.to_vec()
},
forks: RefCell::new(Vec::new()),
});
// Track the fork
self.forks.borrow_mut().push(Rc::clone(&forked));
forked
}
// Append another transcript (only if it's a fork)
pub fn append_transcript(&mut self, other: &mut RestrictedTranscript) {
// Validate that this is a genuine fork
match &other.state {
TranscriptState::Forked { parent_label } => {
// Append using the fork label
let mut append_label = [0u8; 32];
other.transcript.clone_mut().challenge_bytes(b"fork_challenge", &mut append_label);
// Append to this transcript
self.transcript.append_message(b"appended_transcript", &append_label);
},
_ => panic!("Can only append forked transcripts"),
}
}
// Delegate other Transcript methods
pub fn append_message(&mut self, label: &'static [u8], message: &[u8]) {
self.transcript.append_message(label, message);
}
pub fn challenge_bytes(&mut self, label: &'static [u8], dest: &mut [u8]) {
self.transcript.challenge_bytes(label, dest);
}
}
fn main() {
// Example usage
let mut original = RestrictedTranscript::new(b"protocol");
// Controlled fork
let mut fork1 = original.fork();
// This would fail to compile/panic
// let illegal_clone = fork1.clone();
// Demonstrating append
original.append_transcript(&mut fork1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment