Post-quantum cryptography is now one pip-install away for the entire Python ecosystem. With funding from the Sovereign Tech Agency, we implemented support for ML-KEM, the NIST-standard key-establishment primitive, and ML-DSA, the NIST-standard digital-signature primitive, in pyca/cryptography.
On June 22, 2026, the White House ordered the U.S. government to accelerate its transition to post-quantum cryptography. The order says large-scale quantum computers, especially in adversarial hands, will threaten widely used cryptographic systems, and that attackers may already be collecting encrypted data now so they can decrypt it later. It also sets concrete migration deadlines: high-value and high-impact federal systems must use post-quantum key establishment by December 31, 2030, and post-quantum digital signatures by December 31, 2031. And even if you don’t care about quantum resistance, that’s not a problem because quantum resistance isn’t the main benefit of post-quantum crypto.
That transition cannot happen only at the policy layer. Every application that signs packages, validates certificates, establishes secure channels, or protects long-lived secrets depends on cryptographic libraries. If those libraries do not expose post-quantum algorithms, the software stack cannot migrate.
Almost every Python program that touches cryptography goes through pyca/cryptography. It’s currently the eleventh most-downloaded package on PyPI, pulling 1.2 billion downloads in the last month alone. The pyca/cryptography package handles the cryptographic operations of projects like Ansible, Certbot (the Let’s Encrypt client), Apache Airflow, paramiko (the Python-only SSH client), and many others. If pyca/cryptography doesn’t ship post-quantum primitives, the Python ecosystem can’t begin to migrate.
As of cryptography>=48, support for post quantum algorithms is just a pip install away. The version 48 release includes our Rust bindings for ML-KEM and ML-DSA, the cross binding API and tests, and support for AWS-LC as a cryptographic backend. It also includes work from pyca/cryptography’s maintainers to support the other cryptographic backends. Sadly, this is not enough for a post-quantum migration drop-in swap. These primitives have different size, performance, and integration tradeoffs than the classical algorithms they replace.
Post-quantum primitives keep the same security strength, but they change the size of the data on the wire. Public keys, signatures, and ciphertexts are often 1–2 orders of magnitude larger than the classical values they replace. The operations are also more complex and therefore slower, but on modern hardware they are still imperceptible for regular use, and are likely to get faster with improved hardware and algorithms.
For signatures, here’s how the classical primitive (Ed25519) compares to its post-quantum equivalent (ML-DSA-65):
| Algorithm | Public key | Private key | Output |
|---|---|---|---|
| Ed25519 | 32 B | 32 B | 64 B sig |
| ML-DSA-65 | 1,952 B | 32 B | 3,309 B sig |
And for key exchange and encryption, here’s how X25519 compares to its post-quantum equivalent (ML-KEM-768):
| Algorithm | Public key | Private key | Output |
|---|---|---|---|
| X25519 | 32 B | 32 B | 32 B shared |
| ML-KEM-768 | 1,184 B | 64 B | 1,088 B ciphertext |
If you maintain a protocol or wire format that hardcodes Ed25519-sized signatures or X25519-sized public keys, the post-quantum migration involves more than a primitive swap. The surrounding fields, length prefixes, and chunking assumptions need to grow with it.
ML-DSA is the lattice-based signature scheme that replaces RSA, ECDSA, and Ed25519. The Python API mirrors the existing asymmetric primitives:
from cryptography.hazmat.primitives.asymmetric import mldsa
private_key = mldsa.MLDSA65PrivateKey.generate()
public_key = private_key.public_key()
signature = private_key.sign(b"message")
public_key.verify(signature, b"message") # raises InvalidSignature on failureML-KEM is a key encapsulation mechanism (KEM) for establishing shared secrets. The construction is different, though. ML-KEM is a key encapsulation mechanism, not a Diffie-Hellman exchange. Instead of both parties combining key shares to derive a shared secret, one party encapsulates a fresh shared secret to the receiver’s public key, and the receiver decapsulates it with the matching private key. These operations allow both parties to exchange a secret but in a manner fundamentally different from Diffie-Hellman, and resistant to quantum factoring attacks.
from cryptography.hazmat.primitives.asymmetric import mlkem
# Receiver generates a keypair and publishes the public key.
private_key = mlkem.MLKEM768PrivateKey.generate()
public_key = private_key.public_key()
# Sender encapsulates a fresh shared secret to that public key.
shared_secret_sender, ciphertext = public_key.encapsulate()
# Receiver decapsulates the same shared secret from the ciphertext.
shared_secret_receiver = private_key.decapsulate(ciphertext)
assert shared_secret_sender == shared_secret_receiverTwo areas are still in progress: a third NIST standard, and the work of integrating these primitives into real protocols.
SLH-DSA (FIPS 205) is NIST’s hash-based digital signature standard. Like ML-DSA, it is meant to replace classical signature schemes such as RSA, ECDSA, and Ed25519. Its tradeoff is different: SLH-DSA has very large signatures and slow signing, but it relies only on the security properties of hash functions, which have been studied for decades. That makes it a conservative backstop if future cryptanalysis weakens lattice-based signatures. SLH-DSA is not supported in pyca/cryptography 48, but we’ve started working on it.
Primitives are the foundation, but the post-quantum migration will be complete only when protocols use the post-quantum resistant algorithms. You’re unlikely to use PQ algorithms directly in tools like Certbot or Ansible until common protocols add support for them. While well-designed to replace existing implementations, algorithm changes require cautious development, testing, and auditing. We are actively working on helping maintainers integrate PQ algorithms into applications.
This work was funded by the Sovereign Tech Agency, whose mission is to support the open-source infrastructure that public digital systems depend on.
We’re also indebted to pyca/cryptography’s maintainers, Paul Kehrer and Alex Gaynor, who offered constant feedback and review throughout the development process, and continue to steward this critical piece of open-source software.