Skip to main content

saorsa_pqc/
lib.rs

1//! # Saorsa Post-Quantum Cryptography Library
2//!
3//! A comprehensive, production-ready Post-Quantum Cryptography (PQC) library implementing
4//! NIST-standardized algorithms FIPS 203 (ML-KEM), FIPS 204 (ML-DSA), and FIPS 205 (SLH-DSA)
5//! with both pure PQC and hybrid (classical + PQC) modes.
6//!
7//! ## Features
8//!
9//! ### Key Encapsulation Mechanisms (KEM) - FIPS 203
10//! - **ML-KEM-512**: NIST Level 1 security (128-bit)
11//! - **ML-KEM-768**: NIST Level 3 security (192-bit)
12//! - **ML-KEM-1024**: NIST Level 5 security (256-bit)
13//! - **Hybrid KEM**: Classical ECDH + ML-KEM for defense-in-depth
14//!
15//! ### Digital Signatures - FIPS 204
16//! - **ML-DSA-44**: NIST Level 2 security (~128-bit)
17//! - **ML-DSA-65**: NIST Level 3 security (~192-bit)
18//! - **ML-DSA-87**: NIST Level 5 security (~256-bit)
19//! - **Hybrid Signatures**: Classical Ed25519 + ML-DSA for defense-in-depth
20//!
21//! ### Hash-Based Signatures - FIPS 205
22//! - **SLH-DSA**: 12 parameter sets (SHA2/SHAKE, 128/192/256-bit, fast/small)
23//!
24//! ### Symmetric Encryption (Quantum-Resistant)
25//! - **ChaCha20-Poly1305**: AEAD cipher providing quantum-resistant symmetric encryption
26//! - **Password-based Key Derivation**: PBKDF2 for secure key derivation from passwords
27//! - **Authenticated Encryption**: Built-in authentication prevents tampering
28//!
29//! ### Network Protocol Support
30//! - **Raw Public Keys**: Ed25519 key support for P2P authentication
31//! - **Key Derivation**: Utilities for network identity derivation
32//! - **Protocol Agnostic**: Designed for use with any network protocol
33//!
34//! ### Security Features
35//! - **Memory Protection**: Secure memory handling and cleanup
36//! - **Constant-Time Operations**: Resistance to side-channel attacks
37//! - **Algorithm Negotiation**: Automatic algorithm selection and fallback
38//! - **Security Validation**: Comprehensive parameter and key validation
39//!
40//! ## Quick Start
41//!
42//! ```rust,no_run
43//! use saorsa_pqc::pqc::{MlKem768, MlKemOperations, HybridPublicKeyEncryption};
44//! use saorsa_pqc::symmetric::{SymmetricKey, ChaCha20Poly1305Cipher};
45//!
46//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
47//! // Key encapsulation with ML-KEM
48//! let ml_kem = MlKem768::new();
49//! let (pub_key, sec_key) = ml_kem.generate_keypair()?;
50//! let (ciphertext, shared_secret) = ml_kem.encapsulate(&pub_key)?;
51//! let recovered_secret = ml_kem.decapsulate(&sec_key, &ciphertext)?;
52//! assert_eq!(shared_secret.as_bytes(), recovered_secret.as_bytes());
53//!
54//! // Public key encryption
55//! let pke = HybridPublicKeyEncryption::new();
56//! let plaintext = b"Secret message";
57//! let associated_data = b"context";
58//! let encrypted = pke.encrypt(&pub_key, plaintext, associated_data)?;
59//! let decrypted = pke.decrypt(&sec_key, &encrypted, associated_data)?;
60//! assert_eq!(plaintext, &decrypted[..]);
61//!
62//! // Quantum-resistant symmetric encryption
63//! let key = SymmetricKey::generate();
64//! let cipher = ChaCha20Poly1305Cipher::new(&key);
65//! let (ciphertext, nonce) = cipher.encrypt(b"Quantum-safe data", None)?;
66//! let decrypted = cipher.decrypt(&ciphertext, &nonce, None)?;
67//! assert_eq!(b"Quantum-safe data", &decrypted[..]);
68//! # Ok(())
69//! # }
70//! ```
71//!
72//! ## Security Considerations
73//!
74//! This library is designed with security as the primary concern:
75//!
76//! - **No Panics**: All operations return `Result` types with proper error handling
77//! - **Memory Safety**: Sensitive data is zeroed on drop and uses secure allocators
78//! - **Timing Attacks**: Constant-time implementations where cryptographically relevant
79//! - **Algorithm Agility**: Support for multiple algorithms and hybrid modes
80//! - **Validation**: Comprehensive input validation and parameter checking
81//!
82//! ## Performance
83//!
84//! The library is optimized for both security and performance:
85//!
86//! - **FIPS-Compliant Implementations**: Uses FIPS 203/204/205 certified crates
87//! - **Memory Pooling**: Reduces allocation overhead for frequent operations
88//! - **Parallel Processing**: Optional multi-threading for batch operations
89//! - **Zero-Copy**: Minimal data copying in critical paths
90//!
91//! ## Feature Flags
92//!
93//! The library is designed to work out-of-the-box with sensible defaults.
94//! Optional features are available for specific use cases:
95//!
96//! - `simd`: Enable SIMD acceleration for performance (requires `wide` crate)
97//! - `cert_compression`: Enable certificate compression optimization
98//! - `dangerous_configuration`: Enable dangerous configuration options (not recommended)
99//! - `test-utils`: Enable testing utilities
100//! - `benchmarks`: Enable benchmarking support
101//!
102//! ## Safety and Compliance
103//!
104//! - **NIST Standards**: Implements FIPS 203 (ML-KEM) and FIPS 204 (ML-DSA)
105//! - **No Unsafe Code**: Forbidden by lint configuration
106//! - **Comprehensive Testing**: Property-based testing and fuzzing
107//! - **Security Auditing**: Regular security audits and vulnerability scanning
108
109#![deny(
110    missing_docs,
111    unsafe_code,
112    unused_must_use,
113    clippy::panic,
114    clippy::unimplemented,
115    clippy::todo
116)]
117#![warn(clippy::correctness, clippy::suspicious, clippy::perf)]
118#![cfg_attr(docsrs, feature(doc_cfg))]
119
120// Core PQC modules - the main attraction
121pub mod pqc;
122
123// Symmetric encryption (quantum-resistant)
124pub mod symmetric;
125
126// Comprehensive API module
127pub mod api;
128
129// Re-export the comprehensive API for easy access
130pub use api::{
131    // Utils
132    init as api_init,
133    kdf::helpers as kdf_helpers,
134    // Convenience functions
135    kem::ml_kem_768,
136    sig::ml_dsa_65,
137    slh::slh_dsa_sha2_128s,
138
139    supported_algorithms,
140    version as api_version,
141    // KDF exports
142    HkdfSha3_256,
143    HkdfSha3_512,
144    KdfAlgorithm,
145    MlDsa,
146    MlDsaPublicKey as ApiMlDsaPublicKey,
147    MlDsaSecretKey as ApiMlDsaSecretKey,
148    MlDsaSignature as ApiMlDsaSignature,
149    MlDsaVariant,
150    // Main APIs
151    MlKem,
152    MlKemCiphertext as ApiMlKemCiphertext,
153    MlKemPublicKey as ApiMlKemPublicKey,
154    MlKemSecretKey as ApiMlKemSecretKey,
155    MlKemSharedSecret,
156    MlKemVariant,
157    // Error types
158    PqcError as ApiError,
159    PqcResult as ApiResult,
160
161    SlhDsa,
162    SlhDsaPublicKey,
163    SlhDsaSecretKey,
164    SlhDsaSignature,
165
166    SlhDsaVariant,
167};
168
169// Re-export the most commonly used types and traits for convenience (legacy)
170pub use pqc::{
171    // Types
172    types::{
173        HybridKemCiphertext, HybridKemPublicKey, HybridKemSecretKey, HybridSignaturePublicKey,
174        HybridSignatureSecretKey, HybridSignatureValue, MlDsaPublicKey, MlDsaSecretKey,
175        MlDsaSignature, MlKemCiphertext, MlKemPublicKey, MlKemSecretKey, PqcError, PqcResult,
176        SharedSecret,
177    },
178    EncryptedMessage,
179
180    // Hybrid modes
181    HybridKem,
182    // Public key encryption
183    HybridPublicKeyEncryption,
184    HybridSignature,
185
186    MlDsa65,
187    MlDsaOperations,
188
189    // Implementations
190    MlKem768,
191    // Core traits
192    MlKemOperations,
193};
194
195// Re-export symmetric encryption for convenience
196pub use symmetric::{
197    ChaCha20Poly1305Cipher, EncryptedMessage as SymmetricEncryptedMessage, SymmetricError,
198    SymmetricKey,
199};
200
201// Note: This is a pure PQC library - protocol integration is left to consuming crates
202
203/// Library version information
204pub const VERSION: &str = env!("CARGO_PKG_VERSION");
205
206// Re-export FIPS implementations directly
207pub use fips203::{ml_kem_1024, ml_kem_512, ml_kem_768, traits as kem_traits};
208
209pub use fips204::{ml_dsa_44, ml_dsa_65, ml_dsa_87, traits as dsa_traits};
210
211pub use fips205::{
212    slh_dsa_sha2_128f, slh_dsa_sha2_128s, slh_dsa_sha2_192f, slh_dsa_sha2_192s, slh_dsa_sha2_256f,
213    slh_dsa_sha2_256s, slh_dsa_shake_128f, slh_dsa_shake_128s, slh_dsa_shake_192f,
214    slh_dsa_shake_192s, slh_dsa_shake_256f, slh_dsa_shake_256s, traits as slh_traits,
215};
216
217/// Supported ML-KEM parameter sets
218pub const SUPPORTED_ML_KEM: &[&str] = &["ML-KEM-768"];
219
220/// Supported ML-DSA parameter sets  
221pub const SUPPORTED_ML_DSA: &[&str] = &["ML-DSA-65"];
222
223/// Default security level provided by this library
224pub const DEFAULT_SECURITY_LEVEL: &str = "NIST Level 3 (192-bit quantum security)";
225
226/// Initialize the library with optimal settings
227///
228/// This function should be called once at application startup to configure
229/// the library for optimal performance and security.
230///
231/// # Examples
232///
233/// ```no_run
234/// // Initialize once at application startup
235/// saorsa_pqc::init().expect("failed to initialize saorsa_pqc");
236/// ```
237/// Initialize the library with optimal settings
238///
239/// # Errors
240/// Returns an error if initialization of internal components fails.
241pub fn init() -> Result<(), Box<dyn std::error::Error>> {
242    // Initialize logging if available
243    // Note: Logging setup is application-specific, not library-specific
244
245    // Initialize memory pools (always enabled)
246    pqc::memory_pool::initialize_global_pool()?;
247
248    // Validate algorithm availability - always available now
249    // Test that we can create algorithm instances
250    let _ml_kem = pqc::MlKem768::new();
251    let _ml_dsa = pqc::MlDsa65::new();
252
253    Ok(())
254}
255
256/// Get library information and capabilities
257///
258/// Returns information about the library version, supported algorithms,
259/// available features, and compatibility information.
260#[must_use]
261pub fn get_info() -> LibraryInfo {
262    // Parse version string to extract major.minor.patch
263    let version_parts: Vec<&str> = VERSION.split('.').collect();
264    let (major, minor, patch) = if version_parts.len() >= 3 {
265        (
266            version_parts.first().unwrap_or(&"0").parse().unwrap_or(0),
267            version_parts.get(1).unwrap_or(&"3").parse().unwrap_or(3),
268            version_parts.get(2).unwrap_or(&"6").parse().unwrap_or(6),
269        )
270    } else {
271        (0, 3, 6) // Default fallback
272    };
273
274    LibraryInfo {
275        version: VERSION.to_string(),
276        supported_ml_kem: SUPPORTED_ML_KEM.iter().map(|s| (*s).to_string()).collect(),
277        supported_ml_dsa: SUPPORTED_ML_DSA.iter().map(|s| (*s).to_string()).collect(),
278        features: get_enabled_features(),
279        security_level: DEFAULT_SECURITY_LEVEL.to_string(),
280        api_version: ApiCompatibilityInfo {
281            major,
282            minor,
283            patch,
284            min_supported_version: "0.3.0".to_string(), // Maintain compatibility back to 0.3.0
285            stability: "stable".to_string(),
286        },
287        dependencies: DependencyVersionInfo {
288            fips203_version: "0.4".to_string(), // Track major.minor for compatibility
289            fips204_version: "0.4".to_string(), // Track major.minor for compatibility
290            fips205_version: "0.4".to_string(), // Track major.minor for compatibility
291            bincode_version: "2.0".to_string(), // Major version for compatibility tracking
292            serde_version: "1.0".to_string(),   // Major version for compatibility tracking
293        },
294    }
295}
296
297/// Information about the library capabilities
298#[derive(Debug, Clone, PartialEq, Eq)]
299pub struct LibraryInfo {
300    /// Library version
301    pub version: String,
302    /// Supported ML-KEM parameter sets
303    pub supported_ml_kem: Vec<String>,
304    /// Supported ML-DSA parameter sets
305    pub supported_ml_dsa: Vec<String>,
306    /// Enabled features
307    pub features: Vec<String>,
308    /// Default security level
309    pub security_level: String,
310    /// API compatibility information
311    pub api_version: ApiCompatibilityInfo,
312    /// Core dependency versions for compatibility tracking
313    pub dependencies: DependencyVersionInfo,
314}
315
316/// API compatibility and version tracking information
317#[derive(Debug, Clone, PartialEq, Eq)]
318pub struct ApiCompatibilityInfo {
319    /// Current API major version
320    pub major: u32,
321    /// Current API minor version  
322    pub minor: u32,
323    /// Current API patch version
324    pub patch: u32,
325    /// Minimum supported API version for backwards compatibility
326    pub min_supported_version: String,
327    /// API stability level
328    pub stability: String,
329}
330
331/// Core dependency versions for backwards compatibility tracking
332#[derive(Debug, Clone, PartialEq, Eq)]
333pub struct DependencyVersionInfo {
334    /// FIPS 203 (ML-KEM) crate version
335    pub fips203_version: String,
336    /// FIPS 204 (ML-DSA) crate version
337    pub fips204_version: String,
338    /// FIPS 205 (SLH-DSA) crate version
339    pub fips205_version: String,
340    /// Bincode version for serialization compatibility
341    pub bincode_version: String,
342    /// Serde version for serialization compatibility
343    pub serde_version: String,
344}
345
346impl ApiCompatibilityInfo {
347    /// Check if this API version is compatible with a minimum required version
348    #[must_use]
349    pub fn is_compatible_with(&self, min_version: &str) -> bool {
350        use std::cmp::Ordering;
351        // Parse the minimum version string
352        let min_parts: Vec<&str> = min_version.split('.').collect();
353        if min_parts.len() < 3 {
354            return false;
355        }
356
357        let Ok(min_major) = min_parts.first().unwrap_or(&"0").parse::<u32>() else {
358            return false;
359        };
360        let Ok(min_minor) = min_parts.get(1).unwrap_or(&"0").parse::<u32>() else {
361            return false;
362        };
363        let Ok(min_patch) = min_parts.get(2).unwrap_or(&"0").parse::<u32>() else {
364            return false;
365        };
366
367        // Check compatibility using semantic versioning rules
368        match self.major.cmp(&min_major) {
369            Ordering::Greater => true,
370            Ordering::Equal => match self.minor.cmp(&min_minor) {
371                Ordering::Greater => true,
372                Ordering::Equal => self.patch >= min_patch,
373                Ordering::Less => false,
374            },
375            Ordering::Less => false,
376        }
377    }
378
379    /// Get the full version string
380    #[must_use]
381    pub fn version_string(&self) -> String {
382        format!("{}.{}.{}", self.major, self.minor, self.patch)
383    }
384}
385
386/// Check if the current library version supports backward compatibility with a specific version
387#[must_use]
388pub fn is_compatible_with_version(required_version: &str) -> bool {
389    get_info().api_version.is_compatible_with(required_version)
390}
391
392/// Get the list of enabled features
393fn get_enabled_features() -> Vec<String> {
394    #[allow(unused_mut)]
395    let mut features: Vec<String> = vec![
396        // Core features always enabled
397        "pqc".to_string(),
398        "parallel".to_string(),
399        "memory-pool".to_string(),
400        "secure-memory".to_string(),
401        "constant-time".to_string(),
402        "hpke-support".to_string(),
403        "extended-crypto".to_string(),
404    ];
405
406    #[cfg(feature = "simd")]
407    {
408        features.push("simd".to_string());
409    }
410
411    #[cfg(feature = "cert_compression")]
412    {
413        features.push("cert_compression".to_string());
414    }
415
416    #[cfg(feature = "dangerous_configuration")]
417    {
418        features.push("dangerous_configuration".to_string());
419    }
420
421    features
422}
423
424#[cfg(test)]
425#[allow(clippy::unwrap_used, clippy::expect_used)]
426mod tests {
427    use super::*;
428
429    #[test]
430    fn test_library_init() {
431        let result = init();
432        assert!(result.is_ok(), "Library initialization should succeed");
433    }
434
435    #[test]
436    fn test_get_info() {
437        let info = get_info();
438        assert_eq!(info.version, VERSION);
439        assert!(info.supported_ml_kem.contains(&"ML-KEM-768".to_string()));
440        assert!(info.supported_ml_dsa.contains(&"ML-DSA-65".to_string()));
441        assert!(!info.features.is_empty());
442
443        // Test new version tracking fields
444        assert_eq!(info.api_version.stability, "stable");
445        assert_eq!(info.api_version.min_supported_version, "0.3.0");
446        assert!(!info.dependencies.fips203_version.is_empty());
447        assert!(!info.dependencies.fips204_version.is_empty());
448        assert!(!info.dependencies.fips205_version.is_empty());
449    }
450
451    #[test]
452    fn test_version_compatibility() {
453        let info = get_info();
454
455        // Test compatibility with older versions
456        assert!(info.api_version.is_compatible_with("0.3.0"));
457        assert!(info.api_version.is_compatible_with("0.3.1"));
458
459        // Test compatibility with current version
460        assert!(info
461            .api_version
462            .is_compatible_with(&info.api_version.version_string()));
463
464        // Test public API function
465        assert!(is_compatible_with_version("0.3.0"));
466
467        // Test invalid version string handling
468        assert!(!info.api_version.is_compatible_with("invalid"));
469        assert!(!info.api_version.is_compatible_with("1.0"));
470    }
471
472    #[test]
473    fn test_enabled_features() {
474        let features = get_enabled_features();
475        assert!(
476            !features.is_empty(),
477            "Should have at least one feature enabled"
478        );
479    }
480
481    #[test]
482    #[allow(clippy::const_is_empty)]
483    fn test_constants() {
484        assert!(!SUPPORTED_ML_KEM.is_empty());
485        assert!(!SUPPORTED_ML_DSA.is_empty());
486        assert!(!DEFAULT_SECURITY_LEVEL.is_empty());
487        assert!(!VERSION.is_empty());
488    }
489}