1
1
use crate :: { Digest , Tiger , TigerCore } ;
2
- use alloc :: vec :: Vec ;
2
+ use arrayvec :: ArrayVec ;
3
3
use core:: fmt;
4
4
use digest:: {
5
5
core_api:: {
@@ -11,18 +11,37 @@ use digest::{
11
11
HashMarker , Output ,
12
12
} ;
13
13
14
+ #[ derive( Clone ) ]
15
+ struct TigerTreeNode {
16
+ level : u32 ,
17
+ hash : Output < TigerCore > ,
18
+ }
19
+
14
20
/// Core Tiger hasher state.
15
21
#[ derive( Clone ) ]
16
22
pub struct TigerTreeCore {
17
- leaves : Vec < Output < TigerCore > > ,
23
+ nodes : ArrayVec < TigerTreeNode , MAX_TREE_HEIGHT > ,
18
24
hasher : Tiger ,
19
25
blocks_processed : usize ,
20
26
}
21
27
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
+
22
41
impl Default for TigerTreeCore {
23
42
fn default ( ) -> Self {
24
43
Self {
25
- leaves : Vec :: default ( ) ,
44
+ nodes : ArrayVec :: default ( ) ,
26
45
hasher : Tiger :: new_with_prefix ( [ LEAF_SIG ] ) ,
27
46
blocks_processed : 0 ,
28
47
}
@@ -32,6 +51,7 @@ impl Default for TigerTreeCore {
32
51
type DataBlockSize = U1024 ;
33
52
const LEAF_SIG : u8 = 0u8 ;
34
53
const NODE_SIG : u8 = 1u8 ;
54
+ const MAX_TREE_HEIGHT : usize = ( usize:: BITS - DataBlockSize :: USIZE . ilog2 ( ) + 1 ) as usize ;
35
55
/// The number of TigerCore blocks in a TigerTree data block
36
56
const LEAF_BLOCKS : usize = DataBlockSize :: USIZE / <TigerCore as BlockSizeUser >:: BlockSize :: USIZE ;
37
57
@@ -54,7 +74,7 @@ impl TigerTreeCore {
54
74
fn finalize_blocks ( & mut self ) {
55
75
let hasher = core:: mem:: replace ( & mut self . hasher , Tiger :: new_with_prefix ( [ LEAF_SIG ] ) ) ;
56
76
let hash = hasher. finalize ( ) ;
57
- self . leaves . push ( hash) ;
77
+ self . add_node ( 0 , hash) ;
58
78
self . blocks_processed = 0 ;
59
79
}
60
80
@@ -89,31 +109,15 @@ impl FixedOutputCore for TigerTreeCore {
89
109
self . finalize_blocks ( )
90
110
}
91
111
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 ( ) ) ;
116
119
}
120
+ out. copy_from_slice ( hash. as_slice ( ) ) ;
117
121
}
118
122
}
119
123
0 commit comments