chie_crypto/
dilithium.rs

1//! Post-Quantum Signatures with CRYSTALS-Dilithium.
2//!
3//! This module implements CRYSTALS-Dilithium, a NIST-standardized post-quantum
4//! digital signature scheme designed to be secure against attacks by quantum
5//! computers.
6//!
7//! # Security Levels
8//! - Dilithium2: Security level 2 (AES-128 equivalent)
9//! - Dilithium3: Security level 3 (AES-192 equivalent) - **Recommended**
10//! - Dilithium5: Security level 5 (AES-256 equivalent)
11//!
12//! # Use Cases for CHIE Protocol
13//! - Future-proof digital signatures resistant to quantum attacks
14//! - Long-term secure content signing and verification
15//! - Migration path from Ed25519 to post-quantum signatures
16//! - Hybrid signatures during transition period
17//!
18//! # Example
19//! ```
20//! use chie_crypto::dilithium::*;
21//!
22//! // Generate a keypair
23//! let (pk, sk) = Dilithium3::keypair();
24//!
25//! // Sign a message
26//! let message = b"Important content hash";
27//! let signature = Dilithium3::sign(message, &sk);
28//!
29//! // Verify the signature
30//! assert!(Dilithium3::verify(message, &signature, &pk).is_ok());
31//!
32//! // Invalid message should fail verification
33//! let wrong_message = b"Different content";
34//! assert!(Dilithium3::verify(wrong_message, &signature, &pk).is_err());
35//! ```
36
37use pqcrypto_dilithium::{dilithium2, dilithium3, dilithium5};
38use pqcrypto_traits::sign::{DetachedSignature as _, PublicKey as _, SecretKey as _};
39use serde::{Deserialize, Serialize};
40use zeroize::Zeroizing;
41
42/// Errors that can occur during Dilithium operations.
43#[derive(Debug, Clone, PartialEq, Eq)]
44pub enum DilithiumError {
45    /// Invalid public key length
46    InvalidPublicKey,
47    /// Invalid secret key length
48    InvalidSecretKey,
49    /// Invalid signature length
50    InvalidSignature,
51    /// Signature verification failed
52    VerificationFailed,
53    /// Signing failed
54    SigningFailed,
55    /// Serialization/deserialization error
56    SerializationError,
57}
58
59impl std::fmt::Display for DilithiumError {
60    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61        match self {
62            DilithiumError::InvalidPublicKey => write!(f, "Invalid public key length"),
63            DilithiumError::InvalidSecretKey => write!(f, "Invalid secret key length"),
64            DilithiumError::InvalidSignature => write!(f, "Invalid signature length"),
65            DilithiumError::VerificationFailed => write!(f, "Signature verification failed"),
66            DilithiumError::SigningFailed => write!(f, "Signing failed"),
67            DilithiumError::SerializationError => {
68                write!(f, "Serialization/deserialization error")
69            }
70        }
71    }
72}
73
74impl std::error::Error for DilithiumError {}
75
76/// Result type for Dilithium operations.
77pub type DilithiumResult<T> = Result<T, DilithiumError>;
78
79/// Dilithium2 public key (security level 2).
80#[derive(Clone, Serialize, Deserialize)]
81pub struct Dilithium2PublicKey(Vec<u8>);
82
83/// Dilithium2 secret key (security level 2).
84#[derive(Clone)]
85pub struct Dilithium2SecretKey(Zeroizing<Vec<u8>>);
86
87impl Serialize for Dilithium2SecretKey {
88    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
89    where
90        S: serde::Serializer,
91    {
92        self.0.as_slice().serialize(serializer)
93    }
94}
95
96impl<'de> Deserialize<'de> for Dilithium2SecretKey {
97    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
98    where
99        D: serde::Deserializer<'de>,
100    {
101        let bytes = Vec::<u8>::deserialize(deserializer)?;
102        Ok(Dilithium2SecretKey(Zeroizing::new(bytes)))
103    }
104}
105
106/// Dilithium2 signature.
107#[derive(Clone, Serialize, Deserialize)]
108pub struct Dilithium2Signature(Vec<u8>);
109
110/// Dilithium3 public key (security level 3) - Recommended.
111#[derive(Clone, Serialize, Deserialize)]
112pub struct Dilithium3PublicKey(Vec<u8>);
113
114/// Dilithium3 secret key (security level 3) - Recommended.
115#[derive(Clone)]
116pub struct Dilithium3SecretKey(Zeroizing<Vec<u8>>);
117
118impl Serialize for Dilithium3SecretKey {
119    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
120    where
121        S: serde::Serializer,
122    {
123        self.0.as_slice().serialize(serializer)
124    }
125}
126
127impl<'de> Deserialize<'de> for Dilithium3SecretKey {
128    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
129    where
130        D: serde::Deserializer<'de>,
131    {
132        let bytes = Vec::<u8>::deserialize(deserializer)?;
133        Ok(Dilithium3SecretKey(Zeroizing::new(bytes)))
134    }
135}
136
137/// Dilithium3 signature.
138#[derive(Clone, Serialize, Deserialize)]
139pub struct Dilithium3Signature(Vec<u8>);
140
141/// Dilithium5 public key (security level 5).
142#[derive(Clone, Serialize, Deserialize)]
143pub struct Dilithium5PublicKey(Vec<u8>);
144
145/// Dilithium5 secret key (security level 5).
146#[derive(Clone)]
147pub struct Dilithium5SecretKey(Zeroizing<Vec<u8>>);
148
149impl Serialize for Dilithium5SecretKey {
150    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
151    where
152        S: serde::Serializer,
153    {
154        self.0.as_slice().serialize(serializer)
155    }
156}
157
158impl<'de> Deserialize<'de> for Dilithium5SecretKey {
159    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
160    where
161        D: serde::Deserializer<'de>,
162    {
163        let bytes = Vec::<u8>::deserialize(deserializer)?;
164        Ok(Dilithium5SecretKey(Zeroizing::new(bytes)))
165    }
166}
167
168/// Dilithium5 signature.
169#[derive(Clone, Serialize, Deserialize)]
170pub struct Dilithium5Signature(Vec<u8>);
171
172/// Dilithium2 - Security level 2 (AES-128 equivalent).
173pub struct Dilithium2;
174
175impl Dilithium2 {
176    /// Generate a new keypair.
177    pub fn keypair() -> (Dilithium2PublicKey, Dilithium2SecretKey) {
178        let (pk, sk) = dilithium2::keypair();
179        (
180            Dilithium2PublicKey(pk.as_bytes().to_vec()),
181            Dilithium2SecretKey(Zeroizing::new(sk.as_bytes().to_vec())),
182        )
183    }
184
185    /// Sign a message.
186    pub fn sign(message: &[u8], sk: &Dilithium2SecretKey) -> Dilithium2Signature {
187        let secret_key = dilithium2::SecretKey::from_bytes(&sk.0).unwrap();
188        let sig = dilithium2::detached_sign(message, &secret_key);
189        Dilithium2Signature(sig.as_bytes().to_vec())
190    }
191
192    /// Verify a signature.
193    pub fn verify(
194        message: &[u8],
195        signature: &Dilithium2Signature,
196        pk: &Dilithium2PublicKey,
197    ) -> DilithiumResult<()> {
198        let public_key = dilithium2::PublicKey::from_bytes(&pk.0)
199            .map_err(|_| DilithiumError::InvalidPublicKey)?;
200        let sig = dilithium2::DetachedSignature::from_bytes(&signature.0)
201            .map_err(|_| DilithiumError::InvalidSignature)?;
202
203        dilithium2::verify_detached_signature(&sig, message, &public_key)
204            .map_err(|_| DilithiumError::VerificationFailed)
205    }
206}
207
208/// Dilithium3 - Security level 3 (AES-192 equivalent) - **Recommended**.
209pub struct Dilithium3;
210
211impl Dilithium3 {
212    /// Generate a new keypair.
213    pub fn keypair() -> (Dilithium3PublicKey, Dilithium3SecretKey) {
214        let (pk, sk) = dilithium3::keypair();
215        (
216            Dilithium3PublicKey(pk.as_bytes().to_vec()),
217            Dilithium3SecretKey(Zeroizing::new(sk.as_bytes().to_vec())),
218        )
219    }
220
221    /// Sign a message.
222    pub fn sign(message: &[u8], sk: &Dilithium3SecretKey) -> Dilithium3Signature {
223        let secret_key = dilithium3::SecretKey::from_bytes(&sk.0).unwrap();
224        let sig = dilithium3::detached_sign(message, &secret_key);
225        Dilithium3Signature(sig.as_bytes().to_vec())
226    }
227
228    /// Verify a signature.
229    pub fn verify(
230        message: &[u8],
231        signature: &Dilithium3Signature,
232        pk: &Dilithium3PublicKey,
233    ) -> DilithiumResult<()> {
234        let public_key = dilithium3::PublicKey::from_bytes(&pk.0)
235            .map_err(|_| DilithiumError::InvalidPublicKey)?;
236        let sig = dilithium3::DetachedSignature::from_bytes(&signature.0)
237            .map_err(|_| DilithiumError::InvalidSignature)?;
238
239        dilithium3::verify_detached_signature(&sig, message, &public_key)
240            .map_err(|_| DilithiumError::VerificationFailed)
241    }
242}
243
244/// Dilithium5 - Security level 5 (AES-256 equivalent).
245pub struct Dilithium5;
246
247impl Dilithium5 {
248    /// Generate a new keypair.
249    pub fn keypair() -> (Dilithium5PublicKey, Dilithium5SecretKey) {
250        let (pk, sk) = dilithium5::keypair();
251        (
252            Dilithium5PublicKey(pk.as_bytes().to_vec()),
253            Dilithium5SecretKey(Zeroizing::new(sk.as_bytes().to_vec())),
254        )
255    }
256
257    /// Sign a message.
258    pub fn sign(message: &[u8], sk: &Dilithium5SecretKey) -> Dilithium5Signature {
259        let secret_key = dilithium5::SecretKey::from_bytes(&sk.0).unwrap();
260        let sig = dilithium5::detached_sign(message, &secret_key);
261        Dilithium5Signature(sig.as_bytes().to_vec())
262    }
263
264    /// Verify a signature.
265    pub fn verify(
266        message: &[u8],
267        signature: &Dilithium5Signature,
268        pk: &Dilithium5PublicKey,
269    ) -> DilithiumResult<()> {
270        let public_key = dilithium5::PublicKey::from_bytes(&pk.0)
271            .map_err(|_| DilithiumError::InvalidPublicKey)?;
272        let sig = dilithium5::DetachedSignature::from_bytes(&signature.0)
273            .map_err(|_| DilithiumError::InvalidSignature)?;
274
275        dilithium5::verify_detached_signature(&sig, message, &public_key)
276            .map_err(|_| DilithiumError::VerificationFailed)
277    }
278}
279
280#[cfg(test)]
281mod tests {
282    use super::*;
283
284    #[test]
285    fn test_dilithium2_keypair_generation() {
286        let (_pk, _sk) = Dilithium2::keypair();
287        // Just verify it doesn't panic
288    }
289
290    #[test]
291    fn test_dilithium2_sign_verify() {
292        let (pk, sk) = Dilithium2::keypair();
293        let message = b"Test message";
294
295        let signature = Dilithium2::sign(message, &sk);
296        assert!(Dilithium2::verify(message, &signature, &pk).is_ok());
297    }
298
299    #[test]
300    fn test_dilithium2_wrong_message_fails() {
301        let (pk, sk) = Dilithium2::keypair();
302        let message = b"Original message";
303        let wrong_message = b"Wrong message";
304
305        let signature = Dilithium2::sign(message, &sk);
306        assert!(Dilithium2::verify(wrong_message, &signature, &pk).is_err());
307    }
308
309    #[test]
310    fn test_dilithium2_wrong_public_key_fails() {
311        let (_pk1, sk1) = Dilithium2::keypair();
312        let (pk2, _sk2) = Dilithium2::keypair();
313        let message = b"Test message";
314
315        let signature = Dilithium2::sign(message, &sk1);
316        assert!(Dilithium2::verify(message, &signature, &pk2).is_err());
317    }
318
319    #[test]
320    fn test_dilithium3_keypair_generation() {
321        let (_pk, _sk) = Dilithium3::keypair();
322        // Just verify it doesn't panic
323    }
324
325    #[test]
326    fn test_dilithium3_sign_verify() {
327        let (pk, sk) = Dilithium3::keypair();
328        let message = b"Test message";
329
330        let signature = Dilithium3::sign(message, &sk);
331        assert!(Dilithium3::verify(message, &signature, &pk).is_ok());
332    }
333
334    #[test]
335    fn test_dilithium3_wrong_message_fails() {
336        let (pk, sk) = Dilithium3::keypair();
337        let message = b"Original message";
338        let wrong_message = b"Wrong message";
339
340        let signature = Dilithium3::sign(message, &sk);
341        assert!(Dilithium3::verify(wrong_message, &signature, &pk).is_err());
342    }
343
344    #[test]
345    fn test_dilithium3_wrong_public_key_fails() {
346        let (_pk1, sk1) = Dilithium3::keypair();
347        let (pk2, _sk2) = Dilithium3::keypair();
348        let message = b"Test message";
349
350        let signature = Dilithium3::sign(message, &sk1);
351        assert!(Dilithium3::verify(message, &signature, &pk2).is_err());
352    }
353
354    #[test]
355    fn test_dilithium5_keypair_generation() {
356        let (_pk, _sk) = Dilithium5::keypair();
357        // Just verify it doesn't panic
358    }
359
360    #[test]
361    fn test_dilithium5_sign_verify() {
362        let (pk, sk) = Dilithium5::keypair();
363        let message = b"Test message";
364
365        let signature = Dilithium5::sign(message, &sk);
366        assert!(Dilithium5::verify(message, &signature, &pk).is_ok());
367    }
368
369    #[test]
370    fn test_dilithium5_wrong_message_fails() {
371        let (pk, sk) = Dilithium5::keypair();
372        let message = b"Original message";
373        let wrong_message = b"Wrong message";
374
375        let signature = Dilithium5::sign(message, &sk);
376        assert!(Dilithium5::verify(wrong_message, &signature, &pk).is_err());
377    }
378
379    #[test]
380    fn test_dilithium3_serialization() {
381        let (pk, sk) = Dilithium3::keypair();
382
383        let pk_serialized = crate::codec::encode(&pk).unwrap();
384        let sk_serialized = crate::codec::encode(&sk).unwrap();
385
386        let pk_deserialized: Dilithium3PublicKey = crate::codec::decode(&pk_serialized).unwrap();
387        let sk_deserialized: Dilithium3SecretKey = crate::codec::decode(&sk_serialized).unwrap();
388
389        let message = b"Test message";
390        let signature = Dilithium3::sign(message, &sk_deserialized);
391        assert!(Dilithium3::verify(message, &signature, &pk_deserialized).is_ok());
392    }
393
394    #[test]
395    fn test_dilithium3_signature_serialization() {
396        let (pk, sk) = Dilithium3::keypair();
397        let message = b"Test message";
398        let signature = Dilithium3::sign(message, &sk);
399
400        let sig_serialized = crate::codec::encode(&signature).unwrap();
401        let sig_deserialized: Dilithium3Signature = crate::codec::decode(&sig_serialized).unwrap();
402
403        assert!(Dilithium3::verify(message, &sig_deserialized, &pk).is_ok());
404    }
405
406    #[test]
407    fn test_dilithium3_deterministic_signatures() {
408        let (pk, sk) = Dilithium3::keypair();
409        let message = b"Test message";
410
411        let sig1 = Dilithium3::sign(message, &sk);
412        let sig2 = Dilithium3::sign(message, &sk);
413
414        // Dilithium signatures are deterministic
415        assert_eq!(sig1.0, sig2.0);
416
417        assert!(Dilithium3::verify(message, &sig1, &pk).is_ok());
418        assert!(Dilithium3::verify(message, &sig2, &pk).is_ok());
419    }
420
421    #[test]
422    fn test_dilithium_all_levels_independent() {
423        let (pk2, sk2) = Dilithium2::keypair();
424        let (pk3, sk3) = Dilithium3::keypair();
425        let (pk5, sk5) = Dilithium5::keypair();
426
427        let message = b"Test message";
428
429        let sig2 = Dilithium2::sign(message, &sk2);
430        let sig3 = Dilithium3::sign(message, &sk3);
431        let sig5 = Dilithium5::sign(message, &sk5);
432
433        assert!(Dilithium2::verify(message, &sig2, &pk2).is_ok());
434        assert!(Dilithium3::verify(message, &sig3, &pk3).is_ok());
435        assert!(Dilithium5::verify(message, &sig5, &pk5).is_ok());
436    }
437
438    #[test]
439    fn test_dilithium3_empty_message() {
440        let (pk, sk) = Dilithium3::keypair();
441        let message = b"";
442
443        let signature = Dilithium3::sign(message, &sk);
444        assert!(Dilithium3::verify(message, &signature, &pk).is_ok());
445    }
446
447    #[test]
448    fn test_dilithium3_large_message() {
449        let (pk, sk) = Dilithium3::keypair();
450        let message = vec![42u8; 10_000];
451
452        let signature = Dilithium3::sign(&message, &sk);
453        assert!(Dilithium3::verify(&message, &signature, &pk).is_ok());
454    }
455}