Skip to content

Commit 265d08f

Browse files
committed
feat: eip-7951 ecdsa p256
1 parent e1ffd8d commit 265d08f

File tree

2 files changed

+121
-0
lines changed

2 files changed

+121
-0
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package evmprecompiles
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/consensys/gnark/frontend"
7+
"github.com/consensys/gnark/std/algebra/emulated/sw_emulated"
8+
"github.com/consensys/gnark/std/math/emulated"
9+
"github.com/consensys/gnark/std/signature/ecdsa"
10+
)
11+
12+
// P256Verify implements [P256Verify] precompile contract at address 0x100.
13+
//
14+
// ...
15+
//
16+
// [P256Verify]: https://eips.ethereum.org/EIPS/eip-7951
17+
func P256Verify(api frontend.API,
18+
msgHash emulated.Element[emulated.P256Fr],
19+
r, s emulated.Element[emulated.P256Fr],
20+
qx, qy emulated.Element[emulated.P256Fp],
21+
) frontend.Variable {
22+
// Input validation
23+
// 1. input_length == 160 ==> enforced by emulated.P256Fr, and emulated.P256Fp?
24+
// 2. 0 < r < n and 0 < s < n ==> enforced by IsValid()
25+
// 3. (qx, qy) is a valid point on the curve P256
26+
curve, err := sw_emulated.New[emulated.P256Fp, emulated.P256Fr](api, sw_emulated.GetP256Params())
27+
if err != nil {
28+
panic(fmt.Sprintf("new curve: %v", err))
29+
}
30+
q := sw_emulated.AffinePoint[emulated.P256Fp]{
31+
X: qx,
32+
Y: qy,
33+
}
34+
curve.AssertIsOnCurve(&q) // todo: return bit
35+
// 4. (qx, qy) != O
36+
// impelemnt in sw_emulated
37+
38+
pk := ecdsa.PublicKey[emulated.P256Fp, emulated.P256Fr]{
39+
X: qx,
40+
Y: qy,
41+
}
42+
sig := ecdsa.Signature[emulated.P256Fr]{
43+
R: r,
44+
S: s,
45+
}
46+
47+
verified := pk.IsValid(api, sw_emulated.GetCurveParams[emulated.P256Fp](), &msgHash, &sig)
48+
49+
return verified
50+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package evmprecompiles
2+
3+
import (
4+
"crypto/rand"
5+
"math/big"
6+
"testing"
7+
8+
"github.com/consensys/gnark-crypto/ecc"
9+
"github.com/consensys/gnark-crypto/ecc/secp256r1/ecdsa"
10+
"github.com/consensys/gnark/frontend"
11+
"github.com/consensys/gnark/std/math/emulated"
12+
"github.com/consensys/gnark/test"
13+
)
14+
15+
type p256verifyCircuit struct {
16+
MsgHash emulated.Element[emulated.P256Fr]
17+
R emulated.Element[emulated.P256Fr]
18+
S emulated.Element[emulated.P256Fr]
19+
Qx, Qy emulated.Element[emulated.P256Fp]
20+
Expected frontend.Variable
21+
}
22+
23+
func (c *p256verifyCircuit) Define(api frontend.API) error {
24+
res := P256Verify(api, c.MsgHash, c.R, c.S, c.Qx, c.Qy)
25+
api.AssertIsEqual(c.Expected, res)
26+
return nil
27+
}
28+
29+
func TestP256VerifyCircuit(t *testing.T) {
30+
assert := test.NewAssert(t)
31+
// key generation
32+
sk, err := ecdsa.GenerateKey(rand.Reader)
33+
if err != nil {
34+
t.Fatal("generate", err)
35+
}
36+
pk := sk.PublicKey
37+
// signing
38+
msg := []byte("test")
39+
sigBuf, err := sk.Sign(msg, nil)
40+
if err != nil {
41+
t.Fatal("sign", err)
42+
}
43+
// verification
44+
verified, err := sk.PublicKey.Verify(sigBuf, msg, nil)
45+
if err != nil {
46+
t.Fatal("verify", err)
47+
}
48+
// marshalling
49+
var sig ecdsa.Signature
50+
sig.SetBytes(sigBuf[:])
51+
var r, s big.Int
52+
r.SetBytes(sig.R[:])
53+
s.SetBytes(sig.S[:])
54+
hash := ecdsa.HashToInt(msg)
55+
var expected frontend.Variable
56+
if verified {
57+
expected = 1
58+
}
59+
60+
circuit := p256verifyCircuit{}
61+
witness := p256verifyCircuit{
62+
MsgHash: emulated.ValueOf[emulated.P256Fr](hash),
63+
R: emulated.ValueOf[emulated.P256Fr](r),
64+
S: emulated.ValueOf[emulated.P256Fr](s),
65+
Qx: emulated.ValueOf[emulated.P256Fp](pk.A.X),
66+
Qy: emulated.ValueOf[emulated.P256Fp](pk.A.Y),
67+
Expected: expected,
68+
}
69+
err = test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField())
70+
assert.NoError(err)
71+
}

0 commit comments

Comments
 (0)