dcrypt_algorithms/xof/
mod.rs1#[cfg(feature = "alloc")]
7extern crate alloc;
8
9use crate::error::{validate, Error, Result};
10#[cfg(feature = "alloc")]
11use dcrypt_internal::zeroing::ZeroizingBytes;
12
13#[cfg(feature = "alloc")]
14pub mod shake;
15
16#[cfg(feature = "alloc")]
17pub mod blake3;
18
19#[cfg(feature = "alloc")]
21pub use shake::{ShakeXof128, ShakeXof256};
22
23#[cfg(feature = "alloc")]
24pub use blake3::Blake3Xof;
25
26#[cfg(feature = "alloc")]
28pub type Xof = ZeroizingBytes;
29
30pub trait ExtendableOutputFunction {
32 fn new() -> Self;
34
35 fn update(&mut self, data: &[u8]) -> Result<()>;
37
38 fn finalize(&mut self) -> Result<()>;
40
41 fn squeeze(&mut self, output: &mut [u8]) -> Result<()>;
43
44 #[cfg(feature = "alloc")]
47 fn squeeze_into_vec(&mut self, len: usize) -> Result<ZeroizingBytes>;
48
49 fn reset(&mut self) -> Result<()>;
51
52 fn security_level() -> usize;
54
55 #[cfg(feature = "alloc")]
57 fn generate(data: &[u8], len: usize) -> Result<ZeroizingBytes>
58 where
59 Self: Sized,
60 {
61 validate::parameter(
62 len > 0,
63 "output_length",
64 "XOF output length must be greater than 0",
65 )?;
66
67 let mut xof = Self::new();
68 xof.update(data)?;
69 xof.squeeze_into_vec(len)
70 }
71}
72
73pub trait XofAlgorithm {
75 const SECURITY_LEVEL: usize;
77
78 const MIN_OUTPUT_SIZE: usize;
80
81 const MAX_OUTPUT_SIZE: Option<usize>;
83
84 const ALGORITHM_ID: &'static str;
86
87 fn name() -> &'static str {
89 Self::ALGORITHM_ID
90 }
91
92 fn validate_output_length(len: usize) -> Result<()> {
94 validate::parameter(
95 len >= Self::MIN_OUTPUT_SIZE,
96 "output_length",
97 "Output length below minimum recommended size",
98 )?;
99
100 if let Some(max) = Self::MAX_OUTPUT_SIZE {
101 validate::max_length("XOF output", len, max)?;
102 }
103
104 Ok(())
105 }
106}
107
108pub enum Shake128Algorithm {}
110
111impl XofAlgorithm for Shake128Algorithm {
112 const SECURITY_LEVEL: usize = 128;
113 const MIN_OUTPUT_SIZE: usize = 16; const MAX_OUTPUT_SIZE: Option<usize> = None; const ALGORITHM_ID: &'static str = "SHAKE-128";
116}
117
118pub enum Shake256Algorithm {}
120
121impl XofAlgorithm for Shake256Algorithm {
122 const SECURITY_LEVEL: usize = 256;
123 const MIN_OUTPUT_SIZE: usize = 32; const MAX_OUTPUT_SIZE: Option<usize> = None; const ALGORITHM_ID: &'static str = "SHAKE-256";
126}
127
128pub enum Blake3Algorithm {}
130
131impl XofAlgorithm for Blake3Algorithm {
132 const SECURITY_LEVEL: usize = 256;
133 const MIN_OUTPUT_SIZE: usize = 32; const MAX_OUTPUT_SIZE: Option<usize> = None; const ALGORITHM_ID: &'static str = "BLAKE3-XOF";
136}
137
138pub trait KeyedXof: ExtendableOutputFunction {
140 fn with_key(key: &[u8]) -> Result<Self>
142 where
143 Self: Sized;
144
145 #[cfg(feature = "alloc")]
147 fn keyed_generate(key: &[u8], data: &[u8], len: usize) -> Result<ZeroizingBytes>
148 where
149 Self: Sized,
150 {
151 validate::parameter(
152 len > 0,
153 "output_length",
154 "XOF output length must be greater than 0",
155 )?;
156
157 let mut xof = Self::with_key(key)?;
158 xof.update(data)?;
159 xof.squeeze_into_vec(len)
160 }
161}
162
163pub trait DeriveKeyXof: ExtendableOutputFunction {
165 fn for_derive_key(context: &[u8]) -> Result<Self>
167 where
168 Self: Sized;
169
170 #[cfg(feature = "alloc")]
172 fn derive_key(context: &[u8], data: &[u8], len: usize) -> Result<ZeroizingBytes>
173 where
174 Self: Sized,
175 {
176 validate::parameter(
177 len > 0,
178 "output_length",
179 "Key derivation output length must be greater than 0",
180 )?;
181
182 let mut xof = Self::for_derive_key(context)?;
183 xof.update(data)?;
184 xof.squeeze_into_vec(len)
185 }
186}
187
188impl Error {
190 pub(crate) fn xof_finalized() -> Self {
192 Error::Processing {
193 operation: "XOF",
194 details: "Cannot update after finalization",
195 }
196 }
197
198 pub(crate) fn xof_squeezing() -> Self {
200 Error::Processing {
201 operation: "XOF",
202 details: "Cannot update after squeezing has begun",
203 }
204 }
205}
206
207#[cfg(test)]
208mod tests {
209 use super::*;
210
211 #[test]
212 fn test_xof_algorithm_validation() {
213 assert!(Shake128Algorithm::validate_output_length(16).is_ok());
215 assert!(Shake128Algorithm::validate_output_length(15).is_err());
216
217 assert!(Shake256Algorithm::validate_output_length(32).is_ok());
219 assert!(Shake256Algorithm::validate_output_length(31).is_err());
220
221 assert!(Blake3Algorithm::validate_output_length(32).is_ok());
223 assert!(Blake3Algorithm::validate_output_length(31).is_err());
224 }
225}