mirror of https://github.com/status-im/nim-eth.git
87 lines
2.6 KiB
Nim
87 lines
2.6 KiB
Nim
import
|
|
"."/[trie_bitseq, trie_defs, trie_utils]
|
|
|
|
const
|
|
treeHeight* = 160
|
|
pathByteLen* = treeHeight div 8
|
|
emptyLeafNodeHash* = blankStringHash
|
|
|
|
proc makeInitialEmptyTreeHash(H: static[int]): array[H, KeccakHash] =
|
|
result[^1] = emptyLeafNodeHash
|
|
for i in countdown(H-1, 1):
|
|
result[i - 1] = keccakHash(result[i].data, result[i].data)
|
|
|
|
# cannot yet turn this into compile time constant
|
|
let emptyNodeHashes* = makeInitialEmptyTreeHash(treeHeight)
|
|
|
|
# VerifyProof verifies a Merkle proof.
|
|
proc verifyProofAux*(proof: seq[seq[byte]], root, key, value: openArray[byte]): bool =
|
|
doAssert(root.len == 32)
|
|
doAssert(key.len == pathByteLen)
|
|
var
|
|
path = bits key
|
|
curHash = keccakHash(value)
|
|
|
|
if proof.len != treeHeight: return false
|
|
|
|
for i in countdown(treeHeight - 1, 0):
|
|
var node = proof[i]
|
|
if node.len != 32: return false
|
|
if path[i]: # right
|
|
# reuse curHash without more alloc
|
|
curHash = keccakHash(node, curHash.data)
|
|
else:
|
|
curHash = keccakHash(curHash.data, node)
|
|
|
|
result = curHash.data == root
|
|
|
|
template verifyProof*(proof: seq[seq[byte]], root, key, value: openArray[byte]): bool =
|
|
verifyProofAux(proof, root, key, value)
|
|
|
|
proc count(b: TrieBitSeq, val: bool): int =
|
|
for c in b:
|
|
if c == val: inc result
|
|
|
|
# CompactProof compacts a proof, to reduce its size.
|
|
proc compactProof*(proof: seq[seq[byte]]): seq[seq[byte]] =
|
|
if proof.len != treeHeight: return
|
|
|
|
var
|
|
data = newSeq[byte](pathByteLen)
|
|
bits = bits data
|
|
|
|
result = @[]
|
|
result.add @[]
|
|
for i in 0 ..< treeHeight:
|
|
var node = proof[i]
|
|
if node == emptyNodeHashes[i].data:
|
|
bits[i] = true
|
|
else:
|
|
result.add node
|
|
result[0] = bits.toBytes
|
|
|
|
# decompactProof decompacts a proof, so that it can be used for VerifyProof.
|
|
proc decompactProof*(proof: seq[seq[byte]]): seq[seq[byte]] =
|
|
if proof.len == 0: return
|
|
if proof[0].len != pathByteLen: return
|
|
let bits = bits proof[0]
|
|
if proof.len != bits.count(false) + 1: return
|
|
result = newSeq[seq[byte]](treeHeight)
|
|
|
|
var pos = 1 # skip bits
|
|
for i in 0 ..< treeHeight:
|
|
if bits[i]:
|
|
result[i] = @(emptyNodeHashes[i].data)
|
|
else:
|
|
result[i] = proof[pos]
|
|
inc pos
|
|
|
|
# verifyCompactProof verifies a compacted Merkle proof.
|
|
proc verifyCompactProofAux*(proof: seq[seq[byte]], root, key, value: openArray[byte]): bool =
|
|
var decompactedProof = decompactProof(proof)
|
|
if decompactedProof.len == 0: return false
|
|
verifyProofAux(decompactedProof, root, key, value)
|
|
|
|
template verifyCompactProof*(proof: seq[seq[byte]], root, key, value: openArray[byte]): bool =
|
|
verifyCompactProofAux(proof, root, key, value)
|