Skip to content

Commit 0cbbb41

Browse files
committed
test: add BLS testdata generator
1 parent 7a1a549 commit 0cbbb41

11 files changed

+2652
-2
lines changed

.gitignore

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,9 @@ __pycache__/
106106
/jvm-libs/**/darwin-x86-64
107107

108108
/prover/**/*.csv
109-
/prover/**/testdata/
109+
# Exclude files in testdata directories, but not the directories themselves to allow
110+
# add exceptions (gitignore doesn't permit exceptions when root dir is excluded)
111+
/prover/**/testdata/*
110112
# Testdata, otherwise that's 400MB of data downloaded
111113
/prover/**/integration-testing/testdata/prover-requests/
112114
/prover/**/vendor/
@@ -144,4 +146,6 @@ __pycache__/
144146
!prover/**/testdata/**/*.csv
145147
!prover/**/utils/profiling
146148
!prover/**/verifying_key.bin
147-
!/sdk/src/lib/compressor/bin
149+
!/sdk/src/lib/compressor/bin
150+
# Allow BLS glue testdata generators
151+
!prover/zkevm/prover/bls/testdata/*.go
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package main
2+
3+
import "log/slog"
4+
5+
const (
6+
path_add_g1 = "bls_g1_add_inputs.csv"
7+
path_add_g2 = "bls_g2_add_inputs.csv"
8+
path_msm_g1 = "bls_g1_msm_inputs-%d.csv"
9+
path_msm_g2 = "bls_g2_msm_inputs-%d.csv"
10+
path_pairing = "bls_pairing_inputs-%d.csv"
11+
path_map_g1 = "bls_g1_map_inputs.csv"
12+
path_map_g2 = "bls_g2_map_inputs.csv"
13+
path_pointeval = "bls_pointeval_inputs-%d.csv"
14+
)
15+
16+
const (
17+
maxNbPairingInputs = 3
18+
maxNbMsmInputs = 3
19+
nbRepetitionsMap = 1
20+
)
21+
22+
const (
23+
nbMsmPerOutput = 100
24+
nbPairingPerOutput = 50
25+
nbPointEvalPerOutput = 50
26+
)
27+
28+
//go:generate go run .
29+
func main() {
30+
logger := slog.Default()
31+
32+
logger.Info("Generating test data for BLS operations")
33+
logger.Info("Generating ADD test data", "path_g1", path_add_g1, "path_g2", path_add_g2)
34+
if err := mainAdd(); err != nil {
35+
logger.Error("Failed to generate ADD test data", "error", err)
36+
return
37+
}
38+
logger.Info("Generating MAP test data", "path_g1", path_msm_g1, "path_g2", path_msm_g2)
39+
if err := mainMsm(); err != nil {
40+
logger.Error("Failed to generate MSM test data", "error", err)
41+
return
42+
}
43+
logger.Info("Generating PAIRING test data", "path_pairing", path_pairing)
44+
if err := mainPairing(); err != nil {
45+
logger.Error("Failed to generate PAIRING test data", "error", err)
46+
return
47+
}
48+
logger.Info("Generating MAP test data", "path_g1", path_map_g1, "path_g2", path_map_g2)
49+
if err := mainMap(); err != nil {
50+
logger.Error("Failed to generate MAP test data", "error", err)
51+
return
52+
}
53+
logger.Info("Generating POINT EVALUATION test data", "path_pointeval", path_pointeval)
54+
if err := mainPointEval(); err != nil {
55+
logger.Error("Failed to generate POINT EVALUATION test data", "error", err)
56+
return
57+
}
58+
logger.Info("Test data generation completed successfully")
59+
}
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
package main
2+
3+
import (
4+
"crypto/rand"
5+
"fmt"
6+
"iter"
7+
"math/big"
8+
"slices"
9+
10+
bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381"
11+
fp_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fp"
12+
fr_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
13+
)
14+
15+
type affine interface {
16+
bls12381.G1Affine | bls12381.G2Affine
17+
}
18+
19+
func generateG1Trivial() bls12381.G1Affine {
20+
var p bls12381.G1Affine
21+
p.SetInfinity()
22+
return p
23+
}
24+
25+
func generateG2Trivial() bls12381.G2Affine {
26+
var p bls12381.G2Affine
27+
p.SetInfinity()
28+
return p
29+
}
30+
31+
func generateTrivial[T affine]() T {
32+
var res T
33+
switch vv := any(&res).(type) {
34+
case *bls12381.G1Affine:
35+
v := generateG1Trivial()
36+
*vv = v
37+
case *bls12381.G2Affine:
38+
v := generateG2Trivial()
39+
*vv = v
40+
}
41+
return res
42+
}
43+
44+
func generateG1OnCurve() bls12381.G1Affine {
45+
var x fp_bls12381.Element
46+
x.MustSetRandom()
47+
P := bls12381.GeneratePointNotInG1(x)
48+
var pa bls12381.G1Affine
49+
pa.FromJacobian(&P)
50+
if !pa.IsOnCurve() {
51+
panic("generated point is not on curve")
52+
}
53+
if pa.IsInSubGroup() {
54+
panic("generated point is in subgroup")
55+
}
56+
return pa
57+
}
58+
59+
func generateG2OnCurve() bls12381.G2Affine {
60+
var x, y fp_bls12381.Element
61+
x.MustSetRandom()
62+
y.MustSetRandom()
63+
e := bls12381.E2{A0: x, A1: y}
64+
P := bls12381.GeneratePointNotInG2(e)
65+
var pa bls12381.G2Affine
66+
pa.FromJacobian(&P)
67+
if !pa.IsOnCurve() {
68+
panic("generated point is not on curve")
69+
}
70+
if pa.IsInSubGroup() {
71+
panic("generated point is in subgroup")
72+
}
73+
return pa
74+
}
75+
76+
func generateOnCurve[T affine]() T {
77+
var res T
78+
switch vv := any(&res).(type) {
79+
case *bls12381.G1Affine:
80+
v := generateG1OnCurve()
81+
*vv = v
82+
case *bls12381.G2Affine:
83+
v := generateG2OnCurve()
84+
*vv = v
85+
}
86+
return res
87+
}
88+
89+
func generateG1InSubgroup() bls12381.G1Affine {
90+
var p bls12381.G1Affine
91+
var s fr_bls12381.Element
92+
s.MustSetRandom()
93+
p.ScalarMultiplicationBase(s.BigInt(new(big.Int)))
94+
return p
95+
}
96+
97+
func generateG2InSubgroup() bls12381.G2Affine {
98+
var p bls12381.G2Affine
99+
var s fr_bls12381.Element
100+
s.MustSetRandom()
101+
p.ScalarMultiplicationBase(s.BigInt(new(big.Int)))
102+
return p
103+
}
104+
105+
func generateInSubgroup[T affine]() T {
106+
var res T
107+
switch vv := any(&res).(type) {
108+
case *bls12381.G1Affine:
109+
v := generateG1InSubgroup()
110+
*vv = v
111+
case *bls12381.G2Affine:
112+
v := generateG2InSubgroup()
113+
*vv = v
114+
}
115+
return res
116+
}
117+
118+
func generateG1Invalid() bls12381.G1Affine {
119+
var p bls12381.G1Affine
120+
for {
121+
p.X.SetRandom()
122+
p.Y.SetRandom()
123+
if !p.IsOnCurve() {
124+
return p
125+
}
126+
}
127+
}
128+
129+
func generateG2Invalid() bls12381.G2Affine {
130+
var p bls12381.G2Affine
131+
for {
132+
p.X.A0.SetRandom()
133+
p.X.A1.SetRandom()
134+
p.Y.A0.SetRandom()
135+
p.Y.A1.SetRandom()
136+
if !p.IsOnCurve() {
137+
return p
138+
}
139+
}
140+
}
141+
142+
func generateInvalid[T affine]() T {
143+
var res T
144+
switch vv := any(&res).(type) {
145+
case *bls12381.G1Affine:
146+
v := generateG1Invalid()
147+
*vv = v
148+
case *bls12381.G2Affine:
149+
v := generateG2Invalid()
150+
*vv = v
151+
}
152+
return res
153+
}
154+
155+
func generateScalar(scalarType msmInputType) *big.Int {
156+
switch scalarType {
157+
case msmScalarTrivial:
158+
return big.NewInt(0)
159+
case msmScalarRange:
160+
r, err := rand.Int(rand.Reader, fr_bls12381.Modulus())
161+
if err != nil {
162+
panic(fmt.Sprintf("failed to generate random scalar: %v", err))
163+
}
164+
return r
165+
case msmScalarBig:
166+
bound := new(big.Int).Lsh(big.NewInt(1), fr_bls12381.Bits)
167+
bound.Sub(bound, fr_bls12381.Modulus()) // ensure the scalar is less than the modulus
168+
// Generate a random scalar that is guaranteed to be big
169+
r, err := rand.Int(rand.Reader, bound)
170+
if err != nil {
171+
panic(fmt.Sprintf("failed to generate random scalar: %v", err))
172+
}
173+
r.Add(r, fr_bls12381.Modulus()) // ensure the scalar is larger than modulus
174+
return r
175+
default:
176+
panic(fmt.Sprintf("unknown scalar type: %d", scalarType))
177+
}
178+
}
179+
180+
func recIt[T any](newIterator func() iter.Seq2[int, func() T], yield func([]T) bool, width int, vals []func() T) {
181+
if width == 0 {
182+
return
183+
}
184+
for _, v := range newIterator() {
185+
newVals := append(vals, v)
186+
if len(newVals) == width {
187+
ret := make([]T, len(newVals))
188+
for i, f := range newVals {
189+
ret[i] = f()
190+
}
191+
if !yield(ret) {
192+
return
193+
}
194+
} else {
195+
recIt(newIterator, yield, width, newVals)
196+
}
197+
}
198+
}
199+
200+
func cartesianProduct[T any](width int, newIterator func() iter.Seq2[int, func() T]) iter.Seq[[]T] {
201+
return func(yield func([]T) bool) {
202+
recIt(newIterator, yield, width, []func() T{})
203+
}
204+
}
205+
206+
func splitG1ToLimbs(p bls12381.G1Affine) []string {
207+
limbs := slices.Concat(
208+
splitBaseToLimbs(p.X),
209+
splitBaseToLimbs(p.Y),
210+
)
211+
return limbs
212+
}
213+
214+
func splitG2ToLimbs(q bls12381.G2Affine) []string {
215+
limbs := slices.Concat(
216+
splitBaseToLimbs(q.X.A1),
217+
splitBaseToLimbs(q.X.A0),
218+
splitBaseToLimbs(q.Y.A1),
219+
splitBaseToLimbs(q.Y.A0),
220+
)
221+
return limbs
222+
}
223+
224+
func splitToLimbs[T affine](p T) []string {
225+
switch vv := any(p).(type) {
226+
case bls12381.G1Affine:
227+
return splitG1ToLimbs(vv)
228+
case bls12381.G2Affine:
229+
return splitG2ToLimbs(vv)
230+
default:
231+
panic(fmt.Sprintf("unknown type for splitting to limbs: %T", p))
232+
}
233+
}
234+
235+
func splitScalarToLimbs(s *big.Int) []string {
236+
var sb [32]byte
237+
s.FillBytes(sb[:])
238+
limbs := []string{
239+
fmt.Sprintf("0x%x", sb[0:16]),
240+
fmt.Sprintf("0x%x", sb[16:32]),
241+
}
242+
return limbs
243+
}
244+
245+
func splitBaseToLimbs(x fp_bls12381.Element) []string {
246+
xb := x.Bytes()
247+
limbs := []string{
248+
"0x00000000000000000000000000000000",
249+
fmt.Sprintf("0x%x", xb[0:16]),
250+
fmt.Sprintf("0x%x", xb[16:32]),
251+
fmt.Sprintf("0x%x", xb[32:48]),
252+
}
253+
return limbs
254+
}
255+
256+
func formatBoolAsInt(b bool) string {
257+
if b {
258+
return "1"
259+
}
260+
return "0"
261+
}
262+
263+
func splitG1CompressedLimbs(bts [bls12381.SizeOfG1AffineCompressed]byte) []string {
264+
limbs := []string{
265+
fmt.Sprintf("0x%x", bts[32:48]),
266+
fmt.Sprintf("0x%x", bts[16:32]),
267+
fmt.Sprintf("0x%x", bts[0:16]),
268+
}
269+
return limbs
270+
}
271+
272+
func splitVersionedHashToLimbs(h [32]byte) []string {
273+
limbs := []string{
274+
fmt.Sprintf("0x%x", h[16:32]),
275+
fmt.Sprintf("0x%x", h[0:16]),
276+
}
277+
return limbs
278+
}

0 commit comments

Comments
 (0)