Files
eth-kzg-ceremony-alt/powersoftau.go
2022-12-09 19:54:22 +01:00

262 lines
7.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package kzgceremony
import (
"fmt"
"math/big"
bls12381 "github.com/kilic/bls12-381"
)
// todo: unify addition & multiplicative notation in the comments
const MinRandomnessLen = 64
type Witness struct {
RunningProducts []*bls12381.PointG1
PotPubKeys []*bls12381.PointG2
BLSSignatures []*bls12381.PointG1
}
type Transcript struct {
NumG1Powers uint64
NumG2Powers uint64
PowersOfTau *SRS
Witness *Witness
}
type State struct {
Transcripts []Transcript
ParticipantIDs []string // WIP
ParticipantECDSASignatures []string
}
type Contribution struct {
NumG1Powers uint64
NumG2Powers uint64
PowersOfTau *SRS
PotPubKey *bls12381.PointG2
}
type BatchContribution struct {
Contributions []Contribution
}
func (cs *State) Contribute(randomness []byte) (*State, error) {
ns := State{}
ns.Transcripts = make([]Transcript, len(cs.Transcripts))
for i := 0; i < len(cs.Transcripts); i++ {
ns.Transcripts[i].NumG1Powers = cs.Transcripts[i].NumG1Powers
ns.Transcripts[i].NumG2Powers = cs.Transcripts[i].NumG2Powers
newSRS, proof, err := Contribute(cs.Transcripts[i].PowersOfTau, randomness)
if err != nil {
return nil, err
}
ns.Transcripts[i].PowersOfTau = newSRS
ns.Transcripts[i].Witness = &Witness{}
ns.Transcripts[i].Witness.RunningProducts =
append(cs.Transcripts[i].Witness.RunningProducts, proof.G1PTau)
ns.Transcripts[i].Witness.PotPubKeys =
append(cs.Transcripts[i].Witness.PotPubKeys, proof.G2P)
ns.Transcripts[i].Witness.BLSSignatures = cs.Transcripts[i].Witness.BLSSignatures
}
ns.ParticipantIDs = cs.ParticipantIDs // TODO add github id (id_token.sub)
ns.ParticipantECDSASignatures = cs.ParticipantECDSASignatures
return &ns, nil
}
func (pb *BatchContribution) Contribute(randomness []byte) (*BatchContribution, error) {
nb := BatchContribution{}
nb.Contributions = make([]Contribution, len(pb.Contributions))
for i := 0; i < len(pb.Contributions); i++ {
nb.Contributions[i].NumG1Powers = pb.Contributions[i].NumG1Powers
nb.Contributions[i].NumG2Powers = pb.Contributions[i].NumG2Powers
newSRS, proof, err := Contribute(pb.Contributions[i].PowersOfTau, randomness)
if err != nil {
return nil, err
}
nb.Contributions[i].PowersOfTau = newSRS
nb.Contributions[i].PotPubKey = proof.G2P
}
return &nb, nil
}
// SRS contains the powers of tau in G1 & G2, eg.
// [τ'⁰]₁, [τ'¹]₁, [τ'²]₁, ..., [τ'ⁿ⁻¹]₁,
// [τ'⁰]₂, [τ'¹]₂, [τ'²]₂, ..., [τ'ⁿ⁻¹]₂
type SRS struct {
G1Powers []*bls12381.PointG1
G2Powers []*bls12381.PointG2
}
type toxicWaste struct {
tau *big.Int
TauG2 *bls12381.PointG2
}
// Proof contains g₂ᵖ and g₂^τ', used by the verifier
type Proof struct {
G2P *bls12381.PointG2 // g₂ᵖ
G1PTau *bls12381.PointG1 // g₂^τ' = g₂^{p ⋅ τ}
}
// newEmptySRS creates an empty SRS
func newEmptySRS(nG1, nG2 int) *SRS {
g1s := make([]*bls12381.PointG1, nG1)
g2s := make([]*bls12381.PointG2, nG2)
g1 := bls12381.NewG1()
g2 := bls12381.NewG2()
// one_G1 := g1.One()
// one_G2 := g2.One()
for i := 0; i < nG1; i++ {
g1s[i] = g1.One()
// g1.MulScalar(g1s[i], one_G1, big.NewInt(int64(i)))
}
for i := 0; i < nG2; i++ {
g2s[i] = g2.One()
// g2.MulScalar(g2s[i], one_G2, big.NewInt(int64(i)))
}
return &SRS{g1s, g2s}
}
func tau(randomness []byte) *toxicWaste {
g2 := bls12381.NewG2()
tau := new(big.Int).Mod(
new(big.Int).SetBytes(randomness),
g2.Q())
tau_Fr := bls12381.NewFr().FromBytes(tau.Bytes())
TauG2 := g2.New()
g2.MulScalar(TauG2, g2.One(), tau_Fr)
return &toxicWaste{tau, TauG2}
}
func computeContribution(t *toxicWaste, prevSRS *SRS) *SRS {
srs := newEmptySRS(len(prevSRS.G1Powers), len(prevSRS.G2Powers))
g1 := bls12381.NewG1()
g2 := bls12381.NewG2()
Q := g1.Q() // Q = |G1| == |G2|
// fmt.Println("Computing [τ'⁰]₁, [τ'¹]₁, [τ'²]₁, ..., [τ'ⁿ⁻¹]₁, for n =", len(prevSRS.G1s))
for i := 0; i < len(prevSRS.G1Powers); i++ {
tau_i := new(big.Int).Exp(t.tau, big.NewInt(int64(i)), Q)
tau_i_Fr := bls12381.NewFr().FromBytes(tau_i.Bytes())
g1.MulScalar(srs.G1Powers[i], prevSRS.G1Powers[i], tau_i_Fr)
}
// fmt.Println("Computing [τ'⁰]₂, [τ'¹]₂, [τ'²]₂, ..., [τ'ⁿ⁻¹]₂, for n =", len(prevSRS.G2s))
for i := 0; i < len(prevSRS.G2Powers); i++ {
tau_i := new(big.Int).Exp(t.tau, big.NewInt(int64(i)), Q)
tau_i_Fr := bls12381.NewFr().FromBytes(tau_i.Bytes())
g2.MulScalar(srs.G2Powers[i], prevSRS.G2Powers[i], tau_i_Fr)
}
return srs
}
func genProof(toxicWaste *toxicWaste, prevSRS, newSRS *SRS) *Proof {
g1 := bls12381.NewG1()
G1_p := g1.New()
tau_Fr := bls12381.NewFr().FromBytes(toxicWaste.tau.Bytes())
g1.MulScalar(G1_p, prevSRS.G1Powers[1], tau_Fr) // g_1^{tau'} = g_1^{p * tau}, where p=toxicWaste.tau
return &Proof{toxicWaste.TauG2, G1_p}
}
// Contribute takes as input the previous SRS and a random
// byte slice, and returns the new SRS together with the Proof
func Contribute(prevSRS *SRS, randomness []byte) (*SRS, *Proof, error) {
if len(randomness) < MinRandomnessLen {
return nil, nil, fmt.Errorf("err randomness") // WIP
}
// set tau from randomness
tw := tau(randomness)
newSRS := computeContribution(tw, prevSRS)
proof := genProof(tw, prevSRS, newSRS)
return newSRS, proof, nil
}
// Verify checks the correct computation of the new SRS respectively from the
// previous SRS
func Verify(prevSRS, newSRS *SRS, proof *Proof) bool {
g1 := bls12381.NewG1()
g2 := bls12381.NewG2()
pairing := bls12381.NewEngine()
// 1. check that elements of the newSRS are valid points
for i := 0; i < len(newSRS.G1Powers); i++ {
// i) non-empty
if newSRS.G1Powers[i] == nil {
return false
}
// ii) non-zero
if g1.IsZero(newSRS.G1Powers[i]) {
return false
}
// iii) in the correct prime order of subgroups
if !g1.IsOnCurve(newSRS.G1Powers[i]) {
return false
}
if !g1.InCorrectSubgroup(newSRS.G1Powers[i]) {
return false
}
}
for i := 0; i < len(newSRS.G2Powers); i++ {
// i) non-empty
if newSRS.G2Powers[i] == nil {
return false
}
// ii) non-zero
if g2.IsZero(newSRS.G2Powers[i]) {
return false
}
// iii) in the correct prime order of subgroups
if !g2.IsOnCurve(newSRS.G2Powers[i]) {
return false
}
if !g2.InCorrectSubgroup(newSRS.G2Powers[i]) {
return false
}
}
// 2. check proof.G1PTau == newSRS.G1Powers[1]
if !g1.Equal(proof.G1PTau, newSRS.G1Powers[1]) {
return false
}
// 3. check newSRS.G1s[1] (g₁^τ'), is correctly related to prevSRS.G1s[1] (g₁^τ)
// e([τ]₁, [p]₂) == e([τ']₁, [1]₂)
eL := pairing.AddPair(prevSRS.G1Powers[1], proof.G2P).Result()
eR := pairing.AddPair(newSRS.G1Powers[1], g2.One()).Result()
if !eL.Equal(eR) {
return false
}
// 4. check newSRS following the powers of tau structure
for i := 0; i < len(newSRS.G1Powers)-1; i++ {
// i) e([τ'ⁱ]₁, [τ']₂) == e([τ'ⁱ⁺¹]₁, [1]₂), for i ∈ [1, n1]
eL := pairing.AddPair(newSRS.G1Powers[i], newSRS.G2Powers[1]).Result()
eR := pairing.AddPair(newSRS.G1Powers[i+1], g2.One()).Result()
if !eL.Equal(eR) {
return false
}
}
for i := 0; i < len(newSRS.G2Powers)-1; i++ {
// ii) e([τ']₁, [τ'ʲ]₂) == e([1]₁, [τ'ʲ⁺¹]₂), for j ∈ [1, m1]
eL := pairing.AddPair(newSRS.G1Powers[1], newSRS.G2Powers[i]).Result()
eR := pairing.AddPair(g1.One(), newSRS.G2Powers[i+1]).Result()
if !eL.Equal(eR) {
return false
}
}
return true
}