---
title: "Two Independent Post-Quantum PGP Implementations Now Interoperate"
description: "I tested ML-KEM and ML-DSA across Sequoia and GopenPGP. They talk to each other. Keyservers reject the keys. Here is what works and what does not."
published: 2026-05-30
tags: ["security"]
---

I spent the weekend testing post-quantum cryptography in PGP. Not reading about it - actually generating keys, encrypting files, signing documents, and checking whether two independent implementations can talk to each other.

They can. The standard works. Keyservers don't accept the keys yet. And almost nobody is using any of this.

## The finding

The IETF draft `draft-ietf-openpgp-pqc` defines hybrid algorithms for OpenPGP - ML-DSA-65+Ed25519 for signing, ML-KEM-768+X25519 for encryption. Two implementations exist:

- **Sequoia PGP** (Rust) - `sq 1.4.0-pqc.1`, backed by the Sequoia team and Red Hat
- **Proton's GopenPGP** (Go) - `v3.4.1-proton`, the library behind Proton Mail

I generated PQC keys with each tool, encrypted messages, and decrypted them with the other:

| | Sequoia decrypts | GopenPGP decrypts |
|---|---|---|
| **Sequoia encrypts** | ✓ | ✓ |
| **GopenPGP encrypts** | ✓ | ✓ |

| | Sequoia verifies | GopenPGP verifies |
|---|---|---|
| **Sequoia signs** | ✓ | ✓ |
| **GopenPGP signs** | ✓ | ✓ |

Two teams, two languages, one spec. Interoperability is the whole point of a standard, and this one works.

## What broke

Keyservers don't accept PQC keys. When I tried uploading to keys.openpgp.org:

```
Error: OpenPGP v6 (RFC 9580) is not yet supported.
```

PQC requires v6 keys (RFC 9580), and the keyserver infrastructure hasn't caught up. So right now, you can generate and use PQC keys locally or share them out-of-band, but there's no public distribution mechanism. This is probably the biggest practical blocker.

Everything else worked on the first try, which genuinely surprised me given these are pre-release implementations of a draft standard.

## Performance

Measured on an M4 MacBook Pro (native, not Docker):

| Operation | Time |
|---|---|
| PQC key generation (4 subkeys) | 75 ms |
| Encrypt 1 MB file | 179 ms |
| Sign 1 MB file | 14 ms |
| Decrypt | ~180 ms |

For comparison, classical Ed25519/X25519 operations are roughly the same speed. The lattice math is not the bottleneck - I/O is.

## The size tax

This is the part that matters for infrastructure:

| | Classical (Ed25519/X25519) | PQC (ML-DSA-65/ML-KEM-768) | Factor |
|---|---|---|---|
| **Public key** | 889 bytes | 47,674 bytes | 54x |
| **Encrypted message** | 344 bytes | 1,888 bytes | 5.5x |
| **Detached signature** | 271 bytes | 4,752 bytes | 17.5x |

For encrypting files - irrelevant, 48KB is nothing. For certificate transparency logs, DANE records, keyservers, or anything that aggregates thousands of signatures - this is a real problem. Package managers with PQC signature chains will need to think about bandwidth.

## The ecosystem

**OpenPGP** (IETF) has full PQC - encryption and signing. Sequoia and GopenPGP implement it.

**LibrePGP** (GnuPG's fork) supports ML-KEM for encryption only. Koch's position is that signing "is not an important topic for now." I think he's wrong - code signing and package verification are arguably the most important PGP use case left, and those need quantum-resistant signatures. Encryption protects data at rest; signatures protect the supply chain.

**Proton** co-authored the IETF draft. When they ship PQC to 100M+ users, it'll be the largest PQC email deployment. But today, if you generate a PQC key, GPG users cannot decrypt your messages.

## The build problem

Sequoia PQC requires **OpenSSL 3.5+** because ML-KEM/ML-DSA support was only added in March 2025. Debian 12 ships 3.0. Ubuntu 24.04 ships 3.0. **Ubuntu 26.04 ships 3.5 and works out of the box.** For older distros, you have to compile OpenSSL from source before building Sequoia.

I packaged this into Docker images so nobody else has to deal with it:

```bash
docker pull ghcr.io/detrin/pqc/sequoia:latest
```

On Ubuntu 26.04, you can also build natively (it ships OpenSSL 3.5):

```bash
sudo apt install libssl-dev pkg-config capnproto clang libclang-dev
cargo install sequoia-sq --version 1.4.0-pqc.1 \
  --locked --no-default-features --features crypto-openssl
```

## Full walkthrough: Sequoia PQC

Here is the complete workflow - keygen, encrypt, decrypt, sign, verify:

```bash
SQ="docker run --rm -v $(pwd):/data ghcr.io/detrin/pqc/sequoia"

# 1. Generate a post-quantum key pair
$SQ key generate \
  --own-key \
  --name "Your Name" \
  --email you@example.com \
  --without-password \
  --profile rfc9580 \
  --cipher-suite mldsa65-ed25519 \
  --output /data/key.pgp \
  --rev-cert /data/key.rev

# 2. Extract public certificate (share this with others)
$SQ key delete \
  --cert-file=/data/key.pgp \
  --output=/data/key.pub.pgp

# 3. Encrypt a file
echo "confidential data" > secret.txt
$SQ encrypt \
  --for-file /data/key.pub.pgp \
  --without-signature \
  --output /data/secret.pgp \
  /data/secret.txt

# 4. Decrypt
$SQ decrypt \
  --recipient-file /data/key.pgp \
  --output /data/decrypted.txt \
  /data/secret.pgp

# 5. Sign a document (detached signature)
$SQ sign \
  --signer-file /data/key.pgp \
  --signature-file /data/doc.sig \
  /data/secret.txt

# 6. Verify
$SQ verify \
  --signer-file /data/key.pub.pgp \
  --signature-file /data/doc.sig \
  /data/secret.txt
```

## Alice and Bob: cross-implementation communication

This is where it gets interesting. Alice uses Sequoia (Rust), Bob uses pqcrypt (Go, built on Proton's GopenPGP). Different tools, same standard - and they interoperate.

```bash
# Alice generates her key with Sequoia
docker run --rm -v $(pwd):/data ghcr.io/detrin/pqc/sequoia key generate \
  --own-key \
  --name "Alice" \
  --email alice@example.com \
  --without-password \
  --profile rfc9580 \
  --cipher-suite mldsa65-ed25519 \
  --output /data/alice.pgp \
  --rev-cert /data/alice.rev

# Bob generates his key with pqcrypt (Go)
docker run --rm -v $(pwd):/data ghcr.io/detrin/pqc/gopenpgp keygen \
  --name "Bob" \
  --email bob@example.com \
  --pqc \
  --output /data/bob

# Alice encrypts a message for Bob using his public key
docker run --rm -v $(pwd):/data ghcr.io/detrin/pqc/sequoia encrypt \
  --for-file /data/bob.pub.asc \
  --without-signature \
  --output /data/for-bob.pgp \
  /data/secret.txt

# Bob decrypts with pqcrypt - different implementation, works fine
docker run --rm -v $(pwd):/data ghcr.io/detrin/pqc/gopenpgp decrypt \
  --key /data/bob.key.asc \
  --input /data/for-bob.pgp \
  --output /data/bob-reads.txt

# Bob signs a response with pqcrypt
docker run --rm -v $(pwd):/data ghcr.io/detrin/pqc/gopenpgp sign \
  --key /data/bob.key.asc \
  --input /data/bob-reads.txt

# Alice verifies Bob's signature with Sequoia
docker run --rm -v $(pwd):/data ghcr.io/detrin/pqc/sequoia verify \
  --signer-file /data/bob.pub.asc \
  --signature-file /data/bob-reads.txt.sig \
  /data/bob-reads.txt
```

Two implementations, two languages, two independently generated PQC keys - full interoperability confirmed.

## Verify it yourself

I signed the following message with my PQC key using:

```bash
echo "This message was signed with a post-quantum key (ML-DSA-65+Ed25519) on 2026-05-30." > message.txt
sq sign --signer-file key.pgp --cleartext message.txt > signed-message.txt
```

Here is the result - a real cleartext-signed message from my PQC key. You can verify it:

```
-----BEGIN PGP SIGNED MESSAGE-----

This message was signed with a post-quantum key (ML-DSA-65+Ed25519) on 2026-05-30.

-----BEGIN PGP SIGNATURE-----

wszFBgEeCgAAACkFgmob8ewiIQYyunlM6WsKBVys9iK01CYOFTRXA8h9rtCHLR5e
Og5EmgAAAAAyViBT80IEdLX/oOuk3l2MSfAEcKbDtVM4S60zxiUDOoCXrN3fOL+d
BzTCeNH7XQZTLMOlvwkmrKgj7vuO74dGsvHLvmAeO6ZzoEj2t6QwtvNU+wGfG5Kg
YVrENhFeqjlr2w23R1hQG5M/nNvYLM2ikTS1j3es9CPg1RAb/SF7T7j0BOOD4EvC
VMcca/msCYyFvI/MREsZ7JcQa38OPSbbQpph5aKjIchquOq4+5HmuMifTRpNw07y
6u8QfH/0MOCMrnvFMITyz6kRGIxLww7WrnfAuZbjyyk5Ek2h1p7le+K9myRdew1W
9ytx3ZlDyNU80fjcfvFFZ2lxrou57vO1FypfsA1XiMN+LY1m602HVu4gM3rijtGS
ec08lI/StZ/HYwjWWMLk19rGwv7ZGwLUodIJpJkQak2Am3XM2CWVlBipWRsSz5AI
x4oZzasSl5MZiMztgi8SOpVlxSYFeH+SZlRFUcmaHhJ3m9zEex7uCiyg6xg1j8KR
TidoMU1APlzyU1KjkYpUP2GNNbpvtW95oTzaqrKdKOKS20x/1gYX3O2NB3grjXJs
HsWt3hCgaJV7ANILUB/8J1Hl7CRfAFvIA2WKpb1TIxIpMnKuZwzji20PnlzYcdRe
9OgECfYeW22a71TNEy1txPTWhpfN+ATduZYjHcreM8EaehDPFDAwGc8zB8ad5p4P
XFI/2m5J8Fw/ECsSgpMPLExLcY9KjQ/XBY+WAgNPdljvtNcEXILZtgSw3iJOEixd
1RneRGzewa0wghlFBvt4hjaFUAcIroVudEFfjfZXAi2XTIvnB/ttnBITmKprmT2A
7cbnjbbOebQYMDl00hKqhqo0JXFb42itGGJgxNbkpcATcGTF29Q0jhm1b7stxHGR
3870yMVaUKxyCwNj8TzxYNxs/J6tcGPtizWIjJMxUPA3Uo0sSXK0jjxEAlXH9M2G
YezRK8pZ0Lilg9W7M1akGSNxMsf3VVtT0wLbqBgB+TE0nsoBS809pxPd3Nr/mG0x
oNWGk2dutSvv3Q3agq7XVR7Qn8V4x2WZdM2YoDv9dRZyidPOd7gBh15diQdo4R5Y
Eo0LorYJ/rb6Lk2Oq9ZxRJ3DgqQWCPJKKVJN35zGTK5i9eHH+T3fgrwwB+mDZgny
GUkVAWUSRQ3c5iwrLoSL9YdTWZPDtADU/wo5q4qIewlecOzmF6ghRtzbd77gv8WY
2qwbbhYzPNML3GRd//zKwGYi3XO7u1neLIvNDzAdP0O4+1kMt83WWr3Gw4Bngcps
Y1gTHGJJciXRy9X+VTI3MfP9pM8nl8NLEUmuHlooo7kgnRKhq6NAc0152Lc+p0pE
zFfIIdoH2IsCEwKPoeYQFgQpiBIHRDLS8oxWrRJoRSkv4nJ7y6yrjFQ2YOcyt+bj
zwlA6HIxvZCXawPwAVlVo6zZnjdh6xFYQEeJa+EZbC46nUm6NUKcI4AzO6eCO+9j
ETutvRlAm7RSgF3kJScES5woxFklnuBPYjTpunuid6Ocm0N1t8PclcVjoEdSgy/h
chaQiYMqrlNqWfET0IbrTb8+5yoHEQOhl8gckJOLn8J0pVhZW/W2rkHqoNPg4rqC
86AtsMaC+vsq3CY7Gtzgca4RoEbeeVhtYXS3Dyv/WMGWa4ve2koXvm8aMBRDIqP5
8E3NO4jNmpcdwrMFXOB9rvlPhNq1H3gegaCl2CfEf98JHJ45C5kFDz1E6MYks88B
6Zf9qABwKuEOzU9E9RVTA64SeJtqqJzEFs0yWEbQb30DhRV1/ugImEXpGCuhG8//
irWrPm7a8DCR1SRH8dCoRFPdxX7N0rV37yDDYVqq3yR19SHUxTlHibXILqwTS+38
ZN+P69UY58A6nOnnqZv2WNzA2/vwK/kEdLZyN9z11vhEgcaa2+i5PT0OvwQaLMwa
qp8RldSR5jJTtoKZdzihKAv73fFaV2IId8bo48xhRIUVcusdVxEtG7Ul4aRGgyga
hui/6ZuPK/TakggP9m7MZGmPLtMh54AEA83MHYq2IJnJmdH+NW4llwDpB2mQ6Qve
Fa1LeXvU9IGUUBPF5SHV/eRb0U6Q8z+PgoEy7/g+2O2IS0HOgyJj3vEVOAGR0Gvx
vT/vNY0orLO6dq/tYKV11Loqx4cBmSwSc+I5FsRuuCDEyuBUA/LMujeVgg4mQ0cv
hxdHa4JrRPoQgoHWB2BAVRj+VGGeYM3fOiobyGb0O3DUjbSbIFko/6yI0Yrjh0oO
eXgYi5IKMou7zOUdDj6ZZF8QyYKPOGksvrYcp5B1DTkKP8IvbkmhHz8xdH42/fr4
oo7Qgp++zAwZwclvH+Dwhqq04E9+5v7UcjSiasBAkozBmZcdun+KmLRGePthre3o
zIvoGm1Yicu5FD8hKobZy3U8rRN6QnGMPvtlMXm3VqnE8WRXCB9lThBp9h6UpVIW
j/em5Rr1iX2iMF1vibO8zLTXPWRmGVn8fKHBb8M50rf+X8vb68oKMGnUywiscVMi
wNNStiAL5T8E8X0ZmIOiPKnQbXlLnw3rRYGRATmbMyCb5p8fhGHqY6EDMqxIAv/V
EOxPmEqFtrn9XjGYUAYyAs1+t0YLU6x+FB8cP7ikWvlS9Kn3oGmz/stSq4zWjCdx
lfNrzmBOoJXeDxJ/mBpMTJPLNSPurkbKS538fte0rsJ2G09OcvKF0Zexs3pzTaEt
HM2Sljt/YF6Sv3Aqy8zOisyzWEerj7oAgRQzi6n6bNQjVxS+o4+TCIJsTD0Hzex/
BbGpZoFvan4XZcqNp/UfLelPb68NSEju+W3BPv/0pZOE2UdiIkFHYR82nc8iJe2D
Eap7QE+AkXBDp/LsRJsAHvMnSLi6oBseSVBz9ixCUtkFglPUaaFHWC1BjDwqx/7z
dnA6ZRkUYmbpVzyQxGiSSeDFCp90z+ZONOGWx5b97CeFXEIGMnNSM37AAzb9abUT
i19e2feAMP+9dMoslzagicgbjV2lSFJPzIalm+ImUr64EN1eaQ/mK5xWuxfyALHS
J7bgBQhk/jlKBWMgCYuE+3OGpBsfbbWOV/hKn+34tSpshj7LOvvba4HfB8H9wR7g
vnI9zMWrExR/gDFq7UzyJzNVFYAWxu9jHMyiwzWBdhsGxmLUlgSZT4qoeNKEt97Q
bNCL9VBFKuQbbwOK0O4ElArWlKS4fBJVKcYsDPYadkA3u/Q4GHfMm5ZtJfnuDjAV
JlDwyzzsDoB+T9WopDAbw1Lr2iw3INJywJJfL2Hsp1uyLTuVB8Xs/08+Aoy+Or/A
DLE0gOGCfKPqMDp9nGEeaD7y6ZHm8Dt8VEZZ+wLxUuDOJ24l5O/YL/d7UjycASHf
Wgw8VRLIIiFyW97++ZXLK8htPE+pC2ORdxXGuZsf/IKGWYcLCVjIGyw8Q53Lfsem
7cUdmas1YS1ogW/hKgrnoT4jP5sHNoZasEs5DSCAyKm56nn4Tgw9hdUXDodhDr6S
uW9l/vNhrA/INKRm7SI9lU51I4QsdVkHG9r7EAc93PH2qGZE4ta3mVYfHv1UQVk2
u8LeV02PDbISkeM03CdW+TjMG+ncSTvFoxHlRfjZuMIQb1DVxcTGzqotCrFM10cn
6WQCl3X3K6GuxOjys4fgc9eREvaZ782M2fA3coZHHawYMmFDZyMgkTER+Q0EIE0C
lISF+bMryXy/qeapV3gW6txHfLha2o2HurEr+ZgBwzdOJrCvZTvShHX4emA48wzj
0GdgQK3Qg5pq+lXJAfw/12MNE/DUpLVdJ+UJgytxh2FYnFFN8kwdSPNamrGPL1m2
z5B5Vpc1CtNpebSOtZ6hlfa3s8VackxXQM/p6j0kePQjLpmGBno9y9PJ4fqaHHwV
nheFcoI9kV2Q71hAhczpNsTIK/lLNlXcdCvwKNWDDEzhjYGCmsmG4X+URRpcGENS
I8H2pUhxKTdookNV28y2PlflKNqJseWuXrqkljCj95hfRfQa+vmNpbQ+D/FFsfdv
UA68pY6xnQ+u8iIpi6Cb3CZ0/ecG0kxxAJqax5HRaO9dGH6E/xVQ4DJ6I8KLPqaN
iuaFpnFK/sk7pDhaVv8awEsMv5f9vL+sGdD+RIWuA333zQVCMRWdqgicV0FMT6Rn
i/pOJeGdenDSHmcxpuaKgCdpIxGAOhHIeptxws9UsX0op8Z0KJOxMVxgYltBXYX4
HYNbx00WHlT6uT5LDQWND8hC5v9fNOaiwNlDApuKebuLTdZ5Im5VTrWwlhYeh62N
kmcTqE7v0s61e7E7DDh4Oak8Ai4WB/WlfQvqiGisjELcuUNA4sz5LPD0XeLqsx3L
jNx4RTdt7l+y0adFRbHc9CuxA2BMcMg97MsCwqaBGllA6RttnxoRWbQ9QhsX8y7Z
E4oSf0sxaBpFeTMmRH3x2VWdw6xFXCeQE4jhjjgXv0QdoIGOHe5LmYXb6eyn9TzR
HvYZzec7FqKKHZ4UxoRbybfxjrVtyfdm06kqqhpOgq+7P0/bEBxTR2efthImTliB
laOmqrS6BBMyTX2AmKKn2+IECzZ2vc3X+w4ZSabYPEvH1CVggL8AAAAAAAAAAAAA
AAALFh4jJys=
=YD8X
-----END PGP SIGNATURE-----
```

To verify, download my public key and run:

```bash
curl -O https://raw.githubusercontent.com/detrin/pqc/main/keys/daniel-herman.pub.pgp
sq verify --signer-file daniel-herman.pub.pgp --cleartext signed-message.txt
```

Output: `Authenticated signature made by B9ABC16E... (Daniel Herman) - 1 authenticated signature.`

My key fingerprint: `B9ABC16EC9A26EE929EEA07860A15523A3F3362853D38D14ACC24A1B55015DB2`

## "PGP is dead, just use Signal"

I hear you. For person-to-person messaging, PGP lost. But PGP isn't just email:

- **Code signing** (git commits, package managers, firmware)
- **File encryption at rest** (backups, archives that outlive you)
- **Document signing** (legal, compliance)

These don't have Signal alternatives. They need PQC because the documents they protect have 10-30 year lifetimes - well within the "harvest now, decrypt later" threat window.

## How ML-KEM actually works

ML-KEM (FIPS 203) is a Key Encapsulation Mechanism. It does not encrypt data directly - it establishes a shared 32-byte secret between two parties, which then serves as the AES-256 key for symmetric encryption.

The security is based on the **Module Learning With Errors (M-LWE)** problem. The core idea:

**Key generation** produces a public matrix $\mathbf{A} \in R_q^{k \times k}$ and computes:

$$\mathbf{t} = \mathbf{A} \cdot \mathbf{s} + \mathbf{e} \pmod{q}$$

where $\mathbf{s}$ is the secret key vector and $\mathbf{e}$ is a small random error vector sampled from a centered binomial distribution. The public key is $(\mathbf{A}, \mathbf{t})$. The private key is $\mathbf{s}$.

**Encapsulation** (sender side) picks a random vector $\mathbf{r}$ and computes:

$$\mathbf{u} = \mathbf{A}^\top \cdot \mathbf{r} + \mathbf{e}_1 \pmod{q}$$

$$v = \mathbf{t}^\top \cdot \mathbf{r} + e_2 + \left\lceil \frac{q}{2} \right\rceil \cdot m \pmod{q}$$

where $m$ is the message to encapsulate (a random shared secret), and $\mathbf{e}_1$, $e_2$ are fresh small noise terms. The ciphertext is $(\mathbf{u}, v)$.

**Decapsulation** (recipient side) computes:

$$v - \mathbf{s}^\top \cdot \mathbf{u} = \left\lceil \frac{q}{2} \right\rceil \cdot m + \underbrace{(\mathbf{e}^\top \cdot \mathbf{r} + e_2 - \mathbf{s}^\top \cdot \mathbf{e}_1)}_{\text{small noise, roundable}}$$

The derivation: since $\mathbf{t} = \mathbf{A} \cdot \mathbf{s} + \mathbf{e}$, we get $\mathbf{t}^\top \cdot \mathbf{r} = \mathbf{s}^\top \cdot \mathbf{A}^\top \cdot \mathbf{r} + \mathbf{e}^\top \cdot \mathbf{r}$, and the $\mathbf{s}^\top \cdot \mathbf{A}^\top \cdot \mathbf{r}$ terms cancel, leaving only the message plus small noise.

The noise terms are bounded: $|\mathbf{e}^\top \cdot \mathbf{r} + e_2 - \mathbf{s}^\top \cdot \mathbf{e}_1| < \frac{q}{4}$, so rounding recovers $m$ exactly. But without knowing $\mathbf{s}$, an attacker sees only noisy linear equations and cannot separate signal from noise.

![LWE visualization - clean lattice vs noisy lattice](/images/pqc/lattice-lwe.svg)

The visualization shows the key intuition. Left: in classical crypto (RSA, ECC), values lie on a clean algebraic structure - Shor's algorithm exploits this periodicity. Right: in ML-KEM, each value (red) is displaced from its lattice position (blue ghost) by random noise **e**. The legitimate recipient knows **s** and can cancel the noise. An attacker would need to solve the M-LWE problem - finding **s** given only **A** and **t = A·s + e** - which no known quantum algorithm can do efficiently.

**ML-KEM-768 parameters** (from FIPS 203):
- Polynomial ring: $R_q = \mathbb{Z}_q[X]/(X^{256} + 1)$, with $q = 3329$
- Module rank $k = 3$ (hence "768" = $3 \times 256$)
- Public key: 1,184 bytes
- Ciphertext: 1,088 bytes
- Shared secret: 32 bytes

## Why RSA falls and lattices don't

**RSA** relies on factoring: $n = p \times q$. Shor's algorithm reduces this to quantum period-finding in the group $(\mathbb{Z}/n\mathbb{Z})^*$ - a clean algebraic structure that the Quantum Fourier Transform exploits in polynomial time $O((\log n)^3)$.

**ML-KEM** relies on M-LWE: given $(\mathbf{A}, \mathbf{t} = \mathbf{A} \cdot \mathbf{s} + \mathbf{e})$, recover $\mathbf{s}$. There is no group structure, no period, no hidden subgroup. The noise destroys any algebraic regularity. The best known quantum attack is Grover-accelerated lattice sieving, which provides only a quadratic speedup - reducing security from $\sim 2^{192}$ to $\sim 2^{96}$, which is still computationally infeasible.

The hybrid construction in OpenPGP PQC combines both:

$$k_{\text{shared}} = \text{KDF}(k_{\text{X25519}} \| k_{\text{ML-KEM}})$$

An attacker must break both X25519 (classical) and ML-KEM (post-quantum) to recover the key.

## Should you use this today?

**Yes, if** you're encrypting data that needs to stay secret for 10+ years, or signing packages where you want the signatures to remain valid past 2030.

**No, if** you need GPG compatibility, keyserver distribution, or are waiting for the final RFC.

The honest timeline: working today → RFC ratified 2026-2027 → Proton ships to users 2027-2028 → NIST mandate 2029.

We're in the "works but nobody uses it" phase.

---

**Repo:** [github.com/detrin/pqc](https://github.com/detrin/pqc) - Docker images, interop tests, and a Go CLI wrapper.