aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm
diff options
context:
space:
mode:
Diffstat (limited to 'core/vm')
-rw-r--r--core/vm/contracts.go64
-rw-r--r--core/vm/contracts_test.go97
2 files changed, 159 insertions, 2 deletions
diff --git a/core/vm/contracts.go b/core/vm/contracts.go
index 0e4fe0198..875054f89 100644
--- a/core/vm/contracts.go
+++ b/core/vm/contracts.go
@@ -18,12 +18,14 @@ package vm
import (
"crypto/sha256"
+ "encoding/binary"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/crypto/blake2b"
"github.com/ethereum/go-ethereum/crypto/bn256"
"github.com/ethereum/go-ethereum/params"
"golang.org/x/crypto/ripemd160"
@@ -70,6 +72,7 @@ var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
+ common.BytesToAddress([]byte{9}): &blake2F{},
}
// RunPrecompiledContract runs and evaluates the output of a precompiled contract.
@@ -431,3 +434,64 @@ func (c *bn256PairingByzantium) RequiredGas(input []byte) uint64 {
func (c *bn256PairingByzantium) Run(input []byte) ([]byte, error) {
return runBn256Pairing(input)
}
+
+type blake2F struct{}
+
+func (c *blake2F) RequiredGas(input []byte) uint64 {
+ // If the input is malformed, we can't calculate the gas, return 0 and let the
+ // actual call choke and fault.
+ if len(input) != blake2FInputLength {
+ return 0
+ }
+ return uint64(binary.BigEndian.Uint32(input[0:4]))
+}
+
+const (
+ blake2FInputLength = 213
+ blake2FFinalBlockBytes = byte(1)
+ blake2FNonFinalBlockBytes = byte(0)
+)
+
+var (
+ errBlake2FInvalidInputLength = errors.New("invalid input length")
+ errBlake2FInvalidFinalFlag = errors.New("invalid final flag")
+)
+
+func (c *blake2F) Run(input []byte) ([]byte, error) {
+ // Make sure the input is valid (correct lenth and final flag)
+ if len(input) != blake2FInputLength {
+ return nil, errBlake2FInvalidInputLength
+ }
+ if input[212] != blake2FNonFinalBlockBytes && input[212] != blake2FFinalBlockBytes {
+ return nil, errBlake2FInvalidFinalFlag
+ }
+ // Parse the input into the Blake2b call parameters
+ var (
+ rounds = binary.BigEndian.Uint32(input[0:4])
+ final = (input[212] == blake2FFinalBlockBytes)
+
+ h [8]uint64
+ m [16]uint64
+ t [2]uint64
+ )
+ for i := 0; i < 8; i++ {
+ offset := 4 + i*8
+ h[i] = binary.LittleEndian.Uint64(input[offset : offset+8])
+ }
+ for i := 0; i < 16; i++ {
+ offset := 68 + i*8
+ m[i] = binary.LittleEndian.Uint64(input[offset : offset+8])
+ }
+ t[0] = binary.LittleEndian.Uint64(input[196:204])
+ t[1] = binary.LittleEndian.Uint64(input[204:212])
+
+ // Execute the compression function, extract and return the result
+ blake2b.F(&h, m, t, final, rounds)
+
+ output := make([]byte, 64)
+ for i := 0; i < 8; i++ {
+ offset := i * 8
+ binary.LittleEndian.PutUint64(output[offset:offset+8], h[i])
+ }
+ return output, nil
+}
diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go
index 96083337c..ae95b4462 100644
--- a/core/vm/contracts_test.go
+++ b/core/vm/contracts_test.go
@@ -19,6 +19,7 @@ package vm
import (
"fmt"
"math/big"
+ "reflect"
"testing"
"github.com/ethereum/go-ethereum/common"
@@ -32,6 +33,14 @@ type precompiledTest struct {
noBenchmark bool // Benchmark primarily the worst-cases
}
+// precompiledFailureTest defines the input/error pairs for precompiled
+// contract failure tests.
+type precompiledFailureTest struct {
+ input string
+ expectedError error
+ name string
+}
+
// modexpTests are the test and benchmark data for the modexp precompiled contract.
var modexpTests = []precompiledTest{
{
@@ -336,8 +345,61 @@ var bn256PairingTests = []precompiledTest{
},
}
+// EIP-152 test vectors
+var blake2FMalformedInputTests = []precompiledFailureTest{
+ {
+ input: "",
+ expectedError: errBlake2FInvalidInputLength,
+ name: "vector 0: empty input",
+ },
+ {
+ input: "00000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
+ expectedError: errBlake2FInvalidInputLength,
+ name: "vector 1: less than 213 bytes input",
+ },
+ {
+ input: "000000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
+ expectedError: errBlake2FInvalidInputLength,
+ name: "vector 2: more than 213 bytes input",
+ },
+ {
+ input: "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000002",
+ expectedError: errBlake2FInvalidFinalFlag,
+ name: "vector 3: malformed final block indicator flag",
+ },
+}
+
+// EIP-152 test vectors
+var blake2FTests = []precompiledTest{
+ {
+ input: "0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
+ expected: "08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b",
+ name: "vector 4",
+ },
+ { // https://tools.ietf.org/html/rfc7693#appendix-A
+ input: "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
+ expected: "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923",
+ name: "vector 5",
+ },
+ {
+ input: "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000",
+ expected: "75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d2875298743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735",
+ name: "vector 6",
+ },
+ {
+ input: "0000000148c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
+ expected: "b63a380cb2897d521994a85234ee2c181b5f844d2c624c002677e9703449d2fba551b3a8333bcdf5f2f7e08993d53923de3d64fcc68c034e717b9293fed7a421",
+ name: "vector 7",
+ },
+ {
+ input: "007A120048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
+ expected: "6d2ce9e534d50e18ff866ae92d70cceba79bbcd14c63819fe48752c8aca87a4bb7dcc230d22a4047f0486cfcfb50a17b24b2899eb8fca370f22240adb5170189",
+ name: "vector 8",
+ },
+}
+
func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
- p := PrecompiledContractsByzantium[common.HexToAddress(addr)]
+ p := PrecompiledContractsIstanbul[common.HexToAddress(addr)]
in := common.Hex2Bytes(test.input)
contract := NewContract(AccountRef(common.HexToAddress("1337")),
nil, new(big.Int), p.RequiredGas(in))
@@ -350,11 +412,25 @@ func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
})
}
+func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing.T) {
+ p := PrecompiledContractsIstanbul[common.HexToAddress(addr)]
+ in := common.Hex2Bytes(test.input)
+ contract := NewContract(AccountRef(common.HexToAddress("31337")),
+ nil, new(big.Int), p.RequiredGas(in))
+
+ t.Run(test.name, func(t *testing.T) {
+ _, err := RunPrecompiledContract(p, in, contract)
+ if !reflect.DeepEqual(err, test.expectedError) {
+ t.Errorf("Expected error [%v], got [%v]", test.expectedError, err)
+ }
+ })
+}
+
func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) {
if test.noBenchmark {
return
}
- p := PrecompiledContractsByzantium[common.HexToAddress(addr)]
+ p := PrecompiledContractsIstanbul[common.HexToAddress(addr)]
in := common.Hex2Bytes(test.input)
reqGas := p.RequiredGas(in)
contract := NewContract(AccountRef(common.HexToAddress("1337")),
@@ -481,3 +557,20 @@ func BenchmarkPrecompiledBn256Pairing(bench *testing.B) {
benchmarkPrecompiled("08", test, bench)
}
}
+func TestPrecompiledBlake2F(t *testing.T) {
+ for _, test := range blake2FTests {
+ testPrecompiled("09", test, t)
+ }
+}
+
+func BenchmarkPrecompiledBlake2F(bench *testing.B) {
+ for _, test := range blake2FTests {
+ benchmarkPrecompiled("09", test, bench)
+ }
+}
+
+func TestPrecompileBlake2FMalformedInput(t *testing.T) {
+ for _, test := range blake2FMalformedInputTests {
+ testPrecompiledFailure("09", test, t)
+ }
+}