From dca3502392b3f481e20dd4dfa3856ae75b6a2b78 Mon Sep 17 00:00:00 2001 From: yperbasis Date: Wed, 13 Dec 2023 14:58:26 +0100 Subject: [PATCH 01/11] newPolycunInstructionSet --- core/vm/jump_table.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 047c9f53845..8aa12c6e2b7 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -99,12 +99,18 @@ func newPragueInstructionSet() JumpTable { // constantinople, istanbul, petersburg, berlin, london, paris, shanghai, // and cancun instructions. func newCancunInstructionSet() JumpTable { + instructionSet := newPolycunInstructionSet() + enable4844(&instructionSet) // BLOBHASH opcode + enable7516(&instructionSet) // BLOBBASEFEE opcode + validateAndFillMaxStack(&instructionSet) + return instructionSet +} + +func newPolycunInstructionSet() JumpTable { instructionSet := newShanghaiInstructionSet() enable1153(&instructionSet) // Transient storage opcodes - enable4844(&instructionSet) // BLOBHASH opcode enable5656(&instructionSet) // MCOPY opcode enable6780(&instructionSet) // SELFDESTRUCT only in same transaction - enable7516(&instructionSet) // BLOBBASEFEE opcode validateAndFillMaxStack(&instructionSet) return instructionSet } From 800ea5130e9c074e624c12effede4ec716d5b6d3 Mon Sep 17 00:00:00 2001 From: yperbasis Date: Wed, 13 Dec 2023 16:02:02 +0100 Subject: [PATCH 02/11] Napoli hard fork --- core/forkid/forkid.go | 9 +++++++-- core/vm/interpreter.go | 2 ++ core/vm/jump_table.go | 5 +++-- erigon-lib/chain/chain_config.go | 13 ++++++++++++- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/core/forkid/forkid.go b/core/forkid/forkid.go index 433c9221b18..63eeb174dfe 100644 --- a/core/forkid/forkid.go +++ b/core/forkid/forkid.go @@ -244,8 +244,13 @@ func GatherForks(config *chain.Config, genesisTime uint64) (heightForks []uint64 heightForks = append(heightForks, *config.Aura.PosdaoTransition) } - if config.Bor != nil && config.Bor.AgraBlock != nil { - heightForks = append(heightForks, config.Bor.AgraBlock.Uint64()) + if config.Bor != nil { + if config.Bor.AgraBlock != nil { + heightForks = append(heightForks, config.Bor.AgraBlock.Uint64()) + } + if config.Bor.NapoliBlock != nil { + heightForks = append(heightForks, config.Bor.NapoliBlock.Uint64()) + } } // Sort the fork block numbers & times to permit chronological XOR diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 161068229bf..e2cf325c105 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -128,6 +128,8 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { jt = &pragueInstructionSet case evm.ChainRules().IsCancun: jt = &cancunInstructionSet + case evm.ChainRules().IsNapoli: + jt = &napoliInstructionSet case evm.ChainRules().IsShanghai: jt = &shanghaiInstructionSet case evm.ChainRules().IsLondon: diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 8aa12c6e2b7..806ae494133 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -61,6 +61,7 @@ var ( berlinInstructionSet = newBerlinInstructionSet() londonInstructionSet = newLondonInstructionSet() shanghaiInstructionSet = newShanghaiInstructionSet() + napoliInstructionSet = newNapoliInstructionSet() cancunInstructionSet = newCancunInstructionSet() pragueInstructionSet = newPragueInstructionSet() ) @@ -99,14 +100,14 @@ func newPragueInstructionSet() JumpTable { // constantinople, istanbul, petersburg, berlin, london, paris, shanghai, // and cancun instructions. func newCancunInstructionSet() JumpTable { - instructionSet := newPolycunInstructionSet() + instructionSet := newNapoliInstructionSet() enable4844(&instructionSet) // BLOBHASH opcode enable7516(&instructionSet) // BLOBBASEFEE opcode validateAndFillMaxStack(&instructionSet) return instructionSet } -func newPolycunInstructionSet() JumpTable { +func newNapoliInstructionSet() JumpTable { instructionSet := newShanghaiInstructionSet() enable1153(&instructionSet) // Transient storage opcodes enable5656(&instructionSet) // MCOPY opcode diff --git a/erigon-lib/chain/chain_config.go b/erigon-lib/chain/chain_config.go index 6e93c59ff90..0a77f4150c0 100644 --- a/erigon-lib/chain/chain_config.go +++ b/erigon-lib/chain/chain_config.go @@ -209,6 +209,13 @@ func (c *Config) IsAgra(num uint64) bool { return isForked(c.Bor.AgraBlock, num) } +func (c *Config) IsNapoli(num uint64) bool { + if c == nil || c.Bor == nil { + return false + } + return isForked(c.Bor.NapoliBlock, num) +} + // IsCancun returns whether time is either equal to the Cancun fork time or greater. func (c *Config) IsCancun(time uint64) bool { return isForked(c.CancunTime, time) @@ -468,6 +475,7 @@ type BorConfig struct { DelhiBlock *big.Int `json:"delhiBlock"` // Delhi switch block (nil = no fork, 0 = already on delhi) IndoreBlock *big.Int `json:"indoreBlock"` // Indore switch block (nil = no fork, 0 = already on indore) AgraBlock *big.Int `json:"agraBlock"` // Agra switch block (nil = no fork, 0 = already in agra) + NapoliBlock *big.Int `json:"NapoliBlock"` // Napoli switch block (nil = no fork, 0 = already in napoli) StateSyncConfirmationDelay map[string]uint64 `json:"stateSyncConfirmationDelay"` // StateSync Confirmation Delay, in seconds, to calculate `to` ParallelUniverseBlock *big.Int `json:"parallelUniverseBlock"` // TODO: update all occurrence, change name and finalize number (hardfork for block-stm related changes) @@ -641,7 +649,9 @@ type Rules struct { ChainID *big.Int IsHomestead, IsTangerineWhistle, IsSpuriousDragon bool IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool - IsBerlin, IsLondon, IsShanghai, IsCancun, IsPrague bool + IsBerlin, IsLondon, IsShanghai bool + IsCancun, IsNapoli bool + IsPrague bool IsAura bool } @@ -665,6 +675,7 @@ func (c *Config) Rules(num uint64, time uint64) *Rules { IsLondon: c.IsLondon(num), IsShanghai: c.IsShanghai(time) || c.IsAgra(num), IsCancun: c.IsCancun(time), + IsNapoli: c.IsNapoli(num), IsPrague: c.IsPrague(time), IsAura: c.Aura != nil, } From 8a991737d7f4589b1a20efda36309b0a536d4ba9 Mon Sep 17 00:00:00 2001 From: yperbasis Date: Wed, 13 Dec 2023 16:20:25 +0100 Subject: [PATCH 03/11] fix letter cases --- erigon-lib/chain/chain_config.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/erigon-lib/chain/chain_config.go b/erigon-lib/chain/chain_config.go index 0a77f4150c0..319cc1e1eb5 100644 --- a/erigon-lib/chain/chain_config.go +++ b/erigon-lib/chain/chain_config.go @@ -471,11 +471,11 @@ type BorConfig struct { OverrideStateSyncRecords map[string]int `json:"overrideStateSyncRecords"` // override state records count BlockAlloc map[string]interface{} `json:"blockAlloc"` - JaipurBlock *big.Int `json:"jaipurBlock"` // Jaipur switch block (nil = no fork, 0 = already on jaipur) - DelhiBlock *big.Int `json:"delhiBlock"` // Delhi switch block (nil = no fork, 0 = already on delhi) - IndoreBlock *big.Int `json:"indoreBlock"` // Indore switch block (nil = no fork, 0 = already on indore) - AgraBlock *big.Int `json:"agraBlock"` // Agra switch block (nil = no fork, 0 = already in agra) - NapoliBlock *big.Int `json:"NapoliBlock"` // Napoli switch block (nil = no fork, 0 = already in napoli) + JaipurBlock *big.Int `json:"jaipurBlock"` // Jaipur switch block (nil = no fork, 0 = already on Jaipur) + DelhiBlock *big.Int `json:"delhiBlock"` // Delhi switch block (nil = no fork, 0 = already on Delhi) + IndoreBlock *big.Int `json:"indoreBlock"` // Indore switch block (nil = no fork, 0 = already on Indore) + AgraBlock *big.Int `json:"agraBlock"` // Agra switch block (nil = no fork, 0 = already on Agra) + NapoliBlock *big.Int `json:"napoliBlock"` // Napoli switch block (nil = no fork, 0 = already on Napoli) StateSyncConfirmationDelay map[string]uint64 `json:"stateSyncConfirmationDelay"` // StateSync Confirmation Delay, in seconds, to calculate `to` ParallelUniverseBlock *big.Int `json:"parallelUniverseBlock"` // TODO: update all occurrence, change name and finalize number (hardfork for block-stm related changes) From 4f82720ef94e4236ef49ce69897fd73419876f67 Mon Sep 17 00:00:00 2001 From: yperbasis Date: Thu, 14 Dec 2023 10:01:52 +0100 Subject: [PATCH 04/11] cosmetics --- erigon-lib/chain/chain_config.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/erigon-lib/chain/chain_config.go b/erigon-lib/chain/chain_config.go index 319cc1e1eb5..1e3c209c9ee 100644 --- a/erigon-lib/chain/chain_config.go +++ b/erigon-lib/chain/chain_config.go @@ -646,13 +646,13 @@ func asSprints(configSprints map[string]uint64) sprints { // Rules is a one time interface meaning that it shouldn't be used in between transition // phases. type Rules struct { - ChainID *big.Int - IsHomestead, IsTangerineWhistle, IsSpuriousDragon bool - IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool - IsBerlin, IsLondon, IsShanghai bool - IsCancun, IsNapoli bool - IsPrague bool - IsAura bool + ChainID *big.Int + IsHomestead, IsTangerineWhistle, IsSpuriousDragon bool + IsByzantium, IsConstantinople, IsPetersburg bool + IsIstanbul, IsBerlin, IsLondon, IsShanghai bool + IsCancun, IsNapoli bool + IsPrague bool + IsAura bool } // Rules ensures c's ChainID is not nil and returns a new Rules instance From ccb633f285e1eac482e9174e0858504e5d7b2d94 Mon Sep 17 00:00:00 2001 From: yperbasis Date: Mon, 15 Jan 2024 11:40:57 +0100 Subject: [PATCH 05/11] post-merge fix --- polygon/bor/borcfg/bor_config.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/polygon/bor/borcfg/bor_config.go b/polygon/bor/borcfg/bor_config.go index d73f20a830a..965506c2f5f 100644 --- a/polygon/bor/borcfg/bor_config.go +++ b/polygon/bor/borcfg/bor_config.go @@ -20,10 +20,11 @@ type BorConfig struct { OverrideStateSyncRecords map[string]int `json:"overrideStateSyncRecords"` // override state records count BlockAlloc map[string]interface{} `json:"blockAlloc"` - JaipurBlock *big.Int `json:"jaipurBlock"` // Jaipur switch block (nil = no fork, 0 = already on jaipur) - DelhiBlock *big.Int `json:"delhiBlock"` // Delhi switch block (nil = no fork, 0 = already on delhi) - IndoreBlock *big.Int `json:"indoreBlock"` // Indore switch block (nil = no fork, 0 = already on indore) - AgraBlock *big.Int `json:"agraBlock"` // Agra switch block (nil = no fork, 0 = already in agra) + JaipurBlock *big.Int `json:"jaipurBlock"` // Jaipur switch block (nil = no fork, 0 = already on Jaipur) + DelhiBlock *big.Int `json:"delhiBlock"` // Delhi switch block (nil = no fork, 0 = already on Delhi) + IndoreBlock *big.Int `json:"indoreBlock"` // Indore switch block (nil = no fork, 0 = already on Indore) + AgraBlock *big.Int `json:"agraBlock"` // Agra switch block (nil = no fork, 0 = already on Agra) + NapoliBlock *big.Int `json:"napoliBlock"` // Napoli switch block (nil = no fork, 0 = already on Napoli) StateSyncConfirmationDelay map[string]uint64 `json:"stateSyncConfirmationDelay"` // StateSync Confirmation Delay, in seconds, to calculate `to` ParallelUniverseBlock *big.Int `json:"parallelUniverseBlock"` // TODO: update all occurrence, change name and finalize number (hardfork for block-stm related changes) @@ -126,6 +127,15 @@ func (c *BorConfig) GetAgraBlock() *big.Int { return c.AgraBlock } +// Refer to https://forum.polygon.technology/t/pip-33-napoli-upgrade +func (c *BorConfig) IsNapoli(num uint64) bool { + return isForked(c.NapoliBlock, num) +} + +func (c *BorConfig) GetNapoliBlock() *big.Int { + return c.NapoliBlock +} + // TODO: modify this function once the block number is finalized func (c *BorConfig) IsParallelUniverse(number uint64) bool { if c.ParallelUniverseBlock != nil { From d3cb31a9258376d36fb1a06c1d630ac0d75fdfd3 Mon Sep 17 00:00:00 2001 From: yperbasis Date: Mon, 15 Jan 2024 12:10:06 +0100 Subject: [PATCH 06/11] Bor headers shouldn't have Cancun fields --- polygon/bor/bor.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polygon/bor/bor.go b/polygon/bor/bor.go index df251b81daa..f9d6d9700f0 100644 --- a/polygon/bor/bor.go +++ b/polygon/bor/bor.go @@ -552,7 +552,7 @@ func ValidateHeaderUnusedFields(header *types.Header) error { return consensus.ErrUnexpectedWithdrawals } - return nil + return misc.VerifyAbsenceOfCancunHeaderFields(header) } // verifyCascadingFields verifies all the header fields that are not standalone, From 941afb22194b3d0620d0baa4060251662c5012ad Mon Sep 17 00:00:00 2001 From: yperbasis Date: Mon, 15 Jan 2024 15:59:22 +0100 Subject: [PATCH 07/11] Merge ParallelUniverse into NapoliBlock --- core/types/block_test.go | 2 +- polygon/bor/bor.go | 6 +++--- polygon/bor/borcfg/bor_config.go | 13 ------------- 3 files changed, 4 insertions(+), 17 deletions(-) diff --git a/core/types/block_test.go b/core/types/block_test.go index 4e2a8303d3f..9db421134ac 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -42,7 +42,7 @@ import ( // the following 2 functions are replica for the test // This is a replica of `bor.GetValidatorBytes` function -// This was needed because currently, `IsParallelUniverse` will always return false. +// This was needed because currently, `IsNapoli` will always return false. func GetValidatorBytesTest(h *Header) []byte { if len(h.Extra) < ExtraVanityLength+ExtraSealLength { log.Error("length of extra is less than vanity and seal") diff --git a/polygon/bor/bor.go b/polygon/bor/bor.go index f9d6d9700f0..af621a6c6c1 100644 --- a/polygon/bor/bor.go +++ b/polygon/bor/bor.go @@ -899,7 +899,7 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header, s // sort validator by address sort.Sort(valset.ValidatorsByAddress(newValidators)) - if c.config.IsParallelUniverse(header.Number.Uint64()) { + if c.config.IsNapoli(header.Number.Uint64()) { // PIP-16: Transaction Dependency Data var tempValidatorBytes []byte for _, validator := range newValidators { @@ -923,7 +923,7 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header, s header.Extra = append(header.Extra, validator.HeaderBytes()...) } } - } else if c.config.IsParallelUniverse(header.Number.Uint64()) { + } else if c.config.IsNapoli(header.Number.Uint64()) { // PIP-16: Transaction Dependency Data blockExtraData := &BlockExtraData{ ValidatorBytes: nil, TxDependency: nil, @@ -1578,7 +1578,7 @@ func GetTxDependency(b *types.Block) [][]uint64 { func GetValidatorBytes(h *types.Header, config *borcfg.BorConfig) []byte { tempExtra := h.Extra - if !config.IsParallelUniverse(h.Number.Uint64()) { + if !config.IsNapoli(h.Number.Uint64()) { return tempExtra[types.ExtraVanityLength : len(tempExtra)-types.ExtraSealLength] } diff --git a/polygon/bor/borcfg/bor_config.go b/polygon/bor/borcfg/bor_config.go index 965506c2f5f..6c02f069b82 100644 --- a/polygon/bor/borcfg/bor_config.go +++ b/polygon/bor/borcfg/bor_config.go @@ -27,8 +27,6 @@ type BorConfig struct { NapoliBlock *big.Int `json:"napoliBlock"` // Napoli switch block (nil = no fork, 0 = already on Napoli) StateSyncConfirmationDelay map[string]uint64 `json:"stateSyncConfirmationDelay"` // StateSync Confirmation Delay, in seconds, to calculate `to` - ParallelUniverseBlock *big.Int `json:"parallelUniverseBlock"` // TODO: update all occurrence, change name and finalize number (hardfork for block-stm related changes) - sprints sprints } @@ -136,17 +134,6 @@ func (c *BorConfig) GetNapoliBlock() *big.Int { return c.NapoliBlock } -// TODO: modify this function once the block number is finalized -func (c *BorConfig) IsParallelUniverse(number uint64) bool { - if c.ParallelUniverseBlock != nil { - if c.ParallelUniverseBlock.Cmp(big.NewInt(0)) == 0 { - return false - } - } - - return isForked(c.ParallelUniverseBlock, number) -} - func (c *BorConfig) CalculateStateSyncDelay(number uint64) uint64 { return borKeyValueConfigHelper(c.StateSyncConfirmationDelay, number) } From 6054e1ce0908ecb11d647d06ac66b8bf17650dc1 Mon Sep 17 00:00:00 2001 From: Anshal Shukla Date: Wed, 17 Jan 2024 17:06:16 +0530 Subject: [PATCH 08/11] add: eip-7212/pip-27 --- core/vm/contracts.go | 55 ++++++++++++++++++- core/vm/contracts_test.go | 57 +++++++++++++------- core/vm/evm.go | 2 + core/vm/testdata/precompiles/p256Verify.json | 37 +++++++++++++ crypto/secp256r1/publickey.go | 26 +++++++++ crypto/secp256r1/verifier.go | 21 ++++++++ erigon-lib/txpool/pool.go | 2 +- params/protocol_params.go | 3 ++ 8 files changed, 181 insertions(+), 22 deletions(-) create mode 100644 core/vm/testdata/precompiles/p256Verify.json create mode 100644 crypto/secp256r1/publickey.go create mode 100644 crypto/secp256r1/verifier.go diff --git a/core/vm/contracts.go b/core/vm/contracts.go index ccc55074486..17bbb717e74 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -20,9 +20,10 @@ import ( "crypto/sha256" "encoding/binary" "errors" - "github.com/ledgerwatch/erigon-lib/crypto/blake2b" "math/big" + "github.com/ledgerwatch/erigon-lib/crypto/blake2b" + "github.com/holiman/uint256" "github.com/ledgerwatch/erigon-lib/chain" @@ -34,6 +35,7 @@ import ( "github.com/ledgerwatch/erigon/crypto" "github.com/ledgerwatch/erigon/crypto/bls12381" "github.com/ledgerwatch/erigon/crypto/bn256" + "github.com/ledgerwatch/erigon/crypto/secp256r1" "github.com/ledgerwatch/erigon/params" @@ -112,6 +114,20 @@ var PrecompiledContractsCancun = map[libcommon.Address]PrecompiledContract{ libcommon.BytesToAddress([]byte{0x0a}): &pointEvaluation{}, } +var PrecompiledContractsNapoli = map[libcommon.Address]PrecompiledContract{ + libcommon.BytesToAddress([]byte{0x01}): &ecrecover{}, + libcommon.BytesToAddress([]byte{0x02}): &sha256hash{}, + libcommon.BytesToAddress([]byte{0x03}): &ripemd160hash{}, + libcommon.BytesToAddress([]byte{0x04}): &dataCopy{}, + libcommon.BytesToAddress([]byte{0x05}): &bigModExp{eip2565: true}, + libcommon.BytesToAddress([]byte{0x06}): &bn256AddIstanbul{}, + libcommon.BytesToAddress([]byte{0x07}): &bn256ScalarMulIstanbul{}, + libcommon.BytesToAddress([]byte{0x08}): &bn256PairingIstanbul{}, + libcommon.BytesToAddress([]byte{0x09}): &blake2F{}, + libcommon.BytesToAddress([]byte{0x0a}): &pointEvaluation{}, + libcommon.BytesToAddress([]byte{0x01, 0x00}): &p256Verify{}, +} + // PrecompiledContractsBLS contains the set of pre-compiled Ethereum // contracts specified in EIP-2537. These are exported for testing purposes. var PrecompiledContractsBLS = map[libcommon.Address]PrecompiledContract{ @@ -127,6 +143,7 @@ var PrecompiledContractsBLS = map[libcommon.Address]PrecompiledContract{ } var ( + PrecompiledAddressesNapoli []libcommon.Address PrecompiledAddressesCancun []libcommon.Address PrecompiledAddressesBerlin []libcommon.Address PrecompiledAddressesIstanbul []libcommon.Address @@ -155,6 +172,8 @@ func init() { // ActivePrecompiles returns the precompiles enabled with the current configuration. func ActivePrecompiles(rules *chain.Rules) []libcommon.Address { switch { + case rules.IsNapoli: + return PrecompiledAddressesNapoli case rules.IsCancun: return PrecompiledAddressesCancun case rules.IsBerlin: @@ -1098,3 +1117,37 @@ func (c *pointEvaluation) RequiredGas(input []byte) uint64 { func (c *pointEvaluation) Run(input []byte) ([]byte, error) { return libkzg.PointEvaluationPrecompile(input) } + +// 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 given 160 bytes of param, returning the output and the used gas +func (c *p256Verify) Run(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(big.NewInt(1).Bytes(), 32), nil + } else { + // Signature is invalid + return nil, nil + } +} diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index a9ca23ef1b6..d9b05437a71 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -48,26 +48,27 @@ type precompiledFailureTest struct { // allPrecompiles does not map to the actual set of precompiles, as it also contains // repriced versions of precompiles at certain slots var allPrecompiles = map[libcommon.Address]PrecompiledContract{ - libcommon.BytesToAddress([]byte{1}): &ecrecover{}, - libcommon.BytesToAddress([]byte{2}): &sha256hash{}, - libcommon.BytesToAddress([]byte{3}): &ripemd160hash{}, - libcommon.BytesToAddress([]byte{4}): &dataCopy{}, - libcommon.BytesToAddress([]byte{5}): &bigModExp{eip2565: false}, - libcommon.BytesToAddress([]byte{0xf5}): &bigModExp{eip2565: true}, - libcommon.BytesToAddress([]byte{6}): &bn256AddIstanbul{}, - libcommon.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{}, - libcommon.BytesToAddress([]byte{8}): &bn256PairingIstanbul{}, - libcommon.BytesToAddress([]byte{9}): &blake2F{}, - libcommon.BytesToAddress([]byte{10}): &bls12381G1Add{}, - libcommon.BytesToAddress([]byte{11}): &bls12381G1Mul{}, - libcommon.BytesToAddress([]byte{12}): &bls12381G1MultiExp{}, - libcommon.BytesToAddress([]byte{13}): &bls12381G2Add{}, - libcommon.BytesToAddress([]byte{14}): &bls12381G2Mul{}, - libcommon.BytesToAddress([]byte{15}): &bls12381G2MultiExp{}, - libcommon.BytesToAddress([]byte{16}): &bls12381Pairing{}, - libcommon.BytesToAddress([]byte{17}): &bls12381MapG1{}, - libcommon.BytesToAddress([]byte{18}): &bls12381MapG2{}, - libcommon.BytesToAddress([]byte{20}): &pointEvaluation{}, + libcommon.BytesToAddress([]byte{1}): &ecrecover{}, + libcommon.BytesToAddress([]byte{2}): &sha256hash{}, + libcommon.BytesToAddress([]byte{3}): &ripemd160hash{}, + libcommon.BytesToAddress([]byte{4}): &dataCopy{}, + libcommon.BytesToAddress([]byte{5}): &bigModExp{eip2565: false}, + libcommon.BytesToAddress([]byte{0xf5}): &bigModExp{eip2565: true}, + libcommon.BytesToAddress([]byte{6}): &bn256AddIstanbul{}, + libcommon.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{}, + libcommon.BytesToAddress([]byte{8}): &bn256PairingIstanbul{}, + libcommon.BytesToAddress([]byte{9}): &blake2F{}, + libcommon.BytesToAddress([]byte{10}): &bls12381G1Add{}, + libcommon.BytesToAddress([]byte{11}): &bls12381G1Mul{}, + libcommon.BytesToAddress([]byte{12}): &bls12381G1MultiExp{}, + libcommon.BytesToAddress([]byte{13}): &bls12381G2Add{}, + libcommon.BytesToAddress([]byte{14}): &bls12381G2Mul{}, + libcommon.BytesToAddress([]byte{15}): &bls12381G2MultiExp{}, + libcommon.BytesToAddress([]byte{16}): &bls12381Pairing{}, + libcommon.BytesToAddress([]byte{17}): &bls12381MapG1{}, + libcommon.BytesToAddress([]byte{18}): &bls12381MapG2{}, + libcommon.BytesToAddress([]byte{20}): &pointEvaluation{}, + libcommon.BytesToAddress([]byte{0x01, 0x00}): &p256Verify{}, } // EIP-152 test vectors @@ -400,3 +401,19 @@ func BenchmarkPrecompiledBLS12381G2MultiExpWorstCase(b *testing.B) { } benchmarkPrecompiled(b, "0f", testcase) } + +// Benchmarks the sample inputs from the P256VERIFY precompile. +func BenchmarkPrecompiledP256Verify(b *testing.B) { + testcase := precompiledTest{ + Input: "4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e", + Expected: "0000000000000000000000000000000000000000000000000000000000000001", + Name: "p256Verify", + } + benchmarkPrecompiled(b, "100", testcase) +} + +func TestPrecompiledP256Verify(t *testing.T) { + t.Parallel() + + testJson("p256Verify", "100", t) +} diff --git a/core/vm/evm.go b/core/vm/evm.go index dc5dce586c8..56ffc3bc2fa 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -37,6 +37,8 @@ var emptyCodeHash = crypto.Keccak256Hash(nil) func (evm *EVM) precompile(addr libcommon.Address) (PrecompiledContract, bool) { var precompiles map[libcommon.Address]PrecompiledContract switch { + case evm.chainRules.IsNapoli: + precompiles = PrecompiledContractsNapoli case evm.chainRules.IsCancun: precompiles = PrecompiledContractsCancun case evm.chainRules.IsBerlin: diff --git a/core/vm/testdata/precompiles/p256Verify.json b/core/vm/testdata/precompiles/p256Verify.json new file mode 100644 index 00000000000..54723147a51 --- /dev/null +++ b/core/vm/testdata/precompiles/p256Verify.json @@ -0,0 +1,37 @@ +[ + { + "Input": "4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Gas": 3450, + "Name": "CallP256Verify", + "NoBenchmark": false + }, + { + "Input": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9414de3726ee4d237b410c1d85ebcb05553dc578561d9f7942b7250795beb9b9027b657067322fc00ab35263fde0acabf998cd9fcf1282df9555f85dba7bdbbe2dc90f74c9e210bc3e0c60aeaa03729c9e6acde4a048ee58fd2e466c1e7b0374e606b8c22ad2985df7d792ff344f03ce94a079da801006b13640bc5af7932a7b9", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Gas": 3450, + "Name": "CallP256Verify", + "NoBenchmark": false + }, + { + "Input": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9b35d6a4f7f6fc5620c97d4287696f5174b3d37fa537b74b5fc26997ba79c725d62fe5e5fe6da76eec924e822c5ef853ede6c17069a9e9133a38f87d61599f68e7d5f3c812a255436846ee84a262b79ec4d0783afccf2433deabdca9ecf62bef5ff24e90988c7f139d378549c3a8bc6c94e6a1c911c1e02e6f48ed65aaf3d296e", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Gas": 3450, + "Name": "CallP256Verify", + "NoBenchmark": false + }, + { + "Input": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9c29c3df6ce3431b6f030b1b68b1589508ad9d1a149830489c638653aa4b08af93f6e86a9a7643403b6f5c593410d9f7234a8cd27309bce90447073ce17476850615ff147863bc8652be1e369444f90bbc5f9df05a26362e609f73ab1f1839fe3cd34fd2ae672c110671d49115825fc56b5148321aabe5ba39f2b46f71149cff9", + "Expected": "", + "Gas": 3450, + "Name": "CallP256Verify", + "NoBenchmark": false + }, + { + "Input": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", + "Expected": "", + "Gas": 3450, + "Name": "CallP256Verify", + "NoBenchmark": false + } +] \ No newline at end of file diff --git a/crypto/secp256r1/publickey.go b/crypto/secp256r1/publickey.go new file mode 100644 index 00000000000..9b84044efa0 --- /dev/null +++ b/crypto/secp256r1/publickey.go @@ -0,0 +1,26 @@ +package secp256r1 + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "math/big" +) + +// Generates approptiate public key format from given coordinates +func newPublicKey(x, y *big.Int) *ecdsa.PublicKey { + // Check if the given coordinates are valid + if x == nil || y == nil || !elliptic.P256().IsOnCurve(x, y) { + return nil + } + + // Check if the given coordinates are the reference point (infinity) + if x.Sign() == 0 && y.Sign() == 0 { + return nil + } + + return &ecdsa.PublicKey{ + Curve: elliptic.P256(), + X: x, + Y: y, + } +} diff --git a/crypto/secp256r1/verifier.go b/crypto/secp256r1/verifier.go new file mode 100644 index 00000000000..ccc0786610b --- /dev/null +++ b/crypto/secp256r1/verifier.go @@ -0,0 +1,21 @@ +package secp256r1 + +import ( + "crypto/ecdsa" + "math/big" +) + +// Verifies the given signature (r, s) for the given hash and public key (x, y). +func Verify(hash []byte, r, s, x, y *big.Int) bool { + // Create the public key format + publicKey := newPublicKey(x, y) + + // Check if they are invalid public key coordinates + if publicKey == nil { + return false + } + + // Verify the signature with the public key, + // then return true if it's valid, false otherwise + return ecdsa.Verify(publicKey, hash, r, s) +} diff --git a/erigon-lib/txpool/pool.go b/erigon-lib/txpool/pool.go index 88026073a99..a3eb55f255f 100644 --- a/erigon-lib/txpool/pool.go +++ b/erigon-lib/txpool/pool.go @@ -945,7 +945,7 @@ func (p *TxPool) isShanghai() bool { } func (p *TxPool) isAgra() bool { - // once this flag has been set for the first time we no longer need to check the timestamp + // once this flag has been set for the first time we no longer need to check the block set := p.isPostAgra.Load() if set { return true diff --git a/params/protocol_params.go b/params/protocol_params.go index 33ffda9a94c..8b8c37325ae 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -168,6 +168,9 @@ const ( // EIP-4844: Shard Blob Transactions PointEvaluationGas uint64 = 50000 + + // PIP-27: secp256r1 elliptic curve signature verifier gas price + P256VerifyGas uint64 = 3450 ) // EIP-4788: Beacon block root in the EVM From 95a59b00e10702fd4188b6923b3fb9af550139fc Mon Sep 17 00:00:00 2001 From: yperbasis Date: Wed, 17 Jan 2024 12:47:44 +0100 Subject: [PATCH 09/11] init PrecompiledAddressesNapoli --- core/vm/contracts.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 17bbb717e74..849d644788f 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -167,6 +167,9 @@ func init() { for k := range PrecompiledContractsCancun { PrecompiledAddressesCancun = append(PrecompiledAddressesCancun, k) } + for k := range PrecompiledContractsNapoli { + PrecompiledAddressesNapoli = append(PrecompiledAddressesNapoli, k) + } } // ActivePrecompiles returns the precompiles enabled with the current configuration. From 7ffb7a3f8d37d52de46c6810779b736702aae26e Mon Sep 17 00:00:00 2001 From: yperbasis Date: Wed, 17 Jan 2024 13:32:23 +0100 Subject: [PATCH 10/11] Exclude pointEvaluation precompile from Napoli --- core/vm/contracts.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 849d644788f..adcf9b0d37b 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -124,7 +124,6 @@ var PrecompiledContractsNapoli = map[libcommon.Address]PrecompiledContract{ libcommon.BytesToAddress([]byte{0x07}): &bn256ScalarMulIstanbul{}, libcommon.BytesToAddress([]byte{0x08}): &bn256PairingIstanbul{}, libcommon.BytesToAddress([]byte{0x09}): &blake2F{}, - libcommon.BytesToAddress([]byte{0x0a}): &pointEvaluation{}, libcommon.BytesToAddress([]byte{0x01, 0x00}): &p256Verify{}, } From 70cac3ca4a136ac1d02c9072afbe9e9e8ccca2a2 Mon Sep 17 00:00:00 2001 From: yperbasis Date: Wed, 17 Jan 2024 13:44:48 +0100 Subject: [PATCH 11/11] nitpicking --- core/vm/contracts.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index adcf9b0d37b..b71f949ef1f 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -22,12 +22,11 @@ import ( "errors" "math/big" - "github.com/ledgerwatch/erigon-lib/crypto/blake2b" - "github.com/holiman/uint256" "github.com/ledgerwatch/erigon-lib/chain" libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/crypto/blake2b" libkzg "github.com/ledgerwatch/erigon-lib/crypto/kzg" "github.com/ledgerwatch/erigon/common" @@ -36,7 +35,6 @@ import ( "github.com/ledgerwatch/erigon/crypto/bls12381" "github.com/ledgerwatch/erigon/crypto/bn256" "github.com/ledgerwatch/erigon/crypto/secp256r1" - "github.com/ledgerwatch/erigon/params" //lint:ignore SA1019 Needed for precompile @@ -1147,7 +1145,7 @@ func (c *p256Verify) Run(input []byte) ([]byte, error) { // Verify the secp256r1 signature if secp256r1.Verify(hash, r, s, x, y) { // Signature is valid - return common.LeftPadBytes(big.NewInt(1).Bytes(), 32), nil + return common.LeftPadBytes(big1.Bytes(), 32), nil } else { // Signature is invalid return nil, nil