X-Wing KEM

X-Wing is a general-purpose hybrid post-quantum / traditional key encapsulation mechanism: it runs ML-KEM-768 and X25519 side by side and binds their shared secrets with SHA3-256, so the resulting key stays secure as long as either ML-KEM-768 or X25519 holds. That is the conservative shape for migrating off classical ECDH today — a harvest-now- decrypt-later attacker must break the lattice KEM, and a hypothetical ML-KEM break still leaves X25519 standing.

The construction follows draft-connolly-cfrg-xwing-kem. The combiner is frozen — it hashes the ML-KEM shared secret, the X25519 shared secret, the X25519 ephemeral public key, the recipient's X25519 public key, and a fixed six-byte label — but the document is still an IETF Internet-Draft, so this primitive is marked experimental and sits beside the other pre-RFC post-quantum drafts (b.crypto.hpke.pq). The wire sizes are fixed: a 1216-byte public key (ML-KEM-768 1184 ‖ X25519 32), a 1120-byte ciphertext (ML-KEM-768 1088 ‖ X25519 32), a 32-byte decapsulation seed, and a 32-byte shared secret.

X-Wing composes the framework's vendored ML-KEM-768 and X25519 plus SHA3 — it adds no new cryptographic core, only the standard combiner and wire framing.

b.crypto.xwing.combiner(ssM, ssX, ctX, pkX) #

experimental0.13.3soc2

The X-Wing combiner: SHA3-256(ssM ‖ ssX ‖ ctX ‖ pkX ‖ label), where the label is the fixed six bytes the draft defines. Exposed for advanced use and known-answer testing; encapsulate and decapsulate call it internally. Each input must be 32 bytes.

var ss = b.crypto.xwing.combiner(ssMlkem, ssX25519, ephPub, recipientPub);
// → 32-byte shared secret

b.crypto.xwing.keygen(seed?) #

experimental0.13.3soc2

Generate an X-Wing keypair. The decapsulation key is a 32-byte seed (store this); the encapsulation key is the 1216-byte public key to publish. Pass a 32-byte seed for deterministic generation, or omit it for a random key.

var kp = b.crypto.xwing.keygen();
kp.publicKey.length;   // → 1216
kp.secretKey.length;   // → 32  (the seed — keep it secret)

b.crypto.xwing.encapsulate(publicKey, eseed?) #

experimental0.13.3soc2

Encapsulate to a 1216-byte X-Wing public key. Returns the 1120-byte ciphertext to send and the 32-byte sharedSecret to key a symmetric cipher with. Pass a 64-byte eseed (X25519 ephemeral scalar ‖ ML-KEM coins) for deterministic encapsulation, or omit it for fresh randomness.

var enc = b.crypto.xwing.encapsulate(recipientPublicKey);
enc.ciphertext.length;   // → 1120
enc.sharedSecret.length; // → 32

b.crypto.xwing.decapsulate(secretKey, ciphertext) #

experimental0.13.3soc2

Recover the 32-byte shared secret from a 1120-byte X-Wing ciphertext using the 32-byte decapsulation seed. ML-KEM-768's implicit-rejection means a tampered ciphertext yields a different (still 32-byte) secret rather than an error, so never branch on success — derive keys and let the AEAD tag fail.

var ss = b.crypto.xwing.decapsulate(kp.secretKey, enc.ciphertext);
ss.equals(enc.sharedSecret);   // → true

Last updated 2026-08-08T16:39:49.652Z by seeder.