mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-24 11:11:59 +00:00
implement EIP-152
This commit is contained in:
parent
3dbf41aac8
commit
b3cbf620d6
141
nimbus/vm/blake2b_f.nim
Normal file
141
nimbus/vm/blake2b_f.nim
Normal file
@ -0,0 +1,141 @@
|
||||
import nimcrypto/utils
|
||||
|
||||
# Blake2 `F` compression function
|
||||
# taken from nimcrypto with modification
|
||||
|
||||
# in nimcrypto, blake2 compression function `F`
|
||||
# is hardcoded for blake2b and blake2s
|
||||
# we need a generic `F` function with
|
||||
# `rounds` parameter
|
||||
|
||||
type
|
||||
Blake2bContext = object
|
||||
h: array[8, uint64]
|
||||
t: array[2, uint64]
|
||||
|
||||
const Sigma = [
|
||||
[0'u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
||||
[14'u8, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
|
||||
[11'u8, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
|
||||
[7'u8, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
|
||||
[9'u8, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
|
||||
[2'u8, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
|
||||
[12'u8, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
|
||||
[13'u8, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
|
||||
[6'u8, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
|
||||
[10'u8, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
|
||||
[0'u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
||||
[14'u8, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3]
|
||||
]
|
||||
|
||||
const B2BIV = [
|
||||
0x6A09E667F3BCC908'u64, 0xBB67AE8584CAA73B'u64,
|
||||
0x3C6EF372FE94F82B'u64, 0xA54FF53A5F1D36F1'u64,
|
||||
0x510E527FADE682D1'u64, 0x9B05688C2B3E6C1F'u64,
|
||||
0x1F83D9ABFB41BD6B'u64, 0x5BE0CD19137E2179'u64
|
||||
]
|
||||
|
||||
template B2B_G(v, a, b, c, d, x, y: untyped) =
|
||||
v[a] = v[a] + v[b] + x
|
||||
v[d] = ROR(v[d] xor v[a], 32)
|
||||
v[c] = v[c] + v[d]
|
||||
v[b] = ROR(v[b] xor v[c], 24)
|
||||
v[a] = v[a] + v[b] + y
|
||||
v[d] = ROR(v[d] xor v[a], 16)
|
||||
v[c] = v[c] + v[d]
|
||||
v[b] = ROR(v[b] xor v[c], 63)
|
||||
|
||||
template B2BROUND(v, m, n: untyped) =
|
||||
B2B_G(v, 0, 4, 8, 12, m[Sigma[n][ 0]], m[Sigma[n][ 1]])
|
||||
B2B_G(v, 1, 5, 9, 13, m[Sigma[n][ 2]], m[Sigma[n][ 3]])
|
||||
B2B_G(v, 2, 6, 10, 14, m[Sigma[n][ 4]], m[Sigma[n][ 5]])
|
||||
B2B_G(v, 3, 7, 11, 15, m[Sigma[n][ 6]], m[Sigma[n][ 7]])
|
||||
B2B_G(v, 0, 5, 10, 15, m[Sigma[n][ 8]], m[Sigma[n][ 9]])
|
||||
B2B_G(v, 1, 6, 11, 12, m[Sigma[n][10]], m[Sigma[n][11]])
|
||||
B2B_G(v, 2, 7, 8, 13, m[Sigma[n][12]], m[Sigma[n][13]])
|
||||
B2B_G(v, 3, 4, 9, 14, m[Sigma[n][14]], m[Sigma[n][15]])
|
||||
|
||||
proc blake2Transform(ctx: var Blake2bContext, input: openArray[byte], last: bool, rounds: uint32) {.inline.} =
|
||||
var v: array[16, uint64]
|
||||
var m: array[16, uint64]
|
||||
|
||||
v[0] = ctx.h[0]; v[1] = ctx.h[1]
|
||||
v[2] = ctx.h[2]; v[3] = ctx.h[3]
|
||||
v[4] = ctx.h[4]; v[5] = ctx.h[5]
|
||||
v[6] = ctx.h[6]; v[7] = ctx.h[7]
|
||||
v[8] = B2BIV[0]; v[9] = B2BIV[1]
|
||||
v[10] = B2BIV[2]; v[11] = B2BIV[3]
|
||||
v[12] = B2BIV[4]; v[13] = B2BIV[5]
|
||||
v[14] = B2BIV[6]; v[15] = B2BIV[7]
|
||||
|
||||
v[12] = v[12] xor ctx.t[0]
|
||||
v[13] = v[13] xor ctx.t[1]
|
||||
if last:
|
||||
v[14] = not(v[14])
|
||||
|
||||
m[0] = leLoad64(input, 0); m[1] = leLoad64(input, 8)
|
||||
m[2] = leLoad64(input, 16); m[3] = leLoad64(input, 24)
|
||||
m[4] = leLoad64(input, 32); m[5] = leLoad64(input, 40)
|
||||
m[6] = leLoad64(input, 48); m[7] = leLoad64(input, 56)
|
||||
m[8] = leLoad64(input, 64); m[9] = leLoad64(input, 72)
|
||||
m[10] = leLoad64(input, 80); m[11] = leLoad64(input, 88)
|
||||
m[12] = leLoad64(input, 96); m[13] = leLoad64(input, 104)
|
||||
m[14] = leLoad64(input, 112); m[15] = leLoad64(input, 120)
|
||||
|
||||
for i in 0..<rounds:
|
||||
B2BROUND(v, m, i mod 10)
|
||||
|
||||
ctx.h[0] = ctx.h[0] xor (v[0] xor v[0 + 8])
|
||||
ctx.h[1] = ctx.h[1] xor (v[1] xor v[1 + 8])
|
||||
ctx.h[2] = ctx.h[2] xor (v[2] xor v[2 + 8])
|
||||
ctx.h[3] = ctx.h[3] xor (v[3] xor v[3 + 8])
|
||||
ctx.h[4] = ctx.h[4] xor (v[4] xor v[4 + 8])
|
||||
ctx.h[5] = ctx.h[5] xor (v[5] xor v[5 + 8])
|
||||
ctx.h[6] = ctx.h[6] xor (v[6] xor v[6 + 8])
|
||||
ctx.h[7] = ctx.h[7] xor (v[7] xor v[7 + 8])
|
||||
|
||||
const
|
||||
blake2FInputLength* = 213
|
||||
blake2FFinalBlockBytes = byte(1)
|
||||
blake2FNonFinalBlockBytes = byte(0)
|
||||
|
||||
# input should exactly 213 bytes
|
||||
# output needs to accomodate 64 bytes
|
||||
proc blake2b_F*(input: openArray[byte], output: var openArray[byte]): bool =
|
||||
# Make sure the input is valid (correct length and final flag)
|
||||
if input.len != blake2FInputLength:
|
||||
return false
|
||||
|
||||
if input[212] notin {blake2FNonFinalBlockBytes, blake2FFinalBlockBytes}:
|
||||
return false
|
||||
|
||||
# Parse the input into the Blake2b call parameters
|
||||
var
|
||||
rounds = beLoad32(input, 0)
|
||||
final = (input[212] == blake2FFinalBlockBytes)
|
||||
ctx: Blake2bContext
|
||||
|
||||
ctx.h[0] = leLoad64(input, 4+0)
|
||||
ctx.h[1] = leLoad64(input, 4+8)
|
||||
ctx.h[2] = leLoad64(input, 4+16)
|
||||
ctx.h[3] = leLoad64(input, 4+24)
|
||||
ctx.h[4] = leLoad64(input, 4+32)
|
||||
ctx.h[5] = leLoad64(input, 4+40)
|
||||
ctx.h[6] = leLoad64(input, 4+48)
|
||||
ctx.h[7] = leLoad64(input, 4+56)
|
||||
|
||||
ctx.t[0] = leLoad64(input, 196)
|
||||
ctx.t[1] = leLoad64(input, 204)
|
||||
|
||||
# Execute the compression function, extract and return the result
|
||||
blake2Transform(ctx, input.toOpenArray(68, 195), final, rounds)
|
||||
|
||||
leStore64(output, 0, ctx.h[0])
|
||||
leStore64(output, 8, ctx.h[1])
|
||||
leStore64(output, 16, ctx.h[2])
|
||||
leStore64(output, 24, ctx.h[3])
|
||||
leStore64(output, 32, ctx.h[4])
|
||||
leStore64(output, 40, ctx.h[5])
|
||||
leStore64(output, 48, ctx.h[6])
|
||||
leStore64(output, 56, ctx.h[7])
|
||||
result = true
|
@ -1,7 +1,7 @@
|
||||
import
|
||||
../vm_types, interpreter/[gas_meter, gas_costs, utils/utils_numeric, vm_forks],
|
||||
../errors, stint, eth/[keys, common], chronicles, tables, macros,
|
||||
message, math, nimcrypto, bncurve/[fields, groups]
|
||||
message, math, nimcrypto, bncurve/[fields, groups], blake2b_f
|
||||
|
||||
type
|
||||
PrecompileAddresses* = enum
|
||||
@ -10,11 +10,13 @@ type
|
||||
paSha256,
|
||||
paRipeMd160,
|
||||
paIdentity,
|
||||
# Byzantium onward
|
||||
# Byzantium and Constantinople
|
||||
paModExp,
|
||||
paEcAdd,
|
||||
paEcMul,
|
||||
paPairing = 8
|
||||
paPairing
|
||||
# Istanbul
|
||||
paBlake2bf = 9
|
||||
|
||||
proc getSignature(computation: BaseComputation): (array[32, byte], Signature) =
|
||||
# input is Hash, V, R, S
|
||||
@ -311,12 +313,31 @@ proc bn256ecPairing*(computation: BaseComputation) =
|
||||
|
||||
computation.rawOutput = @output
|
||||
|
||||
proc blake2bf*(computation: BaseComputation) =
|
||||
template input(): untyped =
|
||||
computation.msg.data
|
||||
|
||||
if len(input) == blake2FInputLength:
|
||||
let gasFee = GasInt(beLoad32(input, 0))
|
||||
computation.gasMeter.consumeGas(gasFee, reason="ecPairing Precompile")
|
||||
|
||||
var output: array[64, byte]
|
||||
if not blake2b_F(input, output):
|
||||
raise newException(ValidationError, "Blake2b F function invalid input")
|
||||
else:
|
||||
computation.rawOutput = @output
|
||||
|
||||
proc getMaxPrecompileAddr(fork: Fork): PrecompileAddresses =
|
||||
if fork < FkByzantium: paIdentity
|
||||
elif fork < FkIstanbul: paPairing
|
||||
else: PrecompileAddresses.high
|
||||
|
||||
proc execPrecompiles*(computation: BaseComputation, fork: Fork): bool {.inline.} =
|
||||
for i in 0..18:
|
||||
if computation.msg.codeAddress[i] != 0: return
|
||||
|
||||
let lb = computation.msg.codeAddress[19]
|
||||
let maxPrecompileAddr = if fork < FkByzantium: paIdentity else: PrecompileAddresses.high
|
||||
let maxPrecompileAddr = getMaxPrecompileAddr(fork)
|
||||
if lb in PrecompileAddresses.low.byte .. maxPrecompileAddr.byte:
|
||||
result = true
|
||||
let precompile = PrecompileAddresses(lb)
|
||||
@ -331,6 +352,7 @@ proc execPrecompiles*(computation: BaseComputation, fork: Fork): bool {.inline.}
|
||||
of paEcAdd: bn256ecAdd(computation)
|
||||
of paEcMul: bn256ecMul(computation)
|
||||
of paPairing: bn256ecPairing(computation)
|
||||
of paBlake2bf: blake2bf(computation)
|
||||
except OutOfGas:
|
||||
let msg = getCurrentExceptionMsg()
|
||||
# cannot use setError here, cyclic dependency
|
||||
|
@ -8,7 +8,8 @@
|
||||
import
|
||||
unittest2, ../nimbus/vm/precompiles, json, stew/byteutils, test_helpers, ospaths, tables,
|
||||
strformat, strutils, eth/trie/db, eth/common, ../nimbus/db/[db_chain, state_db],
|
||||
../nimbus/[constants, vm_types, vm_state], ../nimbus/vm/[computation, message], macros
|
||||
../nimbus/[constants, vm_types, vm_state], ../nimbus/vm/[computation, message], macros,
|
||||
../nimbus/vm/blake2b_f
|
||||
|
||||
proc initAddress(i: byte): EthAddress = result[19] = i
|
||||
|
||||
@ -51,6 +52,71 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
||||
#raise newException(ValueError, "Unknown test vector '" & $label & "'")
|
||||
echo "Unknown test vector '" & $label & "'"
|
||||
|
||||
const blake2InputTests = [
|
||||
(
|
||||
input: "",
|
||||
expected: "error",
|
||||
name: "vector 0: empty input",
|
||||
),
|
||||
(
|
||||
input: "00000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
|
||||
expected: "error",
|
||||
name: "vector 1: less than 213 bytes input",
|
||||
),
|
||||
(
|
||||
input: "000000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
|
||||
expected: "error",
|
||||
name: "vector 2: more than 213 bytes input",
|
||||
),
|
||||
(
|
||||
input: "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000002",
|
||||
expected: "error",
|
||||
name: "vector 3: malformed final block indicator flag",
|
||||
),
|
||||
(
|
||||
input: "0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
|
||||
expected: "08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b",
|
||||
name: "vector 4",
|
||||
),
|
||||
(
|
||||
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",
|
||||
),
|
||||
]
|
||||
|
||||
proc precompilesMain*() =
|
||||
suite "Precompiles":
|
||||
jsonTest("PrecompileTests", testFixture)
|
||||
|
||||
suite "blake2bf":
|
||||
var output: array[64, byte]
|
||||
var expectedOutput: array[64, byte]
|
||||
for x in blake2InputTests:
|
||||
test x.name:
|
||||
let z = if x.input.len == 0: @[] else: hexToSeqByte(x.input)
|
||||
let res = blake2b_F(z, output)
|
||||
if x.expected == "error":
|
||||
check res == false
|
||||
else:
|
||||
hexToByteArray(x.expected, expectedOutput)
|
||||
check res == true
|
||||
check expectedOutput == output
|
||||
|
||||
when isMainModule:
|
||||
precompilesMain()
|
||||
|
Loading…
x
Reference in New Issue
Block a user