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// MinRandomnessLen is the minimum accepted length for the user defined
11// randomness
12const MinRandomnessLen = 64
13
14var g1 *bls12381.G1
15var g2 *bls12381.G2
16
17func init() {
18 g1 = bls12381.NewG1()
19 g2 = bls12381.NewG2()
20}
21
22// State represents the data structure obtained from the Sequencer at the
23// /info/current_state endpoint
24type State struct {
25 Transcripts []Transcript
26 ParticipantIDs []string // WIP
27 ParticipantECDSASignatures []string
28}
29
30// BatchContribution represents the data structure obtained from the Sequencer
31// at the /contribute endpoint
32type BatchContribution struct {
33 Contributions []Contribution
34}
35
36type Contribution struct {
37 NumG1Powers uint64
38 NumG2Powers uint64
39 PowersOfTau *SRS
40 PotPubKey *bls12381.PointG2
41}
42
43type Transcript struct {
44 NumG1Powers uint64
45 NumG2Powers uint64
46 PowersOfTau *SRS
47 Witness *Witness
48}
49
50type Witness struct {
51 RunningProducts []*bls12381.PointG1
52 PotPubKeys []*bls12381.PointG2
53 BLSSignatures []*bls12381.PointG1
54}
55
56// SRS contains the powers of tau in G1 & G2, eg.
57// [τ'⁰]₁, [τ'¹]₁, [τ'²]₁, ..., [τ'ⁿ⁻¹]₁,
58// [τ'⁰]₂, [τ'¹]₂, [τ'²]₂, ..., [τ'ⁿ⁻¹]₂
59type SRS struct {
60 G1Powers []*bls12381.PointG1
61 G2Powers []*bls12381.PointG2
62}
63
64type toxicWaste struct {
65 tau *big.Int
66 TauG2 *bls12381.PointG2 // Proof.G2P
67}
68
69// Proof contains g₂ᵖ and g₂^τ', used by the verifier
70type Proof struct {
71 G2P *bls12381.PointG2 // g₂ᵖ
72 G1PTau *bls12381.PointG1 // g₂^τ' = g₂^{p ⋅ τ}
73}
74
75// Contribute takes the last State and computes a new State using the defined
76// randomness
77func (cs *State) Contribute(randomness []byte) (*State, error) {
78 ns := State{}
79 ns.Transcripts = make([]Transcript, len(cs.Transcripts))
80 for i := 0; i < len(cs.Transcripts); i++ {
81 ns.Transcripts[i].NumG1Powers = cs.Transcripts[i].NumG1Powers
82 ns.Transcripts[i].NumG2Powers = cs.Transcripts[i].NumG2Powers
83
84 newSRS, proof, err := Contribute(cs.Transcripts[i].PowersOfTau, randomness)
85 if err != nil {
86 return nil, err
87 }
88 ns.Transcripts[i].PowersOfTau = newSRS
89
90 ns.Transcripts[i].Witness = &Witness{}
91 ns.Transcripts[i].Witness.RunningProducts =
92 append(cs.Transcripts[i].Witness.RunningProducts, proof.G1PTau)
93 ns.Transcripts[i].Witness.PotPubKeys =
94 append(cs.Transcripts[i].Witness.PotPubKeys, proof.G2P)
95 ns.Transcripts[i].Witness.BLSSignatures = cs.Transcripts[i].Witness.BLSSignatures
96 }
97 ns.ParticipantIDs = cs.ParticipantIDs // TODO add github id (id_token.sub)
98 ns.ParticipantECDSASignatures = cs.ParticipantECDSASignatures
99
100 return &ns, nil
101}
102
103// Contribute takes the last BatchContribution and computes a new
104// BatchContribution using the defined randomness
105func (pb *BatchContribution) Contribute(randomness []byte) (*BatchContribution, error) {
106 nb := BatchContribution{}
107 nb.Contributions = make([]Contribution, len(pb.Contributions))
108 for i := 0; i < len(pb.Contributions); i++ {
109 nb.Contributions[i].NumG1Powers = pb.Contributions[i].NumG1Powers
110 nb.Contributions[i].NumG2Powers = pb.Contributions[i].NumG2Powers
111
112 newSRS, proof, err := Contribute(pb.Contributions[i].PowersOfTau, randomness)
113 if err != nil {
114 return nil, err
115 }
116 nb.Contributions[i].PowersOfTau = newSRS
117
118 nb.Contributions[i].PotPubKey = proof.G2P
119 }
120
121 return &nb, nil
122}
123
124// newEmptySRS creates an empty SRS filled by [1]₁ & [1]₂ points in all
125// respective arrays positions
126func newEmptySRS(nG1, nG2 int) *SRS {
127 g1s := make([]*bls12381.PointG1, nG1)
128 g2s := make([]*bls12381.PointG2, nG2)
129 for i := 0; i < nG1; i++ {
130 g1s[i] = g1.One()
131 }
132 for i := 0; i < nG2; i++ {
133 g2s[i] = g2.One()
134 }
135 return &SRS{g1s, g2s}
136}
137
138func tau(randomness []byte) *toxicWaste {
139 tau := new(big.Int).Mod(
140 new(big.Int).SetBytes(randomness),
141 g2.Q())
142 tau_Fr := bls12381.NewFr().FromBytes(tau.Bytes())
143 TauG2 := g2.New()
144 g2.MulScalar(TauG2, g2.One(), tau_Fr)
145
146 return &toxicWaste{tau, TauG2}
147}
148
149func computeContribution(t *toxicWaste, prevSRS *SRS) *SRS {
150 srs := newEmptySRS(len(prevSRS.G1Powers), len(prevSRS.G2Powers))
151 Q := g1.Q() // Q = |G1| == |G2|
152
153 // fmt.Println("Computing [τ'⁰]₁, [τ'¹]₁, [τ'²]₁, ..., [τ'ⁿ⁻¹]₁, for n =", len(prevSRS.G1s))
154 for i := 0; i < len(prevSRS.G1Powers); i++ {
155 tau_i := new(big.Int).Exp(t.tau, big.NewInt(int64(i)), Q)
156 tau_i_Fr := bls12381.NewFr().FromBytes(tau_i.Bytes())
157 g1.MulScalar(srs.G1Powers[i], prevSRS.G1Powers[i], tau_i_Fr)
158 }
159 // fmt.Println("Computing [τ'⁰]₂, [τ'¹]₂, [τ'²]₂, ..., [τ'ⁿ⁻¹]₂, for n =", len(prevSRS.G2s))
160 for i := 0; i < len(prevSRS.G2Powers); i++ {
161 tau_i := new(big.Int).Exp(t.tau, big.NewInt(int64(i)), Q)
162 tau_i_Fr := bls12381.NewFr().FromBytes(tau_i.Bytes())
163 g2.MulScalar(srs.G2Powers[i], prevSRS.G2Powers[i], tau_i_Fr)
164 }
165
166 return srs
167}
168
169func genProof(toxicWaste *toxicWaste, prevSRS, newSRS *SRS) *Proof {
170 G1_p := g1.New()
171 tau_Fr := bls12381.NewFr().FromBytes(toxicWaste.tau.Bytes())
172 g1.MulScalar(G1_p, prevSRS.G1Powers[1], tau_Fr) // g_1^{tau'} = g_1^{p * tau}, where p=toxicWaste.tau
173
174 return &Proof{toxicWaste.TauG2, G1_p}
175}
176
177// Contribute takes as input the previous SRS and a random
178// byte slice, and returns the new SRS together with the Proof
179func Contribute(prevSRS *SRS, randomness []byte) (*SRS, *Proof, error) {
180 if len(randomness) < MinRandomnessLen {
181 return nil, nil, fmt.Errorf("err randomness") // WIP
182 }
183 // set tau from randomness
184 tw := tau(randomness)
185
186 newSRS := computeContribution(tw, prevSRS)
187
188 proof := genProof(tw, prevSRS, newSRS)
189
190 return newSRS, proof, nil
191}
192
193func checkG1PointCorrectness(p *bls12381.PointG1) error {
194 // i) non-empty
195 if p == nil {
196 return fmt.Errorf("empty point value")
197 }
198 // ii) non-zero
199 if g1.IsZero(p) {
200 return fmt.Errorf("point can not be zero")
201 }
202 // iii) in the correct prime order of subgroups
203 if !g1.IsOnCurve(p) {
204 return fmt.Errorf("point not on curve")
205 }
206 if !g1.InCorrectSubgroup(p) {
207 return fmt.Errorf("point not in the correct prime order of subgroups")
208 }
209 return nil
210}
211
212func checkG2PointCorrectness(p *bls12381.PointG2) error {
213 // i) non-empty
214 if p == nil {
215 return fmt.Errorf("empty point value")
216 }
217 // ii) non-zero
218 if g2.IsZero(p) {
219 return fmt.Errorf("point can not be zero")
220 }
221 // iii) in the correct prime order of subgroups
222 if !g2.IsOnCurve(p) {
223 return fmt.Errorf("point not on curve")
224 }
225 if !g2.InCorrectSubgroup(p) {
226 return fmt.Errorf("point not in the correct prime order of subgroups")
227 }
228 return nil
229}
230
231// Verify checks the correct computation of the new SRS respectively from the
232// previous SRS
233func Verify(prevSRS, newSRS *SRS, proof *Proof) bool {
234 pairing := bls12381.NewEngine()
235
236 // 1. check that elements of the newSRS are valid points
237 for i := 0; i < len(newSRS.G1Powers); i++ {
238 if err := checkG1PointCorrectness(newSRS.G1Powers[i]); err != nil {
239 return false
240 }
241 }
242 for i := 0; i < len(newSRS.G2Powers); i++ {
243 if err := checkG2PointCorrectness(newSRS.G2Powers[i]); err != nil {
244 return false
245 }
246 }
247
248 // 2. check proof.G1PTau == newSRS.G1Powers[1]
249 if !g1.Equal(proof.G1PTau, newSRS.G1Powers[1]) {
250 return false
251 }
252
253 // 3. check newSRS.G1s[1] (g₁^τ'), is correctly related to prevSRS.G1s[1] (g₁^τ)
254 // e([τ]₁, [p]₂) == e([τ']₁, [1]₂)
255 eL := pairing.AddPair(prevSRS.G1Powers[1], proof.G2P).Result()
256 eR := pairing.AddPair(newSRS.G1Powers[1], g2.One()).Result()
257 if !eL.Equal(eR) {
258 return false
259 }
260
261 // 4. check newSRS following the powers of tau structure
262 for i := 0; i < len(newSRS.G1Powers)-1; i++ {
263 // i) e([τ'ⁱ]₁, [τ']₂) == e([τ'ⁱ⁺¹]₁, [1]₂), for i ∈ [1, n−1]
264 eL := pairing.AddPair(newSRS.G1Powers[i], newSRS.G2Powers[1]).Result()
265 eR := pairing.AddPair(newSRS.G1Powers[i+1], g2.One()).Result()
266 if !eL.Equal(eR) {
267 return false
268 }
269 }
270
271 for i := 0; i < len(newSRS.G2Powers)-1; i++ {
272 // ii) e([τ']₁, [τ'ʲ]₂) == e([1]₁, [τ'ʲ⁺¹]₂), for j ∈ [1, m−1]
273 eL := pairing.AddPair(newSRS.G1Powers[1], newSRS.G2Powers[i]).Result()
274 eR := pairing.AddPair(g1.One(), newSRS.G2Powers[i+1]).Result()
275 if !eL.Equal(eR) {
276 return false
277 }
278 }
279
280 return true
281}