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")
|
runTest("tests/db/all_tests")
|
||||||
|
|
||||||
task test_ssz, "Run ssz tests":
|
task test_ssz, "Run ssz tests":
|
||||||
runTest("tests/ssz/test_merkleization")
|
runTest("tests/ssz/all_tests")
|
||||||
|
|
||||||
task test, "Run all tests":
|
task test, "Run all tests":
|
||||||
for filename in [
|
for filename in [
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
{.push raises: [Defect].}
|
{.push raises: [Defect].}
|
||||||
|
|
||||||
import
|
import
|
||||||
|
math,
|
||||||
stew/[bitops2, endians2, ptrops],
|
stew/[bitops2, endians2, ptrops],
|
||||||
stew/ranges/ptr_arith, nimcrypto/[hash, sha2],
|
stew/ranges/ptr_arith, nimcrypto/[hash, sha2],
|
||||||
serialization/testing/tracing,
|
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
|
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
|
import
|
||||||
sequtils, unittest,
|
sequtils, unittest,
|
||||||
nimcrypto/[hash, sha2], stew/endians2,
|
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