dcrypt_algorithms/xof/
mod.rs

1//! Extendable Output Functions (XOF)
2//!
3//! This module contains implementations of Extendable Output Functions (XOFs)
4//! which can produce outputs of arbitrary length.
5
6#![cfg_attr(not(feature = "std"), no_std)]
7
8#[cfg(feature = "alloc")]
9extern crate alloc;
10
11#[cfg(not(feature = "std"))]
12#[cfg(feature = "alloc")]
13use alloc::vec::Vec;
14
15#[cfg(feature = "std")]
16use std::vec::Vec;
17
18use crate::error::{validate, Error, Result};
19
20#[cfg(feature = "alloc")]
21pub mod shake;
22
23#[cfg(feature = "alloc")]
24pub mod blake3;
25
26// Re-exports
27#[cfg(feature = "alloc")]
28pub use shake::{ShakeXof128, ShakeXof256};
29
30#[cfg(feature = "alloc")]
31pub use blake3::Blake3Xof;
32
33/// An Extendable Output Function (XOF) produces output of arbitrary length
34#[cfg(feature = "alloc")]
35pub type Xof = Vec<u8>;
36
37/// Trait for extendable output functions
38pub trait ExtendableOutputFunction {
39    /// Creates a new instance of the XOF
40    fn new() -> Self;
41
42    /// Updates the XOF state with new data
43    fn update(&mut self, data: &[u8]) -> Result<()>;
44
45    /// Finalizes the XOF state for output
46    fn finalize(&mut self) -> Result<()>;
47
48    /// Squeezes output bytes into the provided buffer
49    fn squeeze(&mut self, output: &mut [u8]) -> Result<()>;
50
51    /// Squeezes the specified number of output bytes into a new vector
52    #[cfg(feature = "alloc")]
53    fn squeeze_into_vec(&mut self, len: usize) -> Result<Vec<u8>>;
54
55    /// Resets the XOF state
56    fn reset(&mut self) -> Result<()>;
57
58    /// Returns the security level in bits
59    fn security_level() -> usize;
60
61    /// Convenience method to generate output in a single call
62    #[cfg(feature = "alloc")]
63    fn generate(data: &[u8], len: usize) -> Result<Vec<u8>>
64    where
65        Self: Sized,
66    {
67        validate::parameter(
68            len > 0,
69            "output_length",
70            "XOF output length must be greater than 0",
71        )?;
72
73        let mut xof = Self::new();
74        xof.update(data)?;
75        xof.squeeze_into_vec(len)
76    }
77}
78
79/// Trait for XOF algorithms with compile-time guarantees
80pub trait XofAlgorithm {
81    /// Security level in bits
82    const SECURITY_LEVEL: usize;
83
84    /// Minimum recommended output size in bytes
85    const MIN_OUTPUT_SIZE: usize;
86
87    /// Maximum output size in bytes (None for unlimited)
88    const MAX_OUTPUT_SIZE: Option<usize>;
89
90    /// Algorithm identifier
91    const ALGORITHM_ID: &'static str;
92
93    /// Algorithm name
94    fn name() -> &'static str {
95        Self::ALGORITHM_ID
96    }
97
98    /// Validate output length
99    fn validate_output_length(len: usize) -> Result<()> {
100        validate::parameter(
101            len >= Self::MIN_OUTPUT_SIZE,
102            "output_length",
103            "Output length below minimum recommended size",
104        )?;
105
106        if let Some(max) = Self::MAX_OUTPUT_SIZE {
107            validate::max_length("XOF output", len, max)?;
108        }
109
110        Ok(())
111    }
112}
113
114/// Type-level constants for SHAKE-128
115pub enum Shake128Algorithm {}
116
117impl XofAlgorithm for Shake128Algorithm {
118    const SECURITY_LEVEL: usize = 128;
119    const MIN_OUTPUT_SIZE: usize = 16; // 128 bits
120    const MAX_OUTPUT_SIZE: Option<usize> = None; // Unlimited
121    const ALGORITHM_ID: &'static str = "SHAKE-128";
122}
123
124/// Type-level constants for SHAKE-256
125pub enum Shake256Algorithm {}
126
127impl XofAlgorithm for Shake256Algorithm {
128    const SECURITY_LEVEL: usize = 256;
129    const MIN_OUTPUT_SIZE: usize = 32; // 256 bits
130    const MAX_OUTPUT_SIZE: Option<usize> = None; // Unlimited
131    const ALGORITHM_ID: &'static str = "SHAKE-256";
132}
133
134/// Type-level constants for BLAKE3
135pub enum Blake3Algorithm {}
136
137impl XofAlgorithm for Blake3Algorithm {
138    const SECURITY_LEVEL: usize = 256;
139    const MIN_OUTPUT_SIZE: usize = 32; // 256 bits
140    const MAX_OUTPUT_SIZE: Option<usize> = None; // Unlimited
141    const ALGORITHM_ID: &'static str = "BLAKE3-XOF";
142}
143
144/// Helper trait for XOFs that need keyed variants
145pub trait KeyedXof: ExtendableOutputFunction {
146    /// Creates a new keyed XOF instance
147    fn with_key(key: &[u8]) -> Result<Self>
148    where
149        Self: Sized;
150
151    /// Generates keyed output in a single call
152    #[cfg(feature = "alloc")]
153    fn keyed_generate(key: &[u8], data: &[u8], len: usize) -> Result<Vec<u8>>
154    where
155        Self: Sized,
156    {
157        validate::parameter(
158            len > 0,
159            "output_length",
160            "XOF output length must be greater than 0",
161        )?;
162
163        let mut xof = Self::with_key(key)?;
164        xof.update(data)?;
165        xof.squeeze_into_vec(len)
166    }
167}
168
169/// Helper trait for XOFs that support key derivation mode
170pub trait DeriveKeyXof: ExtendableOutputFunction {
171    /// Creates a new XOF instance for key derivation
172    fn for_derive_key(context: &[u8]) -> Result<Self>
173    where
174        Self: Sized;
175
176    /// Derives key material in a single call
177    #[cfg(feature = "alloc")]
178    fn derive_key(context: &[u8], data: &[u8], len: usize) -> Result<Vec<u8>>
179    where
180        Self: Sized,
181    {
182        validate::parameter(
183            len > 0,
184            "output_length",
185            "Key derivation output length must be greater than 0",
186        )?;
187
188        let mut xof = Self::for_derive_key(context)?;
189        xof.update(data)?;
190        xof.squeeze_into_vec(len)
191    }
192}
193
194// Error conversion helpers for XOF-specific errors
195impl Error {
196    /// Create an XOF finalization error
197    pub(crate) fn xof_finalized() -> Self {
198        Error::Processing {
199            operation: "XOF",
200            details: "Cannot update after finalization",
201        }
202    }
203
204    /// Create an XOF squeezing error
205    pub(crate) fn xof_squeezing() -> Self {
206        Error::Processing {
207            operation: "XOF",
208            details: "Cannot update after squeezing has begun",
209        }
210    }
211}
212
213#[cfg(test)]
214mod tests {
215    use super::*;
216
217    #[test]
218    fn test_xof_algorithm_validation() {
219        // Test SHAKE-128 validation
220        assert!(Shake128Algorithm::validate_output_length(16).is_ok());
221        assert!(Shake128Algorithm::validate_output_length(15).is_err());
222
223        // Test SHAKE-256 validation
224        assert!(Shake256Algorithm::validate_output_length(32).is_ok());
225        assert!(Shake256Algorithm::validate_output_length(31).is_err());
226
227        // Test BLAKE3 validation
228        assert!(Blake3Algorithm::validate_output_length(32).is_ok());
229        assert!(Blake3Algorithm::validate_output_length(31).is_err());
230    }
231}