@@ -35,120 +35,80 @@ const LEAF_PREFIX: &[u8] = &[0];
35
35
const NODE_PREFIX : & [ u8 ] = & [ 1 ] ;
36
36
const NULL_PREFIX : & [ u8 ] = & [ 2 ] ;
37
37
38
- fn hash_leaf < H : Hasher > ( leaf : & [ u8 ] ) -> H :: Hash {
39
- H :: hashv ( & [ LEAF_PREFIX , leaf] )
40
- }
41
-
42
- fn hash_node < H : Hasher > ( l : & H :: Hash , r : & H :: Hash ) -> H :: Hash {
43
- H :: hashv ( & [
44
- NODE_PREFIX ,
45
- ( if l <= r { l } else { r } ) . as_ref ( ) ,
46
- ( if l <= r { r } else { l } ) . as_ref ( ) ,
47
- ] )
48
- }
49
-
50
- fn hash_null < H : Hasher > ( ) -> H :: Hash {
51
- H :: hashv ( & [ NULL_PREFIX ] )
52
- }
53
-
38
+ /// A MerklePath contains a list of hashes that form a proof for membership in a tree.
54
39
#[ derive( Clone , Default , Debug , Hash , PartialEq , Eq , Serialize , Deserialize ) ]
55
40
pub struct MerklePath < H : Hasher > ( Vec < H :: Hash > ) ;
56
41
42
+ /// A MerkleRoot contains the root hash of a MerkleTree.
57
43
#[ derive( Clone , Default , Debug , Hash , PartialEq , Eq , Serialize , Deserialize ) ]
58
44
pub struct MerkleRoot < H : Hasher > ( H :: Hash ) ;
59
45
46
+ /// A MerkleTree is a binary tree where each node is the hash of its children.
47
+ #[ derive(
48
+ Debug , Clone , PartialEq , Eq , BorshSerialize , BorshDeserialize , Serialize , Deserialize , Default ,
49
+ ) ]
50
+ pub struct MerkleTree < H : Hasher = Keccak256 > {
51
+ pub root : MerkleRoot < H > ,
52
+ #[ serde( skip) ]
53
+ pub nodes : Vec < H :: Hash > ,
54
+ }
55
+
56
+ /// Implements functionality for using standalone MerkleRoots.
60
57
impl < H : Hasher > MerkleRoot < H > {
58
+ /// Construct a MerkleRoot from an existing Hash.
61
59
pub fn new ( root : H :: Hash ) -> Self {
62
60
Self ( root)
63
61
}
64
62
63
+ /// Given a item and corresponding MerklePath, check that it is a valid membership proof.
65
64
pub fn check ( & self , proof : MerklePath < H > , item : & [ u8 ] ) -> bool {
66
- let mut current: <H as Hasher >:: Hash = hash_leaf :: < H > ( item) ;
65
+ let mut current: <H as Hasher >:: Hash = MerkleTree :: < H > :: hash_leaf ( item) ;
67
66
for hash in proof. 0 {
68
- current = hash_node :: < H > ( & current, & hash) ;
67
+ current = MerkleTree :: < H > :: hash_node ( & current, & hash) ;
69
68
}
70
69
current == self . 0
71
70
}
72
71
}
73
72
73
+ /// Implements functionality for working with MerklePath (proofs).
74
74
impl < H : Hasher > MerklePath < H > {
75
+ /// Given a Vector of hashes representing a merkle proof, construct a MerklePath.
75
76
pub fn new ( path : Vec < H :: Hash > ) -> Self {
76
77
Self ( path)
77
78
}
78
79
}
79
80
80
- /// A MerkleAccumulator maintains a Merkle Tree.
81
- ///
82
- /// The implementation is based on Solana's Merkle Tree implementation. This structure also stores
83
- /// the items that are in the tree due to the need to look-up the index of an item in the tree in
84
- /// order to create a proof.
85
- #[ derive(
86
- Debug , Clone , PartialEq , Eq , BorshSerialize , BorshDeserialize , Serialize , Deserialize , Default ,
87
- ) ]
88
- pub struct MerkleAccumulator < H : Hasher = Keccak256 > {
89
- pub root : MerkleRoot < H > ,
90
- #[ serde( skip) ]
91
- pub nodes : Vec < H :: Hash > ,
92
- }
93
-
94
- // Layout:
95
- //
96
- // ```
97
- // 4 bytes: magic number
98
- // 1 byte: update type
99
- // 4 byte: storage id
100
- // 32 bytes: root hash
101
- // ```
102
- //
103
- // TODO: This code does not belong to MerkleAccumulator, we should be using the wire data types in
104
- // calling code to wrap this value.
105
- impl < ' a , H : Hasher + ' a > MerkleAccumulator < H > {
106
- pub fn serialize ( & self , slot : u64 , ring_size : u32 ) -> Vec < u8 > {
107
- let mut serialized = vec ! [ ] ;
108
- serialized. extend_from_slice ( 0x41555756u32 . to_be_bytes ( ) . as_ref ( ) ) ;
109
- serialized. extend_from_slice ( 0u8 . to_be_bytes ( ) . as_ref ( ) ) ;
110
- serialized. extend_from_slice ( slot. to_be_bytes ( ) . as_ref ( ) ) ;
111
- serialized. extend_from_slice ( ring_size. to_be_bytes ( ) . as_ref ( ) ) ;
112
- serialized. extend_from_slice ( self . root . 0 . as_ref ( ) ) ;
113
- serialized
114
- }
115
- }
116
-
117
- impl < ' a , H : Hasher + ' a > Accumulator < ' a > for MerkleAccumulator < H > {
81
+ /// Presents an Accumulator friendly interface for MerkleTree.
82
+ impl < ' a , H : Hasher + ' a > Accumulator < ' a > for MerkleTree < H > {
118
83
type Proof = MerklePath < H > ;
119
84
85
+ /// Construct a MerkleTree from an iterator of items.
120
86
fn from_set ( items : impl Iterator < Item = & ' a [ u8 ] > ) -> Option < Self > {
121
87
let items: Vec < & [ u8 ] > = items. collect ( ) ;
122
88
Self :: new ( & items)
123
89
}
124
90
91
+ /// Prove an item is in the tree by returning a MerklePath.
125
92
fn prove ( & ' a self , item : & [ u8 ] ) -> Option < Self :: Proof > {
126
- let item = hash_leaf :: < H > ( item) ;
93
+ let item = MerkleTree :: < H > :: hash_leaf ( item) ;
127
94
let index = self . nodes . iter ( ) . position ( |i| i == & item) ?;
128
95
Some ( self . find_path ( index) )
129
96
}
130
97
131
- // NOTE: This `check` call is intended to be generic accross accumulator implementations, but
132
- // for a merkle tree the proof does not use the `self` parameter as the proof is standalone
133
- // and doesn't need the original nodes. Normally a merkle API would be something like:
134
- //
135
- // ```
136
- // MerkleTree::check(proof)
137
- // ```
138
- //
139
- // or even:
140
- //
141
- // ```
142
- // proof.verify()
143
- // ```
144
- //
145
- // But to stick to the Accumulator trait we do it via the trait method.
98
+ // NOTE: This `check` call is intended to fit the generic accumulator implementation, but for a
99
+ // merkle tree the proof does not usually need the `self` parameter as the proof is standalone
100
+ // and doesn't need the original nodes.
146
101
fn check ( & ' a self , proof : Self :: Proof , item : & [ u8 ] ) -> bool {
147
- self . root . check ( proof, item)
102
+ self . verify_path ( proof, item)
148
103
}
149
104
}
150
105
151
- impl < H : Hasher > MerkleAccumulator < H > {
106
+ /// Implement a MerkleTree-specific interface for interacting with trees.
107
+ impl < H : Hasher > MerkleTree < H > {
108
+ /// Construct a new MerkleTree from a list of byte slices.
109
+ ///
110
+ /// This list does not have to be a set which means the tree may contain duplicate items. It is
111
+ /// up to the caller to enforce a strict set-like object if that is desired.
152
112
pub fn new ( items : & [ & [ u8 ] ] ) -> Option < Self > {
153
113
if items. is_empty ( ) {
154
114
return None ;
@@ -160,9 +120,9 @@ impl<H: Hasher> MerkleAccumulator<H> {
160
120
// Filling the leaf hashes
161
121
for i in 0 ..( 1 << depth) {
162
122
if i < items. len ( ) {
163
- tree[ ( 1 << depth) + i] = hash_leaf :: < H > ( items[ i] ) ;
123
+ tree[ ( 1 << depth) + i] = MerkleTree :: < H > :: hash_leaf ( items[ i] ) ;
164
124
} else {
165
- tree[ ( 1 << depth) + i] = hash_null :: < H > ( ) ;
125
+ tree[ ( 1 << depth) + i] = MerkleTree :: < H > :: hash_null ( ) ;
166
126
}
167
127
}
168
128
@@ -172,7 +132,7 @@ impl<H: Hasher> MerkleAccumulator<H> {
172
132
let level_num_nodes = 1 << level;
173
133
for i in 0 ..level_num_nodes {
174
134
let id = ( 1 << level) + i;
175
- tree[ id] = hash_node :: < H > ( & tree[ id * 2 ] , & tree[ id * 2 + 1 ] ) ;
135
+ tree[ id] = MerkleTree :: < H > :: hash_node ( & tree[ id * 2 ] , & tree[ id * 2 + 1 ] ) ;
176
136
}
177
137
}
178
138
@@ -182,14 +142,62 @@ impl<H: Hasher> MerkleAccumulator<H> {
182
142
} )
183
143
}
184
144
185
- fn find_path ( & self , mut index : usize ) -> MerklePath < H > {
145
+ /// Produces a Proof of membership for an index in the tree.
146
+ pub fn find_path ( & self , mut index : usize ) -> MerklePath < H > {
186
147
let mut path = Vec :: new ( ) ;
187
148
while index > 1 {
188
149
path. push ( self . nodes [ index ^ 1 ] ) ;
189
150
index /= 2 ;
190
151
}
191
152
MerklePath :: new ( path)
192
153
}
154
+
155
+ /// Check if a given MerklePath is a valid proof for a corresponding item.
156
+ pub fn verify_path ( & self , proof : MerklePath < H > , item : & [ u8 ] ) -> bool {
157
+ self . root . check ( proof, item)
158
+ }
159
+
160
+ #[ inline]
161
+ pub fn hash_leaf ( leaf : & [ u8 ] ) -> H :: Hash {
162
+ H :: hashv ( & [ LEAF_PREFIX , leaf] )
163
+ }
164
+
165
+ #[ inline]
166
+ pub fn hash_node ( l : & H :: Hash , r : & H :: Hash ) -> H :: Hash {
167
+ H :: hashv ( & [
168
+ NODE_PREFIX ,
169
+ ( if l <= r { l } else { r } ) . as_ref ( ) ,
170
+ ( if l <= r { r } else { l } ) . as_ref ( ) ,
171
+ ] )
172
+ }
173
+
174
+ #[ inline]
175
+ pub fn hash_null ( ) -> H :: Hash {
176
+ H :: hashv ( & [ NULL_PREFIX ] )
177
+ }
178
+
179
+ /// Serialize a MerkleTree into a Vec<u8>.
180
+ ///
181
+ ///Layout:
182
+ ///
183
+ /// ```rust,ignore
184
+ /// 4 bytes: magic number
185
+ /// 1 byte: update type
186
+ /// 4 byte: storage id
187
+ /// 32 bytes: root hash
188
+ /// ```
189
+ ///
190
+ /// TODO: This code does not belong to MerkleTree, we should be using the wire data types in
191
+ /// calling code to wrap this value.
192
+ pub fn serialize ( & self , slot : u64 , ring_size : u32 ) -> Vec < u8 > {
193
+ let mut serialized = vec ! [ ] ;
194
+ serialized. extend_from_slice ( 0x41555756u32 . to_be_bytes ( ) . as_ref ( ) ) ;
195
+ serialized. extend_from_slice ( 0u8 . to_be_bytes ( ) . as_ref ( ) ) ;
196
+ serialized. extend_from_slice ( slot. to_be_bytes ( ) . as_ref ( ) ) ;
197
+ serialized. extend_from_slice ( ring_size. to_be_bytes ( ) . as_ref ( ) ) ;
198
+ serialized. extend_from_slice ( self . root . 0 . as_ref ( ) ) ;
199
+ serialized
200
+ }
193
201
}
194
202
195
203
#[ cfg( test) ]
@@ -231,12 +239,12 @@ mod test {
231
239
}
232
240
233
241
#[ derive( Debug ) ]
234
- struct MerkleAccumulatorDataWrapper {
235
- pub accumulator : MerkleAccumulator ,
242
+ struct MerkleTreeDataWrapper {
243
+ pub accumulator : MerkleTree ,
236
244
pub data : BTreeSet < Vec < u8 > > ,
237
245
}
238
246
239
- impl Arbitrary for MerkleAccumulatorDataWrapper {
247
+ impl Arbitrary for MerkleTreeDataWrapper {
240
248
type Parameters = usize ;
241
249
242
250
fn arbitrary_with ( size : Self :: Parameters ) -> Self :: Strategy {
@@ -248,9 +256,8 @@ mod test {
248
256
. prop_map ( |v| {
249
257
let data: BTreeSet < Vec < u8 > > = v. into_iter ( ) . collect ( ) ;
250
258
let accumulator =
251
- MerkleAccumulator :: < Keccak256 > :: from_set ( data. iter ( ) . map ( |i| i. as_ref ( ) ) )
252
- . unwrap ( ) ;
253
- MerkleAccumulatorDataWrapper { accumulator, data }
259
+ MerkleTree :: < Keccak256 > :: from_set ( data. iter ( ) . map ( |i| i. as_ref ( ) ) ) . unwrap ( ) ;
260
+ MerkleTreeDataWrapper { accumulator, data }
254
261
} )
255
262
. boxed ( )
256
263
}
@@ -303,14 +310,14 @@ mod test {
303
310
set. insert ( & item_b) ;
304
311
set. insert ( & item_c) ;
305
312
306
- let accumulator = MerkleAccumulator :: < Keccak256 > :: from_set ( set. into_iter ( ) ) . unwrap ( ) ;
313
+ let accumulator = MerkleTree :: < Keccak256 > :: from_set ( set. into_iter ( ) ) . unwrap ( ) ;
307
314
let proof = accumulator. prove ( & item_a) . unwrap ( ) ;
308
315
309
- assert ! ( accumulator. check ( proof, & item_a) ) ;
316
+ assert ! ( accumulator. verify_path ( proof, & item_a) ) ;
310
317
let proof = accumulator. prove ( & item_a) . unwrap ( ) ;
311
318
assert_eq ! ( size_of:: <<Keccak256 as Hasher >:: Hash >( ) , 32 ) ;
312
319
313
- assert ! ( !accumulator. check ( proof, & item_d) ) ;
320
+ assert ! ( !accumulator. verify_path ( proof, & item_d) ) ;
314
321
}
315
322
316
323
#[ test]
@@ -327,11 +334,11 @@ mod test {
327
334
set. insert ( & item_b) ;
328
335
329
336
// Attempt to prove empty proofs that are not in the accumulator.
330
- let accumulator = MerkleAccumulator :: < Keccak256 > :: from_set ( set. into_iter ( ) ) . unwrap ( ) ;
337
+ let accumulator = MerkleTree :: < Keccak256 > :: from_set ( set. into_iter ( ) ) . unwrap ( ) ;
331
338
let proof = MerklePath :: < Keccak256 > :: default ( ) ;
332
- assert ! ( !accumulator. check ( proof, & item_a) ) ;
339
+ assert ! ( !accumulator. verify_path ( proof, & item_a) ) ;
333
340
let proof = MerklePath :: < Keccak256 > ( vec ! [ Default :: default ( ) ] ) ;
334
- assert ! ( !accumulator. check ( proof, & item_a) ) ;
341
+ assert ! ( !accumulator. verify_path ( proof, & item_a) ) ;
335
342
}
336
343
337
344
#[ test]
@@ -349,7 +356,7 @@ mod test {
349
356
set. insert ( & item_d) ;
350
357
351
358
// Accumulate
352
- let accumulator = MerkleAccumulator :: < Keccak256 > :: from_set ( set. into_iter ( ) ) . unwrap ( ) ;
359
+ let accumulator = MerkleTree :: < Keccak256 > :: from_set ( set. into_iter ( ) ) . unwrap ( ) ;
353
360
354
361
// For each hash in the resulting proofs, corrupt one hash and confirm that the proof
355
362
// cannot pass check.
@@ -358,7 +365,7 @@ mod test {
358
365
for ( i, _) in proof. 0 . iter ( ) . enumerate ( ) {
359
366
let mut corrupted_proof = proof. clone ( ) ;
360
367
corrupted_proof. 0 [ i] = Default :: default ( ) ;
361
- assert ! ( !accumulator. check ( corrupted_proof, item) ) ;
368
+ assert ! ( !accumulator. verify_path ( corrupted_proof, item) ) ;
362
369
}
363
370
}
364
371
}
@@ -381,9 +388,9 @@ mod test {
381
388
set. insert ( & item_d) ;
382
389
383
390
// Accumulate into a 2 level tree.
384
- let accumulator = MerkleAccumulator :: < Keccak256 > :: from_set ( set. into_iter ( ) ) . unwrap ( ) ;
391
+ let accumulator = MerkleTree :: < Keccak256 > :: from_set ( set. into_iter ( ) ) . unwrap ( ) ;
385
392
let proof = accumulator. prove ( & item_a) . unwrap ( ) ;
386
- assert ! ( accumulator. check ( proof, & item_a) ) ;
393
+ assert ! ( accumulator. verify_path ( proof, & item_a) ) ;
387
394
388
395
// We now have a 2 level tree with 4 nodes:
389
396
//
@@ -410,7 +417,7 @@ mod test {
410
417
// implementation did not use a different hash for nodes and leaves then it is possible to
411
418
// falsely prove `A` was in the original tree by tricking the implementation into performing
412
419
// H(a || b) at the leaf.
413
- let faulty_accumulator = MerkleAccumulator :: < Keccak256 > {
420
+ let faulty_accumulator = MerkleTree :: < Keccak256 > {
414
421
root : accumulator. root ,
415
422
nodes : vec ! [
416
423
accumulator. nodes[ 0 ] ,
@@ -422,38 +429,41 @@ mod test {
422
429
423
430
// `a || b` is the concatenation of a and b, which when hashed without pre-image fixes in
424
431
// place generates A as a leaf rather than a pair node.
425
- let fake_leaf_A = & [
426
- hash_leaf :: < Keccak256 > ( & item_b) ,
427
- hash_leaf :: < Keccak256 > ( & item_a) ,
432
+ let fake_leaf = & [
433
+ MerkleTree :: < Keccak256 > :: hash_leaf ( & item_b) ,
434
+ MerkleTree :: < Keccak256 > :: hash_leaf ( & item_a) ,
428
435
]
429
436
. concat ( ) ;
430
437
431
438
// Confirm our combined hash existed as a node pair in the original tree.
432
- assert_eq ! ( hash_leaf:: <Keccak256 >( fake_leaf_A) , accumulator. nodes[ 2 ] ) ;
439
+ assert_eq ! (
440
+ MerkleTree :: <Keccak256 >:: hash_leaf( fake_leaf) ,
441
+ accumulator. nodes[ 2 ]
442
+ ) ;
433
443
434
444
// Now we can try and prove leaf membership in the faulty accumulator. NOTE: this should
435
445
// fail but to confirm that the test is actually correct you can remove the PREFIXES from
436
446
// the hash functions and this test will erroneously pass.
437
- let proof = faulty_accumulator. prove ( fake_leaf_A ) . unwrap ( ) ;
438
- assert ! ( faulty_accumulator. check ( proof, fake_leaf_A ) ) ;
447
+ let proof = faulty_accumulator. prove ( fake_leaf ) . unwrap ( ) ;
448
+ assert ! ( faulty_accumulator. verify_path ( proof, fake_leaf ) ) ;
439
449
}
440
450
441
451
proptest ! {
442
452
// Use proptest to generate arbitrary Merkle trees as part of our fuzzing strategy. This
443
453
// will help us identify any edge cases or unexpected behavior in the implementation.
444
454
#[ test]
445
- fn test_merkle_tree( v in any:: <MerkleAccumulatorDataWrapper >( ) ) {
455
+ fn test_merkle_tree( v in any:: <MerkleTreeDataWrapper >( ) ) {
446
456
for d in v. data {
447
457
let proof = v. accumulator. prove( & d) . unwrap( ) ;
448
- assert!( v. accumulator. check ( proof, & d) ) ;
458
+ assert!( v. accumulator. verify_path ( proof, & d) ) ;
449
459
}
450
460
}
451
461
452
462
// Use proptest to generate arbitrary proofs for Merkle Trees trying to find a proof that
453
463
// passes which should not.
454
464
#[ test]
455
465
fn test_fake_merkle_proofs(
456
- v in any:: <MerkleAccumulatorDataWrapper >( ) ,
466
+ v in any:: <MerkleTreeDataWrapper >( ) ,
457
467
p in any:: <MerklePath <Keccak256 >>( ) ,
458
468
) {
459
469
// Reject 1-sized trees as they will always pass due to root being the only elements
@@ -463,7 +473,7 @@ mod test {
463
473
}
464
474
465
475
for d in v. data {
466
- assert!( !v. accumulator. check ( p. clone( ) , & d) ) ;
476
+ assert!( !v. accumulator. verify_path ( p. clone( ) , & d) ) ;
467
477
}
468
478
}
469
479
}
0 commit comments