1111
1212pub use digest;
1313
14- use core:: fmt;
14+ use core:: { fmt, marker :: PhantomData } ;
1515use digest:: {
1616 CollisionResistance , CustomizedInit , ExtendableOutput , HashMarker , Update , XofReader ,
17- array:: Array ,
17+ array:: ArraySize ,
1818 block_api:: { AlgorithmName , BlockSizeUser } ,
19- block_buffer:: { BlockSizes , EagerBuffer , LazyBuffer , ReadBuffer } ,
2019 consts:: { U16 , U32 , U136 , U168 } ,
2120} ;
2221use keccak:: { Keccak , State1600 } ;
22+ use sponge_cursor:: SpongeCursor ;
2323
2424const SHAKE_PAD : u8 = 0x1F ;
2525const CSHAKE_PAD : u8 = 0x04 ;
@@ -33,21 +33,22 @@ pub type CShake256 = CShake<U136>;
3333///
3434/// Rate MUST be either [`U168`] or [`U136`] for cSHAKE128 and cSHAKE256 respectively.
3535#[ derive( Clone ) ]
36- pub struct CShake < Rate : BlockSizes > {
36+ pub struct CShake < Rate : ArraySize > {
3737 state : State1600 ,
38- buffer : EagerBuffer < Rate > ,
38+ cursor : SpongeCursor < Rate > ,
3939 pad : u8 ,
4040 keccak : Keccak ,
41+ _pd : PhantomData < Rate > ,
4142}
4243
43- impl < Rate : BlockSizes > Default for CShake < Rate > {
44+ impl < Rate : ArraySize > Default for CShake < Rate > {
4445 #[ inline]
4546 fn default ( ) -> Self {
4647 Self :: new_with_function_name ( b"" , b"" )
4748 }
4849}
4950
50- impl < Rate : BlockSizes > CShake < Rate > {
51+ impl < Rate : ArraySize > CShake < Rate > {
5152 /// Creates a new cSHAKE instance with the given function name and customization.
5253 ///
5354 /// Note that the function name is intended for use by NIST and should only be set to
@@ -57,16 +58,16 @@ impl<Rate: BlockSizes> CShake<Rate> {
5758 assert ! ( Rate :: USIZE == 168 || Rate :: USIZE == 136 , "unsupported rate" ) ;
5859 }
5960
60- let buffer = Default :: default ( ) ;
6161 let keccak = Keccak :: new ( ) ;
6262 let mut state = State1600 :: default ( ) ;
6363
6464 if function_name. is_empty ( ) && customization. is_empty ( ) {
6565 return Self {
6666 state,
67- buffer,
68- keccak,
67+ cursor : Default :: default ( ) ,
6968 pad : SHAKE_PAD ,
69+ keccak,
70+ _pd : PhantomData ,
7071 } ;
7172 }
7273
@@ -79,102 +80,83 @@ impl<Rate: BlockSizes> CShake<Rate> {
7980 }
8081
8182 keccak. with_f1600 ( |f1600| {
82- let mut buffer : LazyBuffer < Rate > = Default :: default ( ) ;
83+ let mut cursor : SpongeCursor < Rate > = Default :: default ( ) ;
8384 let state = & mut state;
8485 let mut b = [ 0u8 ; 9 ] ;
8586
86- buffer. digest_blocks ( left_encode ( Rate :: U64 , & mut b) , |blocks| {
87- update_blocks ( f1600, state, blocks)
88- } ) ;
87+ cursor. absorb_u64_le ( state, f1600, left_encode ( Rate :: U64 , & mut b) ) ;
8988
9089 let mut encode_str = |str : & [ u8 ] | {
9190 let str_bits_len = 8 * u64:: try_from ( str. len ( ) )
9291 . expect ( "in practice strings can not be longer than u64::MAX" ) ;
9392 let encoded_len = left_encode ( str_bits_len, & mut b) ;
94- buffer . digest_blocks ( encoded_len , |blocks| update_blocks ( f1600, state , blocks ) ) ;
95- buffer . digest_blocks ( str , |blocks| update_blocks ( f1600, state , blocks ) ) ;
93+ cursor . absorb_u64_le ( state , f1600, encoded_len ) ;
94+ cursor . absorb_u64_le ( state , f1600, str ) ;
9695 } ;
9796
9897 encode_str ( function_name) ;
9998 encode_str ( customization) ;
10099
101- update_blocks ( f1600, state, & [ buffer. pad_with_zeros ( ) ] )
100+ if cursor. pos ( ) != 0 {
101+ f1600 ( state) ;
102+ }
102103 } ) ;
103104
104105 Self {
105106 state,
106- buffer,
107- keccak,
107+ cursor : Default :: default ( ) ,
108108 pad : CSHAKE_PAD ,
109+ keccak,
110+ _pd : PhantomData ,
109111 }
110112 }
111113}
112114
113- impl < Rate : BlockSizes > CustomizedInit for CShake < Rate > {
115+ impl < Rate : ArraySize > CustomizedInit for CShake < Rate > {
114116 #[ inline]
115117 fn new_customized ( customization : & [ u8 ] ) -> Self {
116118 Self :: new_with_function_name ( & [ ] , customization)
117119 }
118120}
119121
120- impl < Rate : BlockSizes > HashMarker for CShake < Rate > { }
122+ impl < Rate : ArraySize > HashMarker for CShake < Rate > { }
121123
122- impl < Rate : BlockSizes > BlockSizeUser for CShake < Rate > {
124+ impl < Rate : ArraySize > BlockSizeUser for CShake < Rate > {
123125 type BlockSize = Rate ;
124126}
125127
126- impl < Rate : BlockSizes > Update for CShake < Rate > {
128+ impl < Rate : ArraySize > Update for CShake < Rate > {
127129 fn update ( & mut self , data : & [ u8 ] ) {
128- let Self {
129- state,
130- buffer,
131- keccak,
132- ..
133- } = self ;
134-
135- keccak. with_f1600 ( |f1600| {
136- buffer. digest_blocks ( data, |blocks| update_blocks ( f1600, state, blocks) ) ;
130+ self . keccak . with_f1600 ( |f1600| {
131+ self . cursor . absorb_u64_le ( & mut self . state , f1600, data) ;
137132 } ) ;
138133 }
139134}
140135
141- impl < Rate : BlockSizes > CShake < Rate > {
142- fn finalize_dirty ( & mut self ) {
143- let Self {
144- state,
145- buffer,
146- pad,
147- keccak,
148- } = self ;
149-
150- let pos = buffer. get_pos ( ) ;
151- let mut block = buffer. pad_with_zeros ( ) ;
152- block[ pos] = * pad;
153- let n = block. len ( ) ;
154- block[ n - 1 ] |= 0x80 ;
155-
156- keccak. with_f1600 ( |f1600| {
157- xor_block ( state, & block) ;
158- f1600 ( state) ;
159- } ) ;
160- }
161- }
162-
163- impl < Rate : BlockSizes > ExtendableOutput for CShake < Rate > {
136+ impl < Rate : ArraySize > ExtendableOutput for CShake < Rate > {
164137 type Reader = CShakeReader < Rate > ;
165138
166139 #[ inline]
167140 fn finalize_xof ( mut self ) -> Self :: Reader {
168- self . finalize_dirty ( ) ;
141+ let pos = self . cursor . pos ( ) ;
142+ let word_offset = pos / 8 ;
143+ let byte_offset = pos % 8 ;
144+
145+ let pad = u64:: from ( self . pad ) << ( 8 * byte_offset) ;
146+ self . state [ word_offset] ^= pad;
147+ self . state [ Rate :: USIZE / 8 - 1 ] ^= 1 << 63 ;
148+
149+ // Note that `CShakeReader` applies the permutation to the state before reading from it
150+
169151 Self :: Reader {
170152 state : self . state ,
153+ cursor : Default :: default ( ) ,
171154 keccak : self . keccak ,
172- buffer : Default :: default ( ) ,
173155 }
174156 }
175157}
176158
177- impl < Rate : BlockSizes > AlgorithmName for CShake < Rate > {
159+ impl < Rate : ArraySize > AlgorithmName for CShake < Rate > {
178160 fn write_alg_name ( f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
179161 let alg_name = match Rate :: USIZE {
180162 168 => "cSHAKE128" ,
@@ -185,7 +167,7 @@ impl<Rate: BlockSizes> AlgorithmName for CShake<Rate> {
185167 }
186168}
187169
188- impl < Rate : BlockSizes > fmt:: Debug for CShake < Rate > {
170+ impl < Rate : ArraySize > fmt:: Debug for CShake < Rate > {
189171 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
190172 let debug_str = match Rate :: USIZE {
191173 168 => "CShake128 { ... }" ,
@@ -196,53 +178,39 @@ impl<Rate: BlockSizes> fmt::Debug for CShake<Rate> {
196178 }
197179}
198180
199- impl < Rate : BlockSizes > Drop for CShake < Rate > {
181+ impl < Rate : ArraySize > Drop for CShake < Rate > {
200182 fn drop ( & mut self ) {
201183 #[ cfg( feature = "zeroize" ) ]
202184 {
203185 use digest:: zeroize:: Zeroize ;
204186 self . state . zeroize ( ) ;
187+ self . cursor . zeroize ( ) ;
205188 self . pad . zeroize ( ) ;
206- // self.buffer is zeroized by its `Drop`
207189 }
208190 }
209191}
210192
211193#[ cfg( feature = "zeroize" ) ]
212- impl < Rate : BlockSizes > digest:: zeroize:: ZeroizeOnDrop for CShake < Rate > { }
194+ impl < Rate : ArraySize > digest:: zeroize:: ZeroizeOnDrop for CShake < Rate > { }
213195
214196/// Generic cSHAKE XOF reader
215197#[ derive( Clone ) ]
216- pub struct CShakeReader < Rate : BlockSizes > {
198+ pub struct CShakeReader < Rate : ArraySize > {
217199 state : State1600 ,
200+ cursor : SpongeCursor < Rate > ,
218201 keccak : Keccak ,
219- buffer : ReadBuffer < Rate > ,
220202}
221203
222- impl < Rate : BlockSizes > XofReader for CShakeReader < Rate > {
204+ impl < Rate : ArraySize > XofReader for CShakeReader < Rate > {
223205 #[ inline]
224206 fn read ( & mut self , buf : & mut [ u8 ] ) {
225- let Self {
226- state,
227- keccak,
228- buffer,
229- } = self ;
230-
231- buffer. read ( buf, |block| {
232- let mut chunks = block. chunks_exact_mut ( 8 ) ;
233- for ( src, dst) in state. iter ( ) . zip ( & mut chunks) {
234- dst. copy_from_slice ( & src. to_le_bytes ( ) ) ;
235- }
236- assert ! (
237- chunks. into_remainder( ) . is_empty( ) ,
238- "rate is either 136 or 168" ,
239- ) ;
240- keccak. with_f1600 ( |f1600| f1600 ( state) ) ;
207+ self . keccak . with_f1600 ( |f1600| {
208+ self . cursor . squeeze_u64_le ( & mut self . state , f1600, buf) ;
241209 } ) ;
242210 }
243211}
244212
245- impl < Rate : BlockSizes > fmt:: Debug for CShakeReader < Rate > {
213+ impl < Rate : ArraySize > fmt:: Debug for CShakeReader < Rate > {
246214 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
247215 let debug_str = match Rate :: USIZE {
248216 168 => "TurboShakeReader128 { ... }" ,
@@ -253,44 +221,22 @@ impl<Rate: BlockSizes> fmt::Debug for CShakeReader<Rate> {
253221 }
254222}
255223
256- impl < Rate : BlockSizes > Drop for CShakeReader < Rate > {
224+ impl < Rate : ArraySize > Drop for CShakeReader < Rate > {
257225 fn drop ( & mut self ) {
258226 #[ cfg( feature = "zeroize" ) ]
259227 {
260228 use digest:: zeroize:: Zeroize ;
261229 self . state . zeroize ( ) ;
262- // self.buffer is zeroized by its `Drop`
230+ self . cursor . zeroize ( ) ;
263231 }
264232 }
265233}
266234
267- // https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-185.pdf#[{"num":68,"gen":0},{"name":"XYZ"},108,440,null]
235+ // See Section 8.3 of NIST SP 800-185:
236+ // https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-185.pdf
268237impl CollisionResistance for CShake128 {
269238 type CollisionResistance = U16 ;
270239}
271240impl CollisionResistance for CShake256 {
272241 type CollisionResistance = U32 ;
273242}
274-
275- fn xor_block ( state : & mut State1600 , block : & [ u8 ] ) {
276- assert ! ( size_of_val( block) < size_of_val( state) ) ;
277-
278- let mut chunks = block. chunks_exact ( 8 ) ;
279- for ( s, chunk) in state. iter_mut ( ) . zip ( & mut chunks) {
280- * s ^= u64:: from_le_bytes ( chunk. try_into ( ) . unwrap ( ) ) ;
281- }
282-
283- let rem = chunks. remainder ( ) ;
284- assert ! ( rem. is_empty( ) , "block size is equal to 136 or 168" ) ;
285- }
286-
287- fn update_blocks < N : BlockSizes > (
288- f1600 : keccak:: Fn1600 ,
289- state : & mut State1600 ,
290- blocks : & [ Array < u8 , N > ] ,
291- ) {
292- for block in blocks {
293- xor_block ( state, block) ;
294- f1600 ( state) ;
295- }
296- }
0 commit comments