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