diff options
author | Piotr Dyraga <piotr.dyraga@keep.network> | 2019-06-18 01:19:47 +0800 |
---|---|---|
committer | Péter Szilágyi <peterke@gmail.com> | 2019-08-21 18:09:15 +0800 |
commit | 2890f060b7f9f13649a7e0ec95393f61f1d254a0 (patch) | |
tree | 1cccfe8bf1ea84b405c456ec129527e3fa11023d /core/vm/contracts.go | |
parent | dbb03fe9893dd19f6b1de1ee3b768317f22fd135 (diff) | |
download | go-tangerine-2890f060b7f9f13649a7e0ec95393f61f1d254a0.tar go-tangerine-2890f060b7f9f13649a7e0ec95393f61f1d254a0.tar.gz go-tangerine-2890f060b7f9f13649a7e0ec95393f61f1d254a0.tar.bz2 go-tangerine-2890f060b7f9f13649a7e0ec95393f61f1d254a0.tar.lz go-tangerine-2890f060b7f9f13649a7e0ec95393f61f1d254a0.tar.xz go-tangerine-2890f060b7f9f13649a7e0ec95393f61f1d254a0.tar.zst go-tangerine-2890f060b7f9f13649a7e0ec95393f61f1d254a0.zip |
core/vm, crypto/blake2b: add BLAKE2b compression func at 0x09
The precompile at 0x09 wraps the BLAKE2b F compression function:
https://tools.ietf.org/html/rfc7693#section-3.2
The precompile requires 6 inputs tightly encoded, taking exactly 213
bytes, as explained below.
- `rounds` - the number of rounds - 32-bit unsigned big-endian word
- `h` - the state vector - 8 unsigned 64-bit little-endian words
- `m` - the message block vector - 16 unsigned 64-bit little-endian words
- `t_0, t_1` - offset counters - 2 unsigned 64-bit little-endian words
- `f` - the final block indicator flag - 8-bit word
[4 bytes for rounds][64 bytes for h][128 bytes for m][8 bytes for t_0]
[8 bytes for t_1][1 byte for f]
The boolean `f` parameter is considered as `true` if set to `1`.
The boolean `f` parameter is considered as `false` if set to `0`.
All other values yield an invalid encoding of `f` error.
The precompile should compute the F function as specified in the RFC
(https://tools.ietf.org/html/rfc7693#section-3.2) and return the updated
state vector `h` with unchanged encoding (little-endian).
See EIP-152 for details.
Diffstat (limited to 'core/vm/contracts.go')
-rw-r--r-- | core/vm/contracts.go | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 0e4fe0198..1ddfac455 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,67 @@ 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 len(input) != blake2FInputLength { + // Input is malformed, we can't read the number of rounds. + // Precompile can't be executed so we set its price to 0. + return 0 + } + + rounds := binary.BigEndian.Uint32(input[0:4]) + return uint64(rounds) +} + +const blake2FInputLength = 213 +const blake2FFinalBlockBytes = byte(1) +const blake2FNonFinalBlockBytes = byte(0) + +var errBlake2FIncorrectInputLength = errors.New( + "input length for Blake2 F precompile should be exactly 213 bytes", +) + +var errBlake2FIncorrectFinalBlockIndicator = errors.New( + "incorrect final block indicator flag", +) + +func (c *blake2F) Run(input []byte) ([]byte, error) { + if len(input) != blake2FInputLength { + return nil, errBlake2FIncorrectInputLength + } + if input[212] != blake2FNonFinalBlockBytes && input[212] != blake2FFinalBlockBytes { + return nil, errBlake2FIncorrectFinalBlockIndicator + } + + rounds := binary.BigEndian.Uint32(input[0:4]) + + var h [8]uint64 + for i := 0; i < 8; i++ { + offset := 4 + i*8 + h[i] = binary.LittleEndian.Uint64(input[offset : offset+8]) + } + + var m [16]uint64 + for i := 0; i < 16; i++ { + offset := 68 + i*8 + m[i] = binary.LittleEndian.Uint64(input[offset : offset+8]) + } + + var t [2]uint64 + t[0] = binary.LittleEndian.Uint64(input[196:204]) + t[1] = binary.LittleEndian.Uint64(input[204:212]) + + f := (input[212] == blake2FFinalBlockBytes) + + blake2b.F(&h, m, t, f, rounds) + + var output [64]byte + for i := 0; i < 8; i++ { + offset := i * 8 + binary.LittleEndian.PutUint64(output[offset:offset+8], h[i]) + } + + return output[:], nil +} |