Skip to content

Commit

Permalink
Feat/add ip and p256 verify precompiles (#14)
Browse files Browse the repository at this point in the history
* add precompile support royalty LRP policy

* Add dynamic required gas cost

* feat(core/vm): adds eip-7212 precompile

* update to support all fork sets

* feat(core/vm): add nostoi hard-fork config changes

---------

Co-authored-by: Kingster <[email protected]>
Co-authored-by: Yao <[email protected]>
  • Loading branch information
3 people authored Sep 24, 2024
1 parent 59fb0b6 commit a54ef9e
Show file tree
Hide file tree
Showing 17 changed files with 6,119 additions and 59 deletions.
4 changes: 4 additions & 0 deletions cmd/geth/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ func makeFullNode(ctx *cli.Context) *node.Node {
v := ctx.Uint64(utils.OverrideVerkle.Name)
cfg.Eth.OverrideVerkle = &v
}
if ctx.IsSet(utils.OverrideStoryNostoi.Name) {
v := ctx.Uint64(utils.OverrideStoryNostoi.Name)
cfg.Eth.OverrideStoryNostoi = &v
}

backend, eth := utils.RegisterEthService(stack, &cfg.Eth)

Expand Down
1 change: 1 addition & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ var (
utils.SmartCardDaemonPathFlag,
utils.OverrideCancun,
utils.OverrideVerkle,
utils.OverrideStoryNostoi,
utils.EnablePersonal,
utils.TxPoolLocalsFlag,
utils.TxPoolNoLocalsFlag,
Expand Down
5 changes: 5 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,11 @@ var (
Usage: "Manually specify the Cancun fork timestamp, overriding the bundled setting",
Category: flags.EthCategory,
}
OverrideStoryNostoi = &cli.Uint64Flag{
Name: "override.nostoi",
Usage: "Manually specify the Story nostoi fork block number, overriding the bundled setting",
Category: flags.EthCategory,
}
OverrideVerkle = &cli.Uint64Flag{
Name: "override.verkle",
Usage: "Manually specify the Verkle fork timestamp, overriding the bundled setting",
Expand Down
5 changes: 5 additions & 0 deletions core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ func (e *GenesisMismatchError) Error() string {
type ChainOverrides struct {
OverrideCancun *uint64
OverrideVerkle *uint64
// Story iliad
OverrideStoryNostoi *uint64
}

// SetupGenesisBlock writes or updates the genesis block in db.
Expand Down Expand Up @@ -279,6 +281,9 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
if overrides != nil && overrides.OverrideVerkle != nil {
config.VerkleTime = overrides.OverrideVerkle
}
if overrides != nil && overrides.OverrideStoryNostoi != nil {
config.NostoiBlock = new(big.Int).SetUint64(*overrides.OverrideStoryNostoi)
}
}
}
// Just commit the new block if there is no stored genesis block.
Expand Down
131 changes: 101 additions & 30 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/ethereum/go-ethereum/crypto/blake2b"
"github.com/ethereum/go-ethereum/crypto/bn256"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/crypto/secp256r1"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"golang.org/x/crypto/ripemd160"
Expand All @@ -50,51 +51,51 @@ type PrecompiledContract interface {
// PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum
// contracts used in the Frontier and Homestead releases.
var PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{0x1}): &ecrecover{},
common.BytesToAddress([]byte{0x2}): &sha256hash{},
common.BytesToAddress([]byte{0x3}): &ripemd160hash{},
common.BytesToAddress([]byte{0x4}): &dataCopy{},
common.BytesToAddress([]byte{0x1}): &ecrecover{},
common.BytesToAddress([]byte{0x2}): &sha256hash{},
common.BytesToAddress([]byte{0x3}): &ripemd160hash{},
common.BytesToAddress([]byte{0x4}): &dataCopy{},
}

// PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum
// contracts used in the Byzantium release.
var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{0x1}): &ecrecover{},
common.BytesToAddress([]byte{0x2}): &sha256hash{},
common.BytesToAddress([]byte{0x3}): &ripemd160hash{},
common.BytesToAddress([]byte{0x4}): &dataCopy{},
common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: false},
common.BytesToAddress([]byte{0x6}): &bn256AddByzantium{},
common.BytesToAddress([]byte{0x7}): &bn256ScalarMulByzantium{},
common.BytesToAddress([]byte{0x8}): &bn256PairingByzantium{},
common.BytesToAddress([]byte{0x1}): &ecrecover{},
common.BytesToAddress([]byte{0x2}): &sha256hash{},
common.BytesToAddress([]byte{0x3}): &ripemd160hash{},
common.BytesToAddress([]byte{0x4}): &dataCopy{},
common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: false},
common.BytesToAddress([]byte{0x6}): &bn256AddByzantium{},
common.BytesToAddress([]byte{0x7}): &bn256ScalarMulByzantium{},
common.BytesToAddress([]byte{0x8}): &bn256PairingByzantium{},
}

// PrecompiledContractsIstanbul contains the default set of pre-compiled Ethereum
// contracts used in the Istanbul release.
var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{0x1}): &ecrecover{},
common.BytesToAddress([]byte{0x2}): &sha256hash{},
common.BytesToAddress([]byte{0x3}): &ripemd160hash{},
common.BytesToAddress([]byte{0x4}): &dataCopy{},
common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: false},
common.BytesToAddress([]byte{0x6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{0x7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{0x9}): &blake2F{},
common.BytesToAddress([]byte{0x1}): &ecrecover{},
common.BytesToAddress([]byte{0x2}): &sha256hash{},
common.BytesToAddress([]byte{0x3}): &ripemd160hash{},
common.BytesToAddress([]byte{0x4}): &dataCopy{},
common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: false},
common.BytesToAddress([]byte{0x6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{0x7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{0x9}): &blake2F{},
}

// PrecompiledContractsBerlin contains the default set of pre-compiled Ethereum
// contracts used in the Berlin release.
var PrecompiledContractsBerlin = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{0x1}): &ecrecover{},
common.BytesToAddress([]byte{0x2}): &sha256hash{},
common.BytesToAddress([]byte{0x3}): &ripemd160hash{},
common.BytesToAddress([]byte{0x4}): &dataCopy{},
common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: true},
common.BytesToAddress([]byte{0x6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{0x7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{0x9}): &blake2F{},
common.BytesToAddress([]byte{0x1}): &ecrecover{},
common.BytesToAddress([]byte{0x2}): &sha256hash{},
common.BytesToAddress([]byte{0x3}): &ripemd160hash{},
common.BytesToAddress([]byte{0x4}): &dataCopy{},
common.BytesToAddress([]byte{0x5}): &bigModExp{eip2565: true},
common.BytesToAddress([]byte{0x6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{0x7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{0x8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{0x9}): &blake2F{},
}

// PrecompiledContractsCancun contains the default set of pre-compiled Ethereum
Expand Down Expand Up @@ -135,13 +136,42 @@ var PrecompiledContractsPrague = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{0x11}): &bls12381Pairing{},
common.BytesToAddress([]byte{0x12}): &bls12381MapG1{},
common.BytesToAddress([]byte{0x13}): &bls12381MapG2{},
common.BytesToAddress([]byte{0x1a}): &ipGraph{},
}

// PrecompiledContractsNostoi contains the set of pre-compiled Ethereum
// contracts used in the iliad nostoi release.
var PrecompiledContractsNostoi = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{0x01}): &ecrecover{},
common.BytesToAddress([]byte{0x02}): &sha256hash{},
common.BytesToAddress([]byte{0x03}): &ripemd160hash{},
common.BytesToAddress([]byte{0x04}): &dataCopy{},
common.BytesToAddress([]byte{0x05}): &bigModExp{eip2565: true},
common.BytesToAddress([]byte{0x06}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{0x07}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{0x08}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{0x09}): &blake2F{},
common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{},
common.BytesToAddress([]byte{0x0b}): &bls12381G1Add{},
common.BytesToAddress([]byte{0x0c}): &bls12381G1Mul{},
common.BytesToAddress([]byte{0x0d}): &bls12381G1MultiExp{},
common.BytesToAddress([]byte{0x0e}): &bls12381G2Add{},
common.BytesToAddress([]byte{0x0f}): &bls12381G2Mul{},
common.BytesToAddress([]byte{0x10}): &bls12381G2MultiExp{},
common.BytesToAddress([]byte{0x11}): &bls12381Pairing{},
common.BytesToAddress([]byte{0x12}): &bls12381MapG1{},
common.BytesToAddress([]byte{0x13}): &bls12381MapG2{},
common.BytesToAddress([]byte{0x1a}): &ipGraphDynamicGas{}, // redirect 0x1a to ipGraphDynamicGas
common.BytesToAddress([]byte{0x1b}): &ipGraphWithPolicyKind{},
common.BytesToAddress([]byte{0x01, 0x00}): &p256Verify{},
}

var PrecompiledContractsBLS = PrecompiledContractsPrague

var PrecompiledContractsVerkle = PrecompiledContractsPrague

var (
PrecompiledAddressesNostoi []common.Address
PrecompiledAddressesPrague []common.Address
PrecompiledAddressesCancun []common.Address
PrecompiledAddressesBerlin []common.Address
Expand Down Expand Up @@ -169,11 +199,16 @@ func init() {
for k := range PrecompiledContractsPrague {
PrecompiledAddressesPrague = append(PrecompiledAddressesPrague, k)
}
for k := range PrecompiledContractsNostoi {
PrecompiledAddressesNostoi = append(PrecompiledAddressesNostoi, k)
}
}

// ActivePrecompiles returns the precompiles enabled with the current configuration.
func ActivePrecompiles(rules params.Rules) []common.Address {
switch {
case rules.IsStoryNostoi:
return PrecompiledAddressesNostoi
case rules.IsPrague:
return PrecompiledAddressesPrague
case rules.IsCancun:
Expand Down Expand Up @@ -1227,3 +1262,39 @@ func kZGToVersionedHash(kzg kzg4844.Commitment) common.Hash {

return h
}

// P256VERIFY (secp256r1 signature verification)
// implemented as a native contract
type p256Verify struct{}

// RequiredGas returns the gas required to execute the precompiled contract
func (c *p256Verify) RequiredGas(input []byte) uint64 {
return params.P256VerifyGas
}

// Run executes the precompiled contract with the given input and EVM context, returning the output and the used gas
func (c *p256Verify) Run(evm *EVM, input []byte) ([]byte, error) {
// Required input length is 160 bytes
const p256VerifyInputLength = 160

// Check the input length
if len(input) != p256VerifyInputLength {
// Input length is invalid

return nil, nil
}

// Extract the hash, r, s, x, y from the input
hash := input[0:32]
r, s := new(big.Int).SetBytes(input[32:64]), new(big.Int).SetBytes(input[64:96])
x, y := new(big.Int).SetBytes(input[96:128]), new(big.Int).SetBytes(input[128:160])

// Verify the secp256r1 signature
if secp256r1.Verify(hash, r, s, x, y) {
// Signature is valid
return common.LeftPadBytes([]byte{1}, 32), nil
} else {
// Signature is invalid
return nil, nil
}
}
14 changes: 14 additions & 0 deletions core/vm/contracts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ var allPrecompiles = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{9}): &blake2F{},
common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{},

common.BytesToAddress([]byte{0x01, 0x00}): &p256Verify{},

common.BytesToAddress([]byte{0x0f, 0x0a}): &bls12381G1Add{},
common.BytesToAddress([]byte{0x0f, 0x0b}): &bls12381G1Mul{},
common.BytesToAddress([]byte{0x0f, 0x0c}): &bls12381G1MultiExp{},
Expand Down Expand Up @@ -425,3 +427,15 @@ func BenchmarkPrecompiledBLS12381G2MultiExpWorstCase(b *testing.B) {
}
benchmarkPrecompiled("f0f", testcase, b)
}

// Benchmarks the sample inputs from the P256VERIFY precompile.
func BenchmarkPrecompiledP256Verify(bench *testing.B) {
t := precompiledTest{
Input: "4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e",
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
Name: "p256Verify",
}
benchmarkPrecompiled("100", t, bench)
}

func TestPrecompiledP256Verify(t *testing.T) { testJson("p256Verify", "100", t) }
2 changes: 2 additions & 0 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ type (
func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
var precompiles map[common.Address]PrecompiledContract
switch {
case evm.chainRules.IsStoryNostoi:
precompiles = PrecompiledContractsNostoi
case evm.chainRules.IsVerkle:
precompiles = PrecompiledContractsVerkle
case evm.chainRules.IsPrague:
Expand Down
Loading

0 comments on commit a54ef9e

Please sign in to comment.