Skip to main content

X-Wing hybrid KEM for Python (X25519 + ML-KEM-768), per draft-connolly-cfrg-xwing-kem

Project description

xwing-kem

The X-Wing hybrid post-quantum KEM (X25519 + ML-KEM-768) for Python.

CI PyPI Python License: MIT

xwing-kem is a single, drop-in key-encapsulation mechanism that stays secure as long as either classical X25519 or post-quantum ML-KEM-768 holds. It implements draft-connolly-cfrg-xwing-kem faithfully, so you get the vetted hybrid construction without ever hand-rolling a combiner — the single most common (and dangerous) post-quantum migration bug.

⚠️ Pre-1.0 — please read before production use

xwing-kem is validated against all three official X-Wing Known-Answer-Test (KAT) vectors from the draft: key generation from seed and the SHA3-256 combiner are checked byte-for-byte, and derandomized encapsulation is verified against the draft's reference implementation.

Honest limits that still apply: no ML-KEM backend exposes seeded encapsulation, so the library's own randomized encapsulate() is validated transitively (round-trip + keygen KAT + combiner KAT + reference-encaps KAT), not by a direct ciphertext-byte match; constant-time guarantees come only from the C-backend primitives, not the Python glue; and secret keys are not portable between backends. The full, candid accounting is in KNOWN-GAPS.md.


Contents

Key Features

  • 🛡️ Hybrid by construction — secure unless an attacker breaks both X25519 and ML-KEM-768.
  • 🎯 Concrete, not generic — algorithms, combiner (SHA3-256), and security level (NIST PQC level 1) are all fixed. Nothing to misconfigure.
  • 🔌 Two real backends, auto-selected — native cryptography preferred, with a liboqs fallback. No simulated math.
  • Inherits native speed — sits above the primitives, so it gets faster the moment your platform ships native ML-KEM.
  • KAT-validated — checked byte-for-byte against the official draft vectors (see the status note above).
  • 🧩 Consistent, predictable API — functional and class forms return values in the same order; fixed 1216-byte public keys, 1120-byte ciphertexts, and a 32-byte shared secret.
  • 🪶 Narrow, auditable scope — X-Wing only, MIT-licensed.

Quick Start

Both APIs return values in the same orderencapsulate() gives you (shared_secret, ciphertext).

Functional API:

from xwing_kem import generate_keypair, encapsulate, decapsulate

kp = generate_keypair()                                  # kp.public_key, kp.secret_key
shared_sender, ciphertext = encapsulate(kp.public_key)
shared_recipient = decapsulate(ciphertext, kp.secret_key)

assert shared_sender == shared_recipient                 # 32-byte shared secret

Class-based API:

from xwing_kem import XWing

kem = XWing()
public_key, secret_key = kem.generate_keypair()
shared_sender, ciphertext = kem.encapsulate(public_key)
shared_recipient = kem.decapsulate(ciphertext, secret_key)

assert shared_sender == shared_recipient

The only difference between the two forms is how the key pair is handed back: the functional generate_keypair() returns a small XWingKeyPair object (.public_key / .secret_key), while XWing.generate_keypair() returns a plain (public_key, secret_key) tuple. Pick whichever reads better for you.

More runnable scripts live in examples/.

Installation

pip install xwing-kem

That's it — the library auto-detects an ML-KEM backend at import time, so most users need nothing further. ML-KEM-768 is provided natively by cryptography>=48 when its wheel is built against OpenSSL 3.5+, AWS-LC, or BoringSSL. If your platform's wheel lacks post-quantum support, install the optional liboqs fallback backend:

pip install "xwing-kem[liboqs]"   # requires liboqs.so on the system

See Backend Selection to inspect or pin the active choice.

When to Use X-Wing

Reach for X-Wing when:

  • You're adding post-quantum protection to key exchange and want defense-in-depth — security that holds if either the classical or the post-quantum component is later broken.
  • You want a standards-track, opinionated construction with no knobs to tune, suitable for HPKE-style sealing, secure messaging, or wrapping data keys.
  • You'd otherwise be tempted to glue X25519 and ML-KEM together yourself — this library is exactly that glue, done to spec.

Look elsewhere when:

  • You need a bare ML-KEM or bare X25519 KEM (use cryptography or liboqs directly).
  • You need signatures or an authenticated KEM — out of scope here.
  • You require certified constant-time guarantees across the whole stack; the Python combiner layer offers no timing guarantee (see Validation & Limitations).

Why X-Wing?

Migrating to post-quantum cryptography, you almost never want a raw KEM — you want a hybrid that survives the failure of either half. The dangerous part is the combiner that mixes the two shared secrets; a hand-rolled one is the classic PQ-migration footgun, and getting the byte order or omitted inputs wrong silently produces incompatible or insecure secrets.

X-Wing removes that risk by being opinionated and concrete:

  • No parameters. The constituent algorithms (X25519 + ML-KEM-768), the combiner hash (SHA3-256), and the security target are all fixed by the spec.
  • Belt-and-suspenders security. An attacker must defeat both a well-studied elliptic curve and a NIST-standardized lattice KEM.
  • One obvious API. generate_keypair / encapsulate / decapsulate, fixed lengths, a 32-byte secret — easy to wire into HPKE, TLS-like handshakes, or file/message encryption.

This library exists so you can adopt the vetted construction instead of writing the combiner yourself.

The X-Wing Construction

The 32-byte shared secret is the SHA3-256 hash of the two component secrets, the X25519 ciphertext and public key, and a fixed label:

ss = SHA3-256( ss_M || ss_X || ct_X || pk_X || XWING_LABEL )
Symbol Meaning Size
ss_M ML-KEM-768 shared secret 32 B
ss_X X25519 raw shared secret 32 B
ct_X X25519 ciphertext (the ephemeral public key) 32 B
pk_X recipient's X25519 public key 32 B
XWING_LABEL the 6-byte X-Wing sigil, appended last 6 B

The ML-KEM ciphertext ct_M is deliberately omitted from the hash: ML-KEM-768 is ciphertext-collision-resistant, so mixing it in is unnecessary, and leaving it out is exactly what gives X-Wing its performance edge over a generic combiner.

Backend Selection

By default, no choice is required. The library auto-selects a backend at first use — native cryptography first, then liboqs — and caches it. You can inspect the active choice or pin it explicitly:

import xwing_kem
from xwing_kem import generate_keypair, XWing

# Which backend is active right now?
print(xwing_kem.active_backend())            # 'cryptography' or 'liboqs'

# Force a specific backend for a single call...
kp = generate_keypair(prefer_backend="liboqs")

# ...or for every operation on an object-style instance:
kem = XWing(prefer_backend="cryptography")
print(kem.backend_name)                      # 'cryptography'
public_key, secret_key = kem.generate_keypair()

prefer_backend accepts "cryptography", "liboqs", or None (auto). An unavailable choice raises rather than silently falling back, so pinning is always explicit and predictable.

Performance

xwing-kem is intentionally a thin, correct layer over the primitives — all the heavy lattice and curve math runs in vetted C inside the chosen backend, not in Python. That has two practical consequences:

  1. It inherits native speed. As native ML-KEM lands in cryptography / OpenSSL, this package gets faster automatically — no code change on your side.
  2. The construction itself is lean. By omitting the ML-KEM ciphertext from the combiner, X-Wing avoids extra hashing that a generic combiner would incur.

Indicative single-thread timings (median of 300 runs, cryptography backend, Python 3.12, x86-64), compared against pure X25519 used KEM-style (ephemeral keygen + DH for "encapsulate", DH for "decapsulate"):

Operation X-Wing Pure X25519 Overhead
keygen ~240 µs ~51 µs 4.7×
encapsulate ~145 µs ~117 µs 1.2×
decapsulate ~294 µs ~54 µs 5.5×

Takeaway: full post-quantum protection costs roughly 2–6× a bare X25519 exchange, yet every operation still completes in well under a millisecond. Encapsulation is nearly free relative to X25519, because ML-KEM encapsulation is fast and X-Wing layers only a single curve operation on top. Numbers vary by machine, Python version, and backend.

Validation & Limitations

This project follows an honest-documentation discipline. The short version:

  • KAT-validated. Key generation from seed and the SHA3-256 combiner are checked byte-for-byte against all three official draft vectors; derandomized encapsulation is verified against the reference implementation.
  • ⚠️ Randomized encapsulate() is validated transitively. No backend exposes seeded encapsulation, so it is covered by round-trip + keygen KAT + combiner KAT + reference-encaps KAT rather than a direct ciphertext-byte match.
  • ⚠️ Constant-time only in the C primitives. The Python combiner glue does no secret-dependent branching, but Python offers no timing guarantees — don't rely on this layer in a hostile co-located environment.
  • ⚠️ Secret keys are not portable between backends (cryptography stores the 64-byte seed form; liboqs the expanded form).

The complete accounting lives in KNOWN-GAPS.md. Please read it before depending on this in production.

Design Notes

  • Future-proof by position. This package sits above the primitives, so it inherits faster/native ML-KEM the moment your wheel has it.
  • No simulated cryptography. Both backends use real, vetted C implementations.
  • Deliberately narrow scope. X-Wing only — no ML-KEM-1024 variant, no authenticated KEM, no signatures, no HPKE/TLS wiring.

Contributing & Security

Contributions are welcome — see CONTRIBUTING.md. For vulnerability reports and the disclosure process, see SECURITY.md.

License

MIT.


X-Wing is the work of the IETF CFRG draft authors; this package is just a faithful, well-tested Python home for it. If it helps you ship post-quantum protection with a little more confidence, it's doing its job — issues and improvements are always welcome.

Soli Deo Gloria — 1 Corinthians 10:31.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xwing_kem-0.2.0.tar.gz (33.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xwing_kem-0.2.0-py3-none-any.whl (12.6 kB view details)

Uploaded Python 3

File details

Details for the file xwing_kem-0.2.0.tar.gz.

File metadata

  • Download URL: xwing_kem-0.2.0.tar.gz
  • Upload date:
  • Size: 33.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for xwing_kem-0.2.0.tar.gz
Algorithm Hash digest
SHA256 96a26c36cfcda8a7f3a9059592bfa1a22176bec45655f5a77038d8b8b8a72f9d
MD5 7e6ebaa9c3853c1fa2cf5b171e3fa349
BLAKE2b-256 21d31571639ae2f8f87cf855de10f3fac3f1fc13d8dace57ebc476610c7c28b9

See more details on using hashes here.

Provenance

The following attestation bundles were made for xwing_kem-0.2.0.tar.gz:

Publisher: release.yml on systemslibrarian/xwing-kem

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file xwing_kem-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: xwing_kem-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 12.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for xwing_kem-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e3e8d9732c141cb34ba93ae440910ffd97986ff2dd9da5e00de44eb7ac2a3f84
MD5 e48f2676e468ad5cd908a19a7ed9b4af
BLAKE2b-256 f60757ae34419e435e2ed141998a794ff8dfb3b89e86733d781ecf367186dfc6

See more details on using hashes here.

Provenance

The following attestation bundles were made for xwing_kem-0.2.0-py3-none-any.whl:

Publisher: release.yml on systemslibrarian/xwing-kem

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page