Post-quantum key exchange
Zeq closes harvest-now-decrypt-later on the surfaces it controls by putting the
post-quantum math in its own code (the audited
@noble/post-quantum), not
in the TLS transport. That means it ships today, on the current edge, with no
OpenSSL upgrade.
ZeqKeyEx — ML-KEM-768 first contact
ML-KEM-768 (NIST FIPS 203) is a post-quantum key-encapsulation mechanism. Two machines that have never shared a secret can derive an identical key:
- The responder publishes its ML-KEM public key:
GET /api/keyex/:slug/pubkey→{ public_key, fingerprint, machine_id, alg: "ML-KEM-768" }. The key pair is generated lazily on first request; the secret key is sealed at rest under the deployment'sZEQ_FIELD_KEY. - The initiator encapsulates to that public key — producing a ciphertext and a shared secret — then HKDF-derives an AES-256 record key.
POST /api/keyex/:slug/handshake { cipher_text }→ the responder decapsulates with its secret key, derives the same record key, stores the session, and returns a key-confirmation sealed under that key. If the initiator can open it, both sides hold the identical key.
Sizes (ML-KEM-768): public key 1184 B, secret key 2400 B, ciphertext 1088 B, shared secret 32 B. The record layer is AES-256-GCM — symmetric/hash only, consistent with the post-quantum posture.
Honest boundary. A bare KEM is unauthenticated. This closes
harvest-now-decrypt-later (a passive recorder can't recover the secret), but
first-contact MITM needs a trust anchor: pin the responder's published
fingerprint against its observer (and, ahead, the global identity layer)
before trusting first contact. We do not claim authenticated first contact from
the KEM alone.
ZeqSSL Mode-B, seeded by ML-KEM
ZeqSSL is the framework's own application-layer secure channel — its record layer (AES-256-GCM + HMAC-SHA256 + SHA-256, re-keyed every Zeqond) was always post-quantum-safe. The one piece that wasn't was how two strangers agree on the first Mode-B seed. ML-KEM now supplies it:
POST /api/ssl/peer-seed/keyex/initiate(admin) — fetches the peer's ML-KEM public key, enforces the fingerprint pin (409 fingerprint_mismatchon a bad pin), encapsulates, derives the Mode-B seed, stores it, returns the ciphertext.POST /api/ssl/peer-seed/keyex/respond(admin) — decapsulates with its own ML-KEM key, derives the identical seed, stores it. A matchingseed_commitmenton both sides confirms agreement without revealing the seed.
The result is an end-to-end post-quantum ZeqSSL session, first-touch, with no prior shared secret and no OpenSSL dependency.
What is and isn't post-quantum here
| Layer | Posture |
|---|---|
| ZeqSSL data-plane (machine↔machine, SDK, bridge-inward) | Post-quantum today (ML-KEM seed + AES-256-GCM records). |
| Browser↔edge outer TLS | Classical ECDHE today. Hybrid X25519MLKEM768 is on the roadmap, blocked on an OpenSSL 3.5+ upgrade. |
A plain browser can't speak ZeqSSL natively (it reaches the bridge, which terminates classical TLS first), so the browser↔edge hop stays classical until that upgrade. The PQ path covers the fleet-internal / SDK / inward legs — the surfaces most exposed to harvest-now-decrypt-later of Zeq data.
Verify it yourself
# 1. Fetch a machine's ML-KEM public key + fingerprint
curl https://zeqstate.com/api/keyex/<slug>/pubkey
# 2. (admin) establish a ZeqSSL Mode-B seed with a peer, pinning its fingerprint
curl -X POST https://zeqstate.com/api/ssl/peer-seed/keyex/initiate \
-H 'content-type: application/json' -b "$COOKIE" \
-d '{"local_machine":"<slug>","peer_origin":"https://zeqond.com","peer_machine":"<peer-slug>","expected_fingerprint":"<pin>"}'
# → { cipher_text, seed_commitment, peer_machine_id, ... }
Source: shared/api-core/src/lib/zeqKeyEx.ts, lib/zeqSslKeyex.ts,
routes/keyEx.ts, routes/ssl.ts.