-
Notifications
You must be signed in to change notification settings - Fork 267
/
merkle_tree.py
44 lines (38 loc) · 1.58 KB
/
merkle_tree.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
from typing import Any, Collection, Tuple
def build_update_tree(height, modifications: Collection[Tuple[int, Any]]):
"""
Constructs a tree from leaf updates. This is not a full binary tree. It is just the subtree
induced by the modification leaves.
Returns a tree. A tree is either:
* None
* a pair of trees
* A leaf, which is a pair (leaf_index, modification)
"""
# Bottom layer. This will prefer the last modification to an index.
if len(modifications) == 0:
return None
# A layer is a dictionary from index in current merkle layer (0 to 2**layer_height) to a tree.
# A tree is either None, a leaf, or a pair of trees.
layer = dict(modifications)
for _ in range(height):
parents = set(index // 2 for index in layer.keys())
layer = {index: (layer.get(index * 2), layer.get(index * 2 + 1)) for index in parents}
assert len(layer) == 1
# We reached layer_height=0, the top layer with only the root (with index 0).
return layer[0]
def decode_node(node):
"""
Given a node generated by build_update_tree(), returns which update case it belongs to,
and both children. This is a utility to make cairo hints shorter.
Cases: both, if both children are to be updated, and left or right, if only one child is to be
updated.
"""
left_child, right_child = node
if left_child is None:
assert right_child is not None, "No updates in tree"
case = "right"
elif right_child is None:
case = "left"
else:
case = "both"
return left_child, right_child, case