← Back to Blog

Post Quantum Cryptography for Developers: Your First Quantum Resistant Code

Post Quantum Cryptography for Developers: Your First Quantum Resistant Code - QNSQY post-quantum encryption guide

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

  1. Integrate into your TLS stack via OpenSSL 3 + oqs-provider.
  2. For WebPKI, experiment with hybrid certificates.
  3. For production, prefer OpenSSL/BoringSSL/AWS-LC over raw liboqs calls.
  4. 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

  1. liboqs GitHub
  2. liboqs-python
  3. FIPS 203

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 QNSQY

Originally published at quantumsequrity.com/blog/pqc-for-developers-first-steps.