Skip to content

Commit 9c9cf0d

Browse files
authored
test: handle gnark-crypto not returning malleable signatures anymore (#1601)
1 parent 5026f3e commit 9c9cf0d

File tree

4 files changed

+32
-55
lines changed

4 files changed

+32
-55
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ require (
77
github.com/blang/semver/v4 v4.0.0
88
github.com/consensys/bavard v0.2.1
99
github.com/consensys/compress v0.2.5
10-
github.com/consensys/gnark-crypto v0.19.3-0.20251114101102-c7c3213680f8
10+
github.com/consensys/gnark-crypto v0.19.3-0.20251115174214-022ec58e8c19
1111
github.com/fxamacker/cbor/v2 v2.9.0
1212
github.com/google/go-cmp v0.7.0
1313
github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ github.com/consensys/bavard v0.2.1 h1:i2/ZeLXpp7eblPWzUIWf+dtfBocKQIxuiqy9XZlNSf
6161
github.com/consensys/bavard v0.2.1/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.19.3-0.20251114101102-c7c3213680f8 h1:47ph0eGnz4NgmCdROVZvR4tMwwAanu0dsdMdA8DXmuk=
65-
github.com/consensys/gnark-crypto v0.19.3-0.20251114101102-c7c3213680f8/go.mod h1:OgCH7cSoJ46c+nOzvQuwOrIE9fawpXMYOQFzj22Vy3E=
64+
github.com/consensys/gnark-crypto v0.19.3-0.20251115174214-022ec58e8c19 h1:uUbFaofcFwkv5T/zbR/Gyfm06v84Rua9a1xv9VZrPAA=
65+
github.com/consensys/gnark-crypto v0.19.3-0.20251115174214-022ec58e8c19/go.mod h1:OgCH7cSoJ46c+nOzvQuwOrIE9fawpXMYOQFzj22Vy3E=
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=

std/evmprecompiles/01-ecrecover_test.go

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func (c *ecrecoverCircuit) Define(api frontend.API) error {
6060
return nil
6161
}
6262

63-
func testRoutineECRecover(t *testing.T, wantStrict bool) (circ, wit *ecrecoverCircuit, largeS bool) {
63+
func testRoutineECRecover(t *testing.T, forceLargeS bool) (circ, wit *ecrecoverCircuit) {
6464
halfFr := new(big.Int).Sub(fr.Modulus(), big.NewInt(1))
6565
halfFr.Div(halfFr, big.NewInt(2))
6666

@@ -72,18 +72,22 @@ func testRoutineECRecover(t *testing.T, wantStrict bool) (circ, wit *ecrecoverCi
7272
msg := []byte("test")
7373
var r, s *big.Int
7474
var v uint
75-
for {
76-
v, r, s, err = sk.SignForRecover(msg, nil)
77-
if err != nil {
78-
t.Fatal("sign", err)
79-
}
80-
if !wantStrict || halfFr.Cmp(s) > 0 {
81-
break
82-
}
75+
v, r, s, err = sk.SignForRecover(msg, nil)
76+
if err != nil {
77+
t.Fatal("sign", err)
8378
}
84-
strict := 0
85-
if wantStrict {
86-
strict = 1
79+
// SignForRecover always returns s < r_mod/2. But in the tests we want
80+
// to check that the circuit fails when s > r_mod/2 in strict mode.
81+
if forceLargeS {
82+
// first we make s large
83+
s.Sub(fr.Modulus(), s)
84+
// but we also have to swap the sign of the recovered public key
85+
v ^= 1
86+
}
87+
88+
strict := 1
89+
if forceLargeS {
90+
strict = 0
8791
}
8892
circuit := ecrecoverCircuit{}
8993
witness := ecrecoverCircuit{
@@ -98,19 +102,19 @@ func testRoutineECRecover(t *testing.T, wantStrict bool) (circ, wit *ecrecoverCi
98102
Y: emulated.ValueOf[emulated.Secp256k1Fp](pk.A.Y),
99103
},
100104
}
101-
return &circuit, &witness, halfFr.Cmp(s) <= 0
105+
return &circuit, &witness
102106
}
103107

104108
func TestECRecoverCircuitShortStrict(t *testing.T) {
105109
assert := test.NewAssert(t)
106-
circuit, witness, _ := testRoutineECRecover(t, true)
110+
circuit, witness := testRoutineECRecover(t, false)
107111
err := test.IsSolved(circuit, witness, ecc.BN254.ScalarField())
108112
assert.NoError(err)
109113
}
110114

111115
func TestECRecoverCircuitShortLax(t *testing.T) {
112116
assert := test.NewAssert(t)
113-
circuit, witness, _ := testRoutineECRecover(t, false)
117+
circuit, witness := testRoutineECRecover(t, true)
114118
err := test.IsSolved(circuit, witness, ecc.BN254.ScalarField())
115119
assert.NoError(err)
116120
}
@@ -120,25 +124,21 @@ func TestECRecoverCircuitShortMismatch(t *testing.T) {
120124
halfFr := new(big.Int).Sub(fr.Modulus(), big.NewInt(1))
121125
halfFr.Div(halfFr, big.NewInt(2))
122126
var circuit, witness *ecrecoverCircuit
123-
var largeS bool
124-
for {
125-
circuit, witness, largeS = testRoutineECRecover(t, false)
126-
if largeS {
127-
witness.Strict = 1
128-
break
129-
}
130-
}
127+
circuit, witness = testRoutineECRecover(t, true)
128+
witness.Strict = 1
131129
err := test.IsSolved(circuit, witness, ecc.BN254.ScalarField())
132130
assert.Error(err)
133131
}
134132

135133
func TestECRecoverCircuitFull(t *testing.T) {
136134
assert := test.NewAssert(t)
137-
circuit, witness, _ := testRoutineECRecover(t, false)
135+
circuit, witness := testRoutineECRecover(t, false)
136+
_, witness2 := testRoutineECRecover(t, true)
138137

139138
assert.CheckCircuit(
140139
circuit,
141140
test.WithValidAssignment(witness),
141+
test.WithValidAssignment(witness2),
142142
test.WithCurves(ecc.BN254, ecc.BLS12_377),
143143
test.NoProverChecks(),
144144
)
@@ -256,10 +256,14 @@ func TestECRecoverInfinityWoFailure(t *testing.T) {
256256

257257
func TestInvalidFailureTag(t *testing.T) {
258258
assert := test.NewAssert(t)
259-
circuit, witness, _ := testRoutineECRecover(t, false)
259+
circuit, witness := testRoutineECRecover(t, false)
260260
witness.IsFailure = 1
261261
err := test.IsSolved(circuit, witness, ecc.BN254.ScalarField())
262262
assert.Error(err)
263+
_, witness2 := testRoutineECRecover(t, true)
264+
witness2.IsFailure = 1
265+
err = test.IsSolved(circuit, witness2, ecc.BN254.ScalarField())
266+
assert.Error(err)
263267
}
264268

265269
func TestLargeV(t *testing.T) {

std/signature/ecdsa/ecdsa_secpr_test.go

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@ import (
1010
"testing"
1111

1212
"github.com/consensys/gnark-crypto/ecc"
13-
"github.com/consensys/gnark/constraint"
14-
"github.com/consensys/gnark/frontend"
15-
"github.com/consensys/gnark/frontend/cs/r1cs"
16-
"github.com/consensys/gnark/frontend/cs/scs"
1713
"github.com/consensys/gnark/std/math/emulated"
1814
"github.com/consensys/gnark/test"
1915
"golang.org/x/crypto/cryptobyte"
@@ -113,26 +109,3 @@ func TestEcdsaP384PreHashed(t *testing.T) {
113109
assert.NoError(err)
114110

115111
}
116-
117-
var ccsBench constraint.ConstraintSystem
118-
119-
func BenchmarkCompile(b *testing.B) {
120-
// create an empty cs
121-
var circuit EcdsaCircuit[emulated.P384Fp, emulated.P384Fr]
122-
123-
var ccs constraint.ConstraintSystem
124-
b.ResetTimer()
125-
for i := 0; i < b.N; i++ {
126-
ccs, _ = frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &circuit)
127-
}
128-
b.Log("scs constraints", ccs.GetNbConstraints())
129-
130-
b.Run("groth16", func(b *testing.B) {
131-
for i := 0; i < b.N; i++ {
132-
ccsBench, _ = frontend.Compile(ecc.BW6_633.ScalarField(), r1cs.NewBuilder, &circuit)
133-
}
134-
135-
})
136-
b.Log("r1cs constraints", ccsBench.GetNbConstraints())
137-
138-
}

0 commit comments

Comments
 (0)