1
- use crate :: { utils:: to_blocks, Block , DigestBuffer } ;
2
- use generic_array:: ArrayLength ;
1
+ use crate :: {
2
+ utils:: { to_blocks, to_blocks_mut} ,
3
+ Block , DigestBuffer , InvalidLength ,
4
+ } ;
5
+ use core:: slice;
6
+ use generic_array:: { typenum:: U1 , ArrayLength } ;
3
7
4
8
/// Buffer for lazy block processing of data.
5
9
#[ derive( Clone , Default ) ]
@@ -9,6 +13,65 @@ pub struct LazyBlockBuffer<BlockSize: ArrayLength<u8>> {
9
13
}
10
14
11
15
impl < BlockSize : ArrayLength < u8 > > LazyBlockBuffer < BlockSize > {
16
+ /// Process `data` in blocks and write result to `out_buf`, storing
17
+ /// leftovers for future use.
18
+ #[ inline]
19
+ pub fn block_mode_processing < ' a > (
20
+ & mut self ,
21
+ mut data : & [ u8 ] ,
22
+ buf : & ' a mut [ u8 ] ,
23
+ mut process : impl FnMut ( & mut [ Block < BlockSize > ] ) ,
24
+ ) -> Result < & ' a [ u8 ] , InvalidLength > {
25
+ let pos = self . get_pos ( ) ;
26
+ let rem = self . remaining ( ) ;
27
+ let mut blocks_processed = 0 ;
28
+ let ( _, mut buf_blocks, _) = to_blocks_mut :: < BlockSize , U1 > ( buf) ;
29
+ if pos != 0 {
30
+ let n = data. len ( ) ;
31
+ if n <= rem {
32
+ // double slicing allows to remove panic branches
33
+ self . buffer [ pos..] [ ..n] . copy_from_slice ( data) ;
34
+ self . set_pos_unchecked ( pos + n) ;
35
+ return Ok ( & buf[ ..0 ] ) ;
36
+ }
37
+ if buf_blocks. is_empty ( ) {
38
+ return Err ( InvalidLength ) ;
39
+ }
40
+
41
+ let ( l, r) = buf_blocks. split_at_mut ( 1 ) ;
42
+ let buf_block = & mut l[ 0 ] ;
43
+ buf_blocks = r;
44
+ let ( l, r) = data. split_at ( rem) ;
45
+ data = r;
46
+
47
+ buf_block[ ..pos] . copy_from_slice ( & self . buffer [ ..pos] ) ;
48
+ buf_block[ pos..] . copy_from_slice ( l) ;
49
+
50
+ process ( slice:: from_mut ( buf_block) ) ;
51
+ blocks_processed += 1 ;
52
+ }
53
+
54
+ let ( data_blocks, leftover) = to_blocks_lazy ( data) ;
55
+ let buf_blocks = buf_blocks
56
+ . get_mut ( ..data_blocks. len ( ) )
57
+ . ok_or ( InvalidLength ) ?;
58
+ buf_blocks. clone_from_slice ( data_blocks) ;
59
+ process ( buf_blocks) ;
60
+ blocks_processed += buf_blocks. len ( ) ;
61
+
62
+ let n = leftover. len ( ) ;
63
+ self . buffer [ ..n] . copy_from_slice ( leftover) ;
64
+ self . set_pos_unchecked ( n) ;
65
+
66
+ let res = unsafe {
67
+ let res_len = BlockSize :: USIZE * blocks_processed;
68
+ // SAFETY: number of processed blocks never exceeds capacity of `buf`
69
+ debug_assert ! ( buf. len( ) >= res_len) ;
70
+ buf. get_unchecked ( ..res_len)
71
+ } ;
72
+ Ok ( res)
73
+ }
74
+
12
75
/// Pad remaining data with zeros and call `compress` with resulting block.
13
76
pub fn pad_zeros ( & mut self ) -> & mut Block < BlockSize > {
14
77
let pos = self . get_pos ( ) ;
@@ -17,6 +80,15 @@ impl<BlockSize: ArrayLength<u8>> LazyBlockBuffer<BlockSize> {
17
80
& mut self . buffer
18
81
}
19
82
83
+ /// Return block if buffer is full, otherwise returns `None`.
84
+ #[ inline]
85
+ pub fn get_full_block ( & mut self ) -> Option < & mut Block < BlockSize > > {
86
+ match self . remaining ( ) {
87
+ 0 => Some ( & mut self . buffer ) ,
88
+ _ => None ,
89
+ }
90
+ }
91
+
20
92
/// Return size of the internall buffer in bytes.
21
93
#[ inline]
22
94
pub fn size ( & self ) -> usize {
@@ -82,17 +154,7 @@ impl<B: ArrayLength<u8>> DigestBuffer<B> for LazyBlockBuffer<B> {
82
154
compress ( core:: slice:: from_ref ( & self . buffer ) ) ;
83
155
}
84
156
85
- let ( mut blocks, mut leftover) = to_blocks ( input) ;
86
- if leftover. is_empty ( ) {
87
- debug_assert ! ( !blocks. is_empty( ) ) ;
88
- let m = blocks. len ( ) - 1 ;
89
- // SAFETY: at this stage `input` always contains at least one byte,
90
- // so either `leftover` is not empty or we have at least one block
91
- unsafe {
92
- leftover = blocks. get_unchecked ( m) ;
93
- blocks = blocks. get_unchecked ( ..m) ;
94
- }
95
- }
157
+ let ( blocks, leftover) = to_blocks_lazy ( input) ;
96
158
compress ( blocks) ;
97
159
98
160
let n = leftover. len ( ) ;
@@ -105,3 +167,18 @@ impl<B: ArrayLength<u8>> DigestBuffer<B> for LazyBlockBuffer<B> {
105
167
self . pos = 0 ;
106
168
}
107
169
}
170
+
171
+ fn to_blocks_lazy < N : ArrayLength < u8 > > ( data : & [ u8 ] ) -> ( & [ Block < N > ] , & [ u8 ] ) {
172
+ let ( mut blocks, mut leftover) = to_blocks ( data) ;
173
+ if leftover. is_empty ( ) {
174
+ debug_assert ! ( !blocks. is_empty( ) ) ;
175
+ let m = blocks. len ( ) - 1 ;
176
+ // SAFETY: at this stage `input` always contains at least one byte,
177
+ // so either `leftover` is not empty or we have at least one block
178
+ unsafe {
179
+ leftover = blocks. get_unchecked ( m) ;
180
+ blocks = blocks. get_unchecked ( ..m) ;
181
+ }
182
+ }
183
+ ( blocks, leftover)
184
+ }
0 commit comments