Files
crypto/ipa/common/transcript.go
T
Hanzo AI 22b99bca01 banderwagon: extract canonical home, ipa imports from here
The Banderwagon prime-order group used by Verkle / IPA had been vendored
internally under lux/crypto/ipa/banderwagon. Extract it to
lux/crypto/banderwagon as the canonical Lux public surface; rewrite all
internal ipa callers (prover, verifier, config, multiproof, common,
transcript, test_helper, tests) to import from the canonical home.

- Provenance comment on every file: github.com/crate-crypto/go-ipa
  (Apache-2.0 / MIT dual). Adds LICENSE-GO-IPA-APACHE2 and
  LICENSE-GO-IPA-MIT alongside the package.
- Element / Generator / Identity / Fr / MSMPrecomp / PrecompPoint /
  CompressedSize / UncompressedSize / SetBytes / SetBytesUncompressed /
  ElementsToBytes / BatchToBytesUncompressed / BatchNormalize /
  MapToScalarField / BatchMapToScalarField / Add / Sub / Double / Neg /
  ScalarMul / MultiExp now have one and only one home: lux/crypto/banderwagon.
- Verkle (parallel branch) will switch its banderwagon import to this
  canonical surface.
- KAT vectors from the upstream go-ipa Verkle reference suite preserved
  (TestEncodingFixedVectors, TestPointAtInfinityComponent) plus all
  precomp MSM-vs-gnark random-round tests (1000 * NumCPU rounds).

Tests: go test ./banderwagon/... ./ipa/... — all PASS (banderwagon 27s,
ipa 16s, ipa/bandersnatch 24s, fp/fr 4s+2s, common 3s).
2025-12-28 06:21:30 -08:00

88 lines
1.9 KiB
Go

package common
import (
"bytes"
"crypto/sha256"
"hash"
"github.com/luxfi/crypto/banderwagon"
"github.com/luxfi/crypto/ipa/bandersnatch/fr"
)
// The transcript is used to create challenge scalars.
// See: Fiat-Shamir
type Transcript struct {
state hash.Hash
buff *bytes.Buffer
}
func NewTranscript(label string) *Transcript {
digest := sha256.New()
digest.Write([]byte(label))
transcript := &Transcript{
state: digest,
buff: bytes.NewBuffer(make([]byte, 0, 1024)),
}
return transcript
}
func (t *Transcript) AppendMessage(message []byte, label []byte) {
t.buff.Write(label)
t.buff.Write(message)
}
// Appends a Scalar to the transcript
//
// Converts the scalar to 32 bytes, then appends it to
// the state
func (t *Transcript) AppendScalar(scalar *fr.Element, label []byte) {
tmpBytes := scalar.BytesLE()
t.AppendMessage(tmpBytes[:], label)
}
// Appends a Point to the transcript
//
// Compresses the Point into a 32 byte slice, then appends it to
// the state
func (t *Transcript) AppendPoint(point *banderwagon.Element, label []byte) {
tmp_bytes := point.Bytes()
t.AppendMessage(tmp_bytes[:], label)
}
func (t *Transcript) DomainSep(label []byte) {
t.buff.Write(label)
}
// Computes a challenge based off of the state of the transcript
//
// Hash the transcript state, then reduce the hash modulo the size of the
// scalar field
//
// Note that calling the transcript twice, will yield two different challenges
func (t *Transcript) ChallengeScalar(label []byte) fr.Element {
t.DomainSep(label)
t.state.Write(t.buff.Bytes())
t.buff.Reset()
// Reverse the endian so we are using little-endian
// SetBytes interprets the bytes in Big Endian
bytes := t.state.Sum(nil)
var tmp fr.Element
tmp.SetBytesLE(bytes)
// Clear the state
t.state.Reset()
// Add the new challenge to the state
// Which "summarises" the previous state before we cleared it
t.AppendScalar(&tmp, label)
// Return the new challenge
return tmp
}