Post-Quantum Cryptography
Since: cryptopp-modern 2026.3.0
Post-Quantum Cryptography (PQC) provides cryptographic algorithms designed to be secure against attacks by both classical and quantum computers. cryptopp-modern implements the NIST-standardized PQC algorithms from FIPS 203, 204, and 205.
Why Post-Quantum Cryptography?
Quantum computers pose a significant threat to current cryptographic systems:
- RSA, ECDSA, ECDH, Ed25519, X25519 - All vulnerable to Shor’s algorithm on a sufficiently powerful quantum computer
- AES, SHA-3, BLAKE3 - Remain secure (Grover’s algorithm only halves effective security)
The “Harvest Now, Decrypt Later” Threat: Adversaries may be collecting encrypted data today, planning to decrypt it once quantum computers become available. Data with long-term confidentiality requirements (medical records, state secrets, financial data) should transition to PQC now.
Available Algorithms
Key Encapsulation (Key Exchange)
| Algorithm | Standard | Security Basis | Recommended For |
|---|---|---|---|
| ML-KEM | FIPS 203 | Module lattices | Pure post-quantum key exchange |
| X-Wing | IETF Draft | Hybrid (X25519 + ML-KEM) | Defence in depth (recommended) |
Digital Signatures
| Algorithm | Standard | Security Basis | Recommended For |
|---|---|---|---|
| ML-DSA | FIPS 204 | Module lattices | General-purpose signatures |
| SLH-DSA | FIPS 205 | Hash functions | Conservative security (no lattice assumptions) |
Quick Comparison
Key Encapsulation Mechanisms
| Property | ML-KEM-768 | X-Wing | X25519 (classical) |
|---|---|---|---|
| Public Key | 1184 bytes | 1216 bytes | 32 bytes |
| Secret Key (seed) | 64 bytes | 32 bytes | 32 bytes* |
| Ciphertext | 1088 bytes | 1120 bytes | 32 bytes |
| Shared Secret | 32 bytes | 32 bytes | 32 bytes |
| Quantum Secure | Yes | Yes | No |
| Classical Secure | Yes | Yes | Yes |
| Security if lattices broken | No | Yes (X25519 backup) | N/A |
*X25519 secret key is not a seed in the ML-KEM/X-Wing sense.
Digital Signatures
| Property | ML-DSA-65 | SLH-DSA-SHA2-128f | Ed25519 (classical) |
|---|---|---|---|
| Public Key | 1952 bytes | 32 bytes | 32 bytes |
| Secret Key | 4032 bytes | 64 bytes | 64 bytes |
| Signature | 3309 bytes | 17088 bytes | 64 bytes |
| Quantum Secure | Yes | Yes | No |
| Security Basis | Lattices | Hash functions | Elliptic curves |
| Signing Speed | Fast | Slow | Very Fast |
| Verification Speed | Fast | Slow | Fast |
Choosing the Right Algorithm
For Key Exchange / Encryption
Do you need defence against both classical AND quantum attacks today?
├── YES: Use X-Wing (hybrid X25519 + ML-KEM-768)
│ - Secure even if lattice cryptography is broken
│ - Secure even if quantum computers arrive
│ - Recommended for most applications
│
└── NO: Are you building a pure post-quantum system?
├── YES: Use ML-KEM-768
│ - NIST standard (FIPS 203)
│ - Smaller than X-Wing
│
└── NO: Use X25519 (classical)
- Smallest keys/ciphertexts
- Well-understood securityFor Digital Signatures
What are your priorities?
├── Conservative security (no lattice assumptions)?
│ └── Use SLH-DSA
│ - Based only on hash function security
│ - Larger signatures but different security basis
│ - Choose 'f' variants for speed, 's' variants for smaller signatures
│
├── Balanced performance and security?
│ └── Use ML-DSA-65
│ - NIST standard (FIPS 204)
│ - Good balance of key/signature sizes and speed
│ - Based on lattice assumptions
│
└── Maximum security level?
└── Use ML-DSA-87 or SLH-DSA-256 variants
- 256-bit security level
- Larger keys and signaturesSecurity Levels
NIST defines security levels based on the computational effort to break:
| Level | Comparable To | Algorithms |
|---|---|---|
| 1 | AES-128 work factor | ML-KEM-512, SLH-DSA-128* |
| 2 | SHA-256 collision | ML-DSA-44 |
| 3 | AES-192 work factor | ML-KEM-768, ML-DSA-65, SLH-DSA-192* |
| 5 | AES-256 work factor | ML-KEM-1024, ML-DSA-87, SLH-DSA-256* |
Recommendation: Level 3 (ML-KEM-768, ML-DSA-65) provides excellent security for most applications.
Quick Examples
Hybrid Key Exchange with X-Wing (Recommended)
#include <cryptopp/xwing.h>
#include <cryptopp/osrng.h>
#include <cryptopp/secblock.h>
#include <cryptopp/cryptlib.h>
#include <cryptopp/hkdf.h>
#include <cryptopp/sha3.h>
using namespace CryptoPP;
// Recipient generates key pair
AutoSeededRandomPool rng;
XWingDecapsulator recipient(rng);
// Extract public key to send to sender
SecByteBlock publicKey(recipient.GetKey().GetPublicKeySize());
recipient.GetKey().GetPublicKey(publicKey.begin());
// Sender encapsulates (creates shared secret + ciphertext)
XWingEncapsulator sender(publicKey.begin(), publicKey.size());
SecByteBlock ciphertext(sender.CiphertextLength());
SecByteBlock senderSecret(sender.SharedSecretLength());
sender.Encapsulate(rng, ciphertext.begin(), senderSecret.begin());
// Recipient decapsulates to get same shared secret
SecByteBlock recipientSecret(recipient.SharedSecretLength());
bool success = recipient.Decapsulate(ciphertext.begin(), recipientSecret.begin());
if (!success) { throw Exception(Exception::OTHER_ERROR, "Decapsulation failed"); }
// Derive encryption key from shared secret using HKDF
HKDF<SHA3_256> hkdf;
SecByteBlock encryptionKey(32);
const byte info[] = "encryption";
hkdf.DeriveKey(encryptionKey.begin(), encryptionKey.size(),
senderSecret.begin(), senderSecret.size(),
nullptr, 0, // salt (optional)
info, sizeof(info) - 1); // info
Post-Quantum Signatures with ML-DSA
#include <cryptopp/mldsa.h>
#include <cryptopp/osrng.h>
#include <cryptopp/secblock.h>
#include <string>
using namespace CryptoPP;
AutoSeededRandomPool rng;
// Generate key pair
MLDSASigner<MLDSA_65> signer(rng);
MLDSAVerifier<MLDSA_65> verifier(signer);
// Sign a message
std::string message = "Important document";
SecByteBlock signature(signer.SignatureLength());
size_t sigLen = signer.SignMessage(rng,
(const byte*)message.data(), message.size(),
signature.begin());
// Verify the signature
bool valid = verifier.VerifyMessage(
(const byte*)message.data(), message.size(),
signature.begin(), sigLen);Migration Strategy
Phase 1: Hybrid Mode (Recommended Now)
Use hybrid algorithms that combine classical and post-quantum cryptography:
- Key Exchange: X-Wing (X25519 + ML-KEM-768)
- Signatures: Consider dual signatures (Ed25519 + ML-DSA) for critical applications
Benefits:
- Secure against both classical and quantum attacks
- If PQC algorithms have undiscovered weaknesses, classical algorithms provide backup
- Gradual transition without breaking compatibility
Phase 2: Pure Post-Quantum (Future)
Once PQC algorithms are thoroughly analyzed and quantum computers become a near-term threat:
- Key Exchange: ML-KEM-768 or ML-KEM-1024
- Signatures: ML-DSA-65 or SLH-DSA
Timeline Considerations
| Application | Recommended Action |
|---|---|
| Long-term secrets (25+ years) | Migrate to hybrid PQC now |
| Financial/healthcare data | Begin hybrid migration |
| Real-time communications | Plan for hybrid, classical still acceptable |
| Short-term sessions | Classical acceptable, plan for future |
Indicative Performance
Key Generation
| Algorithm | Approximate Time |
|---|---|
| X25519 | ~40 µs |
| ML-KEM-768 | ~100 µs |
| X-Wing | ~150 µs |
| ML-DSA-65 | ~200 µs |
| SLH-DSA-SHA2-128f | ~5 ms |
| SLH-DSA-SHA2-128s | ~50 ms |
Operations
| Operation | ML-KEM-768 | X-Wing | ML-DSA-65 | SLH-DSA-128f |
|---|---|---|---|---|
| Encaps/Sign | ~150 µs | ~200 µs | ~500 µs | ~100 ms |
| Decaps/Verify | ~100 µs | ~150 µs | ~200 µs | ~10 ms |
Performance varies by platform and implementation; benchmark in your target environment.
Guidance:
- ML-KEM and ML-DSA are fast enough for most applications
- SLH-DSA is slower but provides hash-based security (no lattice assumptions)
- X-Wing adds minimal overhead over pure ML-KEM
Thread Safety
PQC class instances are not thread-safe. Use one instance per thread:
// CORRECT: Per-thread instances
void signInThread(const MLDSAPrivateKey<MLDSA_65>& privateKey) {
AutoSeededRandomPool rng;
MLDSASigner<MLDSA_65> signer;
signer.AccessPrivateKey().AssignFrom(privateKey);
// ... sign ...
}
// INCORRECT: Shared instance
MLDSASigner<MLDSA_65> globalSigner; // Don't do this
Algorithm Details
ML-KEM (FIPS 203)
Module-Lattice Key Encapsulation Mechanism. Successor to CRYSTALS-Kyber.
- Three parameter sets: ML-KEM-512, ML-KEM-768, ML-KEM-1024
- IND-CCA2 secure with implicit rejection
- Recommended: ML-KEM-768 for most applications
ML-DSA (FIPS 204)
Module-Lattice Digital Signature Algorithm. Successor to CRYSTALS-Dilithium.
- Three parameter sets: ML-DSA-44, ML-DSA-65, ML-DSA-87
- EUF-CMA secure, probabilistic signing
- Recommended: ML-DSA-65 for most applications
SLH-DSA (FIPS 205)
Stateless Hash-Based Digital Signature Algorithm. Successor to SPHINCS+.
- 12 parameter sets (SHA2/SHAKE × 128/192/256 × fast/small)
- Security based only on hash function properties
- Recommended: SLH-DSA-SHA2-128f for speed, SLH-DSA-SHA2-128s for smaller signatures
X-Wing
Hybrid Key Encapsulation combining X25519 and ML-KEM-768.
- Defence in depth: secure if either algorithm is secure
- Proposed in IETF CFRG with active industry involvement (including Cloudflare)
- Recommended: Default choice for new applications
Standards Compliance
| Algorithm | Standard | Status |
|---|---|---|
| ML-KEM | FIPS 203 | Final (13 August 2024) |
| ML-DSA | FIPS 204 | Final (13 August 2024) |
| SLH-DSA | FIPS 205 | Final (13 August 2024) |
| X-Wing | IETF Draft | Draft |
See Also
- ML-KEM API Reference - Key encapsulation
- ML-DSA API Reference - Digital signatures
- SLH-DSA API Reference - Hash-based signatures
- X-Wing API Reference - Hybrid key encapsulation
- X25519 - Classical key exchange
- Ed25519 - Classical signatures