mirror of https://github.com/status-im/nim-eth.git
add merkle proof verification (#379)
* add merkle proof verification * remove redundant buffer * simplify verification function
This commit is contained in:
parent
20ad6504b7
commit
e3fba48f0f
|
@ -67,7 +67,7 @@ task test_db, "Run db tests":
|
|||
runTest("tests/db/all_tests")
|
||||
|
||||
task test_ssz, "Run ssz tests":
|
||||
runTest("tests/ssz/test_merkleization")
|
||||
runTest("tests/ssz/all_tests")
|
||||
|
||||
task test, "Run all tests":
|
||||
for filename in [
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
{.push raises: [Defect].}
|
||||
|
||||
import
|
||||
math,
|
||||
stew/[bitops2, endians2, ptrops],
|
||||
stew/ranges/ptr_arith, nimcrypto/[hash, sha2],
|
||||
serialization/testing/tracing,
|
||||
|
@ -609,3 +610,29 @@ func hash_tree_root*(x: auto): Digest {.raises: [Defect].} =
|
|||
|
||||
trs "HASH TREE ROOT FOR ", name(type x), " = ", "0x", $result
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/dev/ssz/merkle-proofs.md#get_generalized_index_length
|
||||
func getGeneralizedIndexLength(x: uint64): int =
|
||||
log2trunc(x)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/dev/ssz/merkle-proofs.md#get_generalized_index_bit
|
||||
func getGeneralizedIndexBit(index: uint64, position: uint64): bool =
|
||||
(index and (1'u64 shl position)) > 0
|
||||
|
||||
# validates merkle proof. Provided index should be a generalized index of leaf node
|
||||
# as defined in: https://github.com/ethereum/eth2.0-specs/blob/dev/ssz/merkle-proofs.md#generalized-merkle-tree-index
|
||||
func isValidProof*(leaf: Digest, proof: openArray[Digest],
|
||||
index: uint64, root: Digest): bool =
|
||||
if len(proof) == getGeneralizedIndexLength(index):
|
||||
var
|
||||
value = leaf
|
||||
|
||||
for i, digest in proof:
|
||||
value =
|
||||
if getGeneralizedIndexBit(index, uint64 i):
|
||||
mergeBranches(digest, value)
|
||||
else:
|
||||
mergeBranches(value, digest)
|
||||
|
||||
value == root
|
||||
else:
|
||||
false
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
import
|
||||
./test_merkleization,
|
||||
./test_verification
|
|
@ -1,3 +1,5 @@
|
|||
{.used.}
|
||||
|
||||
import
|
||||
sequtils, unittest,
|
||||
nimcrypto/[hash, sha2], stew/endians2,
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
{.used.}
|
||||
|
||||
import
|
||||
sequtils, unittest,
|
||||
nimcrypto/[hash, sha2],
|
||||
../eth/ssz/merkleization
|
||||
|
||||
type TestCase = object
|
||||
root: string
|
||||
proof: seq[string]
|
||||
leaf: string
|
||||
index: uint64
|
||||
valid: bool
|
||||
|
||||
let testCases = @[
|
||||
TestCase(
|
||||
root: "2a23ef2b7a7221eaac2ffb3842a506a981c009ca6c2fcbf20adbc595e56f1a93",
|
||||
proof: @[
|
||||
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b"
|
||||
],
|
||||
leaf: "0100000000000000000000000000000000000000000000000000000000000000",
|
||||
index: 4,
|
||||
valid: true
|
||||
),
|
||||
TestCase(
|
||||
root: "2a23ef2b7a7221eaac2ffb3842a506a981c009ca6c2fcbf20adbc595e56f1a93",
|
||||
proof: @[
|
||||
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b"
|
||||
],
|
||||
leaf: "0100000000000000000000000000000000000000000000000000000000000000",
|
||||
index: 6,
|
||||
valid: false
|
||||
),
|
||||
TestCase(
|
||||
root: "2a23ef2b7a7221eaac2ffb3842a506a981c009ca6c2fcbf20adbc595e56f1a93",
|
||||
proof: @[
|
||||
"0100000000000000000000000000000000000000000000000000000000000000",
|
||||
"f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b"
|
||||
],
|
||||
leaf: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
index: 5,
|
||||
valid: true
|
||||
),
|
||||
TestCase(
|
||||
root: "f1824b0084956084591ff4c91c11bcc94a40be82da280e5171932b967dd146e9",
|
||||
proof: @[
|
||||
"35210d64853aee79d03f30cf0f29c1398706cbbcacaf05ab9524f00070aec91e",
|
||||
"f38a181470ef1eee90a29f0af0a9dba6b7e5d48af3c93c29b4f91fa11b777582"
|
||||
],
|
||||
leaf: "0100000000000000000000000000000000000000000000000000000000000000",
|
||||
index: 7,
|
||||
valid: true
|
||||
),
|
||||
TestCase(
|
||||
root: "f1824b0084956084591ff4c91c11bcc94a40be82da280e5171932b967dd146e9",
|
||||
proof: @[
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b",
|
||||
"0100000000000000000000000000000000000000000000000000000000000000",
|
||||
"f38a181470ef1eee90a29f0af0a9dba6b7e5d48af3c93c29b4f91fa11b777582"
|
||||
],
|
||||
leaf: "6001000000000000000000000000000000000000000000000000000000000000",
|
||||
index: 49,
|
||||
valid: true
|
||||
)
|
||||
]
|
||||
|
||||
suite "Merkle Proof verification":
|
||||
test "correctly verify proof":
|
||||
for testCase in testCases:
|
||||
let root = MDigest[256].fromHex(testCase.root)
|
||||
let proof = map(testCase.proof, proc(x: string): Digest = MDigest[256].fromHex(x))
|
||||
let leaf = MDigest[256].fromHex(testCase.leaf)
|
||||
let valid = isValidProof(leaf, proof, testCase.index, root)
|
||||
|
||||
if (testCase.valid):
|
||||
check valid
|
||||
else:
|
||||
check (not valid)
|
Loading…
Reference in New Issue