diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 237450ea96..24f1b738ca 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/bn256" "github.com/ethereum/go-ethereum/params" + "golang.org/x/crypto/ed25519" "golang.org/x/crypto/ripemd160" ) @@ -59,6 +60,20 @@ var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{8}): &bn256Pairing{}, } +// PrecompiledContractsConstantinople contains the default set of pre-compiled Ethereum +// contracts used in the Constantinople release. +var PrecompiledContractsConstantinople = map[common.Address]PrecompiledContract{ + common.BytesToAddress([]byte{1}): &ecrecover{}, + common.BytesToAddress([]byte{2}): &sha256hash{}, + common.BytesToAddress([]byte{3}): &ripemd160hash{}, + common.BytesToAddress([]byte{4}): &dataCopy{}, + common.BytesToAddress([]byte{5}): &bigModExp{}, + common.BytesToAddress([]byte{6}): &bn256Add{}, + common.BytesToAddress([]byte{7}): &bn256ScalarMul{}, + common.BytesToAddress([]byte{8}): &bn256Pairing{}, + common.BytesToAddress([]byte{9}): &ed25519Verify{}, +} + // RunPrecompiledContract runs and evaluates the output of a precompiled contract. func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) { gas := p.RequiredGas(input) @@ -358,3 +373,26 @@ func (c *bn256Pairing) Run(input []byte) ([]byte, error) { } return false32Byte, nil } + +// ed25519Verify implements a native Ed25519 signature verification. +type ed25519Verify struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +func (c *ed25519Verify) RequiredGas(input []byte) uint64 { + return params.Ed25519VerifyGas +} + +func (c *ed25519Verify) Run(input []byte) ([]byte, error) { + // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-665.md#specification + message := getData(input, 0, 32) + publicKey := getData(input, 32, 32) + sig := getData(input, 64, 64) + + // Verify the Ed25519 signature against the public key and message + // and return result + // https://godoc.org/golang.org/x/crypto/ed25519#Verify + if ed25519.Verify(publicKey, message, sig) { + return true32Byte, nil + } + return false32Byte, nil +} diff --git a/core/vm/evm.go b/core/vm/evm.go index 96676c314a..3e0cc28150 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -45,6 +45,9 @@ func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) { if evm.ChainConfig().IsByzantium(evm.BlockNumber) { precompiles = PrecompiledContractsByzantium } + if evm.ChainConfig().IsConstantinople(evm.BlockNumber) { + precompiles = PrecompiledContractsConstantinople + } if p := precompiles[*contract.CodeAddr]; p != nil { return RunPrecompiledContract(p, input, contract) } @@ -159,6 +162,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas if evm.ChainConfig().IsByzantium(evm.BlockNumber) { precompiles = PrecompiledContractsByzantium } + if evm.ChainConfig().IsConstantinople(evm.BlockNumber) { + precompiles = PrecompiledContractsConstantinople + } if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 { return nil, gas, nil } diff --git a/params/protocol_params.go b/params/protocol_params.go index 5a0b14d61a..8655bcc983 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -77,6 +77,7 @@ const ( Bn256ScalarMulGas uint64 = 40000 // Gas needed for an elliptic curve scalar multiplication Bn256PairingBaseGas uint64 = 100000 // Base price for an elliptic curve pairing check Bn256PairingPerPointGas uint64 = 80000 // Per-point price for an elliptic curve pairing check + Ed25519VerifyGas uint64 = 2000 // Ed25519 signature verification gas price ) var (