eth-kzg-ceremony-alt/powersoftau.go
powersoftau.goRaw
1package kzgceremony
2
3import (
4 "fmt"
5 "math/big"
6
7 bls12381 "github.com/kilic/bls12-381"
8)
9
10// todo: unify addition & multiplicative notation in the comments
11
12type Witness struct {
13 RunningProducts []*bls12381.PointG1
14 PotPubKeys []*bls12381.PointG2
15 BLSSignatures []*bls12381.PointG1
16}
17
18type Transcript struct {
19 NumG1Powers uint64
20 NumG2Powers uint64
21 PowersOfTau *SRS
22 Witness *Witness
23}
24
25type State struct {
26 Transcripts []Transcript
27 ParticipantIDs []string // WIP
28 ParticipantECDSASignatures []string
29}
30
31func (cs *State) Contribute(randomness []byte) (*State, error) {
32 ns := State{}
33 ns.Transcripts = make([]Transcript, len(cs.Transcripts))
34 for i := 0; i < len(cs.Transcripts); i++ {
35 ns.Transcripts[i].NumG1Powers = cs.Transcripts[i].NumG1Powers
36 ns.Transcripts[i].NumG2Powers = cs.Transcripts[i].NumG2Powers
37
38 newSRS, proof, err := Contribute(cs.Transcripts[i].PowersOfTau, randomness)
39 if err != nil {
40 return nil, err
41 }
42 ns.Transcripts[i].PowersOfTau = newSRS
43
44 ns.Transcripts[i].Witness = &Witness{}
45 ns.Transcripts[i].Witness.RunningProducts =
46 append(cs.Transcripts[i].Witness.RunningProducts, proof.G1PTau)
47 ns.Transcripts[i].Witness.PotPubKeys =
48 append(cs.Transcripts[i].Witness.PotPubKeys, proof.G2P)
49 ns.Transcripts[i].Witness.BLSSignatures = cs.Transcripts[i].Witness.BLSSignatures
50 }
51 ns.ParticipantIDs = cs.ParticipantIDs
52 ns.ParticipantECDSASignatures = cs.ParticipantECDSASignatures
53
54 return &ns, nil
55}
56
57// SRS contains the powers of tau in G1 & G2, eg.
58// [τ'⁰]₁, [τ'¹]₁, [τ'²]₁, ..., [τ'ⁿ⁻¹]₁,
59// [τ'⁰]₂, [τ'¹]₂, [τ'²]₂, ..., [τ'ⁿ⁻¹]₂
60type SRS struct {
61 G1Powers []*bls12381.PointG1
62 G2Powers []*bls12381.PointG2
63}
64
65type toxicWaste struct {
66 tau *big.Int
67 TauG2 *bls12381.PointG2
68}
69
70// Proof contains g₂ᵖ and g₂^τ', used by the verifier
71type Proof struct {
72 G2P *bls12381.PointG2 // g₂ᵖ
73 G1PTau *bls12381.PointG1 // g₂^τ' = g₂^{p ⋅ τ}
74}
75
76// newEmptySRS creates an empty SRS
77func newEmptySRS(nG1, nG2 int) *SRS {
78 g1s := make([]*bls12381.PointG1, nG1)
79 g2s := make([]*bls12381.PointG2, nG2)
80 g1 := bls12381.NewG1()
81 g2 := bls12381.NewG2()
82 // one_G1 := g1.One()
83 // one_G2 := g2.One()
84 for i := 0; i < nG1; i++ {
85 g1s[i] = g1.One()
86 // g1.MulScalar(g1s[i], one_G1, big.NewInt(int64(i)))
87 }
88 for i := 0; i < nG2; i++ {
89 g2s[i] = g2.One()
90 // g2.MulScalar(g2s[i], one_G2, big.NewInt(int64(i)))
91 }
92 return &SRS{g1s, g2s}
93}
94
95func tau(randomness []byte) *toxicWaste {
96 g2 := bls12381.NewG2()
97 tau := new(big.Int).Mod(
98 new(big.Int).SetBytes(randomness),
99 g2.Q())
100 tau_Fr := bls12381.NewFr().FromBytes(tau.Bytes())
101 TauG2 := g2.New()
102 g2.MulScalar(TauG2, g2.One(), tau_Fr)
103
104 return &toxicWaste{tau, TauG2}
105}
106
107func computeContribution(t *toxicWaste, prevSRS *SRS) *SRS {
108 srs := newEmptySRS(len(prevSRS.G1Powers), len(prevSRS.G2Powers))
109 g1 := bls12381.NewG1()
110 g2 := bls12381.NewG2()
111 Q := g1.Q() // Q = |G1| == |G2|
112
113 // fmt.Println("Computing [τ'⁰]₁, [τ'¹]₁, [τ'²]₁, ..., [τ'ⁿ⁻¹]₁, for n =", len(prevSRS.G1s))
114 for i := 0; i < len(prevSRS.G1Powers); i++ {
115 tau_i := new(big.Int).Exp(t.tau, big.NewInt(int64(i)), Q)
116 tau_i_Fr := bls12381.NewFr().FromBytes(tau_i.Bytes())
117 g1.MulScalar(srs.G1Powers[i], prevSRS.G1Powers[i], tau_i_Fr)
118 }
119 // fmt.Println("Computing [τ'⁰]₂, [τ'¹]₂, [τ'²]₂, ..., [τ'ⁿ⁻¹]₂, for n =", len(prevSRS.G2s))
120 for i := 0; i < len(prevSRS.G2Powers); i++ {
121 tau_i := new(big.Int).Exp(t.tau, big.NewInt(int64(i)), Q)
122 tau_i_Fr := bls12381.NewFr().FromBytes(tau_i.Bytes())
123 g2.MulScalar(srs.G2Powers[i], prevSRS.G2Powers[i], tau_i_Fr)
124 }
125
126 return srs
127}
128
129func genProof(toxicWaste *toxicWaste, prevSRS, newSRS *SRS) *Proof {
130 g1 := bls12381.NewG1()
131 G1_p := g1.New()
132 tau_Fr := bls12381.NewFr().FromBytes(toxicWaste.tau.Bytes())
133 g1.MulScalar(G1_p, prevSRS.G1Powers[1], tau_Fr) // g_1^{tau'} = g_1^{p * tau}, where p=toxicWaste.tau
134
135 return &Proof{toxicWaste.TauG2, G1_p}
136}
137
138// Contribute takes as input the previous SRS and a random
139// byte slice, and returns the new SRS together with the Proof
140func Contribute(prevSRS *SRS, randomness []byte) (*SRS, *Proof, error) {
141 if len(randomness) < 64 {
142 return nil, nil, fmt.Errorf("err randomness") // WIP
143 }
144 // set tau from randomness
145 tw := tau(randomness)
146
147 newSRS := computeContribution(tw, prevSRS)
148
149 proof := genProof(tw, prevSRS, newSRS)
150
151 return newSRS, proof, nil
152}
153
154// Verify checks the correct computation of the new SRS respectively from the
155// previous SRS
156func Verify(prevSRS, newSRS *SRS, proof *Proof) bool {
157 g1 := bls12381.NewG1()
158 g2 := bls12381.NewG2()
159 pairing := bls12381.NewEngine()
160
161 // 1. check that elements of the newSRS are valid points
162 for i := 0; i < len(newSRS.G1Powers); i++ {
163 // i) non-empty
164 if newSRS.G1Powers[i] == nil {
165 return false
166 }
167 // ii) non-zero
168 if g1.IsZero(newSRS.G1Powers[i]) {
169 return false
170 }
171 // iii) in the correct prime order of subgroups
172 if !g1.IsOnCurve(newSRS.G1Powers[i]) {
173 return false
174 }
175 if !g1.InCorrectSubgroup(newSRS.G1Powers[i]) {
176 return false
177 }
178 }
179 for i := 0; i < len(newSRS.G2Powers); i++ {
180 // i) non-empty
181 if newSRS.G2Powers[i] == nil {
182 return false
183 }
184 // ii) non-zero
185 if g2.IsZero(newSRS.G2Powers[i]) {
186 return false
187 }
188 // iii) in the correct prime order of subgroups
189 if !g2.IsOnCurve(newSRS.G2Powers[i]) {
190 return false
191 }
192 if !g2.InCorrectSubgroup(newSRS.G2Powers[i]) {
193 return false
194 }
195 }
196
197 // 2. check proof.G1PTau == newSRS.G1Powers[1]
198 if !g1.Equal(proof.G1PTau, newSRS.G1Powers[1]) {
199 return false
200 }
201
202 // 3. check newSRS.G1s[1] (g₁^τ'), is correctly related to prevSRS.G1s[1] (g₁^τ)
203 // e([τ]₁, [p]₂) == e([τ']₁, [1]₂)
204 eL := pairing.AddPair(prevSRS.G1Powers[1], proof.G2P).Result()
205 eR := pairing.AddPair(newSRS.G1Powers[1], g2.One()).Result()
206 if !eL.Equal(eR) {
207 return false
208 }
209
210 // 4. check newSRS following the powers of tau structure
211 for i := 0; i < len(newSRS.G1Powers)-1; i++ {
212 // i) e([τ'ⁱ]₁, [τ']₂) == e([τ'ⁱ⁺¹]₁, [1]₂), for i ∈ [1, n−1]
213 eL := pairing.AddPair(newSRS.G1Powers[i], newSRS.G2Powers[1]).Result()
214 eR := pairing.AddPair(newSRS.G1Powers[i+1], g2.One()).Result()
215 if !eL.Equal(eR) {
216 return false
217 }
218 }
219
220 for i := 0; i < len(newSRS.G2Powers)-1; i++ {
221 // ii) e([τ']₁, [τ'ʲ]₂) == e([1]₁, [τ'ʲ⁺¹]₂), for j ∈ [1, m−1]
222 eL := pairing.AddPair(newSRS.G1Powers[1], newSRS.G2Powers[i]).Result()
223 eR := pairing.AddPair(g1.One(), newSRS.G2Powers[i+1]).Result()
224 if !eL.Equal(eR) {
225 return false
226 }
227 }
228
229 return true
230}