@@ -8,14 +8,18 @@ pub struct PrunedMerklePaths<Data, F> {
88 pub original_order : Vec < usize > ,
99 pub leaf_data : Vec < Vec < Data > > ,
1010 pub paths : Vec < ( usize , Vec < [ F ; DIGEST_LEN_FE ] > ) > ,
11+ pub n_trailing_zeros : usize ,
1112}
1213
1314fn lca_level ( a : usize , b : usize ) -> usize {
1415 ( usize:: BITS - ( a ^ b) . leading_zeros ( ) ) as usize
1516}
1617
1718impl < Data : Clone , F : Clone > MerklePaths < Data , F > {
18- pub fn prune ( self ) -> PrunedMerklePaths < Data , F > {
19+ pub fn prune ( self ) -> PrunedMerklePaths < Data , F >
20+ where
21+ Data : Default + PartialEq ,
22+ {
1923 assert ! ( !self . 0 . is_empty( ) ) ;
2024 let merkle_height = self . 0 [ 0 ] . sibling_hashes . len ( ) ;
2125
@@ -34,6 +38,16 @@ impl<Data: Clone, F: Clone> MerklePaths<Data, F> {
3438 }
3539 }
3640
41+ let default = Data :: default ( ) ;
42+ let leaf_len = deduped[ 0 ] . leaf_data . len ( ) ;
43+ let mut n_trailing_zeros = 0 ;
44+ for offset in ( 0 ..leaf_len) . rev ( ) {
45+ if deduped. iter ( ) . any ( |p| p. leaf_data [ offset] != default) {
46+ break ;
47+ }
48+ n_trailing_zeros += 1 ;
49+ }
50+
3751 let paths = deduped
3852 . iter ( )
3953 . enumerate ( )
@@ -56,21 +70,38 @@ impl<Data: Clone, F: Clone> MerklePaths<Data, F> {
5670 PrunedMerklePaths {
5771 merkle_height,
5872 original_order,
59- leaf_data : deduped. into_iter ( ) . map ( |p| p. leaf_data ) . collect ( ) ,
73+ leaf_data : deduped
74+ . into_iter ( )
75+ . map ( |p| {
76+ let effective_len = p. leaf_data . len ( ) - n_trailing_zeros;
77+ p. leaf_data [ ..effective_len] . to_vec ( )
78+ } )
79+ . collect ( ) ,
6080 paths,
81+ n_trailing_zeros,
6182 }
6283 }
6384}
6485
6586impl < Data : Clone , F : Clone > PrunedMerklePaths < Data , F > {
6687 pub fn restore (
67- self ,
88+ mut self ,
6889 hash_leaf : & impl Fn ( & [ Data ] ) -> [ F ; DIGEST_LEN_FE ] ,
6990 hash_combine : & impl Fn ( & [ F ; DIGEST_LEN_FE ] , & [ F ; DIGEST_LEN_FE ] ) -> [ F ; DIGEST_LEN_FE ] ,
70- ) -> Option < MerklePaths < Data , F > > {
91+ ) -> Option < MerklePaths < Data , F > >
92+ where
93+ Data : Default ,
94+ {
7195 let n = self . paths . len ( ) ;
7296 let h = self . merkle_height ;
7397
98+ if self . n_trailing_zeros > 1024 {
99+ return None ; // prevent DoS with huge leaf data
100+ }
101+ self . leaf_data
102+ . iter_mut ( )
103+ . for_each ( |d| d. resize ( d. len ( ) + self . n_trailing_zeros , Data :: default ( ) ) ) ;
104+
74105 let levels = |i : usize | {
75106 i. checked_sub ( 1 )
76107 . map_or ( h, |j| lca_level ( self . paths [ j] . 0 , self . paths [ i] . 0 ) )
@@ -388,58 +419,30 @@ mod tests {
388419 }
389420
390421 #[ test]
391- fn test_restore_returns_none_on_missing_leaf_data ( ) {
392- let pruned: PrunedMerklePaths < u8 , u8 > = PrunedMerklePaths {
393- merkle_height : 2 ,
394- original_order : vec ! [ 0 ] ,
395- leaf_data : vec ! [ ] , // Empty - should cause failure
396- paths : vec ! [ ( 0 , vec![ [ 1 ; DIGEST_LEN_FE ] , [ 2 ; DIGEST_LEN_FE ] ] ) ] ,
397- } ;
398- assert ! ( pruned. restore( & simple_hash, & hash_combine) . is_none( ) ) ;
399- }
422+ fn test_trailing_zeros_stripped ( ) {
423+ let leaves: Vec < Vec < u8 > > = ( 0u8 ..8 ) . map ( |i| vec ! [ i + 1 , i + 10 , 0 , 0 , 0 ] ) . collect ( ) ;
424+ let tree = build_merkle_tree ( & leaves) ;
400425
401- #[ test]
402- fn test_restore_returns_none_on_invalid_original_order ( ) {
403- let pruned: PrunedMerklePaths < u8 , u8 > = PrunedMerklePaths {
404- merkle_height : 2 ,
405- original_order : vec ! [ 5 ] , // Out of bounds index
406- leaf_data : vec ! [ vec![ 0 ] ] ,
407- paths : vec ! [ ( 0 , vec![ [ 1 ; DIGEST_LEN_FE ] , [ 2 ; DIGEST_LEN_FE ] ] ) ] ,
408- } ;
409- assert ! ( pruned. restore( & simple_hash, & hash_combine) . is_none( ) ) ;
410- }
426+ let indices = [ 2 , 5 , 7 ] ;
427+ let paths = MerklePaths (
428+ indices
429+ . iter ( )
430+ . map ( |& i| generate_auth_path ( leaves[ i] . clone ( ) , i, & tree) )
431+ . collect ( ) ,
432+ ) ;
411433
412- #[ test]
413- fn test_restore_returns_none_on_missing_siblings ( ) {
414- let pruned: PrunedMerklePaths < u8 , u8 > = PrunedMerklePaths {
415- merkle_height : 3 ,
416- original_order : vec ! [ 0 ] ,
417- leaf_data : vec ! [ vec![ 0 ] ] ,
418- paths : vec ! [ ( 0 , vec![ [ 1 ; DIGEST_LEN_FE ] ] ) ] , // Only 1 sibling, need 3
419- } ;
420- assert ! ( pruned. restore( & simple_hash, & hash_combine) . is_none( ) ) ;
421- }
434+ let pruned = paths. clone ( ) . prune ( ) ;
422435
423- #[ test]
424- fn test_restore_returns_none_on_mismatched_paths_and_leaf_data ( ) {
425- let pruned: PrunedMerklePaths < u8 , u8 > = PrunedMerklePaths {
426- merkle_height : 2 ,
427- original_order : vec ! [ 0 , 1 ] ,
428- leaf_data : vec ! [ vec![ 0 ] ] , // Only 1, but paths has 2
429- paths : vec ! [ ( 0 , vec![ [ 1 ; DIGEST_LEN_FE ] ] ) , ( 1 , vec![ [ 2 ; DIGEST_LEN_FE ] ] ) ] ,
430- } ;
431- assert ! ( pruned. restore( & simple_hash, & hash_combine) . is_none( ) ) ;
432- }
436+ assert_eq ! ( pruned. n_trailing_zeros, 3 ) ;
437+ for leaf in & pruned. leaf_data {
438+ assert_eq ! ( leaf. len( ) , 2 ) ;
439+ }
433440
434- #[ test]
435- fn test_restore_returns_none_on_empty_paths ( ) {
436- let pruned: PrunedMerklePaths < u8 , u8 > = PrunedMerklePaths {
437- merkle_height : 2 ,
438- original_order : vec ! [ 0 ] ,
439- leaf_data : vec ! [ ] ,
440- paths : vec ! [ ] ,
441- } ;
442- // original_order[0] = 0, but restored is empty
443- assert ! ( pruned. restore( & simple_hash, & hash_combine) . is_none( ) ) ;
441+ let restored = pruned. restore ( & simple_hash, & hash_combine) . unwrap ( ) ;
442+ for ( orig, rest) in paths. 0 . iter ( ) . zip ( restored. 0 . iter ( ) ) {
443+ assert_eq ! ( orig. leaf_index, rest. leaf_index) ;
444+ assert_eq ! ( orig. leaf_data, rest. leaf_data) ;
445+ assert_eq ! ( orig. sibling_hashes, rest. sibling_hashes) ;
446+ }
444447 }
445448}
0 commit comments