@@ -112,6 +112,40 @@ pub fn node_indices_added_by_append(old_leaf_count: u64) -> Vec<u64> {
112112 added_node_indices
113113}
114114
115+ /// Get the node indices of the authentication path starting from the specified
116+ /// leaf, to its peak.
117+ pub fn auth_path_node_indices ( num_leafs : u64 , leaf_index : u64 ) -> Vec < u64 > {
118+ assert ! (
119+ leaf_index < num_leafs,
120+ "Leaf index out-of-bounds: {leaf_index}/{num_leafs}"
121+ ) ;
122+
123+ let ( mut merkle_tree_index, _) = leaf_index_to_mt_index_and_peak_index ( leaf_index, num_leafs) ;
124+ let mut node_index = leaf_index_to_node_index ( leaf_index) ;
125+ let mut height = 0 ;
126+ let tree_height = u64:: BITS - merkle_tree_index. leading_zeros ( ) - 1 ;
127+ let mut ret = Vec :: with_capacity ( tree_height as usize ) ;
128+ while merkle_tree_index > 1 {
129+ let is_left_sibling = merkle_tree_index & 1 == 0 ;
130+ let height_pow = 1u64 << ( height + 1 ) ;
131+ let as_1_or_minus_1: u64 = ( 2 * ( is_left_sibling as i64 ) - 1 ) as u64 ;
132+ let signed_height_pow = height_pow. wrapping_mul ( as_1_or_minus_1) ;
133+ let sibling = node_index
134+ . wrapping_add ( signed_height_pow)
135+ . wrapping_sub ( as_1_or_minus_1) ;
136+
137+ node_index += 1 << ( ( height + 1 ) * is_left_sibling as u32 ) ;
138+
139+ ret. push ( sibling) ;
140+ merkle_tree_index >>= 1 ;
141+ height += 1 ;
142+ }
143+
144+ debug_assert_eq ! ( tree_height, ret. len( ) as u32 , "Allocation must be optimal" ) ;
145+
146+ ret
147+ }
148+
115149/// Get the node indices of the authentication path hash digest needed
116150/// to calculate the digest of `peak_node_index` from `start_node_index`
117151pub fn get_authentication_path_node_indices (
@@ -506,6 +540,40 @@ mod mmr_test {
506540 }
507541 }
508542
543+ #[ test]
544+ fn auth_path_indices_unit_test ( ) {
545+ assert_eq ! ( vec![ 2 , 6 , 14 , 30 ] , auth_path_node_indices( 16 , 0 ) ) ;
546+ assert_eq ! ( vec![ 1 , 6 , 14 , 30 ] , auth_path_node_indices( 16 , 1 ) ) ;
547+ assert_eq ! ( vec![ 5 , 3 , 14 , 30 ] , auth_path_node_indices( 16 , 2 ) ) ;
548+ assert_eq ! ( vec![ 4 , 3 , 14 , 30 ] , auth_path_node_indices( 16 , 3 ) ) ;
549+ assert_eq ! ( vec![ 9 , 13 , 7 , 30 ] , auth_path_node_indices( 16 , 4 ) ) ;
550+ assert_eq ! ( vec![ 8 , 13 , 7 , 30 ] , auth_path_node_indices( 16 , 5 ) ) ;
551+ assert_eq ! ( vec![ 12 , 10 , 7 , 30 ] , auth_path_node_indices( 16 , 6 ) ) ;
552+ assert_eq ! ( vec![ 11 , 10 , 7 , 30 ] , auth_path_node_indices( 16 , 7 ) ) ;
553+ assert_eq ! ( vec![ 17 , 21 , 29 , 15 ] , auth_path_node_indices( 16 , 8 ) ) ;
554+ assert_eq ! ( vec![ 16 , 21 , 29 , 15 ] , auth_path_node_indices( 16 , 9 ) ) ;
555+ assert_eq ! ( vec![ 20 , 18 , 29 , 15 ] , auth_path_node_indices( 16 , 10 ) ) ;
556+ assert_eq ! ( vec![ 19 , 18 , 29 , 15 ] , auth_path_node_indices( 16 , 11 ) ) ;
557+ assert_eq ! ( vec![ 24 , 28 , 22 , 15 ] , auth_path_node_indices( 16 , 12 ) ) ;
558+ assert_eq ! ( vec![ 23 , 28 , 22 , 15 ] , auth_path_node_indices( 16 , 13 ) ) ;
559+ assert_eq ! ( vec![ 27 , 25 , 22 , 15 ] , auth_path_node_indices( 16 , 14 ) ) ;
560+ assert_eq ! ( vec![ 26 , 25 , 22 , 15 ] , auth_path_node_indices( 16 , 15 ) ) ;
561+
562+ assert_eq ! ( Vec :: <u64 >:: new( ) , auth_path_node_indices( 1 , 0 ) ) ;
563+ assert_eq ! ( vec![ 2 ] , auth_path_node_indices( 2 , 0 ) ) ;
564+ assert_eq ! ( vec![ 1 ] , auth_path_node_indices( 2 , 1 ) ) ;
565+
566+ let mut expected = vec ! [ ] ;
567+ for i in 1 ..63 {
568+ expected. push ( ( 1u64 << ( i + 1 ) ) - 2 ) ;
569+ assert_eq ! (
570+ expected,
571+ auth_path_node_indices( 1 << i, 0 ) ,
572+ "must match for i={i}"
573+ ) ;
574+ }
575+ }
576+
509577 #[ proptest]
510578 fn right_lineage_length_from_node_index_does_not_crash ( node_index : u64 ) {
511579 right_lineage_length_from_node_index ( node_index) ;
0 commit comments