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:: { fmt, marker:: PhantomData , num:: NonZero , ops:: Mul } ;
6+ use digest:: { ExtendableOutput , HashMarker , Update , XofReader } ;
7+ use hybrid_array:: {
8+ ArraySize ,
9+ typenum:: { IsLess , U2 , U256 } ,
10+ } ;
11+
12+ /// Implements `expand_message_xof` via the [`ExpandMsg`] trait:
13+ /// <https://www.rfc-editor.org/rfc/rfc9380.html#name-expand_message_xof>
14+ ///
15+ /// `K` is the target security level in bytes:
16+ /// <https://www.rfc-editor.org/rfc/rfc9380.html#section-8.9-2.2>
17+ /// <https://www.rfc-editor.org/rfc/rfc9380.html#name-target-security-levels>
1018///
1119/// # Errors
1220/// - `dst.is_empty()`
13- /// - `len_in_bytes == 0`
1421/// - `len_in_bytes > u16::MAX`
15- pub struct ExpandMsgXof < HashT >
22+ pub struct ExpandMsgXof < HashT , K >
1623where
17- HashT : Default + ExtendableOutput + Update ,
24+ HashT : Default + ExtendableOutput + Update + HashMarker ,
25+ K : Mul < U2 > ,
26+ <K as Mul < U2 > >:: Output : ArraySize + IsLess < U256 > ,
1827{
1928 reader : <HashT as ExtendableOutput >:: Reader ,
29+ _k : PhantomData < K > ,
2030}
2131
22- impl < HashT > fmt:: Debug for ExpandMsgXof < HashT >
32+ impl < HashT , K > fmt:: Debug for ExpandMsgXof < HashT , K >
2333where
24- HashT : Default + ExtendableOutput + Update ,
34+ HashT : Default + ExtendableOutput + Update + HashMarker ,
35+ K : Mul < U2 > ,
36+ <K as Mul < U2 > >:: Output : ArraySize + IsLess < U256 > ,
2537 <HashT as ExtendableOutput >:: Reader : fmt:: Debug ,
2638{
2739 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
@@ -31,25 +43,24 @@ where
3143 }
3244}
3345
34- /// ExpandMsgXof implements `expand_message_xof` for the [`ExpandMsg`] trait
35- impl < ' a , HashT > ExpandMsg < ' a > for ExpandMsgXof < HashT >
46+ impl < ' a , HashT , K > ExpandMsg < ' a > for ExpandMsgXof < HashT , K >
3647where
37- HashT : Default + ExtendableOutput + Update ,
48+ HashT : Default + ExtendableOutput + Update + HashMarker ,
49+ // If DST is larger than 255 bytes, the length of the computed DST is calculated by `K * 2`.
50+ // https://www.rfc-editor.org/rfc/rfc9380.html#section-5.3.1-2.1
51+ K : Mul < U2 > ,
52+ <K as Mul < U2 > >:: Output : ArraySize + IsLess < U256 > ,
3853{
3954 type Expander = Self ;
4055
4156 fn expand_message (
4257 msgs : & [ & [ u8 ] ] ,
4358 dsts : & ' a [ & ' a [ u8 ] ] ,
44- len_in_bytes : usize ,
59+ len_in_bytes : NonZero < usize > ,
4560 ) -> 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 ) ?;
61+ let len_in_bytes = u16:: try_from ( len_in_bytes. get ( ) ) . map_err ( |_| Error ) ?;
5162
52- let domain = Domain :: < U32 > :: xof :: < HashT > ( dsts) ?;
63+ let domain = Domain :: < < K as Mul < U2 > > :: Output > :: xof :: < HashT > ( dsts) ?;
5364 let mut reader = HashT :: default ( ) ;
5465
5566 for msg in msgs {
@@ -60,13 +71,18 @@ where
6071 domain. update_hash ( & mut reader) ;
6172 reader. update ( & [ domain. len ( ) ] ) ;
6273 let reader = reader. finalize_xof ( ) ;
63- Ok ( Self { reader } )
74+ Ok ( Self {
75+ reader,
76+ _k : PhantomData ,
77+ } )
6478 }
6579}
6680
67- impl < HashT > Expander for ExpandMsgXof < HashT >
81+ impl < HashT , K > Expander for ExpandMsgXof < HashT , K >
6882where
69- HashT : Default + ExtendableOutput + Update ,
83+ HashT : Default + ExtendableOutput + Update + HashMarker ,
84+ K : Mul < U2 > ,
85+ <K as Mul < U2 > >:: Output : ArraySize + IsLess < U256 > ,
7086{
7187 fn fill_bytes ( & mut self , okm : & mut [ u8 ] ) {
7288 self . reader . read ( okm) ;
@@ -78,7 +94,10 @@ mod test {
7894 use super :: * ;
7995 use core:: mem:: size_of;
8096 use hex_literal:: hex;
81- use hybrid_array:: { Array , ArraySize , typenum:: U128 } ;
97+ use hybrid_array:: {
98+ Array , ArraySize ,
99+ typenum:: { U16 , U32 , U128 } ,
100+ } ;
82101 use sha3:: Shake128 ;
83102
84103 fn assert_message ( msg : & [ u8 ] , domain : & Domain < ' _ , U32 > , len_in_bytes : u16 , bytes : & [ u8 ] ) {
@@ -110,13 +129,16 @@ mod test {
110129 #[ allow( clippy:: panic_in_result_fn) ]
111130 fn assert < HashT , L > ( & self , dst : & ' static [ u8 ] , domain : & Domain < ' _ , U32 > ) -> Result < ( ) >
112131 where
113- HashT : Default + ExtendableOutput + Update ,
132+ HashT : Default + ExtendableOutput + Update + HashMarker ,
114133 L : ArraySize ,
115134 {
116135 assert_message ( self . msg , domain, L :: to_u16 ( ) , self . msg_prime ) ;
117136
118- let mut expander =
119- ExpandMsgXof :: < HashT > :: expand_message ( & [ self . msg ] , & [ dst] , L :: to_usize ( ) ) ?;
137+ let mut expander = ExpandMsgXof :: < HashT , U16 > :: expand_message (
138+ & [ self . msg ] ,
139+ & [ dst] ,
140+ NonZero :: new ( L :: to_usize ( ) ) . ok_or ( Error ) ?,
141+ ) ?;
120142
121143 let mut uniform_bytes = Array :: < u8 , L > :: default ( ) ;
122144 expander. fill_bytes ( & mut uniform_bytes) ;
0 commit comments