noise-pq: add Noise_XXhfs_25519+ML-KEM-768_ChaChaPoly_SHA256 spec (Stage 1 Working Draft) - #716
noise-pq: add Noise_XXhfs_25519+ML-KEM-768_ChaChaPoly_SHA256 spec (Stage 1 Working Draft)#716paschal533 wants to merge 2 commits into
Conversation
- Protocol name: Noise_XXhfs_25519+ML-KEM-768_ChaChaPoly_SHA256 - Protocol ID: /noise-mlkem768-hfs/0.1.0 - KEM: raw ML-KEM-768 (FIPS 203), removing X-Wing composite wrapper - Wire sizes: Msg A 1216 B, Msg B 1200 B (was 1248/1232 with X-Wing) - Add Rust reference impl (royzah/rust-libp2p PR libp2p#1) - Add triangle interop results (JS/Python/Rust -- 3/3 PASS, 2026-06-24)
|
Status update on this draft. Since I opened it in June, the evidence base has changed enough that I think it is worth summarising in one place, because the two questions a spec like this normally has to answer — is it implementable from the text alone? and is it affordable? — now have concrete answers rather than estimates. Four independent implementations
Four different ML-KEM-768 libraries, four codebases written separately against the prose in this document. All six pairwise combinations interoperate
Every pair completed a live handshake over TCP. No implementation required a protocol change to interoperate with any other. That is the main thing I wanted to establish about this text: four people reading it separately produced the same bytes on the wire. Where a pair also exchanged application data after the handshake, that covers both transport keys, since The affordability questionThis is the part that has genuinely changed. The early numbers made hybrid key exchange look expensive — +5.0x over classical in JavaScript, +12.9x in Python. Benchmarking the Nim implementation, which is the only one whose KEM is compiled assembly-optimised C rather than interpreted or WASM, gives a different picture:
Same wire protocol, same 2,288 bytes of overhead, same lattice operations. The cost of quantum resistance in this design is not a property of the protocol — it is a property of whether the runtime ships an optimised ML-KEM-768. With a good one the KEM is under a tenth of handshake time and the hybrid handshake costs 14% more than the classical one. The rest is classical crypto that a deployment was already paying for. Two caveats I would rather state than have someone find. nim-libp2p optimises only the KEM — its X25519 and ChaCha20-Poly1305 come from BearSSL, SHA-256 from a pure-Nim library, Ed25519 from a pure-Nim reference port — so its 2.8 ms classical baseline is not a floor, and 1.14x is the ratio that particular composition pays rather than a general figure. And all interop runs so far were on one machine over loopback, so they establish wire-format agreement, not behaviour under loss or reordering on a real path. What I am asking forI am not asking for a merge. Per the spec lifecycle this needs interest group formation and broader review to move past Stage 1, and I do not think that is something I can do from the PR alone. What would help most:
Happy to split, restructure, or rewrite whatever is useful. All four implementation PRs are gated on this document, so any direction at all is more useful to me than the PR continuing to sit. |
|
Correcting the performance table in my previous comment. The direction of the correction matters for this draft, because the earlier figures overstated the cost of the protocol this document specifies. Corrected measurementsAll four implementations, measured the same week, each holding its own cryptographic backend constant:
Previously I reported 12.9x, 5.0x and 1.14x, with Rust unmeasured. Three faults produced the difference, and every one of them inflated the apparent cost:
Why this bears on the draftThe practical objection to a hybrid handshake is usually cost, and the honest answer is now considerably better than the one I gave in June. Three of four independent implementations put the overhead between 1.1x and 1.5x. The outlier is Python at 10.5x, and that is entirely attributable to Rust is a new data point since my last comment. Its benchmark existed in the repository and had simply never been run. It matters because Rust and Nim use entirely different KEM libraries and land at 1.30x and 1.13x, which is what allows the result to be attributed to the protocol design rather than to any single vendor's optimisation work. The wire overhead of 2,288 bytes, which is the figure this draft specifies, is unchanged and is now derived independently by three implementations. Where the draft standsStill open since 25 June with no review. Four implementations are complete, tested, and interoperable in all six pairwise combinations, and none of them can merge until the protocol exists as a specification. The three questions from my earlier comment stand, and I would still value an answer to any of them:
I am happy to restructure, split, or rewrite whatever would help. Silence is the only outcome I cannot work with. |
Summary
This PR adds a new protocol spec for
Noise_XXhfs_25519+ML-KEM-768_ChaChaPoly_SHA256, a post-quantum hybrid extension of the classical Noise XX handshake used in libp2p.Update (2026-06-24): The spec has been revised from an earlier X-Wing draft to use raw ML-KEM-768 (FIPS 203). The Noise XXhfs pattern already provides classical security through three independent DH operations (
ee,es,se), so using X-Wing (which bundles an extra X25519 inside the KEM) would be redundant — adding 64 bytes of wire overhead with no security benefit. Raw ML-KEM-768 gives the same hybrid security guarantee with a smaller footprint, and aligns with the Rust reference implementation royzah/rust-libp2p PR #1 (Rust).The spec is filed at Stage 1 (Working Draft) per the libp2p spec lifecycle.
e1andekem1HFS token extensions from the Noise HFS draft, applied to the existing Noise XX patternekem1slotMotivation
NIST finalized ML-KEM (FIPS 203) in August 2024. Harvest-now-decrypt-later attacks make forward secrecy the most urgent deployment target. The XXhfs pattern adds quantum-safe forward secrecy with no changes to the classical authentication layer, giving operators a safe incremental migration path.
Reference Implementations
Three independent implementations exist and have been validated against each other:
ml-kemcrate (RustCrypto)Triangle interoperability (2026-06-24)
All three implementations were tested pairwise over real TCP connections:
Test plan
encryptAndHashbeforemixKeyinekem1)