@@ -358,6 +358,71 @@ impl MerkleTree {
358358 Ok ( set_difference. sorted_unstable ( ) . rev ( ) )
359359 }
360360
361+ /// Construct an [authentication structure][Self::authentication_structure]
362+ /// without access to a full [`MerkleTree`], only the leafs. Particularly
363+ /// useful in combination with [RAM-frugal root][frugal] computation.
364+ ///
365+ /// [frugal]: Self::sequential_frugal_root
366+ pub fn sequential_authentication_structure_from_leafs (
367+ leafs : & [ Digest ] ,
368+ leaf_indices : & [ MerkleTreeLeafIndex ] ,
369+ ) -> Result < Vec < Digest > > {
370+ Self :: authentication_structure_node_indices ( leafs. len ( ) , leaf_indices) ?
371+ . map ( |node_index| Self :: subtree_leafs ( leafs, node_index) )
372+ . map ( Self :: sequential_frugal_root)
373+ . collect ( )
374+ }
375+
376+ /// Construct an [authentication structure][Self::authentication_structure]
377+ /// without access to a full [`MerkleTree`], only the leafs. Particularly
378+ /// useful in combination with [RAM-frugal root][frugal] computation.
379+ ///
380+ /// [frugal]: Self::par_frugal_root
381+ pub fn par_authentication_structure_from_leafs (
382+ leafs : & [ Digest ] ,
383+ leaf_indices : & [ MerkleTreeLeafIndex ] ,
384+ ) -> Result < Vec < Digest > > {
385+ Self :: authentication_structure_node_indices ( leafs. len ( ) , leaf_indices) ?
386+ . collect_vec ( )
387+ . into_par_iter ( )
388+ . map ( |node_index| Self :: subtree_leafs ( leafs, node_index) )
389+ . map ( Self :: par_frugal_root)
390+ . collect ( )
391+ }
392+
393+ /// Given a list of leafs and a [`MerkleTreeNodeIndex`] within the tree
394+ /// defined by those leafs, return the leafs that are part of the subtree
395+ /// rooted at the given node index.
396+ ///
397+ /// For example, given 4 leafs and node index 3, returns the leafs with
398+ /// node indices 6 and 7:
399+ ///
400+ /// ```markdown
401+ /// 1
402+ /// ╱ ╲
403+ /// 2 3
404+ /// ╱ ╲ ╱ ╲
405+ /// 4 5 6 7
406+ /// ```
407+ ///
408+ /// Because this is an internal helper function (and only for that reason),
409+ /// it's the caller's responsibility to ensure that the arguments are
410+ /// integral:
411+ /// - the number of `leafs` must be a power of 2
412+ /// - the `node_index` must be valid with respect to the tree induced by the
413+ /// `leafs`
414+ fn subtree_leafs ( leafs : & [ Digest ] , node_index : MerkleTreeNodeIndex ) -> & [ Digest ] {
415+ let total_num_leafs = leafs. len ( ) ;
416+ let total_tree_height = total_num_leafs. ilog2 ( ) ;
417+
418+ let tree_height = total_tree_height - node_index. ilog2 ( ) ;
419+ let left_leaf_node_index = node_index * ( 1 << tree_height) ;
420+ let left_leaf_index = left_leaf_node_index - total_num_leafs;
421+ let num_leafs = 1 << tree_height;
422+
423+ & leafs[ left_leaf_index..left_leaf_index + num_leafs]
424+ }
425+
361426 /// Generate a de-duplicated authentication structure for the given
362427 /// [`MerkleTreeLeafIndex`]es.
363428 ///
@@ -1076,6 +1141,59 @@ pub mod merkle_tree_test {
10761141 assert_eq ! ( auth_path_with_nodes( [ 14 , 6 , 2 ] ) , auth_path_for_leaf( 7 ) ) ;
10771142 }
10781143
1144+ #[ test]
1145+ fn authentication_paths_of_very_small_tree_are_identical_when_using_tree_or_only_leafs ( ) {
1146+ let tree = MerkleTree :: test_tree_of_height ( 3 ) ;
1147+ let leafs = tree. leafs ( ) . copied ( ) . collect_vec ( ) ;
1148+
1149+ let tree_path = |i| tree. authentication_structure ( & [ i] ) . unwrap ( ) ;
1150+ let seq_leaf_path =
1151+ |i| MerkleTree :: sequential_authentication_structure_from_leafs ( & leafs, & [ i] ) . unwrap ( ) ;
1152+ let par_leaf_path =
1153+ |i| MerkleTree :: par_authentication_structure_from_leafs ( & leafs, & [ i] ) . unwrap ( ) ;
1154+
1155+ for leaf_idx in 0 ..tree. num_leafs ( ) {
1156+ dbg ! ( leaf_idx) ;
1157+ assert_eq ! ( tree_path( leaf_idx) , seq_leaf_path( leaf_idx) ) ;
1158+ assert_eq ! ( tree_path( leaf_idx) , par_leaf_path( leaf_idx) ) ;
1159+ }
1160+ }
1161+
1162+ #[ proptest( cases = 100 ) ]
1163+ fn auth_structure_is_independent_of_compute_method ( test_tree : MerkleTreeToTest ) {
1164+ let tree = test_tree. tree ;
1165+ let selected_indices = test_tree. selected_indices ;
1166+ let leafs = tree. leafs ( ) . copied ( ) . collect_vec ( ) ;
1167+
1168+ let cached_auth_structure = tree. authentication_structure ( & selected_indices) ?;
1169+ let seq_auth_structure =
1170+ MerkleTree :: sequential_authentication_structure_from_leafs ( & leafs, & selected_indices) ?;
1171+ let par_auth_structure =
1172+ MerkleTree :: par_authentication_structure_from_leafs ( & leafs, & selected_indices) ?;
1173+
1174+ prop_assert_eq ! ( & cached_auth_structure, & seq_auth_structure) ;
1175+ prop_assert_eq ! ( & cached_auth_structure, & par_auth_structure) ;
1176+ }
1177+
1178+ #[ test]
1179+ fn subtree_leafs_are_actually_sub_tree_leafs ( ) {
1180+ let tree = MerkleTree :: test_tree_of_height ( 5 ) ;
1181+ let leafs = tree. leafs ( ) . copied ( ) . collect_vec ( ) ;
1182+ let subtree = |node_idx| MerkleTree :: subtree_leafs ( & leafs, node_idx) ;
1183+
1184+ // Check all node indices, one level at a time. Going level by level
1185+ // ensures that the expected subtrees (per level) have the same number
1186+ // of leafs.
1187+ for node_indices in [ 1 ..2 , 2 ..4 , 4 ..8 , 8 ..16 , 16 ..32 , 32 ..64 ] {
1188+ // the expected number of leafs in any subtree at the current level
1189+ let num_leafs = tree. num_leafs ( ) / node_indices. len ( ) ;
1190+ for ( i, node_index) in node_indices. enumerate ( ) {
1191+ let expected_leafs = & leafs[ i * num_leafs..( i + 1 ) * num_leafs] ;
1192+ assert_eq ! ( expected_leafs, subtree( node_index) ) ;
1193+ }
1194+ }
1195+ }
1196+
10791197 #[ proptest( cases = 10 ) ]
10801198 fn each_leaf_can_be_verified_individually ( test_tree : MerkleTreeToTest ) {
10811199 let tree = test_tree. tree ;
0 commit comments