Skip to content

Hierarchial transcripts #9

@HarryR

Description

@HarryR

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions