Skip to content

Commit 0d58def

Browse files
core/vm, crypto/secp2561r1: implement secp256r1 precompile
Co-authored-by: Ulaş Erdoğan <[email protected]>
1 parent 156280d commit 0d58def

File tree

5 files changed

+5562
-0
lines changed

5 files changed

+5562
-0
lines changed

core/vm/contracts.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"github.com/ethereum/go-ethereum/crypto/blake2b"
3636
"github.com/ethereum/go-ethereum/crypto/bn256"
3737
"github.com/ethereum/go-ethereum/crypto/kzg4844"
38+
"github.com/ethereum/go-ethereum/crypto/secp256r1"
3839
"github.com/ethereum/go-ethereum/params"
3940
"golang.org/x/crypto/ripemd160"
4041
)
@@ -161,6 +162,14 @@ var PrecompiledContractsOsaka = PrecompiledContracts{
161162
common.BytesToAddress([]byte{0x0f}): &bls12381Pairing{},
162163
common.BytesToAddress([]byte{0x10}): &bls12381MapG1{},
163164
common.BytesToAddress([]byte{0x11}): &bls12381MapG2{},
165+
166+
common.BytesToAddress([]byte{0x1, 0x00}): &p256Verify{},
167+
}
168+
169+
// PrecompiledContractsP256Verify contains the precompiled Ethereum
170+
// contract specified in EIP-7212. This is exported for testing purposes.
171+
var PrecompiledContractsP256Verify = PrecompiledContracts{
172+
common.BytesToAddress([]byte{0x1, 0x00}): &p256Verify{},
164173
}
165174

166175
var (
@@ -1232,3 +1241,31 @@ func kZGToVersionedHash(kzg kzg4844.Commitment) common.Hash {
12321241

12331242
return h
12341243
}
1244+
1245+
// P256VERIFY (secp256r1 signature verification)
1246+
// implemented as a native contract
1247+
type p256Verify struct{}
1248+
1249+
// RequiredGas returns the gas required to execute the precompiled contract
1250+
func (c *p256Verify) RequiredGas(input []byte) uint64 {
1251+
return params.P256VerifyGas
1252+
}
1253+
1254+
// Run executes the precompiled contract with given 160 bytes of param, returning the output and the used gas
1255+
func (c *p256Verify) Run(input []byte) ([]byte, error) {
1256+
const p256VerifyInputLength = 160
1257+
if len(input) != p256VerifyInputLength {
1258+
return nil, nil
1259+
}
1260+
1261+
// Extract hash, r, s, x, y from the input.
1262+
hash := input[0:32]
1263+
r, s := new(big.Int).SetBytes(input[32:64]), new(big.Int).SetBytes(input[64:96])
1264+
x, y := new(big.Int).SetBytes(input[96:128]), new(big.Int).SetBytes(input[128:160])
1265+
1266+
// Verify the signature.
1267+
if secp256r1.Verify(hash, r, s, x, y) {
1268+
return true32Byte, nil
1269+
}
1270+
return nil, nil
1271+
}

core/vm/contracts_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ var allPrecompiles = map[common.Address]PrecompiledContract{
6666
common.BytesToAddress([]byte{0x0f, 0x0e}): &bls12381Pairing{},
6767
common.BytesToAddress([]byte{0x0f, 0x0f}): &bls12381MapG1{},
6868
common.BytesToAddress([]byte{0x0f, 0x10}): &bls12381MapG2{},
69+
70+
common.BytesToAddress([]byte{0x0b}): &p256Verify{},
6971
}
7072

7173
// EIP-152 test vectors
@@ -397,3 +399,15 @@ func BenchmarkPrecompiledBLS12381G2MultiExpWorstCase(b *testing.B) {
397399
}
398400
benchmarkPrecompiled("f0d", testcase, b)
399401
}
402+
403+
// Benchmarks the sample inputs from the P256VERIFY precompile.
404+
func BenchmarkPrecompiledP256Verify(bench *testing.B) {
405+
t := precompiledTest{
406+
Input: "4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e",
407+
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
408+
Name: "p256Verify",
409+
}
410+
benchmarkPrecompiled("0b", t, bench)
411+
}
412+
413+
func TestPrecompiledP256Verify(t *testing.T) { testJson("p256Verify", "0b", t) }

0 commit comments

Comments
 (0)