@@ -14,117 +14,110 @@ pub use digest::{self, Digest};
1414mod oids;
1515mod variants;
1616
17- use crate :: variants:: Rate ;
17+ pub use variants:: * ;
18+
1819use bash_f:: { STATE_WORDS , bash_f} ;
1920use core:: fmt;
2021use digest:: {
2122 ExtendableOutput , ExtendableOutputReset , Reset , TryCustomizedInit , Update , XofReader ,
22- typenum:: { U1 , U2 , U16 , U24 , U32 } ,
2323} ;
2424use sponge_cursor:: SpongeCursor ;
25- pub use variants:: { Capacity , SecurityLevel } ;
26-
27- /// Invalid header length error
28- #[ derive( Debug ) ]
29- pub struct InvalidHeaderLength ;
3025
3126/// Data type codes from Table 3 of STB 34.101.77-2020
3227const DATA : u8 = 0b000010 ;
3328/// Data type codes from Table 3 of STB 34.101.77-2020
3429const OUT : u8 = 0b000100 ;
3530
36- /// `bash-prg-hash` hasher generic over security level and capacity.
31+ /// `bash-prg-hash` hasher generic over rate and capacity.
3732///
3833/// # Generic Parameters
3934///
40- /// - `L`: Security level ℓ ∈ {128, 192, 256}. Use `U16`, `U24`, or `U32` from `digest::typenum`.
41- /// - `D`: Capacity d ∈ {1, 2}. Use `U1` or `U2` from `digest::typenum`.
35+ /// Only the following combinations of rate and capacity with
36+ /// the resulting security level are supported:
4237///
43- /// # Examples
38+ /// | Rate, bytes | Capacity | Security level, bits |
39+ /// |:-----------:|:--------:|:--------------------:|
40+ /// | 160 | 1 | 128 |
41+ /// | 128 | 2 | 128 |
42+ /// | 144 | 1 | 192 |
43+ /// | 96 | 2 | 192 |
44+ /// | 128 | 1 | 256 |
45+ /// | 64 | 2 | 256 |
4446///
45- /// ```
46- /// use bash_prg_hash::{BashPrgHash1281, digest::{ExtendableOutput, Update, XofReader}};
47+ /// Trying to initialize hasher state with a different pair of parameters will
48+ /// result in a compilation error.
4749///
48- /// let mut hasher = BashPrgHash1281::default();
49- /// hasher.update(b"hello world");
50- /// let mut reader = hasher.finalize_xof();
51- /// let mut output = [0u8; 32];
52- /// reader.read(&mut output);
53- /// ```
50+ /// Users are recommended to use type aliases (e.g. [`BashPrgHash1281`]) instead of using
51+ /// this type directly.
52+ // Note: Ideally, we would use `LEVEL` instead of `RATE` and define the `cursor` field as
53+ // `SpongeCursor<{192-2*CAPACITY*LEVEL}>`, but it requires stabilized `generic_const_exprs`.
5454#[ derive( Clone ) ]
55- pub struct BashPrgHash < L : SecurityLevel , D : Capacity >
56- where
57- ( L , D ) : Rate ,
58- {
55+ pub struct BashPrgHash < const RATE : usize , const CAPACITY : usize > {
5956 state : [ u64 ; STATE_WORDS ] ,
60- cursor : SpongeCursor < < ( L , D ) as Rate > :: Rate > ,
57+ cursor : SpongeCursor < RATE > ,
6158}
6259
63- impl < L : SecurityLevel , D : Capacity > Default for BashPrgHash < L , D >
64- where
65- ( L , D ) : Rate ,
66- {
60+ impl < const RATE : usize , const CAPACITY : usize > Default for BashPrgHash < RATE , CAPACITY > {
61+ #[ inline]
6762 fn default ( ) -> Self {
68- Self :: try_new_customized ( & [ ] [ .. ] ) . expect ( "Always correct" )
63+ Self :: try_new_customized ( & [ ] ) . expect ( "Always correct" )
6964 }
7065}
7166
72- impl < L : SecurityLevel , D : Capacity > TryCustomizedInit for BashPrgHash < L , D >
73- where
74- ( L , D ) : Rate ,
75- {
76- type Error = InvalidHeaderLength ;
67+ impl < const RATE : usize , const CAPACITY : usize > TryCustomizedInit for BashPrgHash < RATE , CAPACITY > {
68+ type Error = InvalidHeaderError ;
7769
70+ #[ inline]
7871 fn try_new_customized ( header : & [ u8 ] ) -> Result < Self , Self :: Error > {
7972 const MAX_HEADER_LEN : usize = 60 ;
8073
8174 if header. len ( ) > MAX_HEADER_LEN || header. len ( ) % 4 != 0 {
82- return Err ( InvalidHeaderLength ) ;
75+ return Err ( InvalidHeaderError ) ;
8376 }
8477
85- let mut this = Self {
78+ let mut s = Self {
8679 state : [ 0u64 ; STATE_WORDS ] ,
8780 cursor : SpongeCursor :: default ( ) ,
8881 } ;
8982
90- this . start ( header) ;
91- this . commit ( DATA ) ;
83+ s . start ( header) ;
84+ s . commit ( DATA ) ;
9285
93- Ok ( this )
86+ Ok ( s )
9487 }
9588}
9689
97- impl < L : SecurityLevel , D : Capacity > Update for BashPrgHash < L , D >
98- where
99- ( L , D ) : Rate ,
100- {
90+ impl < const RATE : usize , const CAPACITY : usize > BashPrgHash < RATE , CAPACITY > { }
91+
92+ impl < const RATE : usize , const CAPACITY : usize > Update for BashPrgHash < RATE , CAPACITY > {
93+ # [ inline ]
10194 fn update ( & mut self , data : & [ u8 ] ) {
102- self . absorb ( data) ;
95+ // `absorb[ℓ, d](X)` (Section 8.6.2)
96+ self . cursor . absorb_u64_le ( & mut self . state , bash_f, data) ;
10397 }
10498}
10599
106- impl < L : SecurityLevel , D : Capacity > ExtendableOutput for BashPrgHash < L , D >
107- where
108- ( L , D ) : Rate ,
109- {
110- type Reader = BashPrgHashReader < L , D > ;
100+ impl < const RATE : usize , const CAPACITY : usize > ExtendableOutput for BashPrgHash < RATE , CAPACITY > {
101+ type Reader = BashPrgHashReader < RATE , CAPACITY > ;
111102
103+ #[ inline]
112104 fn finalize_xof ( mut self ) -> Self :: Reader {
113- self . finalize ( ) ;
105+ // `squeezePrep[ℓ, d]()` / output preparation: `commit(OUT)` (Section 8.7).
106+ self . commit ( OUT ) ;
114107 BashPrgHashReader {
115108 state : self . state ,
116109 cursor : self . cursor . clone ( ) ,
117110 }
118111 }
119112}
120113
121- impl < L : SecurityLevel , D : Capacity > ExtendableOutputReset for BashPrgHash < L , D >
122- where
123- ( L , D ) : Rate ,
114+ impl < const RATE : usize , const CAPACITY : usize > ExtendableOutputReset
115+ for BashPrgHash < RATE , CAPACITY >
124116{
117+ #[ inline]
125118 fn finalize_xof_reset ( & mut self ) -> Self :: Reader {
126119 let mut hasher_clone = self . clone ( ) ;
127- hasher_clone. finalize ( ) ;
120+ hasher_clone. commit ( OUT ) ;
128121 self . reset ( ) ;
129122 BashPrgHashReader {
130123 state : hasher_clone. state ,
@@ -133,66 +126,47 @@ where
133126 }
134127}
135128
136- impl < L : SecurityLevel , D : Capacity > Reset for BashPrgHash < L , D >
137- where
138- ( L , D ) : Rate ,
139- {
129+ impl < const RATE : usize , const CAPACITY : usize > Reset for BashPrgHash < RATE , CAPACITY > {
130+ #[ inline]
140131 fn reset ( & mut self ) {
141132 * self = Self :: default ( ) ;
142133 }
143134}
144135
145- impl < L : SecurityLevel , D : Capacity > fmt:: Debug for BashPrgHash < L , D >
146- where
147- ( L , D ) : Rate ,
148- {
136+ impl < const RATE : usize , const CAPACITY : usize > fmt:: Debug for BashPrgHash < RATE , CAPACITY > {
137+ #[ inline]
149138 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
150139 f. write_str ( "BashPrgHash { ... }" )
151140 }
152141}
153142
154- impl < L : SecurityLevel , D : Capacity > digest:: CollisionResistance for BashPrgHash < L , D >
155- where
156- ( L , D ) : Rate ,
157- {
158- type CollisionResistance = L ;
159- }
160-
161143#[ cfg( feature = "zeroize" ) ]
162- impl < L : SecurityLevel , D : Capacity > digest:: zeroize:: ZeroizeOnDrop for BashPrgHash < L , D > where
163- ( L , D ) : Rate
144+ impl < const RATE : usize , const CAPACITY : usize > digest:: zeroize:: ZeroizeOnDrop
145+ for BashPrgHash < RATE , CAPACITY >
164146{
165147}
166148
167149/// Reader for bash-prg-hash XOF output.
168150#[ derive( Clone ) ]
169- pub struct BashPrgHashReader < L : SecurityLevel , D : Capacity >
170- where
171- ( L , D ) : Rate ,
172- {
151+ pub struct BashPrgHashReader < const RATE : usize , const CAPACITY : usize > {
173152 state : [ u64 ; STATE_WORDS ] ,
174- cursor : SpongeCursor < < ( L , D ) as Rate > :: Rate > ,
153+ cursor : SpongeCursor < RATE > ,
175154}
176155
177- impl < L : SecurityLevel , D : Capacity > XofReader for BashPrgHashReader < L , D >
178- where
179- ( L , D ) : Rate ,
180- {
156+ impl < const RATE : usize , const CAPACITY : usize > XofReader for BashPrgHashReader < RATE , CAPACITY > {
157+ #[ inline]
181158 fn read ( & mut self , buffer : & mut [ u8 ] ) {
182159 self . squeeze ( buffer) ;
183160 }
184161}
185162
186163#[ cfg( feature = "zeroize" ) ]
187- impl < L : SecurityLevel , D : Capacity > digest:: zeroize:: ZeroizeOnDrop for BashPrgHashReader < L , D > where
188- ( L , D ) : Rate
164+ impl < const RATE : usize , const CAPACITY : usize > digest:: zeroize:: ZeroizeOnDrop
165+ for BashPrgHashReader < RATE , CAPACITY >
189166{
190167}
191168
192- impl < L : SecurityLevel , D : Capacity > BashPrgHash < L , D >
193- where
194- ( L , D ) : Rate ,
195- {
169+ impl < const RATE : usize , const CAPACITY : usize > BashPrgHash < RATE , CAPACITY > {
196170 /// Modify byte at position in state
197171 fn modify_byte ( state : & mut [ u64 ; STATE_WORDS ] , pos : usize , f : impl FnOnce ( & mut u8 ) ) {
198172 let word_idx = pos / 8 ;
@@ -218,21 +192,10 @@ where
218192 self . cursor = SpongeCursor :: new ( pos) . expect ( "pos within bounds" ) ;
219193
220194 // Step 6: S[1472...) <- <ℓ/4 + d>_64
221- self . state [ 23 ] = ( L :: USIZE * 2 + D :: USIZE ) as u64 ;
195+ let level = ( 192 - RATE ) / ( 2 * CAPACITY ) ;
196+ self . state [ 23 ] = ( level * 2 + CAPACITY ) as u64 ;
222197 }
223198
224- /// `squeezePrep[ℓ, d]()` / output preparation: `commit(OUT)` (Section 8.7).
225- fn finalize ( & mut self ) {
226- self . commit ( OUT ) ;
227- }
228- }
229-
230- impl < L : SecurityLevel , D : Capacity > BashPrgHash < L , D >
231- where
232- ( L , D ) : Rate ,
233- {
234- const RATE : usize = 192 - 2 * D :: USIZE * L :: USIZE ;
235-
236199 fn get_byte ( state : & [ u64 ; STATE_WORDS ] , pos : usize ) -> u8 {
237200 let word_idx = pos / 8 ;
238201 let byte_in_word = pos % 8 ;
@@ -245,12 +208,6 @@ where
245208 }
246209 }
247210
248- /// `absorb[ℓ, d](X)` (Section 8.6.2)
249- fn absorb ( & mut self , data : & [ u8 ] ) {
250- self . cursor
251- . absorb_u64_le :: < STATE_WORDS > ( & mut self . state , bash_f, data) ;
252- }
253-
254211 /// `commit[ℓ, d](t)` (Section 8.4.2)
255212 fn commit ( & mut self , t : u8 ) {
256213 let pos = self . cursor . pos ( ) ;
@@ -260,10 +217,8 @@ where
260217 Self :: modify_byte ( & mut self . state , pos, |b| * b ^= tag) ;
261218
262219 // Step 2: S[r] <- S[r] ⊕ 1, where r = 1536 - 2 d ℓ (bit index).
263- let r_bit_in_byte = ( Self :: RATE * 8 ) % 8 ;
264- Self :: modify_byte ( & mut self . state , Self :: RATE , |b| {
265- * b ^= 1u8 << ( 7 - r_bit_in_byte)
266- } ) ;
220+ let r_bit_in_byte = ( RATE * 8 ) % 8 ;
221+ Self :: modify_byte ( & mut self . state , RATE , |b| * b ^= 1u8 << ( 7 - r_bit_in_byte) ) ;
267222
268223 // Step 3: S <- bash-f(S).
269224 bash_f ( & mut self . state ) ;
@@ -272,24 +227,25 @@ where
272227 }
273228}
274229
275- impl < L : SecurityLevel , D : Capacity > BashPrgHashReader < L , D >
276- where
277- ( L , D ) : Rate ,
278- {
230+ impl < const RATE : usize , const CAPACITY : usize > BashPrgHashReader < RATE , CAPACITY > {
279231 /// `squeeze[ℓ, d](Y)` (Section 8.7.2)
280232 fn squeeze ( & mut self , output : & mut [ u8 ] ) {
281233 let mut remaining = output;
282234
283235 while !remaining. is_empty ( ) {
284236 // Step 1: Split Y into the next chunk Yi with |Yi| <= r - pos.
285237 let pos = self . cursor . pos ( ) ;
286- let to_squeeze = remaining. len ( ) . min ( BashPrgHash :: < L , D > :: RATE - pos) ;
238+ let to_squeeze = remaining. len ( ) . min ( RATE - pos) ;
287239
288240 // Step 2: Yi <- S[pos..pos+|Yi|), pos <- pos + |Yi|.
289- BashPrgHash :: < L , D > :: extract_bytes ( & self . state , pos, & mut remaining[ ..to_squeeze] ) ;
241+ BashPrgHash :: < RATE , CAPACITY > :: extract_bytes (
242+ & self . state ,
243+ pos,
244+ & mut remaining[ ..to_squeeze] ,
245+ ) ;
290246 remaining = & mut remaining[ to_squeeze..] ;
291247
292- if pos + to_squeeze == BashPrgHash :: < L , D > :: RATE {
248+ if pos + to_squeeze == RATE {
293249 // Step 3: If pos = r then S <- bash-f(S), pos <- 0.
294250 bash_f ( & mut self . state ) ;
295251 self . cursor = SpongeCursor :: default ( ) ;
@@ -301,10 +257,8 @@ where
301257 }
302258}
303259
304- impl < L : SecurityLevel , D : Capacity > Drop for BashPrgHash < L , D >
305- where
306- ( L , D ) : Rate ,
307- {
260+ impl < const RATE : usize , const CAPACITY : usize > Drop for BashPrgHash < RATE , CAPACITY > {
261+ #[ inline]
308262 fn drop ( & mut self ) {
309263 #[ cfg( feature = "zeroize" ) ]
310264 {
@@ -314,10 +268,8 @@ where
314268 }
315269}
316270
317- impl < L : SecurityLevel , D : Capacity > Drop for BashPrgHashReader < L , D >
318- where
319- ( L , D ) : Rate ,
320- {
271+ impl < const RATE : usize , const CAPACITY : usize > Drop for BashPrgHashReader < RATE , CAPACITY > {
272+ #[ inline]
321273 fn drop ( & mut self ) {
322274 #[ cfg( feature = "zeroize" ) ]
323275 {
@@ -327,15 +279,17 @@ where
327279 }
328280}
329281
330- /// bash-prg-hash with ℓ = 128 and d = 1
331- pub type BashPrgHash1281 = BashPrgHash < U16 , U1 > ;
332- /// bash-prg-hash with ℓ = 128 and d = 2
333- pub type BashPrgHash1282 = BashPrgHash < U16 , U2 > ;
334- /// bash-prg-hash with ℓ = 192 and d = 1
335- pub type BashPrgHash1921 = BashPrgHash < U24 , U1 > ;
336- /// bash-prg-hash with ℓ = 192 and d = 2
337- pub type BashPrgHash1922 = BashPrgHash < U24 , U2 > ;
338- /// bash-prg-hash with ℓ = 256 and d = 1
339- pub type BashPrgHash2561 = BashPrgHash < U32 , U1 > ;
340- /// bash-prg-hash with ℓ = 256 and d = 2
341- pub type BashPrgHash2562 = BashPrgHash < U32 , U2 > ;
282+ /// Invalid `bash-prg-hash` header error.
283+ #[ derive( Debug ) ]
284+ pub struct InvalidHeaderError ;
285+
286+ impl fmt:: Display for InvalidHeaderError {
287+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
288+ f. write_str (
289+ "Invalid `bash-prg-hash` header. \
290+ Header length must be a multiple of 4 bytes and not greater than 60 bytes.",
291+ )
292+ }
293+ }
294+
295+ impl core:: error:: Error for InvalidHeaderError { }
0 commit comments