@@ -23,11 +23,24 @@ use super::mmr_accumulator::MmrAccumulator;
2323
2424const ROOT_MT_INDEX : u64 = 1 ;
2525
26+ /// A witness to facilitate the proving of the authenticity of a Merkle
27+ /// authentication struct.
28+ #[ derive( Debug , Clone ) ]
2629pub struct MerkleAuthenticationStructAuthenticityWitness {
2730 // All indices are Merkle tree node indices
28- nd_auth_struct_indices : Vec < u64 > ,
29- nd_sibling_indices : Vec < ( u64 , u64 ) > ,
30- nd_siblings : Vec < ( Digest , Digest ) > ,
31+ pub nd_auth_struct_indices : Vec < u64 > ,
32+ pub nd_sibling_indices : Vec < ( u64 , u64 ) > ,
33+ pub nd_siblings : Vec < ( Digest , Digest ) > ,
34+ }
35+
36+ /// An authentication structure that can be used to prove membership of a list
37+ /// of leaves in a Merkle tree, along with the indexed leaves in question, and
38+ /// the witness necessary to prove membership in a ZK program.
39+ #[ derive( Debug , Clone ) ]
40+ pub struct AuthenticatedMerkleAuthStruct {
41+ pub auth_struct : Vec < Digest > ,
42+ pub indexed_leafs : Vec < ( u64 , Digest ) > ,
43+ pub witness : MerkleAuthenticationStructAuthenticityWitness ,
3144}
3245
3346impl MerkleAuthenticationStructAuthenticityWitness {
@@ -190,103 +203,120 @@ impl MerkleAuthenticationStructAuthenticityWitness {
190203 pub fn new_from_mmr_membership_proofs (
191204 mmra : & MmrAccumulator ,
192205 indexed_mmr_mps : Vec < ( u64 , Digest , MmrMembershipProof ) > ,
193- ) -> ( Self , Vec < Digest > , Vec < ( u64 , Digest ) > ) {
194- // TODO: Consider rewriting this to return a list of authenticated
195- // authentication structs, one for each peak in question.
206+ ) -> HashMap < u32 , AuthenticatedMerkleAuthStruct > {
207+ #[ derive( Clone , Debug ) ]
208+ struct IndexedAuthenticatedMmrLeaf {
209+ merkle_tree_node_index : u64 ,
210+ merkle_tree_leaf_index : u64 ,
211+ leaf_digest : Digest ,
212+ membership_proof : MmrMembershipProof ,
213+ }
196214
197- // Verify that MMR leaf indices belong to the same peak
215+ // Split indexed MMR-mps into a hashmap with one entry for each
216+ // referenced peak in the MMR.
198217 let num_mmr_leafs = mmra. num_leafs ( ) ;
199- let mt_and_peak_indices = indexed_mmr_mps
200- . iter ( )
201- . map ( |( mmr_leaf_index, _leaf, _mmr_mp) | {
202- leaf_index_to_mt_index_and_peak_index ( * mmr_leaf_index, num_mmr_leafs)
203- } )
204- . collect_vec ( ) ;
218+ let mut peak_index_to_indexed_mmr_mp: HashMap < u32 , Vec < IndexedAuthenticatedMmrLeaf > > =
219+ HashMap :: default ( ) ;
220+ let peak_heights = get_peak_heights ( num_mmr_leafs) ;
221+ for ( mmr_leaf_index, leaf, mmr_mp) in indexed_mmr_mps {
222+ let ( mt_index, peak_index) =
223+ leaf_index_to_mt_index_and_peak_index ( mmr_leaf_index, num_mmr_leafs) ;
224+ let peak_index_as_usize: usize = peak_index. try_into ( ) . unwrap ( ) ;
225+ let num_leafs_local_mt = 1 << peak_heights[ peak_index_as_usize] ;
226+ let mt_leaf_index = mt_index - num_leafs_local_mt;
227+ peak_index_to_indexed_mmr_mp
228+ . entry ( peak_index)
229+ . or_default ( )
230+ . push ( IndexedAuthenticatedMmrLeaf {
231+ merkle_tree_node_index : mt_index,
232+ merkle_tree_leaf_index : mt_leaf_index,
233+ leaf_digest : leaf,
234+ membership_proof : mmr_mp,
235+ } ) ;
236+ }
205237
206- assert ! (
207- mt_and_peak_indices
238+ // Loop over all peaks and collect an authentication witness struct
239+ // for each peak.
240+ let mut peak_index_to_authenticated_auth_struct = HashMap :: default ( ) ;
241+ for ( peak_index, indexed_mmr_mp_structs) in peak_index_to_indexed_mmr_mp {
242+ let peak_index_as_usize: usize = peak_index. try_into ( ) . unwrap ( ) ;
243+ let num_leafs_in_local_mt = 1 << peak_heights[ peak_index_as_usize] ;
244+ let local_mt_leaf_indices = indexed_mmr_mp_structs
208245 . iter ( )
209- . map( |( _mt_index, peak_index) | peak_index)
210- . unique( )
211- . count( )
212- < 2
213- ) ;
214- assert ! ( !mt_and_peak_indices. is_empty( ) , "" ) ;
215-
216- let peak_index = mt_and_peak_indices[ 0 ] . 1 ;
217- let mt_indices = mt_and_peak_indices
218- . into_iter ( )
219- . map ( |( mt_index, _peak_index) | mt_index)
220- . collect_vec ( ) ;
221-
222- let peak_index: usize = peak_index. try_into ( ) . unwrap ( ) ;
223- let height_of_local_mt = get_peak_heights ( num_mmr_leafs) [ peak_index] ;
224- let num_leafs_in_local_mt = 1 << height_of_local_mt;
225- let local_mt_leaf_indices = mt_indices
226- . iter ( )
227- . map ( |mt_index| mt_index - num_leafs_in_local_mt)
228- . collect_vec ( ) ;
229-
230- let ( nd_auth_struct_indices, nd_sibling_indices) =
231- Self :: auth_struct_and_nd_indices ( num_leafs_in_local_mt, & local_mt_leaf_indices) ;
232-
233- // Collect all node digests that can be calculated
234- let peak = mmra. peaks ( ) [ peak_index] ;
235- let mut node_digests: HashMap < u64 , Digest > = HashMap :: default ( ) ;
236- node_digests. insert ( ROOT_MT_INDEX , peak) ;
237- for ( ( _mmr_leaf_index, mut node, mmr_mp) , mut mt_index) in indexed_mmr_mps
238- . clone ( )
239- . into_iter ( )
240- . zip_eq ( mt_indices. clone ( ) )
241- {
242- for ap_elem in mmr_mp. authentication_path . iter ( ) {
243- node_digests. insert ( mt_index, node) ;
244- node_digests. insert ( mt_index ^ 1 , * ap_elem) ;
245- node = if mt_index & 1 == 0 {
246- Tip5 :: hash_pair ( node, * ap_elem)
247- } else {
248- Tip5 :: hash_pair ( * ap_elem, node)
249- } ;
250-
251- mt_index /= 2 ;
246+ . map ( |x| x. merkle_tree_leaf_index )
247+ . collect_vec ( ) ;
248+
249+ let ( nd_auth_struct_indices, nd_sibling_indices) =
250+ Self :: auth_struct_and_nd_indices ( num_leafs_in_local_mt, & local_mt_leaf_indices) ;
251+ let peak = mmra. peaks ( ) [ peak_index_as_usize] ;
252+
253+ let mut node_digests: HashMap < u64 , Digest > = HashMap :: default ( ) ;
254+ node_digests. insert ( ROOT_MT_INDEX , peak) ;
255+
256+ // Loop over all indexed leafs for this peak
257+ for indexed_mmr_mp in indexed_mmr_mp_structs. iter ( ) {
258+ let mut mt_node_index = indexed_mmr_mp. merkle_tree_node_index ;
259+ let mut node = indexed_mmr_mp. leaf_digest ;
260+
261+ // Loop over all authentication path elements for this indexed leaf
262+ for ap_elem in indexed_mmr_mp. membership_proof . authentication_path . iter ( ) {
263+ node_digests. insert ( mt_node_index, node) ;
264+ node_digests. insert ( mt_node_index ^ 1 , * ap_elem) ;
265+ node = if mt_node_index & 1 == 0 {
266+ Tip5 :: hash_pair ( node, * ap_elem)
267+ } else {
268+ Tip5 :: hash_pair ( * ap_elem, node)
269+ } ;
270+
271+ mt_node_index /= 2 ;
272+ }
273+
274+ // Sanity check that MMR-MPs are valid
275+ assert_eq ! ( peak, node, "Derived peak must match provided peak" ) ;
252276 }
253-
254- // Sanity check that MMR-MPs are valid
255- assert_eq ! ( peak, node, "Derived peak must match provided peak" ) ;
277+ let nd_siblings = nd_sibling_indices
278+ . iter ( )
279+ . map ( |( left_idx, right_idx) | ( node_digests[ left_idx] , node_digests[ right_idx] ) )
280+ . collect_vec ( ) ;
281+ let auth_struct = nd_auth_struct_indices
282+ . iter ( )
283+ . map ( |idx| node_digests[ idx] )
284+ . collect_vec ( ) ;
285+ let indexed_leafs = indexed_mmr_mp_structs
286+ . into_iter ( )
287+ . map ( |indexed_mmr_mp| {
288+ (
289+ indexed_mmr_mp. merkle_tree_leaf_index ,
290+ indexed_mmr_mp. leaf_digest ,
291+ )
292+ } )
293+ . collect_vec ( ) ;
294+
295+ let witness = Self {
296+ nd_auth_struct_indices,
297+ nd_sibling_indices,
298+ nd_siblings,
299+ } ;
300+
301+ peak_index_to_authenticated_auth_struct. insert (
302+ peak_index,
303+ AuthenticatedMerkleAuthStruct {
304+ auth_struct,
305+ indexed_leafs,
306+ witness,
307+ } ,
308+ ) ;
256309 }
257310
258- let nd_siblings = nd_sibling_indices
259- . iter ( )
260- . map ( |( left_idx, right_idx) | ( node_digests[ left_idx] , node_digests[ right_idx] ) )
261- . collect_vec ( ) ;
262- let auth_struct = nd_auth_struct_indices
263- . iter ( )
264- . map ( |idx| node_digests[ idx] )
265- . collect_vec ( ) ;
266- let indexed_leafs = local_mt_leaf_indices
267- . into_iter ( )
268- . zip_eq (
269- indexed_mmr_mps
270- . into_iter ( )
271- . map ( |( _mmr_leaf_index, leaf, _mmr_mp) | leaf) ,
272- )
273- . collect_vec ( ) ;
274-
275- let auth_struct_witness = Self {
276- nd_auth_struct_indices,
277- nd_sibling_indices,
278- nd_siblings,
279- } ;
280-
281- ( auth_struct_witness, auth_struct, indexed_leafs)
311+ peak_index_to_authenticated_auth_struct
282312 }
283313
284314 /// Return the authentication structure witness, authentication structure,
285315 /// and the (leaf-index, leaf-digest) pairs.
286316 pub fn new_from_merkle_tree (
287317 tree : & MerkleTree < Tip5 > ,
288318 mut revealed_leaf_indices : Vec < u64 > ,
289- ) -> ( Self , Vec < Digest > , Vec < ( u64 , Digest ) > ) {
319+ ) -> AuthenticatedMerkleAuthStruct {
290320 revealed_leaf_indices. sort_unstable ( ) ;
291321 revealed_leaf_indices. dedup ( ) ;
292322 revealed_leaf_indices. reverse ( ) ;
@@ -322,13 +352,17 @@ impl MerkleAuthenticationStructAuthenticityWitness {
322352 . map ( |node_index| tree. node ( * node_index as usize ) . unwrap ( ) )
323353 . collect_vec ( ) ;
324354
325- let auth_struct_witness = Self {
355+ let witness = Self {
326356 nd_auth_struct_indices,
327357 nd_sibling_indices,
328358 nd_siblings,
329359 } ;
330360
331- ( auth_struct_witness, auth_struct, indexed_leafs)
361+ AuthenticatedMerkleAuthStruct {
362+ auth_struct,
363+ indexed_leafs,
364+ witness,
365+ }
332366 }
333367}
334368
@@ -345,6 +379,48 @@ mod tests {
345379
346380 use super :: * ;
347381
382+ #[ proptest( cases = 20 ) ]
383+ fn root_from_authentication_struct_mmr_prop_test (
384+ #[ strategy( 0 ..u64 :: MAX / 2 ) ] mmr_leaf_count : u64 ,
385+ #[ strategy( 0usize ..20 ) ] _num_revealed_leafs : usize ,
386+ #[ strategy( vec( 0u64 ..#mmr_leaf_count, #_num_revealed_leafs) ) ]
387+ mmr_revealed_leaf_indices : Vec < u64 > ,
388+ ) {
389+ let indexed_leafs_input: Vec < ( u64 , Digest ) > = mmr_revealed_leaf_indices
390+ . iter ( )
391+ . map ( |idx| ( * idx, random ( ) ) )
392+ . collect_vec ( ) ;
393+ let ( mmra, mmr_mps) = mmra_with_mps ( mmr_leaf_count, indexed_leafs_input. clone ( ) ) ;
394+ let indexed_mmr_mps = mmr_mps
395+ . into_iter ( )
396+ . zip_eq ( indexed_leafs_input)
397+ . map ( |( mmr_mp, ( idx, leaf) ) | ( idx, leaf, mmr_mp) )
398+ . collect_vec ( ) ;
399+
400+ let authenticated_auth_structs =
401+ MerkleAuthenticationStructAuthenticityWitness :: new_from_mmr_membership_proofs (
402+ & mmra,
403+ indexed_mmr_mps,
404+ ) ;
405+
406+ let peak_heights = get_peak_heights ( mmr_leaf_count) ;
407+ for ( peak_index, authentication_auth_struct) in authenticated_auth_structs {
408+ let AuthenticatedMerkleAuthStruct {
409+ auth_struct,
410+ indexed_leafs,
411+ witness,
412+ } = & authentication_auth_struct;
413+ let tree_height: u32 = peak_heights[ peak_index as usize ] ;
414+ let computed_root = witness. root_from_authentication_struct (
415+ tree_height,
416+ auth_struct. to_owned ( ) ,
417+ indexed_leafs. to_owned ( ) ,
418+ ) ;
419+
420+ prop_assert_eq ! ( mmra. peaks( ) [ peak_index as usize ] , computed_root) ;
421+ }
422+ }
423+
348424 #[ test]
349425 fn auth_struct_from_mmr_mps_test_height_5_9_indices ( ) {
350426 let local_tree_height = 5 ;
@@ -360,17 +436,26 @@ mod tests {
360436 . map ( |( mmr_mp, ( idx, leaf) ) | ( idx, leaf, mmr_mp) )
361437 . collect_vec ( ) ;
362438
363- let ( mmr_auth_struct , auth_struct , indexed_leafs ) =
439+ let authenticity_witnesses =
364440 MerkleAuthenticationStructAuthenticityWitness :: new_from_mmr_membership_proofs (
365441 & mmra,
366442 indexed_mmr_mps,
367443 ) ;
444+ assert ! (
445+ authenticity_witnesses. len( ) . is_one( ) ,
446+ "All indices belong to first peak"
447+ ) ;
448+ let AuthenticatedMerkleAuthStruct {
449+ auth_struct,
450+ indexed_leafs,
451+ witness,
452+ } = & authenticity_witnesses[ & 0 ] ;
368453
369454 let tree_height: u32 = local_tree_height. try_into ( ) . unwrap ( ) ;
370- let computed_root = mmr_auth_struct . root_from_authentication_struct (
455+ let computed_root = witness . root_from_authentication_struct (
371456 tree_height,
372- auth_struct,
373- indexed_leafs,
457+ auth_struct. to_owned ( ) ,
458+ indexed_leafs. to_owned ( ) ,
374459 ) ;
375460
376461 let peak_index = 0 ;
@@ -393,17 +478,26 @@ mod tests {
393478 . map ( |( mmr_mp, ( idx, leaf) ) | ( idx, leaf, mmr_mp) )
394479 . collect_vec ( ) ;
395480
396- let ( mmr_auth_struct , auth_struct , indexed_leafs ) =
481+ let authenticity_witnesses =
397482 MerkleAuthenticationStructAuthenticityWitness :: new_from_mmr_membership_proofs (
398483 & mmra,
399484 indexed_mmr_mps,
400485 ) ;
486+ assert ! (
487+ authenticity_witnesses. len( ) . is_one( ) ,
488+ "All indices belong to first peak"
489+ ) ;
490+ let AuthenticatedMerkleAuthStruct {
491+ auth_struct,
492+ indexed_leafs,
493+ witness,
494+ } = & authenticity_witnesses[ & 0 ] ;
401495
402496 let tree_height: u32 = local_tree_height. try_into ( ) . unwrap ( ) ;
403- let computed_root = mmr_auth_struct . root_from_authentication_struct (
497+ let computed_root = witness . root_from_authentication_struct (
404498 tree_height,
405- auth_struct,
406- indexed_leafs,
499+ auth_struct. to_owned ( ) ,
500+ indexed_leafs. to_owned ( ) ,
407501 ) ;
408502
409503 let peak_index = 0 ;
@@ -423,18 +517,20 @@ mod tests {
423517 let leafs: Vec < Digest > = random_elements ( num_leafs. try_into ( ) . unwrap ( ) ) ;
424518 let tree = MerkleTree :: < Tip5 > :: new :: < CpuParallel > ( & leafs) . unwrap ( ) ;
425519
426- let ( mmr_auth_struct , auth_struct , indexed_leafs ) =
520+ let authenticated_auth_struct =
427521 MerkleAuthenticationStructAuthenticityWitness :: new_from_merkle_tree (
428522 & tree,
429523 revealed_leaf_indices,
430524 ) ;
431-
432- let tree_height: u32 = tree_height. try_into ( ) . unwrap ( ) ;
433- let computed_root = mmr_auth_struct. root_from_authentication_struct (
434- tree_height,
525+ let AuthenticatedMerkleAuthStruct {
435526 auth_struct,
436527 indexed_leafs,
437- ) ;
528+ witness,
529+ } = authenticated_auth_struct;
530+
531+ let tree_height: u32 = tree_height. try_into ( ) . unwrap ( ) ;
532+ let computed_root =
533+ witness. root_from_authentication_struct ( tree_height, auth_struct, indexed_leafs) ;
438534 let expected_root = tree. root ( ) ;
439535 prop_assert_eq ! ( expected_root, computed_root) ;
440536 }
0 commit comments