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