Skip to content

feat(noise): hybrid post-quantum handshake (X25519 + ML-KEM-768)#6481

Draft
royzah wants to merge 2 commits into
libp2p:masterfrom
royzah:feat/noise-mlkem-hfs
Draft

feat(noise): hybrid post-quantum handshake (X25519 + ML-KEM-768)#6481
royzah wants to merge 2 commits into
libp2p:masterfrom
royzah:feat/noise-mlkem-hfs

Conversation

@royzah

@royzah royzah commented Jun 14, 2026

Copy link
Copy Markdown

Revives #2168.

Summary

Additive, off-by-default mlkem-hfs feature: a hybrid post-quantum Noise handshake (Noise_XXhfs_25519+ML-KEM-768_ChaChaPoly_SHA256) negotiated alongside /noise, falling back to classical X25519 for peers without it.

Why

/noise is classical X25519, so recorded sessions are exposed to harvest-now-decrypt-later. This mixes an ML-KEM-768 ephemeral KEM into the handshake (secure if either primitive holds). Static-key auth stays classical, which cannot be broken retroactively.

Changes

  • mlkem-hfs feature (off by default) -> snow/use-ml-kem
  • new protocol id /noise-mlkem768-hfs/0.1.0, advertised ahead of /noise; pattern selected from the negotiated id
  • KEM sourced from snow's pure-Rust DefaultResolver (ring has no KEM)
  • widened handshake scratch buffer for KEM material (feature-gated)
  • ports the crate to snow 0.10
  • tests: two-peer hybrid handshake + classical fallback

Open questions

  • Protocol id /noise-mlkem768-hfs/0.1.0 is provisional; it needs a cross-implementation spec (go/js-libp2p) before stabilizing. Happy to take it to libp2p/specs.
  • Depends on ML-KEM-768 landing in snow; until released, [patch] points snow at a fork branch.
  • ml-kem is unaudited (passes NIST vectors).

Adds an additive, off-by-default 'mlkem-hfs' feature advertising
Noise_XXhfs_25519+ML-KEM-768_ChaChaPoly_SHA256 under a new protocol id,
falling back to classical /noise for older peers. Ports the crate to
snow 0.10 (patched to our fork carrying the ML-KEM KEM) and widens the
handshake scratch buffer for the KEM material.
@royzah royzah force-pushed the feat/noise-mlkem-hfs branch from 5cd4da1 to a8c5bcf Compare June 14, 2026 15:07
@royzah

royzah commented Jun 14, 2026

Copy link
Copy Markdown
Author

Note on the snow [patch] (intentional, temporary):

  • snow 0.10.0 is published, so the default/classical path builds against released snow with no fork. The [patch] only matters when building the off-by-default mlkem-hfs feature, which needs snow's use-ml-kem (Add ML-KEM-768 (FIPS 203) to the HFS extension mcginty/snow#210).
  • Once that lands in a snow release, the [patch] is removed entirely and the feature resolves from crates.io. Keeping this a draft until then.

@getong

getong commented Jun 21, 2026

Copy link
Copy Markdown

how about changing to use clatter, no_std compatible implementation of Noise protocol framework with Post-Quantum extensions.

@royzah

royzah commented Jun 21, 2026

Copy link
Copy Markdown
Author

Thanks @getong for clatter shout-outs! It is great crate though.

However, in libp2p the Noise static key doesn't prove who you are, the identity key signs it for that. So the handshake only needs PQ for secrecy (harvest-now-decrypt-later), which is what hfs already does. clatter's extra is PQ auth on the static key, which seems redundant here (that's an identity-key job, Ed25519 -> ML-DSA).

Do you see where the static key itself needs to be PQ?

Also interop: the protocol name feeds the handshake hash, so clatter's Noise_hybridXX... and the hfs Noise_XXhfs_25519+ML-KEM-768 wouldn't talk. Feels more like a specs#723 call than a crate one.

WDYT ?

@getong

getong commented Jun 21, 2026

Copy link
Copy Markdown

You are right , go ahead.

@royzah

royzah commented Jun 21, 2026

Copy link
Copy Markdown
Author

Cheers @getong 🙏 Keeping clatter in mind for a future no_std path.

@jxs

jxs commented Jun 22, 2026

Copy link
Copy Markdown
Member

H @royzah, thanks for this! Happy to have this in rust-libp2p but I think we should start by raising the issue in the specs repo, thanks for opening libp2p/specs#723, we should wait there for development before acting on this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants