Skip to main content

lib_q_core/contexts/
signature.rs

1//! Signature context implementation for lib-Q Core
2//!
3//! This module provides the signature context that handles digital signature
4//! operations 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::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/// Signature context for digital signature operations
29#[cfg(feature = "alloc")]
30pub struct SignatureContext {
31    inner: BaseContext<Self>,
32}
33
34#[cfg(feature = "alloc")]
35impl SignatureContext {
36    /// Create a new signature context with no provider
37    pub fn new() -> Self {
38        Self {
39            inner: BaseContext::new(),
40        }
41    }
42
43    /// Create a new signature context with a provider
44    pub fn with_provider(provider: Box<dyn CryptoProvider>) -> Self {
45        Self {
46            inner: BaseContext::with_provider(provider),
47        }
48    }
49
50    /// Create a new signature context with the default provider
51    #[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    /// Set the cryptographic provider
62    pub fn set_provider(&mut self, provider: Box<dyn CryptoProvider>) {
63        self.inner.set_provider(provider);
64    }
65
66    /// Get the current provider
67    pub fn provider(&self) -> Option<&dyn CryptoProvider> {
68        self.inner.provider()
69    }
70
71    /// Generate a keypair for the specified algorithm
72    pub fn generate_keypair(
73        &mut self,
74        algorithm: Algorithm,
75        randomness: Option<&[u8]>,
76    ) -> Result<SigKeypair> {
77        self.inner.ensure_initialized()?;
78
79        // Validate algorithm category
80        if algorithm.category() != AlgorithmCategory::Signature {
81            return Err(crate::error::Error::InvalidAlgorithm {
82                algorithm: "Algorithm is not a signature algorithm",
83            });
84        }
85
86        // Use provider if available
87        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    /// Sign a message using the given secret key
96    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        // Validate algorithm category
111        if algorithm.category() != AlgorithmCategory::Signature {
112            return Err(crate::error::Error::InvalidAlgorithm {
113                algorithm: "Algorithm is not a signature algorithm",
114            });
115        }
116
117        // Use provider if available
118        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    /// Verify a signature for the given message and public key
127    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        // Validate algorithm category
142        if algorithm.category() != AlgorithmCategory::Signature {
143            return Err(crate::error::Error::InvalidAlgorithm {
144                algorithm: "Algorithm is not a signature algorithm",
145            });
146        }
147
148        // Use provider if available
149        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    /// Sign a message under a signing context (FIPS-204 / FIPS-205 domain separation)
158    ///
159    /// An empty `context` is equivalent to [`Self::sign`]. A non-empty context requires a
160    /// provider that supports contexts; others return
161    /// [`NotImplemented`](crate::error::Error::NotImplemented).
162    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    /// Verify a signature under a signing context (FIPS-204 / FIPS-205 domain separation)
194    ///
195    /// An empty `context` is equivalent to [`Self::verify`]. A non-empty context requires a
196    /// provider that supports contexts; others return
197    /// [`NotImplemented`](crate::error::Error::NotImplemented) rather than a `true`/`false`
198    /// verdict computed without the context.
199    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    /// Check if the context is initialized
231    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    // Mock provider for testing
249    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        // Should initialize automatically on first operation
333        let result = context.generate_keypair(Algorithm::MlDsa44, None);
334        assert!(result.is_err()); // Will fail due to no provider, but context should be initialized
335        assert!(context.is_initialized());
336    }
337
338    #[test]
339    fn test_signature_context_algorithm_validation() {
340        let mut context = SignatureContext::new();
341
342        // Try to use a non-signature algorithm
343        let result = context.generate_keypair(Algorithm::Sha3_256, None);
344        assert!(result.is_err());
345        if let Err(crate::error::Error::InvalidAlgorithm { .. }) = result {
346            // Expected error
347        } else {
348            panic!("Expected InvalidAlgorithm error");
349        }
350    }
351}