add merkle proof verification (#379)

* add merkle proof verification

* remove redundant buffer

* simplify verification function
This commit is contained in:
KonradStaniec 2021-07-23 13:40:47 +02:00 committed by GitHub
parent 20ad6504b7
commit e3fba48f0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 115 additions and 1 deletions

View File

@ -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 [

View File

@ -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

3
tests/ssz/all_tests.nim Normal file
View File

@ -0,0 +1,3 @@
import
./test_merkleization,
./test_verification

View File

@ -1,3 +1,5 @@
{.used.}
import
sequtils, unittest,
nimcrypto/[hash, sha2], stew/endians2,

View File

@ -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)