2
2
3
3
use super :: { Domain , ExpandMsg , Expander } ;
4
4
use 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
10
23
///
11
24
/// # Errors
12
25
/// - `dst.is_empty()`
13
- /// - `len_in_bytes == 0`
14
26
/// - `len_in_bytes > u16::MAX`
15
- pub struct ExpandMsgXof < HashT >
27
+ pub struct ExpandMsgXof < HashT , K >
16
28
where
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 > ,
18
33
{
19
34
reader : <HashT as ExtendableOutput >:: Reader ,
35
+ _k : PhantomData < K > ,
20
36
}
21
37
22
- impl < HashT > fmt:: Debug for ExpandMsgXof < HashT >
38
+ impl < HashT , K > fmt:: Debug for ExpandMsgXof < HashT , K >
23
39
where
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 > ,
25
44
<HashT as ExtendableOutput >:: Reader : fmt:: Debug ,
26
45
{
27
46
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
@@ -31,25 +50,28 @@ where
31
50
}
32
51
}
33
52
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 >
36
56
where
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 > ,
38
64
{
39
65
type Expander = Self ;
40
66
41
67
fn expand_message (
42
68
msgs : & [ & [ u8 ] ] ,
43
69
dsts : & ' a [ & ' a [ u8 ] ] ,
44
- len_in_bytes : usize ,
70
+ len_in_bytes : NonZero < usize > ,
45
71
) -> 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 ) ?;
51
73
52
- let domain = Domain :: < U32 > :: xof :: < HashT > ( dsts) ?;
74
+ let domain = Domain :: < HashSize < K > > :: xof :: < HashT > ( dsts) ?;
53
75
let mut reader = HashT :: default ( ) ;
54
76
55
77
for msg in msgs {
@@ -60,13 +82,19 @@ where
60
82
domain. update_hash ( & mut reader) ;
61
83
reader. update ( & [ domain. len ( ) ] ) ;
62
84
let reader = reader. finalize_xof ( ) ;
63
- Ok ( Self { reader } )
85
+ Ok ( Self {
86
+ reader,
87
+ _k : PhantomData ,
88
+ } )
64
89
}
65
90
}
66
91
67
- impl < HashT > Expander for ExpandMsgXof < HashT >
92
+ impl < HashT , K > Expander for ExpandMsgXof < HashT , K >
68
93
where
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 > ,
70
98
{
71
99
fn fill_bytes ( & mut self , okm : & mut [ u8 ] ) {
72
100
self . reader . read ( okm) ;
@@ -78,7 +106,10 @@ mod test {
78
106
use super :: * ;
79
107
use core:: mem:: size_of;
80
108
use hex_literal:: hex;
81
- use hybrid_array:: { Array , ArraySize , typenum:: U128 } ;
109
+ use hybrid_array:: {
110
+ Array , ArraySize ,
111
+ typenum:: { U32 , U128 } ,
112
+ } ;
82
113
use sha3:: Shake128 ;
83
114
84
115
fn assert_message ( msg : & [ u8 ] , domain : & Domain < ' _ , U32 > , len_in_bytes : u16 , bytes : & [ u8 ] ) {
@@ -110,13 +141,16 @@ mod test {
110
141
#[ allow( clippy:: panic_in_result_fn) ]
111
142
fn assert < HashT , L > ( & self , dst : & ' static [ u8 ] , domain : & Domain < ' _ , U32 > ) -> Result < ( ) >
112
143
where
113
- HashT : Default + ExtendableOutput + Update ,
144
+ HashT : Default + ExtendableOutput + Update + HashMarker ,
114
145
L : ArraySize ,
115
146
{
116
147
assert_message ( self . msg , domain, L :: to_u16 ( ) , self . msg_prime ) ;
117
148
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
+ ) ?;
120
154
121
155
let mut uniform_bytes = Array :: < u8 , L > :: default ( ) ;
122
156
expander. fill_bytes ( & mut uniform_bytes) ;
0 commit comments