package primitives import ( "fmt" "golang.org/x/crypto/sha3" "hash" ) // Transcript implements a transcript of a public coin argument. // // We have the following goals: // - Provide a consisted transcript API for our zero knowledge protocols // - Allow sequential proofs over a common transcript (ensuring a single proof cannot be extracted standalone) // - produce an auditable human-readable transcript. // // The design of this API was inspired by Merlin: https://docs.rs/crate/merlin/ // // At some point we might want to extend this to be compatible with Merlin transcripts, built on STROBE type Transcript struct { hash hash.Hash transcript string } // NewTranscript creates a new Transcript with the given Label, the label should be unique to the application func NewTranscript(label string) *Transcript { transcript := new(Transcript) transcript.hash = sha3.New256() transcript.AddToTranscript("protocol", []byte(label)) return transcript } // AddToTranscript appends a value to the transcript with the given label // This binds the given data to the label. func (t *Transcript) AddToTranscript(label string, b []byte) { op := fmt.Sprintf("%s (%d) %x;", label, len(b), b) t.transcript = fmt.Sprintf("%v\n%v", t.transcript, op) t.hash.Write([]byte(op)) } // OutputTranscriptToAudit outputs a human-readable copy of the transcript so far. func (t Transcript) OutputTranscriptToAudit() string { return t.transcript } // CommitToTranscript generates a challenge based on the current transcript, it also commits the challenge to the transcript. func (t *Transcript) CommitToTranscript(label string) []byte { t.AddToTranscript("commit", []byte(label)) b := t.hash.Sum([]byte{}) t.AddToTranscript(label, b) return b }