Post Quantum Cryptography for Developers: Your First Quantum Resistant Code

Get Started in 10 Minutes
This post walks through building your first Post Quantum Cryptography code, from installing liboqs to generating ML-KEM keys and running a hybrid key exchange.
Install liboqs
liboqs is the Open Quantum Safe project's C library. It exposes NIST PQC algorithms via a uniform API.
`` git clone https://github.com/open-quantum-safe/liboqs.git cd liboqs mkdir build && cd build cmake -GNinja .. ninja sudo ninja install ``
Python bindings are available via liboqs-python (pip install liboqs-python).
Generate ML-KEM-768 Keypair
Python example:
``` import oqs
kem = oqs.KeyEncapsulation("ML-KEM-768") public_key = kem.generate_keypair()
# Peer encapsulates to produce shared_secret + ciphertext peer = oqs.KeyEncapsulation("ML-KEM-768") ciphertext, shared_secret_peer = peer.encap_secret(public_key)
# Original decapsulates shared_secret_self = kem.decap_secret(ciphertext)
assert shared_secret_peer == shared_secret_self ```
The two shared_secret bytes objects match. Use them to derive an AES-256-GCM key via HKDF-SHA-384.
Hybrid With X25519
``` import oqs from cryptography.hazmat.primitives.asymmetric import x25519
# Generate X25519 keypair classical_priv = x25519.X25519PrivateKey.generate() classical_pub = classical_priv.public_key()
# Generate ML-KEM-768 keypair kem = oqs.KeyEncapsulation("ML-KEM-768") pqc_pub = kem.generate_keypair()
# Peer encapsulates peer_classical = x25519.X25519PrivateKey.generate() ss_classical = peer_classical.exchange(classical_pub) ct, ss_pqc = oqs.KeyEncapsulation("ML-KEM-768").encap_secret(pqc_pub)
# Combined shared secret combined = ss_classical + ss_pqc # In production: HKDF(ss_classical || ss_pqc) ```
This gives hybrid security: an attacker must break both X25519 and ML-KEM-768 to recover the shared secret.
ML-DSA Signatures
``` import oqs
signer = oqs.Signature("ML-DSA-65") verif_pub = signer.generate_keypair()
msg = b"Hello, post-quantum world" sig = signer.sign(msg)
verifier = oqs.Signature("ML-DSA-65") assert verifier.verify(msg, sig, verif_pub) ```
Next Steps
- Integrate into your TLS stack via OpenSSL 3 + oqs-provider.
- For WebPKI, experiment with hybrid certificates.
- For production, prefer OpenSSL/BoringSSL/AWS-LC over raw liboqs calls.
- Test against Chrome's X25519MLKEM768 (codepoint 0x11EC).
Common Mistakes
- Using ML-KEM directly for authentication; it is a KEM, not a signature.
- Reusing KEM ciphertexts. ML-KEM is IND-CCA2 but you should still use each ciphertext once.
- Skipping HKDF when combining shared secrets.
- Choosing wrong parameter set (use ML-KEM-768 for most cases, ML-KEM-1024 for CNSA 2.0).
Frequently Asked Questions
Which Python library should I use?
liboqs-python for direct algorithm access. For TLS, Python's cryptography library plus OpenSSL 3 with oqs-provider.
Is liboqs production-ready?
For PQC algorithm correctness, yes. For hardened production (side-channel resistance, FIPS validation), use OpenSSL, BoringSSL, AWS-LC, or commercial providers.
Can I use ML-KEM for bulk encryption?
No. ML-KEM is a key encapsulation mechanism; it produces a short shared secret. Use that shared secret (after KDF) as an AES-256-GCM key for bulk encryption.
What about performance?
ML-KEM-768 key generation, encapsulation, and decapsulation are all on the order of 100 microseconds on modern CPUs. Similar to or faster than RSA-2048.
Sources
Related Articles
Protect Your Data Before Q-Day Arrives
QNSQY's NIST-standardized post-quantum encryption protects files against both current and quantum-era threats.
Try QNSQYOriginally published at quantumsequrity.com/blog/pqc-for-developers-first-steps.