Source file gadget_merkle.ml
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
module Make (H : sig
module P : Hash_sig.P_HASH
module V : Hash_sig.HASH
end) =
struct
open Lang_stdlib
open Lang_core
let left = true
let right = false
module P = struct
type tree = Leaf of S.t | Node of S.t * tree * tree
let root = function Leaf h -> h | Node (h, _, _) -> h
let generate_tree ?(leaves = [||]) depth =
let size = Z.(to_int (pow (of_int 2) depth)) in
if not (leaves = [||]) then assert (Array.length leaves = size) ;
let leaves =
if leaves = [||] then Array.init size (fun _ -> S.random ()) else leaves
in
let rec build_tree depth index =
if depth = 0 then Leaf leaves.(index)
else
let index = 2 * index in
let tree1 = build_tree (depth - 1) index in
let tree2 = build_tree (depth - 1) (index + 1) in
let root = H.P.direct ~input_length:2 [|root tree1; root tree2|] in
Node (root, tree1, tree2)
in
build_tree depth 0
let get_depth tree =
let rec aux acc tree =
match tree with Leaf _ -> acc | Node (_, t, _) -> aux (acc + 1) t
in
aux 0 tree
let get_leaves tree =
let depth = get_depth tree in
let size = Z.(to_int (pow (of_int 2) depth)) in
let leaves = Array.init size (fun _i -> S.zero) in
let rec aux tree index =
match tree with
| Node (_, t1, t2) ->
let index = 2 * index in
aux t1 index ;
aux t2 (index + 1)
| Leaf leaf -> Array.set leaves index leaf
in
aux tree 0 ;
leaves
let print_tree tree =
let rec aux tree layer index =
match tree with
| Leaf h ->
Printf.printf
"\n leaf layer %d - index %d: %s"
layer
index
(S.to_string h)
| Node (h, t1, t2) ->
Printf.printf
"\n node layer %d - index %d: %s"
layer
index
(S.to_string h) ;
aux t1 (layer + 1) (2 * index) ;
aux t2 (layer + 1) ((2 * index) + 1)
in
aux tree 0 0
type leaf = H.P.scalar
type path = (H.P.scalar * bool) list
let proof_path pos tree : leaf * path =
let rec to_bin acc x index =
if index = 0 then acc
else
match x mod 2 with
| 0 -> to_bin (0 :: acc) (x / 2) (index - 1)
| 1 -> to_bin (1 :: acc) ((x - 1) / 2) (index - 1)
| _ -> assert false
in
let size = get_depth tree in
let binary = to_bin [] pos size in
let rec aux path bin = function
| Leaf leaf -> (leaf, path)
| Node (_, t1, t2) ->
if List.hd bin = 0 then
aux ((root t2, left) :: path) (List.tl bin) t1
else aux ((root t1, right) :: path) (List.tl bin) t2
in
aux [] binary tree
let update_tree ?input_length tree pos leaf =
let depth = get_depth tree in
let size = Z.(to_int (pow (of_int 2) depth)) in
assert (pos < size) ;
let _, path = proof_path pos tree in
let _, updated_path =
List.fold_left
(fun (index, acc_list) (x, b) ->
if index = -1 then (1, [leaf])
else
let acc = List.hd acc_list in
let left, right = if b then (acc, x) else (x, acc) in
let node = H.P.direct ?input_length [|left; right|] in
(index + 1, node :: acc_list))
(-1, [])
((leaf, false) :: path)
in
let rec update_tree_with_path tree path updated_path =
match tree with
| Leaf _h -> Leaf leaf
| Node (_h, t1, t2) ->
let node = List.hd path in
let updated_node = List.hd updated_path in
let t, t_bar = if snd node = left then (t1, t2) else (t2, t1) in
let updated_branch =
update_tree_with_path t (List.tl path) (List.tl updated_path)
in
let t1, t2 =
if snd node = left then (updated_branch, t_bar)
else (t_bar, updated_branch)
in
Node (updated_node, t1, t2)
in
update_tree_with_path tree (List.rev path) updated_path
end
module type MERKLE = functor (L : LIB) -> sig
open L
open Encodings
type path
type leaf = scalar
type root = scalar
val path_encoding : (P.path, path, (scalar * bool) list) encoding
val merkle_proof : path -> leaf repr -> root repr -> bool repr t
end
module V : MERKLE =
functor
(L : LIB)
->
struct
open L
module Hash = H.V (L)
type path = (scalar * bool) list repr
type leaf = scalar
type root = scalar
let path_encoding =
let open Encodings in
atomic_list_encoding
(atomic_obj2_encoding scalar_encoding bool_encoding)
let merkle_proof : path -> leaf repr -> root repr -> bool repr t =
fun path leaf expected_root ->
with_label ~label:"Merkle.merkle_proof"
@@ let* root =
foldM
(fun computed_h step ->
let w, direction = of_pair step in
let* leftright = Bool.swap direction w computed_h in
let l, r = of_pair leftright in
Hash.digest ~input_length:2 (to_list [l; r]))
leaf
(of_list path)
in
equal root expected_root
end
end