Skip to content

Commit aab575e

Browse files
Tabaieivokub
andauthored
Perf: Poseidon2 GKR circuit (#1410)
Co-authored-by: Ivo Kubjas <[email protected]>
1 parent 33adbaf commit aab575e

File tree

9 files changed

+795
-94
lines changed

9 files changed

+795
-94
lines changed

go.mod

+5-5
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ toolchain go1.22.6
77
require (
88
github.com/bits-and-blooms/bitset v1.20.0
99
github.com/blang/semver/v4 v4.0.0
10-
github.com/consensys/bavard v0.1.27
10+
github.com/consensys/bavard v0.1.29
1111
github.com/consensys/compress v0.2.5
12-
github.com/consensys/gnark-crypto v0.16.1-0.20250205153847-10a243d332ca
12+
github.com/consensys/gnark-crypto v0.16.1-0.20250217214835-5ed804970f85
1313
github.com/fxamacker/cbor/v2 v2.7.0
1414
github.com/google/go-cmp v0.6.0
1515
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8
@@ -19,9 +19,9 @@ require (
1919
github.com/ronanh/intcomp v1.1.0
2020
github.com/rs/zerolog v1.33.0
2121
github.com/stretchr/testify v1.10.0
22-
golang.org/x/crypto v0.32.0
22+
golang.org/x/crypto v0.33.0
2323
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948
24-
golang.org/x/sync v0.10.0
24+
golang.org/x/sync v0.11.0
2525
)
2626

2727
require (
@@ -31,7 +31,7 @@ require (
3131
github.com/mmcloughlin/addchain v0.4.0 // indirect
3232
github.com/pmezard/go-difflib v1.0.0 // indirect
3333
github.com/x448/float16 v0.8.4 // indirect
34-
golang.org/x/sys v0.29.0 // indirect
34+
golang.org/x/sys v0.30.0 // indirect
3535
gopkg.in/yaml.v3 v3.0.1 // indirect
3636
rsc.io/tmplfunc v0.0.3 // indirect
3737
)

go.sum

+10-10
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,12 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
5757
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
5858
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
5959
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
60-
github.com/consensys/bavard v0.1.27 h1:j6hKUrGAy/H+gpNrpLU3I26n1yc+VMGmd6ID5+gAhOs=
61-
github.com/consensys/bavard v0.1.27/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs=
60+
github.com/consensys/bavard v0.1.29 h1:fobxIYksIQ+ZSrTJUuQgu+HIJwclrAPcdXqd7H2hh1k=
61+
github.com/consensys/bavard v0.1.29/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs=
6262
github.com/consensys/compress v0.2.5 h1:gJr1hKzbOD36JFsF1AN8lfXz1yevnJi1YolffY19Ntk=
6363
github.com/consensys/compress v0.2.5/go.mod h1:pyM+ZXiNUh7/0+AUjUf9RKUM6vSH7T/fsn5LLS0j1Tk=
64-
github.com/consensys/gnark-crypto v0.16.1-0.20250205153847-10a243d332ca h1:u6iXwMBfbXODF+hDSwKSTBg6yfD3+eMX6o3PILAK474=
65-
github.com/consensys/gnark-crypto v0.16.1-0.20250205153847-10a243d332ca/go.mod h1:Ke3j06ndtPTVvo++PhGNgvm+lgpLvzbcE2MqljY7diU=
64+
github.com/consensys/gnark-crypto v0.16.1-0.20250217214835-5ed804970f85 h1:3ht4gGH3smFGVLFhpFTKvDbEdagC6eSaPXnHjCQGh94=
65+
github.com/consensys/gnark-crypto v0.16.1-0.20250217214835-5ed804970f85/go.mod h1:A2URlMHUT81ifJ0UlLzSlm7TmnE3t7VxEThApdMukJw=
6666
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
6767
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
6868
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
@@ -304,8 +304,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
304304
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
305305
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
306306
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
307-
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
308-
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
307+
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
308+
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
309309
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
310310
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
311311
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -410,8 +410,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
410410
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
411411
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
412412
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
413-
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
414-
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
413+
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
414+
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
415415
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
416416
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
417417
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -462,8 +462,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
462462
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
463463
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
464464
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
465-
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
466-
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
465+
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
466+
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
467467
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
468468
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
469469
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=

std/gkr/api.go

-5
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,3 @@ func (api *API) Sub(i1, i2 constraint.GkrVariable, in ...constraint.GkrVariable)
4343
func (api *API) Mul(i1, i2 constraint.GkrVariable, in ...constraint.GkrVariable) constraint.GkrVariable {
4444
return api.namedGate2PlusIn("mul", i1, i2, in...)
4545
}
46-
47-
// TODO @Tabaie This can be useful
48-
func (api *API) Println(a ...constraint.GkrVariable) {
49-
panic("not implemented")
50-
}

std/gkr/api_test.go

+74-68
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ import (
1616
bw6761 "github.com/consensys/gnark/constraint/bw6-761"
1717
"github.com/consensys/gnark/test"
1818

19-
"github.com/consensys/gnark-crypto/kzg"
20-
"github.com/consensys/gnark/backend/plonk"
2119
bn254 "github.com/consensys/gnark/constraint/bn254"
2220
"github.com/stretchr/testify/require"
2321

@@ -26,15 +24,12 @@ import (
2624
"github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr"
2725
bn254MiMC "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc"
2826
"github.com/consensys/gnark/backend/groth16"
29-
"github.com/consensys/gnark/backend/witness"
3027
"github.com/consensys/gnark/constraint"
3128
"github.com/consensys/gnark/frontend"
3229
"github.com/consensys/gnark/frontend/cs/r1cs"
33-
"github.com/consensys/gnark/frontend/cs/scs"
3430
stdHash "github.com/consensys/gnark/std/hash"
3531
"github.com/consensys/gnark/std/hash/mimc"
3632
test_vector_utils "github.com/consensys/gnark/std/internal/test_vectors_utils"
37-
"github.com/consensys/gnark/test/unsafekzg"
3833
)
3934

4035
// compressThreshold --> if linear expressions are larger than this, the frontend will introduce
@@ -69,6 +64,7 @@ func (c *doubleNoDependencyCircuit) Define(api frontend.API) error {
6964
}
7065

7166
func TestDoubleNoDependencyCircuit(t *testing.T) {
67+
assert := test.NewAssert(t)
7268

7369
xValuess := [][]frontend.Variable{
7470
{1, 1},
@@ -77,12 +73,13 @@ func TestDoubleNoDependencyCircuit(t *testing.T) {
7773

7874
hashes := []string{"-1", "-20"}
7975

80-
for _, xValues := range xValuess {
76+
for i, xValues := range xValuess {
8177
for _, hashName := range hashes {
8278
assignment := doubleNoDependencyCircuit{X: xValues}
8379
circuit := doubleNoDependencyCircuit{X: make([]frontend.Variable, len(xValues)), hashName: hashName}
84-
85-
test.NewAssert(t).CheckCircuit(&circuit, test.WithValidAssignment(&assignment))
80+
assert.Run(func(assert *test.Assert) {
81+
assert.CheckCircuit(&circuit, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BN254))
82+
}, fmt.Sprintf("xValue=%d/hash=%s", i, hashName))
8683

8784
}
8885
}
@@ -115,6 +112,7 @@ func (c *sqNoDependencyCircuit) Define(api frontend.API) error {
115112
}
116113

117114
func TestSqNoDependencyCircuit(t *testing.T) {
115+
assert := test.NewAssert(t)
118116

119117
xValuess := [][]frontend.Variable{
120118
{1, 1},
@@ -123,12 +121,13 @@ func TestSqNoDependencyCircuit(t *testing.T) {
123121

124122
hashes := []string{"-1", "-20"}
125123

126-
for _, xValues := range xValuess {
124+
for i, xValues := range xValuess {
127125
for _, hashName := range hashes {
128126
assignment := sqNoDependencyCircuit{X: xValues}
129127
circuit := sqNoDependencyCircuit{X: make([]frontend.Variable, len(xValues)), hashName: hashName}
130-
testGroth16(t, &circuit, &assignment)
131-
testPlonk(t, &circuit, &assignment)
128+
assert.Run(func(assert *test.Assert) {
129+
assert.CheckCircuit(&circuit, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BN254))
130+
}, fmt.Sprintf("xValues=%d/hash=%s", i, hashName))
132131
}
133132
}
134133
}
@@ -168,6 +167,7 @@ func (c *mulNoDependencyCircuit) Define(api frontend.API) error {
168167
}
169168

170169
func TestMulNoDependency(t *testing.T) {
170+
assert := test.NewAssert(t)
171171
xValuess := [][]frontend.Variable{
172172
{1, 2},
173173
}
@@ -189,9 +189,9 @@ func TestMulNoDependency(t *testing.T) {
189189
Y: make([]frontend.Variable, len(yValuess[i])),
190190
hashName: hashName,
191191
}
192-
193-
testGroth16(t, &circuit, &assignment)
194-
testPlonk(t, &circuit, &assignment)
192+
assert.Run(func(assert *test.Assert) {
193+
assert.CheckCircuit(&circuit, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BN254))
194+
}, fmt.Sprintf("xValues=%d/hash=%s", i, hashName))
195195
}
196196
}
197197
}
@@ -240,14 +240,13 @@ func (c *mulWithDependencyCircuit) Define(api frontend.API) error {
240240
}
241241

242242
func TestSolveMulWithDependency(t *testing.T) {
243+
assert := test.NewAssert(t)
243244
assignment := mulWithDependencyCircuit{
244245
XLast: 1,
245246
Y: []frontend.Variable{3, 2},
246247
}
247248
circuit := mulWithDependencyCircuit{Y: make([]frontend.Variable, len(assignment.Y)), hashName: "-20"}
248-
249-
testGroth16(t, &circuit, &assignment)
250-
testPlonk(t, &circuit, &assignment)
249+
assert.CheckCircuit(&circuit, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BN254))
251250
}
252251

253252
func TestApiMul(t *testing.T) {
@@ -386,53 +385,6 @@ func (c *benchMiMCMerkleTreeCircuit) Define(api frontend.API) error {
386385
return solution.Verify("-20", challenge)
387386
}
388387

389-
func testGroth16(t *testing.T, circuit, assignment frontend.Circuit) {
390-
cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, circuit, frontend.WithCompressThreshold(compressThreshold))
391-
require.NoError(t, err)
392-
var (
393-
fullWitness witness.Witness
394-
publicWitness witness.Witness
395-
pk groth16.ProvingKey
396-
vk groth16.VerifyingKey
397-
proof groth16.Proof
398-
)
399-
fullWitness, err = frontend.NewWitness(assignment, ecc.BN254.ScalarField())
400-
require.NoError(t, err)
401-
publicWitness, err = fullWitness.Public()
402-
require.NoError(t, err)
403-
pk, vk, err = groth16.Setup(cs)
404-
require.NoError(t, err)
405-
proof, err = groth16.Prove(cs, pk, fullWitness)
406-
require.NoError(t, err)
407-
err = groth16.Verify(proof, vk, publicWitness)
408-
require.NoError(t, err)
409-
}
410-
411-
func testPlonk(t *testing.T, circuit, assignment frontend.Circuit) {
412-
cs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, circuit, frontend.WithCompressThreshold(compressThreshold))
413-
require.NoError(t, err)
414-
var (
415-
fullWitness witness.Witness
416-
publicWitness witness.Witness
417-
pk plonk.ProvingKey
418-
vk plonk.VerifyingKey
419-
proof plonk.Proof
420-
kzgSrs kzg.SRS
421-
)
422-
fullWitness, err = frontend.NewWitness(assignment, ecc.BN254.ScalarField())
423-
require.NoError(t, err)
424-
publicWitness, err = fullWitness.Public()
425-
require.NoError(t, err)
426-
kzgSrs, srsLagrange, err := unsafekzg.NewSRS(cs)
427-
require.NoError(t, err)
428-
pk, vk, err = plonk.Setup(cs, kzgSrs, srsLagrange)
429-
require.NoError(t, err)
430-
proof, err = plonk.Prove(cs, pk, fullWitness)
431-
require.NoError(t, err)
432-
err = plonk.Verify(proof, vk, publicWitness)
433-
require.NoError(t, err)
434-
}
435-
436388
func registerMiMC() {
437389
bn254.RegisterHashBuilder("mimc", func() hash.Hash {
438390
return bn254MiMC.NewMiMC()
@@ -644,19 +596,21 @@ func BenchmarkMiMCNoGkrFullDepthSolve(b *testing.B) {
644596
}
645597

646598
func TestMiMCFullDepthNoDepSolve(t *testing.T) {
599+
assert := test.NewAssert(t)
647600
registerMiMC()
648601
for i := 0; i < 100; i++ {
649602
circuit, assignment := mimcNoDepCircuits(5, 1<<2, "-20")
650-
testGroth16(t, circuit, assignment)
651-
testPlonk(t, circuit, assignment)
603+
assert.Run(func(assert *test.Assert) {
604+
assert.CheckCircuit(circuit, test.WithValidAssignment(assignment), test.WithCurves(ecc.BN254))
605+
}, fmt.Sprintf("i=%d", i))
652606
}
653607
}
654608

655609
func TestMiMCFullDepthNoDepSolveWithMiMCHash(t *testing.T) {
610+
assert := test.NewAssert(t)
656611
registerMiMC()
657612
circuit, assignment := mimcNoDepCircuits(5, 1<<2, "mimc")
658-
testGroth16(t, circuit, assignment)
659-
testPlonk(t, circuit, assignment)
613+
assert.CheckCircuit(circuit, test.WithValidAssignment(assignment), test.WithCurves(ecc.BN254))
660614
}
661615

662616
func mimcNoGkrCircuits(mimcDepth, nbInstances int) (circuit, assignment frontend.Circuit) {
@@ -677,3 +631,55 @@ func mimcNoGkrCircuits(mimcDepth, nbInstances int) (circuit, assignment frontend
677631
}
678632
return
679633
}
634+
635+
func TestSolveInTestEngine(t *testing.T) {
636+
assignment := testSolveInTestEngineCircuit{
637+
X: []frontend.Variable{2, 3, 4, 5, 6, 7, 8, 9},
638+
}
639+
circuit := testSolveInTestEngineCircuit{
640+
X: make([]frontend.Variable, len(assignment.X)),
641+
}
642+
643+
require.NoError(t, test.IsSolved(&circuit, &assignment, ecc.BN254.ScalarField()))
644+
require.NoError(t, test.IsSolved(&circuit, &assignment, ecc.BLS24_315.ScalarField()))
645+
require.NoError(t, test.IsSolved(&circuit, &assignment, ecc.BLS12_381.ScalarField()))
646+
require.NoError(t, test.IsSolved(&circuit, &assignment, ecc.BLS24_317.ScalarField()))
647+
require.NoError(t, test.IsSolved(&circuit, &assignment, ecc.BW6_633.ScalarField()))
648+
require.NoError(t, test.IsSolved(&circuit, &assignment, ecc.BW6_761.ScalarField()))
649+
require.NoError(t, test.IsSolved(&circuit, &assignment, ecc.BLS12_377.ScalarField()))
650+
}
651+
652+
type testSolveInTestEngineCircuit struct {
653+
X []frontend.Variable
654+
}
655+
656+
func (c *testSolveInTestEngineCircuit) Define(api frontend.API) error {
657+
gkr := NewApi()
658+
x, err := gkr.Import(c.X)
659+
if err != nil {
660+
return err
661+
}
662+
Y := make([]frontend.Variable, len(c.X))
663+
Y[0] = 1
664+
y, err := gkr.Import(Y)
665+
if err != nil {
666+
return err
667+
}
668+
669+
z := gkr.Mul(x, y)
670+
671+
for i := range len(c.X) - 1 {
672+
gkr.Series(y, z, i+1, i)
673+
}
674+
675+
assignments := gkr.SolveInTestEngine(api)
676+
677+
product := frontend.Variable(1)
678+
for i := range c.X {
679+
api.AssertIsEqual(assignments[y][i], product)
680+
product = api.Mul(product, c.X[i])
681+
api.AssertIsEqual(assignments[z][i], product)
682+
}
683+
684+
return nil
685+
}

0 commit comments

Comments
 (0)