noise: hybrid post-quantum handshake (X25519 + ML-KEM-768) - #727
Conversation
| Mixed into the handshake hash, so it must match byte-for-byte: | ||
|
|
||
| ```text | ||
| Noise_XXhfs_25519+ML-KEM-768_ChaChaPoly_SHA256 |
There was a problem hiding this comment.
The - must be dropped according to https://noiseprotocol.org/noise.html#cryptographic-algorithm-name-sections
There was a problem hiding this comment.
Right, 8.2 allows alphanumerics and / only. Suite is now Noise_XXhfs_25519+MLKEM768_ChaChaPoly_SHA256, and both implementations follow:
- mcginty/snow#210: 858dc27 renames the parsed name and
Kem::name(). - libp2p/rust-libp2p#6481: 1ae21ce renames
PARAMS_XX_HFS.
Handshake tests pass on both. Thanks for catching it.
| ``` | ||
|
|
||
| Advertised ahead of `/noise`. Two capable peers pick it; otherwise negotiation | ||
| falls back to `/noise` with no extra round trip. |
There was a problem hiding this comment.
It seems to me that there's still a roundtrip if the receiver does not support mlkem768:
- Emitter sends
/noise-mlkem768-hfs/0.1.0 - Receiver replies
na - Emitter sends
/noise - Receiver replies back with
/noise - Handshake starts
There was a problem hiding this comment.
Idea for lines 27-28:
An initiator supporting both protocols SHOULD propose `/noise-mlkem768-hfs/0.1.0` before /noise. A responder supporting this protocol MUST accept that protocol ID. If the responder returns `na`, the initiator MAY subsequently propose /noise.
There was a problem hiding this comment.
Correct, the na costs a round trip. Took your wording verbatim, so the claim is gone.
| ## To pin for interop | ||
|
|
There was a problem hiding this comment.
I'd rename this to Open issues or similar.
| -> s, se | ||
| ``` | ||
|
|
||
| - `e1`: initiator sends the ML-KEM-768 encap key (1184 B). |
There was a problem hiding this comment.
| - `e1`: initiator sends the ML-KEM-768 encap key (1184 B). | |
| - `e1`: initiator sends the ML-KEM-768 encapsulation key (1184 B). |
| ## Why | ||
|
|
||
| [`/noise`][noise] is X25519 only, so recorded sessions are open to | ||
| harvest-now-decrypt-later. This adds a separate handshake that mixes an |
There was a problem hiding this comment.
| harvest-now-decrypt-later. This adds a separate handshake that mixes an | |
| harvest-now-decrypt-later. This specification adds a separate handshake that mixes an |
| ML-KEM-768 KEM into the same `XX` pattern via Noise [HFS][hfs]. It stays secure | ||
| if either primitive holds. | ||
|
|
||
| Auth is unchanged and stays classical: in libp2p the identity key signs the |
There was a problem hiding this comment.
| Auth is unchanged and stays classical: in libp2p the identity key signs the | |
| Authentication is unchanged and stays classical: in libp2p the identity key signs the |
|
|
||
| ## Handshake | ||
|
|
||
| `XX` with the `hfs` modifier. Token placement and KDF order are exactly Noise |
There was a problem hiding this comment.
| `XX` with the `hfs` modifier. Token placement and KDF order are exactly Noise | |
| `XX` with the `hfs` modifier. Token placement and KDF order are exactly as specified by Noise |
| - rust-libp2p: [#6481][pr], off-by-default `mlkem-hfs` feature; classical path | ||
| untouched. Revives [#2168][old]. | ||
| - KEM: ML-KEM-768 in `snow` ([mcginty/snow#210][snow]). Until it ships in a | ||
| release, the impl pins `snow` via `[patch]`; KATs land with it. |
There was a problem hiding this comment.
| release, the impl pins `snow` via `[patch]`; KATs land with it. | |
| release, the implementation pins `snow` via `[patch]`; KATs land with it. |
| ```mermaid | ||
| sequenceDiagram | ||
| participant I as Initiator | ||
| participant R as Responder | ||
| I->>R: e, e1 | ||
| R->>I: e, ee, ekem1, s, es (+ identity) | ||
| I->>R: s, se (+ identity) | ||
| ``` |
There was a problem hiding this comment.
Is this diagram needed or would the pattern described in line 43 be enough?
There was a problem hiding this comment.
Agreed, the pattern block says it. Diagram removed.
Concrete draft for #723, so we have something byte-level to react to instead of an open question.
Additive, separately negotiated handshake that mixes ML-KEM-768 into the
XXpattern via Noise HFS. Advertised ahead of/noise, falls back with no flag day. Auth stays classical (identity key signs the static key), only secrecy is hybridized.Pins the protocol id and suite, defers token/KDF order to Noise HFS. Still open (called out in the doc):
Reference impl: libp2p/rust-libp2p#6481 (off-by-default
mlkem-hfs). Would love go/js eyes early. cc @jxs @thomaseizinger @mxinden @MarcoPolo @achingbrain