
Shipping post-quantum cryptography to Python
Trail of Bits, funded by the Sovereign Tech Agency, implemented Rust bindings for NIST's ML-KEM (FIPS 203) key-establishment and ML-DSA (FIPS 204) digital-signature standards into pyca/cryptography, shipped in version 48 with AWS-LC backend support. The post makes them a pip install away for the Python ecosystem (pyca/cryptography sees 1.2B monthly PyPI downloads and underpins Certbot, Ansible, Airflow, and paramiko), while detailing the size/performance tradeoffs versus Ed25519/X25519 and noting SLH-DSA (FIPS 205) support and protocol-level integration are still in progress.
What it is
Trail of Bits' engineering post on cryptography>=48 (pyca/cryptography), which now ships ML-KEM (FIPS 203) and ML-DSA (FIPS 204). The reader-relevant content the summary omits is the migration guidance: why installing v48 is not a drop-in swap for classical primitives.
Preconditions / Affected
Anything in the Python stack going through pyca/cryptography — the post names Ansible, Certbot, Apache Airflow, and paramiko. The trigger is the White House order of June 22, 2026: high-value/high-impact federal systems need PQ key establishment by December 31, 2030 and PQ signatures by December 31, 2031. The stated threat model is "harvest now, decrypt later" — adversaries collecting ciphertext today for future quantum decryption.
What to do
Two concrete engineering consequences you must plan for before swapping:
- Wire-format sizes grow. PQ public keys, signatures, and ciphertexts are "often 1–2 orders of magnitude larger" than the classical values. If your protocol or wire format hardcodes Ed25519-sized signatures or X25519-sized public keys, the surrounding fields, length prefixes, and chunking assumptions must grow with them. This is code work, not a config change.
- ML-KEM changes the exchange shape, not just the primitive. ML-KEM is a key encapsulation mechanism, not a Diffie-Hellman exchange. Instead of both parties combining key shares, one party encapsulates a fresh shared secret to the receiver's public key and the receiver decapsulates it with the matching private key. Any code assuming DH-style mutual key-share combination needs restructuring, not substitution. ML-DSA, by contrast, mirrors the existing asymmetric-signature API.
Backend note: v48 includes Rust bindings plus AWS-LC backend support, with maintainer work toward the other backends.
Caveats
- SLH-DSA (FIPS 205) is not in v48. Work has started. It's the hash-based conservative backstop — very large signatures and slow signing, but relying only on hash-function security — intended as insurance if lattice-based signatures are later weakened. If your threat model wants a non-lattice signature, it isn't available yet.
- Protocols don't use these primitives yet. You are "unlikely to use PQ algorithms directly in tools like Certbot or Ansible" until common protocols add support. Shipping the primitive in the library is the foundation; end-to-end PQ requires protocol-level integration that Trail of Bits says is still in progress.
- The post shows Ed25519-vs-ML-DSA-65 and X25519-vs-ML-KEM-768 comparison tables, but the numeric figures were not captured in the fetched text — verify exact sizes on the page before sizing buffers.
Organisations named here
- FIPS 203
- FIPS 204
- ML-DSA
- ML-KEM
- SLH-DSA
- Sovereign Tech Agency
Technologies named here
- pyca/cryptography
- Ansible
- AWS-LC
- Certbot
- Apache Airflow
- Paramiko
- Python
- PyPI
- Rust
- NIST
- FIPS 205
- Trail of Bits
- Executive Order 14028
Techniques named here
- ML-KEM
- ML-DSA
- SLH-DSA
- Harvest now, decrypt later
Related in AppSec