Skip to main content

lib_q_core/contexts/
hash.rs

1//! Hash context implementation for lib-Q Core
2//!
3//! This module provides the hash context that handles hash operations
4//! with proper security validation.
5
6#[cfg(feature = "alloc")]
7use alloc::{
8    boxed::Box,
9    string::String,
10    vec::Vec,
11};
12
13use super::BaseContext;
14#[cfg(test)]
15use crate::api::HashOperations;
16use crate::api::{
17    Algorithm,
18    AlgorithmCategory,
19    CryptoProvider,
20};
21use crate::error::Result;
22
23/// Hash context for hash operations
24#[cfg(feature = "alloc")]
25pub struct HashContext {
26    inner: BaseContext<Self>,
27}
28
29#[cfg(feature = "alloc")]
30impl HashContext {
31    /// Create a new hash context with no provider
32    pub fn new() -> Self {
33        Self {
34            inner: BaseContext::new(),
35        }
36    }
37
38    /// Create a new hash context with a provider
39    pub fn with_provider(provider: Box<dyn CryptoProvider>) -> Self {
40        Self {
41            inner: BaseContext::with_provider(provider),
42        }
43    }
44
45    /// Create a new hash context with the default provider
46    #[cfg(feature = "alloc")]
47    pub fn with_default_provider() -> Self {
48        Self {
49            inner: match crate::providers::LibQCryptoProvider::new() {
50                Ok(provider) => BaseContext::with_provider(Box::new(provider)),
51                Err(_) => BaseContext::new(),
52            },
53        }
54    }
55
56    /// Set the cryptographic provider
57    pub fn set_provider(&mut self, provider: Box<dyn CryptoProvider>) {
58        self.inner.set_provider(provider);
59    }
60
61    /// Get the current provider
62    pub fn provider(&self) -> Option<&dyn CryptoProvider> {
63        self.inner.provider()
64    }
65
66    /// Hash data using the specified algorithm
67    pub fn hash(&mut self, algorithm: Algorithm, data: &[u8]) -> Result<Vec<u8>> {
68        self.inner.ensure_initialized()?;
69
70        // Validate algorithm category
71        if algorithm.category() != AlgorithmCategory::Hash {
72            return Err(crate::error::Error::InvalidAlgorithm {
73                algorithm: "Algorithm is not a hash algorithm",
74            });
75        }
76
77        // Use provider if available
78        match self.inner.provider().and_then(|p| p.hash()) {
79            Some(hash_ops) => hash_ops.hash(algorithm, data),
80            None => Err(crate::error::Error::ProviderNotConfigured {
81                operation: String::from("hash"),
82            }),
83        }
84    }
85
86    /// Check if the context is initialized
87    pub fn is_initialized(&self) -> bool {
88        self.inner.is_initialized()
89    }
90}
91
92#[cfg(feature = "alloc")]
93impl Default for HashContext {
94    fn default() -> Self {
95        Self::new()
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102    use crate::api::CryptoProvider;
103
104    // Mock provider for testing
105    struct MockHashProvider;
106
107    impl CryptoProvider for MockHashProvider {
108        fn kem(&self) -> Option<&dyn crate::api::KemOperations> {
109            None
110        }
111        fn signature(&self) -> Option<&dyn crate::api::SignatureOperations> {
112            None
113        }
114        fn hash(&self) -> Option<&dyn HashOperations> {
115            Some(self)
116        }
117        fn aead(&self) -> Option<&dyn crate::api::AeadOperations> {
118            None
119        }
120    }
121
122    impl HashOperations for MockHashProvider {
123        fn hash(&self, _algorithm: Algorithm, _data: &[u8]) -> Result<Vec<u8>> {
124            Err(crate::error::Error::NotImplemented {
125                feature: "Mock hash operations not implemented".to_string(),
126            })
127        }
128    }
129
130    #[test]
131    fn test_hash_context_creation() {
132        let context = HashContext::new();
133        assert!(!context.is_initialized());
134        assert!(context.provider().is_none());
135    }
136
137    #[test]
138    fn test_hash_context_with_provider() {
139        let provider = Box::new(MockHashProvider);
140        let context = HashContext::with_provider(provider);
141        assert!(!context.is_initialized());
142        assert!(context.provider().is_some());
143    }
144
145    #[test]
146    fn test_hash_context_provider_management() {
147        let mut context = HashContext::new();
148        assert!(context.provider().is_none());
149
150        let provider = Box::new(MockHashProvider);
151        context.set_provider(provider);
152        assert!(context.provider().is_some());
153    }
154
155    #[test]
156    fn test_hash_context_initialization() {
157        let mut context = HashContext::new();
158        assert!(!context.is_initialized());
159
160        // Should initialize automatically on first operation
161        let result = context.hash(Algorithm::Sha3_256, b"test data");
162        assert!(result.is_err()); // Will fail due to no provider, but context should be initialized
163        assert!(context.is_initialized());
164    }
165
166    #[test]
167    fn test_hash_context_algorithm_validation() {
168        let mut context = HashContext::new();
169
170        // Try to use a non-hash algorithm
171        let result = context.hash(Algorithm::MlKem512, b"test data");
172        assert!(result.is_err());
173        if let Err(crate::error::Error::InvalidAlgorithm { .. }) = result {
174            // Expected error
175        } else {
176            panic!("Expected InvalidAlgorithm error");
177        }
178    }
179}