lib_q_core/contexts/
hash.rs1#[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#[cfg(feature = "alloc")]
25pub struct HashContext {
26 inner: BaseContext<Self>,
27}
28
29#[cfg(feature = "alloc")]
30impl HashContext {
31 pub fn new() -> Self {
33 Self {
34 inner: BaseContext::new(),
35 }
36 }
37
38 pub fn with_provider(provider: Box<dyn CryptoProvider>) -> Self {
40 Self {
41 inner: BaseContext::with_provider(provider),
42 }
43 }
44
45 #[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 pub fn set_provider(&mut self, provider: Box<dyn CryptoProvider>) {
58 self.inner.set_provider(provider);
59 }
60
61 pub fn provider(&self) -> Option<&dyn CryptoProvider> {
63 self.inner.provider()
64 }
65
66 pub fn hash(&mut self, algorithm: Algorithm, data: &[u8]) -> Result<Vec<u8>> {
68 self.inner.ensure_initialized()?;
69
70 if algorithm.category() != AlgorithmCategory::Hash {
72 return Err(crate::error::Error::InvalidAlgorithm {
73 algorithm: "Algorithm is not a hash algorithm",
74 });
75 }
76
77 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 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 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 let result = context.hash(Algorithm::Sha3_256, b"test data");
162 assert!(result.is_err()); assert!(context.is_initialized());
164 }
165
166 #[test]
167 fn test_hash_context_algorithm_validation() {
168 let mut context = HashContext::new();
169
170 let result = context.hash(Algorithm::MlKem512, b"test data");
172 assert!(result.is_err());
173 if let Err(crate::error::Error::InvalidAlgorithm { .. }) = result {
174 } else {
176 panic!("Expected InvalidAlgorithm error");
177 }
178 }
179}