11use crate :: { Digest , Tiger , TigerCore } ;
2- use alloc :: vec :: Vec ;
2+ use arrayvec :: ArrayVec ;
33use core:: fmt;
44use digest:: {
55 core_api:: {
@@ -11,18 +11,37 @@ use digest::{
1111 HashMarker , Output ,
1212} ;
1313
14+ #[ derive( Clone ) ]
15+ struct TigerTreeNode {
16+ level : u32 ,
17+ hash : Output < TigerCore > ,
18+ }
19+
1420/// Core Tiger hasher state.
1521#[ derive( Clone ) ]
1622pub struct TigerTreeCore {
17- leaves : Vec < Output < TigerCore > > ,
23+ nodes : ArrayVec < TigerTreeNode , MAX_TREE_HEIGHT > ,
1824 hasher : Tiger ,
1925 blocks_processed : usize ,
2026}
2127
28+ impl TigerTreeCore {
29+ fn add_node ( & mut self , level : u32 , hash : Output < TigerCore > ) {
30+ match self . nodes . last ( ) {
31+ Some ( last) if last. level == level => {
32+ let new_hash = Tiger :: digest ( [ & [ NODE_SIG ] [ ..] , & last. hash , & hash] . concat ( ) ) ;
33+ self . nodes . pop ( ) ;
34+ self . add_node ( level + 1 , new_hash) ;
35+ }
36+ _ => self . nodes . push ( TigerTreeNode { level, hash } ) ,
37+ }
38+ }
39+ }
40+
2241impl Default for TigerTreeCore {
2342 fn default ( ) -> Self {
2443 Self {
25- leaves : Vec :: default ( ) ,
44+ nodes : ArrayVec :: default ( ) ,
2645 hasher : Tiger :: new_with_prefix ( [ LEAF_SIG ] ) ,
2746 blocks_processed : 0 ,
2847 }
@@ -32,6 +51,7 @@ impl Default for TigerTreeCore {
3251type DataBlockSize = U1024 ;
3352const LEAF_SIG : u8 = 0u8 ;
3453const NODE_SIG : u8 = 1u8 ;
54+ const MAX_TREE_HEIGHT : usize = ( usize:: BITS - DataBlockSize :: USIZE . ilog2 ( ) + 1 ) as usize ;
3555/// The number of TigerCore blocks in a TigerTree data block
3656const LEAF_BLOCKS : usize = DataBlockSize :: USIZE / <TigerCore as BlockSizeUser >:: BlockSize :: USIZE ;
3757
@@ -54,7 +74,7 @@ impl TigerTreeCore {
5474 fn finalize_blocks ( & mut self ) {
5575 let hasher = core:: mem:: replace ( & mut self . hasher , Tiger :: new_with_prefix ( [ LEAF_SIG ] ) ) ;
5676 let hash = hasher. finalize ( ) ;
57- self . leaves . push ( hash) ;
77+ self . add_node ( 0 , hash) ;
5878 self . blocks_processed = 0 ;
5979 }
6080
@@ -89,31 +109,15 @@ impl FixedOutputCore for TigerTreeCore {
89109 self . finalize_blocks ( )
90110 }
91111
92- let result = hash_nodes ( self . leaves . as_slice ( ) ) ;
93- out. copy_from_slice ( & result) ;
94- }
95- }
96-
97- #[ inline]
98- fn hash_nodes ( hashes : & [ Output < TigerCore > ] ) -> Output < TigerCore > {
99- match hashes. len ( ) {
100- 0 => hash_nodes ( & [ Tiger :: digest ( [ LEAF_SIG ] ) ] ) ,
101- 1 => hashes[ 0 ] ,
102- _ => {
103- let left_hashes = hashes. iter ( ) . step_by ( 2 ) ;
104-
105- let right_hashes = hashes. iter ( ) . map ( Some ) . skip ( 1 ) . chain ( [ None ] ) . step_by ( 2 ) ;
106-
107- let next_level_hashes: Vec < Output < TigerCore > > = left_hashes
108- . zip ( right_hashes)
109- . map ( |( left, right) | match right {
110- Some ( right) => Tiger :: digest ( [ & [ NODE_SIG ] [ ..] , left, right] . concat ( ) ) ,
111- None => * left,
112- } )
113- . collect ( ) ;
114-
115- hash_nodes ( next_level_hashes. as_slice ( ) )
112+ let mut hash = self
113+ . nodes
114+ . pop ( )
115+ . map ( |n| n. hash )
116+ . unwrap_or_else ( || Tiger :: digest ( [ LEAF_SIG ] ) ) ;
117+ while let Some ( left) = self . nodes . pop ( ) {
118+ hash = Tiger :: digest ( [ & [ NODE_SIG ] [ ..] , & left. hash , & hash] . concat ( ) ) ;
116119 }
120+ out. copy_from_slice ( hash. as_slice ( ) ) ;
117121 }
118122}
119123
0 commit comments