Cypheron Core
IMPORTANT DEVELOPMENT STATUS NOTICE
This library is currently in ACTIVE DEVELOPMENT (v0.1.0) and is EXPERIMENTAL.
This is a Rust wrapper around official NIST reference implementations - not custom cryptography. The core algorithms are NIST-certified, but the Rust integration layer has NOT undergone:
- Independent security audits of FFI bindings
- Formal verification of memory safety wrappers
- Production environment validation
DO NOT USE IN PRODUCTION without comprehensive integration review and testing.
Risk areas: FFI safety, memory management, build system - NOT the underlying NIST algorithms.
Post-quantum cryptography library implementing NIST-standardized quantum-resistant algorithms
Cypheron Core is a Rust library implementing NIST-standardized quantum-resistant algorithms designed to protect against both classical and quantum computer attacks. The library provides high-performance implementations with strong security guarantees.
Quick Start
Add to your Cargo.toml
:
[dependencies]
cypheron-core = "0.1.0"
Basic usage:
#![allow(unused)] fn main() { use cypheron_core::kem::{MlKem768, Kem}; // Generate keypair let (public_key, secret_key) = MlKem768::keypair()?; // Encapsulate shared secret let (ciphertext, shared_secret) = MlKem768::encapsulate(&public_key)?; // Decapsulate shared secret let decapsulated_secret = MlKem768::decapsulate(&ciphertext, &secret_key)?; assert_eq!(shared_secret.expose_secret(), decapsulated_secret.expose_secret()); }
Algorithms Supported
Key Encapsulation Mechanisms (KEM)
Digital Signatures
Hybrid Cryptography
- ECC + ML-DSA: Classical elliptic curve + post-quantum signatures
- Hybrid KEM: Combined classical and post-quantum key agreement
Performance
Algorithm | Key Gen | Sign/Encaps | Verify/Decaps |
---|---|---|---|
ML-KEM-768 | ~50μs | ~60μs | ~80μs |
ML-DSA-65 | ~120μs | ~250μs | ~110μs |
Security Features
- Side-channel resistance: Constant-time implementations
- Memory safety: Secure key zeroization
- NIST compliance: Implements FIPS 203, 204, 205 standards
- Production hardened: Extensive testing and validation
Documentation Sections
- Getting Started - Installation and basic usage
- API Reference - Complete API documentation
- Algorithms - Detailed algorithm documentation
- Security - Security model and considerations
- Troubleshooting - Common issues and solutions
Error Handling
When you encounter errors, they include direct links to relevant documentation:
#![allow(unused)] fn main() { match MlKem768::keypair() { Ok((pk, sk)) => { /* use keys */ }, Err(e) => { // Error includes link: ERROR-KEM-001 // See: https://docs.rs/cypheron-core/troubleshooting/errors.html#error-kem-001 eprintln!("Key generation failed: {}", e); } } }
Local Development
Run the documentation locally:
# Install mdBook
cargo install mdbook
# Serve documentation with hot reload
cd docs
mdbook serve
# Open http://localhost:3000 in your browser
License
Licensed under the Apache License 2.0. See LICENSE for details.
Installation
System Requirements
- Rust: 1.80 or higher
- Operating System: Linux, macOS, or Windows
- Architecture: x86_64, aarch64
Cargo Installation
Add Cypheron Core to your Cargo.toml
:
[dependencies]
cypheron-core = "0.1.0"
Then run:
cargo build
Feature Flags
Cypheron Core supports optional features:
[dependencies]
cypheron-core = { version = "0.1.0", features = ["std", "alloc"] }
Available features:
std
(default): Standard library supportalloc
: Allocation support forno_std
environmentshybrid
: Hybrid cryptography algorithmsserialize
: Serde serialization support
No-std Support
For embedded and constrained environments:
[dependencies]
cypheron-core = { version = "0.1.0", default-features = false, features = ["alloc"] }
Development Dependencies
For testing and benchmarking:
[dev-dependencies]
cypheron-core = { version = "0.1.0", features = ["test-utils"] }
criterion = "0.5"
Platform-Specific Notes
Linux
No additional dependencies required.
macOS
Ensure Xcode command line tools are installed:
xcode-select --install
Windows
Requires Visual Studio Build Tools or MSVC.
Verification
Verify your installation:
use cypheron_core::kem::{MlKem768, Kem}; fn main() { match MlKem768::keypair() { Ok(_) => println!("Installation successful!"), Err(e) => eprintln!("Installation issue: {}", e), } }
Next Steps
- Quick Start Guide - Basic usage examples
- API Reference - Complete API documentation
Quick Start Guide
Get up and running with Cypheron Core in minutes.
Installation
Add cypheron-core to your Cargo.toml
:
[dependencies]
cypheron-core = "0.1.0"
Basic KEM Example
Key Encapsulation Mechanisms (KEMs) are used for secure key exchange:
use cypheron_core::kem::{MlKem768, Kem}; fn main() -> Result<(), Box<dyn std::error::Error>> { // Generate a keypair let (public_key, secret_key) = MlKem768::keypair()?; // Alice encapsulates a shared secret using Bob's public key let (ciphertext, shared_secret_alice) = MlKem768::encapsulate(&public_key)?; // Bob decapsulates the shared secret using his secret key let shared_secret_bob = MlKem768::decapsulate(&ciphertext, &secret_key)?; // Both parties now have the same shared secret assert_eq!(shared_secret_alice.expose_secret(), shared_secret_bob.expose_secret()); println!("Key exchange successful!"); Ok(()) }
Basic Signature Example
Digital signatures provide authentication and non-repudiation:
use cypheron_core::sig::{MlDsa65, SignatureEngine}; fn main() -> Result<(), Box<dyn std::error::Error>> { let message = b"Hello, post-quantum world!"; // Generate signing keypair let (public_key, secret_key) = MlDsa65::keypair()?; // Sign the message let signature = MlDsa65::sign(message, &secret_key)?; // Verify the signature let is_valid = MlDsa65::verify(message, &signature, &public_key); assert!(is_valid); println!("Signature verification successful!"); Ok(()) }
Hybrid Example
Combine classical and post-quantum security:
use cypheron_core::hybrid::{EccDilithium, HybridEngine}; fn main() -> Result<(), Box<dyn std::error::Error>> { let message = b"Hybrid security message"; // Generate hybrid keypair (ECC + ML-DSA) let (public_key, secret_key) = EccDilithium::keypair()?; // Create hybrid signature let signature = EccDilithium::sign(message, &secret_key)?; // Verify with different policies use cypheron_core::hybrid::VerificationPolicy; // Require both classical and post-quantum signatures to be valid let strict_valid = EccDilithium::verify_with_policy( message, &signature, &public_key, VerificationPolicy::BothRequired ); // Accept if either classical OR post-quantum signature is valid let relaxed_valid = EccDilithium::verify_with_policy( message, &signature, &public_key, VerificationPolicy::EitherValid ); println!("Strict policy: {}", strict_valid); println!("Relaxed policy: {}", relaxed_valid); Ok(()) }
Error Handling
Cypheron Core uses structured error types with helpful messages:
#![allow(unused)] fn main() { use cypheron_core::kem::{MlKem768, Kem}; match MlKem768::keypair() { Ok((pk, sk)) => { println!("Keypair generated successfully"); // Use the keys... }, Err(e) => { eprintln!("Key generation failed: {}", e); // Error codes like ERROR-KEM-001 link to documentation // See troubleshooting/errors.md for complete error reference } } }
Memory Safety
All sensitive data is automatically zeroized when dropped:
#![allow(unused)] fn main() { use cypheron_core::kem::{MlKem768, Kem}; { let (public_key, secret_key) = MlKem768::keypair().unwrap(); // Use keys... } // secret_key is automatically zeroized when it goes out of scope }
Next Steps
- Algorithm Details - Learn about specific algorithms
- API Reference - Complete API documentation
- Security Model - Understanding security guarantees
- Performance Guide - Optimizing your application
Production Checklist
Before using in production:
- Read the Security Model
- Review Compliance Requirements
- Set up Monitoring
- Test your Error Handling
- Performance test with Benchmarking Guide
Basic Examples
Complete working examples to get you started with Cypheron Core.
Key Encapsulation (KEM) Example
#![allow(unused)] fn main() { use cypheron_core::kem::{MlKem768, Kem}; use cypheron_core::SecretBox; fn kem_example() -> Result<(), Box<dyn std::error::Error>> { // Alice generates a keypair let (alice_pk, alice_sk) = MlKem768::keypair()?; // Bob wants to send a secret to Alice // He encapsulates using Alice's public key let (ciphertext, shared_secret_bob) = MlKem768::encapsulate(&alice_pk)?; // Alice decapsulates using her secret key let shared_secret_alice = MlKem768::decapsulate(&ciphertext, &alice_sk)?; // Both parties now have the same shared secret assert_eq!( shared_secret_alice.expose_secret(), shared_secret_bob.expose_secret() ); println!("Shared secret exchange successful!"); Ok(()) } }
Digital Signature Example
#![allow(unused)] fn main() { use cypheron_core::sig::{MlDsa65, SignatureEngine}; fn signature_example() -> Result<(), Box<dyn std::error::Error>> { let document = b"Important contract terms..."; // Alice generates signing keys let (verify_key, signing_key) = MlDsa65::keypair()?; // Alice signs the document let signature = MlDsa65::sign(document, &signing_key)?; // Bob verifies Alice's signature let is_valid = MlDsa65::verify(document, &signature, &verify_key); if is_valid { println!("Signature is valid - document authenticated!"); } else { println!("Invalid signature - document may be tampered!"); } Ok(()) } }
Hybrid Signature Example
#![allow(unused)] fn main() { use cypheron_core::hybrid::{EccDilithium, HybridEngine, VerificationPolicy}; fn hybrid_example() -> Result<(), Box<dyn std::error::Error>> { let message = b"Quantum-safe hybrid message"; // Generate hybrid keypair (ECC + ML-DSA) let (public_key, secret_key) = EccDilithium::keypair()?; // Create hybrid signature let signature = EccDilithium::sign(message, &secret_key)?; // Verify with strict policy (both signatures must be valid) let strict_valid = EccDilithium::verify_with_policy( message, &signature, &public_key, VerificationPolicy::BothRequired ); // Verify with relaxed policy (either signature valid) let relaxed_valid = EccDilithium::verify_with_policy( message, &signature, &public_key, VerificationPolicy::EitherValid ); println!("Strict policy result: {}", strict_valid); println!("Relaxed policy result: {}", relaxed_valid); Ok(()) } }
Error Handling Example
#![allow(unused)] fn main() { use cypheron_core::kem::{MlKem768, Kem, MlKemError}; fn error_handling_example() { match MlKem768::keypair() { Ok((pk, sk)) => { println!("Keys generated successfully"); // Try to encapsulate match MlKem768::encapsulate(&pk) { Ok((ct, ss)) => { println!("Encapsulation successful"); // Try to decapsulate match MlKem768::decapsulate(&ct, &sk) { Ok(decrypted_ss) => { println!("Decapsulation successful"); }, Err(e) => { eprintln!("Decapsulation failed: {}", e); // Error includes helpful documentation links } } }, Err(e) => eprintln!("Encapsulation failed: {}", e), } }, Err(e) => { eprintln!("Key generation failed: {}", e); // Errors include ERROR-KEM-XXX codes linking to docs } } } }
Memory Safety Example
#![allow(unused)] fn main() { use cypheron_core::kem::{MlKem768, Kem}; use cypheron_core::SecretBox; fn memory_safety_example() -> Result<(), Box<dyn std::error::Error>> { let shared_secret = { let (pk, sk) = MlKem768::keypair()?; let (ct, ss) = MlKem768::encapsulate(&pk)?; // Secret key `sk` is automatically zeroized when it goes out of scope ss }; // Keys are now securely zeroized // Shared secret is still valid and secure println!("Shared secret length: {}", shared_secret.expose_secret().len()); // When shared_secret goes out of scope, it will be zeroized Ok(()) } }
Complete Application Example
use cypheron_core::kem::{MlKem768, Kem}; use cypheron_core::sig::{MlDsa65, SignatureEngine}; struct SecureMessage { encrypted_data: Vec<u8>, signature: Vec<u8>, } fn secure_messaging_example() -> Result<(), Box<dyn std::error::Error>> { // Alice's keys for encryption let (alice_kem_pk, alice_kem_sk) = MlKem768::keypair()?; // Bob's keys for signing let (bob_sig_pk, bob_sig_sk) = MlDsa65::keypair()?; let plaintext = b"Confidential message from Bob to Alice"; // Bob encrypts message for Alice let (ciphertext, shared_secret) = MlKem768::encapsulate(&alice_kem_pk)?; // Use shared secret to encrypt data (simplified - in practice use AES-GCM) let mut encrypted_data = plaintext.to_vec(); for (i, byte) in encrypted_data.iter_mut().enumerate() { *byte ^= shared_secret.expose_secret()[i % 32]; } // Bob signs the encrypted message let signature = MlDsa65::sign(&encrypted_data, &bob_sig_sk)?; let secure_msg = SecureMessage { encrypted_data, signature, }; // Alice receives and verifies the message // First verify Bob's signature let signature_valid = MlDsa65::verify( &secure_msg.encrypted_data, &secure_msg.signature, &bob_sig_pk ); if !signature_valid { return Err("Invalid signature!".into()); } // Then decrypt using her private key let decrypted_secret = MlKem768::decapsulate(&ciphertext, &alice_kem_sk)?; // Decrypt the message let mut decrypted_data = secure_msg.encrypted_data.clone(); for (i, byte) in decrypted_data.iter_mut().enumerate() { *byte ^= decrypted_secret.expose_secret()[i % 32]; } println!("Decrypted message: {}", String::from_utf8_lossy(&decrypted_data)); Ok(()) } fn main() { if let Err(e) = secure_messaging_example() { eprintln!("Secure messaging failed: {}", e); } }
Next Steps
- Algorithm Details - Learn about specific algorithms
- Security Model - Understand security guarantees
- Performance Guide - Optimize your applications
ML-KEM (Module-Lattice-Based Key Encapsulation Mechanism)
ML-KEM is the NIST-standardized quantum-resistant key encapsulation mechanism, formerly known as Kyber. It enables secure key exchange that is resistant to both classical and quantum computer attacks.
Overview
ML-KEM is based on the Module Learning With Errors (M-LWE) problem, which is believed to be hard even for quantum computers. The algorithm provides:
- Key Encapsulation: Secure key exchange between parties
- Quantum Resistance: Security against Shor’s algorithm
- Performance: Efficient operations suitable for real-world use
- Standardization: NIST FIPS 203 compliance
Security Levels
Cypheron Core implements all three ML-KEM variants:
Variant | Security Level | Classical Security | Quantum Security | Key Sizes |
---|---|---|---|---|
ML-KEM-512 | 1 | ~128-bit | ~64-bit | PK: 800B, SK: 1632B |
ML-KEM-768 | 3 | ~192-bit | ~96-bit | PK: 1184B, SK: 2400B |
ML-KEM-1024 | 5 | ~256-bit | ~128-bit | PK: 1568B, SK: 3168B |
Basic Usage
#![allow(unused)] fn main() { use cypheron_core::kem::{MlKem768, Kem}; // Generate keypair let (public_key, secret_key) = MlKem768::keypair()?; // Alice encapsulates a shared secret let (ciphertext, shared_secret_alice) = MlKem768::encapsulate(&public_key)?; // Bob decapsulates the shared secret let shared_secret_bob = MlKem768::decapsulate(&ciphertext, &secret_key)?; // Both parties have the same 32-byte shared secret assert_eq!(shared_secret_alice.expose_secret(), shared_secret_bob.expose_secret()); }
Algorithm Details
Key Generation
- Generate matrix A from public randomness
- Generate secret vectors s and e from centered binomial distribution
- Compute t = A·s + e
- Public key: (ρ, t), Secret key: s
Encapsulation
- Generate ephemeral secret r and error vectors e1, e2
- Compute u = A^T·r + e1
- Compute v = t^T·r + e2 + Encode(m)
- Return ciphertext (u, v) and shared secret KDF(m)
Decapsulation
- Compute m’ = Decode(v - s^T·u)
- Re-encapsulate with m’ to get (u’, v’)
- If (u’, v’) = (u, v), return KDF(m’), else return KDF(z)
Performance Characteristics
ML-KEM operations are highly efficient:
#![allow(unused)] fn main() { use std::time::Instant; use cypheron_core::kem::{MlKem768, Kem}; fn benchmark_ml_kem() -> Result<(), Box<dyn std::error::Error>> { // Key generation let start = Instant::now(); let (pk, sk) = MlKem768::keypair()?; println!("Keygen: {:?}", start.elapsed()); // Encapsulation let start = Instant::now(); let (ct, ss1) = MlKem768::encapsulate(&pk)?; println!("Encaps: {:?}", start.elapsed()); // Decapsulation let start = Instant::now(); let ss2 = MlKem768::decapsulate(&ct, &sk)?; println!("Decaps: {:?}", start.elapsed()); Ok(()) } }
Security Considerations
Proper Usage
#![allow(unused)] fn main() { use cypheron_core::kem::{MlKem768, Kem}; // Correct: Use each key pair only once let (pk, sk) = MlKem768::keypair()?; let (ct, ss) = MlKem768::encapsulate(&pk)?; // Correct: Validate ciphertext before decapsulation if ct.len() == 1088 { // ML-KEM-768 ciphertext size let ss2 = MlKem768::decapsulate(&ct, &sk)?; } // Incorrect: Reusing the same keypair multiple times // This could leak information about the secret key }
Side-Channel Protection
All operations use constant-time implementations:
- Constant-time sampling: Secret values don’t affect execution time
- Constant-time arithmetic: Operations always take the same time
- Memory access patterns: No secret-dependent memory accesses
Migration from Kyber
Cypheron Core provides compatibility aliases for smooth migration:
#![allow(unused)] fn main() { // Old Kyber code use cypheron_core::kem::{Kyber768, KyberError}; // Deprecated // New ML-KEM code use cypheron_core::kem::{MlKem768, MlKemError}; // Recommended // Both interfaces are identical let (pk, sk) = MlKem768::keypair()?; }
Test Vectors
Validation against NIST test vectors:
#![allow(unused)] fn main() { #[cfg(test)] mod tests { use super::*; #[test] fn test_nist_vectors() { // Test against official NIST ML-KEM test vectors // See tests/kat/ directory for complete vectors let (pk, sk) = MlKem768::keypair().unwrap(); let (ct, ss1) = MlKem768::encapsulate(&pk).unwrap(); let ss2 = MlKem768::decapsulate(&ct, &sk).unwrap(); assert_eq!(ss1.expose_secret(), ss2.expose_secret()); } } }
Variants
- ML-KEM-512 - Security Level 1
- ML-KEM-768 - Security Level 3 (Recommended)
- ML-KEM-1024 - Security Level 5
See Also
Hybrid Cryptography Overview
Hybrid cryptography combines classical and post-quantum algorithms to provide defense against both current and future cryptographic attacks.
Why Hybrid?
Hybrid schemes provide multiple layers of security:
- Classical Security: Protection against traditional computing threats
- Quantum Resistance: Protection against quantum computer attacks
- Migration Safety: Smooth transition from classical to post-quantum
- Defense in Depth: Multiple independent security assumptions
Hybrid Strategies
Composite Signatures
Combine classical and post-quantum signature schemes:
#![allow(unused)] fn main() { use cypheron_core::hybrid::{EccDilithium, HybridEngine}; // Generate hybrid keypair (ECC + ML-DSA) let (public_key, secret_key) = EccDilithium::keypair()?; // Create composite signature let message = b"Hybrid signed message"; let signature = EccDilithium::sign(message, &secret_key)?; // Verification can use different policies let is_valid = EccDilithium::verify(message, &signature, &public_key); }
Verification Policies
Different policies for signature verification:
#![allow(unused)] fn main() { use cypheron_core::hybrid::VerificationPolicy; // Strict: Both signatures must be valid let strict_valid = EccDilithium::verify_with_policy( message, &signature, &public_key, VerificationPolicy::BothRequired ); // Relaxed: Either signature can be valid let relaxed_valid = EccDilithium::verify_with_policy( message, &signature, &public_key, VerificationPolicy::EitherValid ); // Migration: Prefer post-quantum but accept classical let migration_valid = EccDilithium::verify_with_policy( message, &signature, &public_key, VerificationPolicy::PostQuantumPreferred ); }
Security Analysis
Combined Security Level
The security of hybrid schemes depends on verification policy:
Policy | Security Level | Description |
---|---|---|
BothRequired | min(classical, pq) | Weakest component determines security |
EitherValid | max(classical, pq) | Strongest component determines security |
PostQuantumPreferred | post-quantum | Prioritizes quantum resistance |
Attack Scenarios
Quantum Computer Attack:
- Classical component: Broken
- Post-quantum component: Secure
- Result with EitherValid: Secure
Classical Cryptanalysis:
- Classical component: Potentially broken
- Post-quantum component: Secure
- Result with EitherValid: Secure
Post-Quantum Cryptanalysis:
- Classical component: Secure
- Post-quantum component: Potentially broken
- Result with EitherValid: Secure
Performance Considerations
Signature Size
Hybrid signatures combine both signature types:
#![allow(unused)] fn main() { // Individual signature sizes (approximate) // ECDSA P-256: ~64 bytes // ML-DSA-65: ~3300 bytes // Combined: ~3364 bytes let (pk, sk) = EccDilithium::keypair()?; let signature = EccDilithium::sign(b"message", &sk)?; println!("Hybrid signature size: {} bytes", signature.len()); // Output: Hybrid signature size: 3364 bytes }
Verification Time
Verification involves both algorithms:
#![allow(unused)] fn main() { use std::time::Instant; let start = Instant::now(); let valid = EccDilithium::verify(message, &signature, &public_key); let duration = start.elapsed(); println!("Hybrid verification: {:?}", duration); // Typical: ~0.5ms (classical) + ~0.1ms (post-quantum) = ~0.6ms }
Migration Strategies
Phase 1: Introduction
Start with relaxed verification policy:
#![allow(unused)] fn main() { // Accept either classical or post-quantum signatures let valid = EccDilithium::verify_with_policy( message, &signature, &public_key, VerificationPolicy::EitherValid ); }
Phase 2: Transition
Require both signatures but log failures:
#![allow(unused)] fn main() { let strict_valid = EccDilithium::verify_with_policy( message, &signature, &public_key, VerificationPolicy::BothRequired ); if !strict_valid { // Log for monitoring but continue processing log::warn!("Hybrid signature verification failed"); // Fallback to relaxed policy during transition let relaxed_valid = EccDilithium::verify_with_policy( message, &signature, &public_key, VerificationPolicy::EitherValid ); return relaxed_valid; } }
Phase 3: Post-Quantum Only
Eventually migrate to pure post-quantum:
#![allow(unused)] fn main() { use cypheron_core::sig::{MlDsa65, SignatureEngine}; // Pure post-quantum signatures let (pk, sk) = MlDsa65::keypair()?; let signature = MlDsa65::sign(message, &sk)?; let valid = MlDsa65::verify(message, &signature, &pk); }
Configuration Management
Policy Configuration
#![allow(unused)] fn main() { use serde::{Serialize, Deserialize}; #[derive(Serialize, Deserialize)] pub struct HybridConfig { pub verification_policy: VerificationPolicy, pub signature_format: SignatureFormat, pub key_rotation_interval: u64, // days } impl Default for HybridConfig { fn default() -> Self { Self { verification_policy: VerificationPolicy::EitherValid, signature_format: SignatureFormat::Concatenated, key_rotation_interval: 90, } } } }
Environment-Based Configuration
#![allow(unused)] fn main() { use std::env; fn get_verification_policy() -> VerificationPolicy { match env::var("CYPHERON_VERIFICATION_POLICY").as_deref() { Ok("strict") => VerificationPolicy::BothRequired, Ok("relaxed") => VerificationPolicy::EitherValid, Ok("pq-preferred") => VerificationPolicy::PostQuantumPreferred, _ => VerificationPolicy::EitherValid, // Default } } }
Interoperability
Wire Format
Hybrid signatures can use different encoding formats:
#![allow(unused)] fn main() { // Concatenated format: [classical_sig][pq_sig] // Tagged format: [tag][len][classical_sig][tag][len][pq_sig] // ASN.1 format: Structured encoding with OIDs }
Protocol Integration
Example integration with TLS:
#![allow(unused)] fn main() { // Custom signature scheme identifier const HYBRID_ECC_MLDSA: u16 = 0xFE00; impl SignatureScheme for EccDilithium { fn scheme_id(&self) -> u16 { HYBRID_ECC_MLDSA } fn sign(&self, message: &[u8], key: &PrivateKey) -> Vec<u8> { // Convert from TLS types to Cypheron types let sk = HybridSecretKey::from_tls(key); EccDilithium::sign(message, &sk).unwrap() } } }
See Also
- ECC + ML-DSA - Specific hybrid implementation
- Hybrid KEM - Key encapsulation mechanisms
- Security Considerations - Security analysis
Core Types
This section documents the core types and data structures used throughout Cypheron Core.
Key Types
Public Keys
All public key types are Clone
and can be safely shared:
#![allow(unused)] fn main() { use cypheron_core::kem::MlKemPublicKey; use cypheron_core::sig::MlDsaPublicKey; // ML-KEM public keys let pk: MlKemPublicKey = // ... from keypair generation let pk_clone = pk.clone(); // Safe to clone // ML-DSA public keys let verify_key: MlDsaPublicKey = // ... from keypair generation }
Secret Keys
Secret keys are wrapped in SecretBox
for memory safety:
#![allow(unused)] fn main() { use cypheron_core::kem::MlKemSecretKey; use cypheron_core::sig::MlDsaSecretKey; use secrecy::ExposeSecret; // Secret keys are automatically zeroized when dropped let sk: MlKemSecretKey = // ... from keypair generation // Access secret data only when needed let secret_bytes = sk.0.expose_secret(); // sk is automatically zeroized when it goes out of scope }
Shared Secrets
Shared secrets from KEM operations are securely managed:
#![allow(unused)] fn main() { use cypheron_core::kem::{MlKem768, Kem}; use secrecy::ExposeSecret; let (pk, sk) = MlKem768::keypair()?; let (ct, shared_secret) = MlKem768::encapsulate(&pk)?; // Access shared secret data let secret_data = shared_secret.expose_secret(); // &[u8; 32] // shared_secret is zeroized when dropped }
Error Types
KEM Errors
#![allow(unused)] fn main() { use cypheron_core::kem::MlKemError; pub enum MlKemError { KeyGenerationEntropyFailure, KeyGenerationInternalError, EncapsulationInvalidKey, EncapsulationInternalError, DecapsulationInvalidCiphertext, DecapsulationInternalError, InvalidCiphertextLength { expected: usize, actual: usize }, InvalidPublicKeyLength { expected: usize, actual: usize }, InvalidSecretKeyLength { expected: usize, actual: usize }, CLibraryError { code: i32 }, } }
Signature Errors
#![allow(unused)] fn main() { use cypheron_core::sig::MlDsaError; pub enum MlDsaError { KeyGenerationFailed, SignatureFailed, VerificationFailed, InvalidSignatureLength { expected: usize, actual: usize }, InvalidPublicKeyLength { expected: usize, actual: usize }, InvalidSecretKeyLength { expected: usize, actual: usize }, CLibraryError { code: i32 }, } }
Trait Definitions
KEM Trait
#![allow(unused)] fn main() { pub trait Kem { type PublicKey; type SecretKey; type Ciphertext; type SharedSecret; type Error; fn keypair() -> Result<(Self::PublicKey, Self::SecretKey), Self::Error>; fn encapsulate(pk: &Self::PublicKey) -> Result<(Self::Ciphertext, Self::SharedSecret), Self::Error>; fn decapsulate(ct: &Self::Ciphertext, sk: &Self::SecretKey) -> Result<Self::SharedSecret, Self::Error>; } }
SignatureEngine Trait
#![allow(unused)] fn main() { pub trait SignatureEngine { type PublicKey; type SecretKey; type Signature; type Error; fn keypair() -> Result<(Self::PublicKey, Self::SecretKey), Self::Error>; fn sign(message: &[u8], sk: &Self::SecretKey) -> Result<Self::Signature, Self::Error>; fn verify(message: &[u8], signature: &Self::Signature, pk: &Self::PublicKey) -> bool; } }
Size Constants
All algorithm parameters are available as constants:
#![allow(unused)] fn main() { use cypheron_core::kem::sizes; use cypheron_core::sig::sizes as sig_sizes; // ML-KEM sizes const ML_KEM_768_PUBLIC: usize = sizes::ML_KEM_768_PUBLIC; // 1184 const ML_KEM_768_SECRET: usize = sizes::ML_KEM_768_SECRET; // 2400 const ML_KEM_768_CIPHERTEXT: usize = sizes::ML_KEM_768_CIPHERTEXT; // 1088 const ML_KEM_768_SHARED: usize = sizes::ML_KEM_768_SHARED; // 32 // ML-DSA sizes const ML_DSA_65_PUBLIC: usize = sig_sizes::ML_DSA_65_PUBLIC; // 1952 const ML_DSA_65_SECRET: usize = sig_sizes::ML_DSA_65_SECRET; // 4032 }
Memory Safety Guarantees
Automatic Zeroization
#![allow(unused)] fn main() { use zeroize::Zeroize; // All secret types implement Zeroize fn example() { let (pk, sk) = MlKem768::keypair().unwrap(); // Use secret key... } // sk is automatically zeroized here when dropped }
SecretBox Protection
#![allow(unused)] fn main() { use secrecy::{SecretBox, ExposeSecret}; // Secret data is protected until explicitly exposed let secret = SecretBox::new([1, 2, 3, 4]); // Only expose when absolutely necessary let data = secret.expose_secret(); // &[u8] // secret is zeroized when dropped }
Serialization Support
With the serialize
feature enabled:
#![allow(unused)] fn main() { use serde::{Serialize, Deserialize}; #[derive(Serialize, Deserialize)] struct KeyPair { public_key: MlKemPublicKey, // Note: Secret keys should NOT be serialized in most cases } // Serialize public key safely let json = serde_json::to_string(&public_key)?; // Deserialize public key let pk: MlKemPublicKey = serde_json::from_str(&json)?; }
Thread Safety
All public key types are Send
and Sync
:
#![allow(unused)] fn main() { use std::sync::Arc; use std::thread; let (pk, _sk) = MlKem768::keypair().unwrap(); let shared_pk = Arc::new(pk); // Public keys can be shared across threads let handles: Vec<_> = (0..4).map(|_| { let pk = shared_pk.clone(); thread::spawn(move || { // Use pk in thread... MlKem768::encapsulate(&pk) }) }).collect(); }
See Also
- KEM Operations - Key Encapsulation APIs
- Signature Operations - Digital Signature APIs
- Error Handling - Error types and handling
Security Model
DEVELOPMENT STATUS WARNING
This security model describes the INTENDED security properties of Cypheron Core v0.1.0.
CRITICAL: This is a Rust wrapper around official NIST reference implementations - not custom cryptography. The core algorithms are NIST-certified, but the Rust integration layer is experimental and has NOT been:
- Independently audited for FFI safety
- Formally verified for memory management
- Validated in production environments
Integration layer uses C vendor code with Rust FFI bindings requiring security evaluation.
Cypheron Core’s security model describes intended cryptographic foundations and defensive programming practices.
Threat Model
Adversarial Capabilities
We protect against adversaries with the following capabilities:
- Classical Computers: Unlimited classical computational power
- Quantum Computers: Large-scale fault-tolerant quantum computers
- Side-Channel Attacks: Timing, power, and electromagnetic analysis
- Memory Attacks: Cold boot attacks, memory dumps, swap file analysis
Security Goals
- Confidentiality: Encrypted data remains secret
- Authenticity: Signatures prove message origin
- Integrity: Tampering is detectable
- Forward Secrecy: Past communications remain secure if keys are compromised
Cryptographic Security
Post-Quantum Resistance
All algorithms are designed to resist quantum computer attacks:
- ML-KEM: Based on Module Learning With Errors (M-LWE)
- ML-DSA: Based on Module Short Integer Solution (M-SIS)
- Falcon: Based on NTRU lattices and Gaussian sampling
- SPHINCS+: Based on hash functions and one-time signatures
Security Levels
Level | Classical Security | Quantum Security | Real-World Equivalent |
---|---|---|---|
1 | 128-bit | 64-bit | AES-128 |
2 | 128-bit | 64-bit | SHA-256 |
3 | 192-bit | 96-bit | AES-192 |
4 | 192-bit | 96-bit | SHA-256 |
5 | 256-bit | 128-bit | AES-256 |
Implementation Security
Constant-Time Operations
All cryptographic operations execute in constant time:
#![allow(unused)] fn main() { // Example: Constant-time secret key usage let (pk, sk) = MlKem768::keypair()?; let (ct, ss) = MlKem768::encapsulate(&pk)?; // Decapsulation time is independent of: // - Secret key content // - Ciphertext validity // - Previous operations let result = MlKem768::decapsulate(&ct, &sk)?; }
Memory Protection
Sensitive data is automatically protected:
#![allow(unused)] fn main() { use secrecy::ExposeSecret; { let (pk, sk) = MlKem768::keypair()?; // Secret key is in protected memory let secret_data = sk.0.expose_secret(); // Use secret_data... } // Secret key memory is zeroized automatically }
Randomness Requirements
Cryptographic operations require high-quality randomness:
- Entropy Sources: Hardware RNG, OS entropy pools
- Seeding: Proper CSPRNG initialization
- Reseeding: Regular entropy pool updates
#![allow(unused)] fn main() { // Entropy failure is handled gracefully match MlKem768::keypair() { Ok((pk, sk)) => { /* success */ }, Err(MlKemError::KeyGenerationEntropyFailure) => { // Handle insufficient entropy std::thread::sleep(std::time::Duration::from_millis(100)); // Retry... }, Err(e) => return Err(e), } }
Side-Channel Protection
Timing Attacks
All operations use constant-time algorithms:
- No secret-dependent branches: Control flow is independent of secrets
- No secret-dependent memory access: Memory patterns are predictable
- No secret-dependent loop bounds: Iteration counts are fixed
Power Analysis
Operations are designed to minimize power analysis vulnerabilities:
- Uniform operations: Similar power consumption patterns
- Masked arithmetic: Secret values are never used directly
- Randomized execution: Some operations include deliberate randomness
Fault Injection
Critical operations include integrity checks:
#![allow(unused)] fn main() { // Example: Built-in integrity verification let (pk, sk) = MlKem768::keypair()?; let (ct, ss1) = MlKem768::encapsulate(&pk)?; // Decapsulation includes implicit ciphertext validation match MlKem768::decapsulate(&ct, &sk) { Ok(ss2) => { // ss1 and ss2 are identical if no faults occurred assert_eq!(ss1.expose_secret(), ss2.expose_secret()); }, Err(MlKemError::DecapsulationInvalidCiphertext) => { // Ciphertext was corrupted or maliciously modified }, } }
Key Management
Key Lifecycle
- Generation: High-entropy key creation
- Storage: Encrypted at rest when possible
- Usage: Minimal exposure time
- Destruction: Cryptographic erasure
#![allow(unused)] fn main() { // Proper key lifecycle management fn secure_key_usage() -> Result<(), Box<dyn std::error::Error>> { // 1. Generation let (pk, sk) = MlKem768::keypair()?; // 2. Usage (minimize exposure time) let (ct, ss) = MlKem768::encapsulate(&pk)?; // 3. Destruction is automatic when variables go out of scope Ok(()) } // Keys are zeroized here }
Key Rotation
Regular key rotation is recommended:
#![allow(unused)] fn main() { use std::time::{Duration, Instant}; struct KeyManager { current_keys: (MlKemPublicKey, MlKemSecretKey), created_at: Instant, rotation_interval: Duration, } impl KeyManager { fn should_rotate(&self) -> bool { self.created_at.elapsed() > self.rotation_interval } fn rotate(&mut self) -> Result<(), MlKemError> { if self.should_rotate() { self.current_keys = MlKem768::keypair()?; self.created_at = Instant::now(); } Ok(()) } } }
Compliance and Standards
NIST Standardization
All algorithms implement NIST-standardized specifications:
- FIPS 203: ML-KEM standard
- FIPS 204: ML-DSA standard
- FIPS 205: SPHINCS+ standard
Security Validations
- Known Answer Tests (KAT): Validation against NIST test vectors
- Monte Carlo Testing: Statistical randomness validation
- Side-Channel Testing: Timing and power analysis resistance
Limitations and Assumptions
Trust Assumptions
- Implementation Correctness: No bugs in cryptographic implementations
- Hardware Security: CPU and memory provide basic security guarantees
- Random Number Generation: OS provides cryptographically secure randomness
Known Limitations
- No Perfect Forward Secrecy: KEM schemes don’t provide PFS by default
- Post-Quantum Assumptions: Security relies on unproven mathematical assumptions
- Implementation Attacks: Hardware vulnerabilities could compromise security
Best Practices
Application Security
#![allow(unused)] fn main() { // ✅ Good: Validate all inputs if ciphertext.len() != EXPECTED_CIPHERTEXT_SIZE { return Err("Invalid ciphertext size"); } // ✅ Good: Handle errors appropriately match MlKem768::decapsulate(&ct, &sk) { Ok(ss) => use_shared_secret(ss), Err(e) => log_security_event(e), } // ❌ Bad: Ignoring security-critical errors let ss = MlKem768::decapsulate(&ct, &sk).unwrap(); // Don't do this! }
Operational Security
- Monitor Entropy: Check system entropy levels
- Log Security Events: Record cryptographic failures
- Update Regularly: Keep libraries up to date
- Test Thoroughly: Validate all error paths
See Also
- Side-Channel Protection - Detailed protection mechanisms
- Memory Safety - Memory security guarantees
- Compliance - Standards compliance
Error Codes Reference
Complete reference for all error codes in Cypheron Core.
KEM Errors
ERROR-KEM-001
Key Generation Entropy Failure
Cause: Insufficient entropy available for key generation.
Solution:
#![allow(unused)] fn main() { // Ensure your system has adequate entropy // On Linux: check /proc/sys/kernel/random/entropy_avail // Consider using hardware RNG if available use cypheron_core::kem::{MlKem768, Kem}; // Retry with backoff for attempt in 1..=3 { match MlKem768::keypair() { Ok(keys) => return Ok(keys), Err(e) if attempt < 3 => { std::thread::sleep(std::time::Duration::from_millis(100 * attempt)); continue; }, Err(e) => return Err(e), } } }
ERROR-KEM-002
Decapsulation Invalid Ciphertext
Cause: Ciphertext was corrupted or not generated with the corresponding public key.
Solution:
#![allow(unused)] fn main() { use cypheron_core::kem::{MlKem768, Kem}; let (pk, sk) = MlKem768::keypair().unwrap(); let (ct, ss1) = MlKem768::encapsulate(&pk).unwrap(); // Verify ciphertext length before decapsulation if ct.len() != 1088 { // ML-KEM-768 ciphertext size return Err("Invalid ciphertext size"); } match MlKem768::decapsulate(&ct, &sk) { Ok(shared_secret) => { /* success */ }, Err(e) => { // Check if ciphertext is corrupted // Verify it was generated with correct public key eprintln!("Decapsulation failed: {}", e); } } }
ERROR-KEM-003
Encapsulation Invalid Public Key
Cause: Public key format is invalid or corrupted.
Solution:
#![allow(unused)] fn main() { // Validate public key before use use cypheron_core::kem::{MlKem768, Kem}; fn validate_public_key(pk_bytes: &[u8]) -> Result<(), &'static str> { if pk_bytes.len() != 1184 { // ML-KEM-768 public key size return Err("Invalid public key size"); } // Additional validation logic... Ok(()) } // Use validated public key if let Err(e) = validate_public_key(&pk_bytes) { return Err(format!("Public key validation failed: {}", e)); } }
Signature Errors
ERROR-SIG-001
Signature Generation Failed
Cause: Internal error during signature generation, possibly due to entropy issues.
Solution:
#![allow(unused)] fn main() { use cypheron_core::sig::{MlDsa65, SignatureEngine}; let message = b"message to sign"; let (pk, sk) = MlDsa65::keypair().unwrap(); match MlDsa65::sign(message, &sk) { Ok(signature) => { /* success */ }, Err(e) => { // Check message size (ML-DSA has no message size limit) // Verify secret key integrity // Ensure adequate system entropy eprintln!("Signature generation failed: {}", e); } } }
ERROR-SIG-002
Signature Verification Failed
Cause: Signature is invalid, message was modified, or wrong public key used.
Solution:
#![allow(unused)] fn main() { use cypheron_core::sig::{MlDsa65, SignatureEngine}; // Ensure exact message match let original_message = b"Hello, world!"; let modified_message = b"Hello, world?"; // Note the different punctuation let (pk, sk) = MlDsa65::keypair().unwrap(); let signature = MlDsa65::sign(original_message, &sk).unwrap(); // This will fail let valid = MlDsa65::verify(modified_message, &signature, &pk); assert!(!valid); // Verification fails due to message modification // This will succeed let valid = MlDsa65::verify(original_message, &signature, &pk); assert!(valid); }
Hybrid Errors
ERROR-HYBRID-001
Composite Key Generation Failed
Cause: Failure in either classical or post-quantum key generation.
Solution:
#![allow(unused)] fn main() { use cypheron_core::hybrid::{EccDilithium, HybridEngine}; // Retry hybrid key generation with error isolation match EccDilithium::keypair() { Ok(keys) => { /* success */ }, Err(e) => { // Error could be from ECC or ML-DSA component // Check system entropy and crypto library status eprintln!("Hybrid key generation failed: {}", e); // Consider fallback to individual algorithms for debugging use cypheron_core::sig::{MlDsa44, SignatureEngine}; let pq_test = MlDsa44::keypair(); match pq_test { Ok(_) => println!("Post-quantum component working"), Err(e) => println!("Post-quantum issue: {}", e), } } } }
Platform-Specific Errors
ERROR-PLATFORM-001
Windows Entropy Source Unavailable
Cause: Windows CryptoAPI is not accessible.
Solution:
#![allow(unused)] fn main() { // Ensure Windows CryptoAPI is available // This is rare but can happen in restricted environments #[cfg(target_os = "windows")] fn check_windows_crypto() -> Result<(), Box<dyn std::error::Error>> { // The library will automatically fallback to other entropy sources // but you can manually check availability use cypheron_core::platform::secure_random_bytes; let mut buffer = vec![0u8; 32]; secure_random_bytes(&mut buffer)?; Ok(()) } }
Memory Errors
ERROR-MEM-001
Secure Memory Allocation Failed
Cause: System cannot allocate secure memory for sensitive operations.
Solution:
#![allow(unused)] fn main() { // Reduce memory pressure or increase available memory // Check system memory limits and available RAM use cypheron_core::kem::{MlKem512, Kem}; // Use smaller variant if needed // Consider using smaller security parameters temporarily let (pk, sk) = MlKem512::keypair()?; // Instead of MlKem1024 }
FFI Errors
ERROR-FFI-001
C Library Binding Failed
Cause: Underlying C library call failed.
Solution:
#![allow(unused)] fn main() { // This indicates an issue with the vendor C implementations // Usually due to memory corruption or invalid parameters // Enable debug logging to get more details std::env::set_var("RUST_LOG", "debug"); env_logger::init(); // The error will include more detailed information in debug mode }
Debugging Tips
Enable Detailed Logging
// Add to your Cargo.toml [dependencies] env_logger = "0.10" // In your code fn main() { env_logger::init(); // Your code here - errors will include more details }
Validate Input Data
#![allow(unused)] fn main() { use cypheron_core::kem::{MlKem768, Kem}; fn safe_decapsulate(ct: &[u8], sk: &SecretKey) -> Result<SharedSecret, String> { // Validate ciphertext size if ct.len() != 1088 { return Err(format!("Invalid ciphertext size: expected 1088, got {}", ct.len())); } // Additional validation... MlKem768::decapsulate(ct, sk) .map_err(|e| format!("Decapsulation failed: {}", e)) } }
Test with Known Good Data
#![allow(unused)] fn main() { #[cfg(test)] mod tests { use super::*; #[test] fn test_with_known_vectors() { // Use NIST test vectors for validation // See tests/kat/ directory for examples let (pk, sk) = MlKem768::keypair().unwrap(); let (ct, ss1) = MlKem768::encapsulate(&pk).unwrap(); let ss2 = MlKem768::decapsulate(&ct, &sk).unwrap(); assert_eq!(ss1.expose_secret(), ss2.expose_secret()); } } }
Getting Help
If you encounter an error not covered here:
- Check the FAQ for common solutions
- Enable debug logging to get more details
- Search GitHub Issues
- Create a minimal reproduction case
- File a new issue with full error details
See Also
- Common Issues - Frequent problems and solutions
- Debug Guide - Advanced debugging techniques
- API Reference - Error type documentation