Skip to main content

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:

  1. 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's ZEQ_FIELD_KEY.
  2. The initiator encapsulates to that public key — producing a ciphertext and a shared secret — then HKDF-derives an AES-256 record key.
  3. 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_mismatch on 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 matching seed_commitment on 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

LayerPosture
ZeqSSL data-plane (machine↔machine, SDK, bridge-inward)Post-quantum today (ML-KEM seed + AES-256-GCM records).
Browser↔edge outer TLSClassical 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.