22
33use super :: { Domain , ExpandMsg , Expander } ;
44use crate :: { Error , Result } ;
5- use core:: fmt;
6- use digest:: { ExtendableOutput , Update , XofReader } ;
7- use hybrid_array:: typenum:: U32 ;
8-
9- /// Placeholder type for implementing `expand_message_xof` based on an extendable output function
5+ use core:: {
6+ fmt,
7+ marker:: PhantomData ,
8+ num:: NonZero ,
9+ ops:: { Div , Mul } ,
10+ } ;
11+ use digest:: { ExtendableOutput , HashMarker , Update , XofReader } ;
12+ use hybrid_array:: {
13+ ArraySize ,
14+ typenum:: { IsLess , U2 , U8 , U256 } ,
15+ } ;
16+
17+ /// Implements `expand_message_xof` via the [`ExpandMsg`] trait:
18+ /// <https://www.rfc-editor.org/rfc/rfc9380.html#name-expand_message_xof>
19+ ///
20+ /// `K` is the target security level in bits:
21+ /// <https://www.rfc-editor.org/rfc/rfc9380.html#section-8.9-2.2>
22+ /// <https://www.rfc-editor.org/rfc/rfc9380.html#name-target-security-levels>
1023///
1124/// # Errors
1225/// - `dst.is_empty()`
13- /// - `len_in_bytes == 0`
1426/// - `len_in_bytes > u16::MAX`
15- pub struct ExpandMsgXof < HashT >
27+ pub struct ExpandMsgXof < HashT , K >
1628where
17- HashT : Default + ExtendableOutput + Update ,
29+ HashT : Default + ExtendableOutput + Update + HashMarker ,
30+ U2 : Mul < K > ,
31+ <U2 as Mul < K > >:: Output : Div < U8 > ,
32+ HashSize < K > : ArraySize + IsLess < U256 > ,
1833{
1934 reader : <HashT as ExtendableOutput >:: Reader ,
35+ _k : PhantomData < K > ,
2036}
2137
22- impl < HashT > fmt:: Debug for ExpandMsgXof < HashT >
38+ impl < HashT , K > fmt:: Debug for ExpandMsgXof < HashT , K >
2339where
24- HashT : Default + ExtendableOutput + Update ,
40+ HashT : Default + ExtendableOutput + Update + HashMarker ,
41+ U2 : Mul < K > ,
42+ <U2 as Mul < K > >:: Output : Div < U8 > ,
43+ HashSize < K > : ArraySize + IsLess < U256 > ,
2544 <HashT as ExtendableOutput >:: Reader : fmt:: Debug ,
2645{
2746 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
@@ -31,25 +50,28 @@ where
3150 }
3251}
3352
34- /// ExpandMsgXof implements `expand_message_xof` for the [`ExpandMsg`] trait
35- impl < ' a , HashT > ExpandMsg < ' a > for ExpandMsgXof < HashT >
53+ type HashSize < K > = <<U2 as Mul < K > >:: Output as Div < U8 > >:: Output ;
54+
55+ impl < ' a , HashT , K > ExpandMsg < ' a > for ExpandMsgXof < HashT , K >
3656where
37- HashT : Default + ExtendableOutput + Update ,
57+ HashT : Default + ExtendableOutput + Update + HashMarker ,
58+ // If DST is larger than 255 bytes, the length of the computed DST is calculated by
59+ // `2 * k / 8`.
60+ // https://www.rfc-editor.org/rfc/rfc9380.html#section-5.3.1-2.1
61+ U2 : Mul < K > ,
62+ <U2 as Mul < K > >:: Output : Div < U8 > ,
63+ HashSize < K > : ArraySize + IsLess < U256 > ,
3864{
3965 type Expander = Self ;
4066
4167 fn expand_message (
4268 msgs : & [ & [ u8 ] ] ,
4369 dsts : & ' a [ & ' a [ u8 ] ] ,
44- len_in_bytes : usize ,
70+ len_in_bytes : NonZero < usize > ,
4571 ) -> Result < Self :: Expander > {
46- if len_in_bytes == 0 {
47- return Err ( Error ) ;
48- }
49-
50- let len_in_bytes = u16:: try_from ( len_in_bytes) . map_err ( |_| Error ) ?;
72+ let len_in_bytes = u16:: try_from ( len_in_bytes. get ( ) ) . map_err ( |_| Error ) ?;
5173
52- let domain = Domain :: < U32 > :: xof :: < HashT > ( dsts) ?;
74+ let domain = Domain :: < HashSize < K > > :: xof :: < HashT > ( dsts) ?;
5375 let mut reader = HashT :: default ( ) ;
5476
5577 for msg in msgs {
@@ -60,13 +82,19 @@ where
6082 domain. update_hash ( & mut reader) ;
6183 reader. update ( & [ domain. len ( ) ] ) ;
6284 let reader = reader. finalize_xof ( ) ;
63- Ok ( Self { reader } )
85+ Ok ( Self {
86+ reader,
87+ _k : PhantomData ,
88+ } )
6489 }
6590}
6691
67- impl < HashT > Expander for ExpandMsgXof < HashT >
92+ impl < HashT , K > Expander for ExpandMsgXof < HashT , K >
6893where
69- HashT : Default + ExtendableOutput + Update ,
94+ HashT : Default + ExtendableOutput + Update + HashMarker ,
95+ U2 : Mul < K > ,
96+ <U2 as Mul < K > >:: Output : Div < U8 > ,
97+ HashSize < K > : ArraySize + IsLess < U256 > ,
7098{
7199 fn fill_bytes ( & mut self , okm : & mut [ u8 ] ) {
72100 self . reader . read ( okm) ;
@@ -78,7 +106,10 @@ mod test {
78106 use super :: * ;
79107 use core:: mem:: size_of;
80108 use hex_literal:: hex;
81- use hybrid_array:: { Array , ArraySize , typenum:: U128 } ;
109+ use hybrid_array:: {
110+ Array , ArraySize ,
111+ typenum:: { U32 , U128 } ,
112+ } ;
82113 use sha3:: Shake128 ;
83114
84115 fn assert_message ( msg : & [ u8 ] , domain : & Domain < ' _ , U32 > , len_in_bytes : u16 , bytes : & [ u8 ] ) {
@@ -110,13 +141,16 @@ mod test {
110141 #[ allow( clippy:: panic_in_result_fn) ]
111142 fn assert < HashT , L > ( & self , dst : & ' static [ u8 ] , domain : & Domain < ' _ , U32 > ) -> Result < ( ) >
112143 where
113- HashT : Default + ExtendableOutput + Update ,
144+ HashT : Default + ExtendableOutput + Update + HashMarker ,
114145 L : ArraySize ,
115146 {
116147 assert_message ( self . msg , domain, L :: to_u16 ( ) , self . msg_prime ) ;
117148
118- let mut expander =
119- ExpandMsgXof :: < HashT > :: expand_message ( & [ self . msg ] , & [ dst] , L :: to_usize ( ) ) ?;
149+ let mut expander = ExpandMsgXof :: < HashT , U128 > :: expand_message (
150+ & [ self . msg ] ,
151+ & [ dst] ,
152+ NonZero :: new ( L :: to_usize ( ) ) . ok_or ( Error ) ?,
153+ ) ?;
120154
121155 let mut uniform_bytes = Array :: < u8 , L > :: default ( ) ;
122156 expander. fill_bytes ( & mut uniform_bytes) ;
0 commit comments