107 lines
3.7 KiB
Go
107 lines
3.7 KiB
Go
package core
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/gtank/merlin"
|
|
ristretto "github.com/gtank/ristretto255"
|
|
"golang.org/x/crypto/sha3"
|
|
"io"
|
|
)
|
|
|
|
// Transcript provides a consistent transcript primitive for our protocols
|
|
//
|
|
// We have the following goals:
|
|
// - Allow sequential proofs over a common transcript (ensuring a single proof cannot be extracted standalone)
|
|
// - be able to produce a human-readable transcript for auditing.
|
|
//
|
|
// The design of this API was inspired by Merlin: https://docs.rs/crate/merlin/
|
|
type Transcript struct {
|
|
merlinTranscript *merlin.Transcript
|
|
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.merlinTranscript = merlin.NewTranscript(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.merlinTranscript.AppendMessage([]byte(label), b)
|
|
}
|
|
|
|
// AddElementToTranscript appends a value to the transcript with the given label
|
|
// This binds the given data to the label.
|
|
func (t *Transcript) AddElementToTranscript(label string, element *ristretto.Element) {
|
|
t.AddToTranscript(label, element.Encode([]byte{}))
|
|
}
|
|
|
|
// OutputTranscriptToAudit outputs a human-readable copy of the transcript so far.
|
|
func (t Transcript) OutputTranscriptToAudit() string {
|
|
return t.transcript
|
|
}
|
|
|
|
// NewProtocol provides explicit protocol separation in a transcript (more readable audit scripts and even more explicit
|
|
// binding of committed values to a given context)
|
|
func (t *Transcript) NewProtocol(label string) {
|
|
op := fmt.Sprintf("---- new-protcol: %s ----", label)
|
|
t.transcript = fmt.Sprintf("%v\n%v", t.transcript, op)
|
|
t.merlinTranscript.AppendMessage([]byte("protocol"), []byte(label))
|
|
}
|
|
|
|
// CommitToTranscript generates a challenge based on the current transcript, it also commits the challenge to the transcript.
|
|
func (t *Transcript) CommitToTranscript(label string) []byte {
|
|
b := t.merlinTranscript.ExtractBytes([]byte(label), 64)
|
|
t.transcript = fmt.Sprintf("%v\nextract %v: %v", t.transcript, label, b)
|
|
return b
|
|
}
|
|
|
|
// PRNG defines a psuedorandom number generator
|
|
type PRNG struct {
|
|
prng io.Reader
|
|
}
|
|
|
|
// Next returns the next "random" scalar from the PRNG
|
|
func (prng *PRNG) Next() *ristretto.Scalar {
|
|
buf := [64]byte{}
|
|
io.ReadFull(prng.prng, buf[:])
|
|
next := new(ristretto.Scalar)
|
|
next.FromUniformBytes(buf[:])
|
|
return next
|
|
}
|
|
|
|
// CommitToPRNG commits the label to the transcript and derives a PRNG from the transcript.
|
|
func (t *Transcript) CommitToPRNG(label string) PRNG {
|
|
b := t.merlinTranscript.ExtractBytes([]byte(label), 64)
|
|
prng := sha3.NewShake256()
|
|
prng.Write(b)
|
|
return PRNG{prng: prng}
|
|
}
|
|
|
|
// CommitToGenerator derives a verifiably random generator from the transcript
|
|
func (t *Transcript) CommitToGenerator(label string) *ristretto.Element {
|
|
c := t.CommitToTranscript(label)
|
|
return new(ristretto.Element).FromUniformBytes(c)
|
|
}
|
|
|
|
// CommitToGenerators derives a set of verifiably random generators from the transcript
|
|
func (t *Transcript) CommitToGenerators(label string, n int) (generators []*ristretto.Element) {
|
|
for i := 0; i < n; i++ {
|
|
generators = append(generators, t.CommitToGenerator(fmt.Sprintf("%v-%d", label, i)))
|
|
}
|
|
return generators
|
|
}
|
|
|
|
// CommitToTranscriptScalar is a convenience method for CommitToTranscript which returns a ristretto Scalar
|
|
func (t *Transcript) CommitToTranscriptScalar(label string) *ristretto.Scalar {
|
|
c := t.CommitToTranscript(label)
|
|
s := new(ristretto.Scalar)
|
|
s.FromUniformBytes(c[:])
|
|
return s
|
|
}
|