Skip to main content

qux_pqc/
lib.rs

1//! # qux-pqc - Post-Quantum Cryptography Library
2//!
3//! A comprehensive Rust library implementing NIST-standardized post-quantum
4//! cryptographic algorithms for key encapsulation and digital signatures.
5//!
6//! ## Features
7//!
8//! - **ML-KEM (CRYSTALS-Kyber)** - NIST FIPS 203 Key Encapsulation Mechanism
9//! - **ML-DSA (CRYSTALS-Dilithium)** - NIST FIPS 204 Digital Signature Algorithm
10//! - **AES-256-GCM** - Symmetric encryption with PQC-derived keys
11//! - **SHA3-256/512** - Quantum-resistant hashing
12//! - **Secure Key Management** - Encrypted key storage with zeroization
13//!
14//! ## Security Levels
15//!
16//! - **Level 3** (~AES-192 equivalent): ML-KEM-768 + ML-DSA-65
17//! - **Level 5** (~AES-256 equivalent): ML-KEM-1024 + ML-DSA-87
18//!
19//! ## Example
20//!
21//! ```rust
22//! use qux_pqc::{kem, dsa, SecurityLevel};
23//!
24//! // Generate KEM key pair
25//! let kem_keys = kem::generate_keypair(SecurityLevel::Level5).unwrap();
26//!
27//! // Encapsulate shared secret
28//! let (ciphertext, shared_secret) = kem::encapsulate(&kem_keys.public_key).unwrap();
29//!
30//! // Decapsulate to recover shared secret
31//! let recovered = kem::decapsulate(&ciphertext, &kem_keys.secret_key).unwrap();
32//! assert_eq!(shared_secret, recovered);
33//!
34//! // Generate DSA key pair and sign
35//! let dsa_keys = dsa::generate_keypair(SecurityLevel::Level5).unwrap();
36//! let message = b"Hello, quantum-safe world!";
37//! let signature = dsa::sign(message, &dsa_keys.secret_key).unwrap();
38//! assert!(dsa::verify(message, &signature, &dsa_keys.public_key).unwrap());
39//! ```
40
41#![cfg_attr(not(feature = "std"), no_std)]
42#![warn(missing_docs)]
43#![warn(clippy::all)]
44
45#[cfg(not(feature = "std"))]
46extern crate alloc;
47
48pub mod dsa;
49pub mod error;
50pub mod kem;
51pub mod keys;
52pub mod symmetric;
53pub mod utils;
54
55pub use error::{Error, Result};
56
57use serde::{Deserialize, Serialize};
58
59/// NIST Security Level for PQC algorithms
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
61pub enum SecurityLevel {
62    /// Security Level 3 (~AES-192): ML-KEM-768 + ML-DSA-65
63    Level3,
64    /// Security Level 5 (~AES-256): ML-KEM-1024 + ML-DSA-87
65    #[default]
66    Level5,
67}
68
69impl SecurityLevel {
70    /// Get the algorithm names for this security level
71    pub fn algorithm_names(&self) -> AlgorithmNames {
72        match self {
73            SecurityLevel::Level3 => AlgorithmNames {
74                kem: "ML-KEM-768",
75                dsa: "ML-DSA-65",
76            },
77            SecurityLevel::Level5 => AlgorithmNames {
78                kem: "ML-KEM-1024",
79                dsa: "ML-DSA-87",
80            },
81        }
82    }
83
84    /// Get the numeric level (3 or 5)
85    pub fn as_u8(&self) -> u8 {
86        match self {
87            SecurityLevel::Level3 => 3,
88            SecurityLevel::Level5 => 5,
89        }
90    }
91}
92
93impl std::fmt::Display for SecurityLevel {
94    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95        match self {
96            SecurityLevel::Level3 => write!(f, "Level 3 (ML-KEM-768 + ML-DSA-65)"),
97            SecurityLevel::Level5 => write!(f, "Level 5 (ML-KEM-1024 + ML-DSA-87)"),
98        }
99    }
100}
101
102/// Algorithm names for a security level
103#[derive(Debug, Clone, Copy)]
104pub struct AlgorithmNames {
105    /// KEM algorithm name
106    pub kem: &'static str,
107    /// DSA algorithm name
108    pub dsa: &'static str,
109}
110
111/// Complete key set containing both KEM and DSA key pairs
112#[derive(Clone, Serialize, Deserialize)]
113pub struct KeySet {
114    /// KEM key pair
115    pub kem: kem::KemKeyPair,
116    /// DSA key pair
117    pub dsa: dsa::DsaKeyPair,
118    /// Security level
119    pub security_level: SecurityLevel,
120    /// Generation timestamp (Unix epoch seconds)
121    pub generated_at: i64,
122}
123
124impl KeySet {
125    /// Generate a complete key set at the specified security level
126    pub fn generate(security_level: SecurityLevel) -> Result<Self> {
127        let kem_keys = kem::generate_keypair(security_level)?;
128        let dsa_keys = dsa::generate_keypair(security_level)?;
129
130        Ok(Self {
131            kem: kem_keys,
132            dsa: dsa_keys,
133            security_level,
134            generated_at: chrono::Utc::now().timestamp(),
135        })
136    }
137
138    /// Get only the public keys
139    pub fn public_keys(&self) -> PublicKeySet {
140        PublicKeySet {
141            kem_public_key: self.kem.public_key.clone(),
142            dsa_public_key: self.dsa.public_key.clone(),
143            security_level: self.security_level,
144        }
145    }
146}
147
148/// Public key set (safe to share)
149#[derive(Clone, Serialize, Deserialize)]
150pub struct PublicKeySet {
151    /// KEM public key
152    pub kem_public_key: Vec<u8>,
153    /// DSA public key
154    pub dsa_public_key: Vec<u8>,
155    /// Security level
156    pub security_level: SecurityLevel,
157}
158
159/// Encrypt data and sign the ciphertext
160///
161/// This combines KEM-based encryption with DSA signing for authenticated encryption.
162pub fn encrypt_and_sign(
163    data: &[u8],
164    recipient_kem_public_key: &[u8],
165    sender_dsa_secret_key: &[u8],
166    security_level: SecurityLevel,
167) -> Result<EncryptedSignedPayload> {
168    // Encapsulate to get shared secret
169    let (kem_ciphertext, shared_secret) =
170        kem::encapsulate_with_level(recipient_kem_public_key, security_level)?;
171
172    // Encrypt data with shared secret
173    let encrypted = symmetric::encrypt_with_secret(data, &shared_secret)?;
174
175    // Create data to sign (ciphertext + nonce + kem_ciphertext)
176    let mut sign_data = Vec::new();
177    sign_data.extend_from_slice(&encrypted.ciphertext);
178    sign_data.extend_from_slice(&encrypted.nonce);
179    sign_data.extend_from_slice(&kem_ciphertext);
180
181    // Sign
182    let signature = dsa::sign_with_level(&sign_data, sender_dsa_secret_key, security_level)?;
183
184    Ok(EncryptedSignedPayload {
185        kem_ciphertext,
186        ciphertext: encrypted.ciphertext,
187        nonce: encrypted.nonce,
188        signature,
189        security_level,
190    })
191}
192
193/// Verify signature and decrypt data
194pub fn verify_and_decrypt(
195    payload: &EncryptedSignedPayload,
196    sender_dsa_public_key: &[u8],
197    recipient_kem_secret_key: &[u8],
198) -> Result<Vec<u8>> {
199    // Recreate data that was signed
200    let mut sign_data = Vec::new();
201    sign_data.extend_from_slice(&payload.ciphertext);
202    sign_data.extend_from_slice(&payload.nonce);
203    sign_data.extend_from_slice(&payload.kem_ciphertext);
204
205    // Verify signature
206    let valid = dsa::verify_with_level(
207        &sign_data,
208        &payload.signature,
209        sender_dsa_public_key,
210        payload.security_level,
211    )?;
212
213    if !valid {
214        return Err(Error::SignatureVerificationFailed);
215    }
216
217    // Decapsulate to get shared secret
218    let shared_secret = kem::decapsulate_with_level(
219        &payload.kem_ciphertext,
220        recipient_kem_secret_key,
221        payload.security_level,
222    )?;
223
224    // Decrypt
225    let encrypted = symmetric::EncryptedData {
226        ciphertext: payload.ciphertext.clone(),
227        nonce: payload.nonce.clone(),
228    };
229
230    symmetric::decrypt_with_secret(&encrypted, &shared_secret)
231}
232
233/// Encrypted and signed payload
234#[derive(Clone, Serialize, Deserialize)]
235pub struct EncryptedSignedPayload {
236    /// KEM ciphertext containing encapsulated shared secret
237    pub kem_ciphertext: Vec<u8>,
238    /// Encrypted data ciphertext
239    pub ciphertext: Vec<u8>,
240    /// Encryption nonce
241    pub nonce: Vec<u8>,
242    /// Digital signature
243    pub signature: Vec<u8>,
244    /// Security level used
245    pub security_level: SecurityLevel,
246}
247
248/// Get library version information
249pub fn version() -> &'static str {
250    env!("CARGO_PKG_VERSION")
251}
252
253/// Get algorithm information for a security level
254pub fn algorithm_info(level: SecurityLevel) -> AlgorithmInfo {
255    let names = level.algorithm_names();
256    AlgorithmInfo {
257        kem: names.kem.to_string(),
258        dsa: names.dsa.to_string(),
259        symmetric: "AES-256-GCM".to_string(),
260        hash: "SHA3-256/512".to_string(),
261        security_level: level,
262        nist_fips: vec![
263            "FIPS 203 (ML-KEM)".to_string(),
264            "FIPS 204 (ML-DSA)".to_string(),
265        ],
266    }
267}
268
269/// Algorithm information
270#[derive(Debug, Clone, Serialize, Deserialize)]
271pub struct AlgorithmInfo {
272    /// KEM algorithm
273    pub kem: String,
274    /// DSA algorithm
275    pub dsa: String,
276    /// Symmetric algorithm
277    pub symmetric: String,
278    /// Hash algorithm
279    pub hash: String,
280    /// Security level
281    pub security_level: SecurityLevel,
282    /// NIST FIPS standards
283    pub nist_fips: Vec<String>,
284}
285
286#[cfg(test)]
287mod tests {
288    use super::*;
289
290    #[test]
291    fn test_security_level_display() {
292        assert!(SecurityLevel::Level5.to_string().contains("Level 5"));
293        assert!(SecurityLevel::Level3.to_string().contains("Level 3"));
294    }
295
296    #[test]
297    fn test_key_set_generation() {
298        let keys = KeySet::generate(SecurityLevel::Level5).unwrap();
299        assert!(!keys.kem.public_key.is_empty());
300        assert!(!keys.dsa.public_key.is_empty());
301        assert_eq!(keys.security_level, SecurityLevel::Level5);
302    }
303
304    #[test]
305    fn test_encrypt_and_sign_verify_and_decrypt() {
306        let alice = KeySet::generate(SecurityLevel::Level5).unwrap();
307        let bob = KeySet::generate(SecurityLevel::Level5).unwrap();
308
309        let message = b"Hello, quantum-safe world!";
310
311        // Alice encrypts to Bob and signs
312        let payload = encrypt_and_sign(
313            message,
314            &bob.kem.public_key,
315            &alice.dsa.secret_key,
316            SecurityLevel::Level5,
317        )
318        .unwrap();
319
320        // Bob verifies and decrypts
321        let decrypted =
322            verify_and_decrypt(&payload, &alice.dsa.public_key, &bob.kem.secret_key).unwrap();
323
324        assert_eq!(message.as_slice(), decrypted.as_slice());
325    }
326
327    #[test]
328    fn test_algorithm_info() {
329        let info = algorithm_info(SecurityLevel::Level5);
330        assert_eq!(info.kem, "ML-KEM-1024");
331        assert_eq!(info.dsa, "ML-DSA-87");
332    }
333}