1#[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::SignatureOperations;
16use crate::api::{
17 Algorithm,
18 AlgorithmCategory,
19 CryptoProvider,
20};
21use crate::error::Result;
22use crate::traits::{
23 SigKeypair,
24 SigPublicKey,
25 SigSecretKey,
26};
27
28#[cfg(feature = "alloc")]
30pub struct SignatureContext {
31 inner: BaseContext<Self>,
32}
33
34#[cfg(feature = "alloc")]
35impl SignatureContext {
36 pub fn new() -> Self {
38 Self {
39 inner: BaseContext::new(),
40 }
41 }
42
43 pub fn with_provider(provider: Box<dyn CryptoProvider>) -> Self {
45 Self {
46 inner: BaseContext::with_provider(provider),
47 }
48 }
49
50 #[cfg(feature = "alloc")]
52 pub fn with_default_provider() -> Self {
53 Self {
54 inner: match crate::providers::LibQCryptoProvider::new() {
55 Ok(provider) => BaseContext::with_provider(Box::new(provider)),
56 Err(_) => BaseContext::new(),
57 },
58 }
59 }
60
61 pub fn set_provider(&mut self, provider: Box<dyn CryptoProvider>) {
63 self.inner.set_provider(provider);
64 }
65
66 pub fn provider(&self) -> Option<&dyn CryptoProvider> {
68 self.inner.provider()
69 }
70
71 pub fn generate_keypair(
73 &mut self,
74 algorithm: Algorithm,
75 randomness: Option<&[u8]>,
76 ) -> Result<SigKeypair> {
77 self.inner.ensure_initialized()?;
78
79 if algorithm.category() != AlgorithmCategory::Signature {
81 return Err(crate::error::Error::InvalidAlgorithm {
82 algorithm: "Algorithm is not a signature algorithm",
83 });
84 }
85
86 match self.inner.provider().and_then(|p| p.signature()) {
88 Some(sig_ops) => sig_ops.generate_keypair(algorithm, randomness),
89 None => Err(crate::error::Error::ProviderNotConfigured {
90 operation: String::from("signature"),
91 }),
92 }
93 }
94
95 pub fn sign(
97 &self,
98 algorithm: Algorithm,
99 secret_key: &SigSecretKey,
100 message: &[u8],
101 randomness: Option<&[u8]>,
102 ) -> Result<Vec<u8>> {
103 if !self.inner.is_initialized() {
104 return Err(crate::error::Error::InvalidState {
105 operation: String::from("sign"),
106 reason: String::from("Context not initialized"),
107 });
108 }
109
110 if algorithm.category() != AlgorithmCategory::Signature {
112 return Err(crate::error::Error::InvalidAlgorithm {
113 algorithm: "Algorithm is not a signature algorithm",
114 });
115 }
116
117 match self.inner.provider().and_then(|p| p.signature()) {
119 Some(sig_ops) => sig_ops.sign(algorithm, secret_key, message, randomness),
120 None => Err(crate::error::Error::ProviderNotConfigured {
121 operation: String::from("signature"),
122 }),
123 }
124 }
125
126 pub fn verify(
128 &self,
129 algorithm: Algorithm,
130 public_key: &SigPublicKey,
131 message: &[u8],
132 signature: &[u8],
133 ) -> Result<bool> {
134 if !self.inner.is_initialized() {
135 return Err(crate::error::Error::InvalidState {
136 operation: String::from("verify"),
137 reason: String::from("Context not initialized"),
138 });
139 }
140
141 if algorithm.category() != AlgorithmCategory::Signature {
143 return Err(crate::error::Error::InvalidAlgorithm {
144 algorithm: "Algorithm is not a signature algorithm",
145 });
146 }
147
148 match self.inner.provider().and_then(|p| p.signature()) {
150 Some(sig_ops) => sig_ops.verify(algorithm, public_key, message, signature),
151 None => Err(crate::error::Error::ProviderNotConfigured {
152 operation: String::from("signature"),
153 }),
154 }
155 }
156
157 pub fn sign_with_context(
163 &self,
164 algorithm: Algorithm,
165 secret_key: &SigSecretKey,
166 message: &[u8],
167 context: &[u8],
168 randomness: Option<&[u8]>,
169 ) -> Result<Vec<u8>> {
170 if !self.inner.is_initialized() {
171 return Err(crate::error::Error::InvalidState {
172 operation: String::from("sign_with_context"),
173 reason: String::from("Context not initialized"),
174 });
175 }
176
177 if algorithm.category() != AlgorithmCategory::Signature {
178 return Err(crate::error::Error::InvalidAlgorithm {
179 algorithm: "Algorithm is not a signature algorithm",
180 });
181 }
182
183 match self.inner.provider().and_then(|p| p.signature()) {
184 Some(sig_ops) => {
185 sig_ops.sign_with_context(algorithm, secret_key, message, context, randomness)
186 }
187 None => Err(crate::error::Error::ProviderNotConfigured {
188 operation: String::from("signature"),
189 }),
190 }
191 }
192
193 pub fn verify_with_context(
200 &self,
201 algorithm: Algorithm,
202 public_key: &SigPublicKey,
203 message: &[u8],
204 context: &[u8],
205 signature: &[u8],
206 ) -> Result<bool> {
207 if !self.inner.is_initialized() {
208 return Err(crate::error::Error::InvalidState {
209 operation: String::from("verify_with_context"),
210 reason: String::from("Context not initialized"),
211 });
212 }
213
214 if algorithm.category() != AlgorithmCategory::Signature {
215 return Err(crate::error::Error::InvalidAlgorithm {
216 algorithm: "Algorithm is not a signature algorithm",
217 });
218 }
219
220 match self.inner.provider().and_then(|p| p.signature()) {
221 Some(sig_ops) => {
222 sig_ops.verify_with_context(algorithm, public_key, message, context, signature)
223 }
224 None => Err(crate::error::Error::ProviderNotConfigured {
225 operation: String::from("signature"),
226 }),
227 }
228 }
229
230 pub fn is_initialized(&self) -> bool {
232 self.inner.is_initialized()
233 }
234}
235
236#[cfg(feature = "alloc")]
237impl Default for SignatureContext {
238 fn default() -> Self {
239 Self::new()
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use super::*;
246 use crate::api::CryptoProvider;
247
248 struct MockSignatureProvider;
250
251 impl CryptoProvider for MockSignatureProvider {
252 fn kem(&self) -> Option<&dyn crate::api::KemOperations> {
253 None
254 }
255 fn signature(&self) -> Option<&dyn SignatureOperations> {
256 Some(self)
257 }
258 fn hash(&self) -> Option<&dyn crate::api::HashOperations> {
259 None
260 }
261 fn aead(&self) -> Option<&dyn crate::api::AeadOperations> {
262 None
263 }
264 }
265
266 impl SignatureOperations for MockSignatureProvider {
267 fn generate_keypair(
268 &self,
269 _algorithm: Algorithm,
270 _randomness: Option<&[u8]>,
271 ) -> Result<SigKeypair> {
272 Err(crate::error::Error::NotImplemented {
273 feature: "Mock signature operations not implemented".to_string(),
274 })
275 }
276
277 fn sign(
278 &self,
279 _algorithm: Algorithm,
280 _secret_key: &SigSecretKey,
281 _message: &[u8],
282 _randomness: Option<&[u8]>,
283 ) -> Result<Vec<u8>> {
284 Err(crate::error::Error::NotImplemented {
285 feature: "Mock signature operations not implemented".to_string(),
286 })
287 }
288
289 fn verify(
290 &self,
291 _algorithm: Algorithm,
292 _public_key: &SigPublicKey,
293 _message: &[u8],
294 _signature: &[u8],
295 ) -> Result<bool> {
296 Err(crate::error::Error::NotImplemented {
297 feature: "Mock signature operations not implemented".to_string(),
298 })
299 }
300 }
301
302 #[test]
303 fn test_signature_context_creation() {
304 let context = SignatureContext::new();
305 assert!(!context.is_initialized());
306 assert!(context.provider().is_none());
307 }
308
309 #[test]
310 fn test_signature_context_with_provider() {
311 let provider = Box::new(MockSignatureProvider);
312 let context = SignatureContext::with_provider(provider);
313 assert!(!context.is_initialized());
314 assert!(context.provider().is_some());
315 }
316
317 #[test]
318 fn test_signature_context_provider_management() {
319 let mut context = SignatureContext::new();
320 assert!(context.provider().is_none());
321
322 let provider = Box::new(MockSignatureProvider);
323 context.set_provider(provider);
324 assert!(context.provider().is_some());
325 }
326
327 #[test]
328 fn test_signature_context_initialization() {
329 let mut context = SignatureContext::new();
330 assert!(!context.is_initialized());
331
332 let result = context.generate_keypair(Algorithm::MlDsa44, None);
334 assert!(result.is_err()); assert!(context.is_initialized());
336 }
337
338 #[test]
339 fn test_signature_context_algorithm_validation() {
340 let mut context = SignatureContext::new();
341
342 let result = context.generate_keypair(Algorithm::Sha3_256, None);
344 assert!(result.is_err());
345 if let Err(crate::error::Error::InvalidAlgorithm { .. }) = result {
346 } else {
348 panic!("Expected InvalidAlgorithm error");
349 }
350 }
351}