From a8115f7622b56c4b8511be7507fc10dc0c64baa9 Mon Sep 17 00:00:00 2001 From: Johnathan Corgan Date: Mon, 2 Feb 2026 02:25:39 +0000 Subject: [PATCH] Unify Noise IK for both link and session layers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Design change: Session layer now uses Noise IK pattern (previously KK), matching the link layer. Rationale: initiator knows destination npub, responder learns initiator identity from handshake - same asymmetry as link connections. Document consistency fixes: - Auth* events → Noise IK msg1/msg2 terminology in state machines - PeerId → NodeId in routing code examples - BloomUpdate → FilterAnnounce terminology - Updated cross-references and tables --- docs/design/README.md | 2 +- docs/design/fips-architecture.md | 53 ++++++++++++++------------- docs/design/fips-intro.md | 13 ++++--- docs/design/fips-routing.md | 12 +++--- docs/design/fips-session-protocol.md | 32 ++++++++-------- docs/design/spanning-tree-dynamics.md | 2 +- 6 files changed, 58 insertions(+), 56 deletions(-) diff --git a/docs/design/README.md b/docs/design/README.md index 23d088f..e5df8c4 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -17,7 +17,7 @@ concepts, and finally the wire-level protocol details. | Document | Description | |------------------------------------------------------|-----------------------------------------------------------| -| [fips-session-protocol.md](fips-session-protocol.md) | End-to-end session flow, Noise KK encryption, terminology | +| [fips-session-protocol.md](fips-session-protocol.md) | End-to-end session flow, Noise IK encryption, terminology | ### 3. Routing (How Packets Find Their Way) diff --git a/docs/design/fips-architecture.md b/docs/design/fips-architecture.md index 47fa787..25016e5 100644 --- a/docs/design/fips-architecture.md +++ b/docs/design/fips-architecture.md @@ -307,28 +307,32 @@ Inbound: ### Peer Lifecycle +The peer lifecycle uses Noise IK for authentication. Noise IK is a 2-message +handshake where the initiator knows the responder's static key. See +[fips-wire-protocol.md](fips-wire-protocol.md) §2 for wire format details. + ``` ┌─────────────────────────────────────────┐ │ Disconnected │ └─────────────────────────────────────────┘ │ │ - [outbound] │ │ [inbound data] + [outbound] │ │ [inbound msg1] ▼ ▼ ┌──────────────────┐ ┌──────────────────┐ - │ Connecting │ │AwaitingAuthInit │ - │(conn-oriented) │ │ │ + │ Connecting │ │ ReceivedMsg1 │ + │(conn-oriented) │ │ (send msg2) │ └──────────────────┘ └──────────────────┘ │ │ - [link ready] │ [recv AuthInit] - ▼ ▼ - ┌──────────────────┐ ┌──────────────────┐ - │AwaitingChallenge │ │AwaitingComplete │ - │ (sent AuthInit) │ │(sent AuthChallenge)│ - └──────────────────┘ └──────────────────┘ + [link ready] │ │ [recv encrypted] + [send msg1] │ │ [verify] + ▼ │ + ┌──────────────────┐ │ + │ AwaitingMsg2 │ │ + │ (sent msg1) │ │ + └──────────────────┘ │ │ │ - [recv AuthChallenge] │ │ [recv AuthComplete] - [verify, send │ │ [verify] - AuthComplete] │ │ + [recv msg2] │ │ + [verify] │ │ ▼ ▼ ┌─────────────────────────────────────────┐ │ Active │ @@ -347,18 +351,18 @@ Inbound: - `Disconnected`: No active connection; for static peers, retry with backoff - `Connecting`: Link establishment in progress (connection-oriented transports only) -- `AwaitingAuthInit`: Inbound connection, waiting for peer's AuthInit -- `AwaitingChallenge`: Sent AuthInit, waiting for AuthChallenge -- `AwaitingComplete`: Sent AuthChallenge, waiting for AuthComplete +- `ReceivedMsg1`: Inbound; received Noise IK msg1, sent msg2, awaiting first encrypted frame +- `AwaitingMsg2`: Outbound; sent Noise IK msg1, waiting for msg2 - `Active`: Authenticated; participating in tree gossip and filter exchange **Crossing connection handling:** -When in `AwaitingChallenge` and we receive an AuthInit from the same peer: +When in `AwaitingMsg2` and we receive a msg1 from the same peer (both sides +initiated simultaneously): -- If local npub < remote npub: Ignore incoming AuthInit, remain initiator -- If local npub > remote npub: Switch to responder role, send AuthChallenge, - transition to `AwaitingComplete` +- If local npub < remote npub: Ignore incoming msg1, remain initiator +- If local npub > remote npub: Switch to responder role, send msg2, + transition to `ReceivedMsg1` **Events:** @@ -367,11 +371,10 @@ PeerEvent ├── Discovered { link_id, transport_addr, hint: Option } ├── LinkConnected ├── LinkFailed { reason } -├── AuthInitReceived { npub, nonce } -├── AuthChallengeReceived { npub, nonce, signature } -├── AuthCompleteReceived { signature } -├── AuthSuccess { npub, node_id } -├── AuthFailed { reason } +├── Msg1Received { noise_payload } +├── Msg2Received { noise_payload } +├── HandshakeComplete { npub, node_id } +├── HandshakeFailed { reason } ├── TreeAnnounceReceived { declaration, ancestry } ├── FilterAnnounceReceived { filter, sequence, ttl } ├── Timeout { kind: TimeoutKind } @@ -945,7 +948,7 @@ configure the same underlying cache but are grouped by purpose. ### Crypto Session Management > **Note**: Crypto sessions provide end-to-end authenticated encryption using -> Noise KK. See [fips-session-protocol.md](fips-session-protocol.md) §6 for details. +> Noise IK. See [fips-session-protocol.md](fips-session-protocol.md) §6 for details. | Parameter | Type | Default | Description | |-----------|------|---------|-------------| diff --git a/docs/design/fips-intro.md b/docs/design/fips-intro.md index 1af9b61..b7ee6e7 100644 --- a/docs/design/fips-intro.md +++ b/docs/design/fips-intro.md @@ -103,7 +103,7 @@ adapts these for multi-transport operation and Nostr identity integration. **Encryption**: Link and session encryption use the [Noise Protocol Framework](https://noiseprotocol.org/), the same foundation used by WireGuard, Lightning Network, and other production systems. FIPS uses the IK pattern for -link authentication and KK pattern for end-to-end sessions. +link authentication and end-to-end sessions. **Cryptographic primitives**: FIPS reuses Nostr's cryptographic stack—secp256k1 for keys, Schnorr signatures, SHA-256 for hashing, and ChaCha20-Poly1305 for @@ -172,7 +172,7 @@ FIPS uses independent encryption at two layers: | Layer | Scope | Pattern | Purpose | |-------------|-------------|----------|--------------------------------------| | **Link** | Hop-by-hop | Noise IK | Encrypt all traffic on each link | -| **Session** | End-to-end | Noise KK | Encrypt payload across multiple hops | +| **Session** | End-to-end | Noise IK | Encrypt payload across multiple hops | ### Link Layer (Peer-to-Peer) @@ -188,8 +188,9 @@ the first handshake message. ### Session Layer (End-to-End) For traffic between non-adjacent nodes, FIPS establishes end-to-end encrypted -sessions using Noise KK. Both parties know each other's npub before initiating, -enabling mutual authentication in a single round-trip. +sessions using Noise IK. The initiator knows the destination's npub; the +responder learns the initiator's identity from the handshake—the same asymmetry +as link-layer connections. A packet from A to D through intermediate node B: @@ -460,7 +461,7 @@ FIPS assumes adversaries with varying capabilities: authentication and forward secrecy. An observer on the underlying transport sees only encrypted packets. -**End-to-end encryption**: Session-layer Noise KK encrypts payloads between +**End-to-end encryption**: Session-layer Noise IK encrypts payloads between endpoints. Intermediate routers cannot read application data. **Signature verification**: All protocol messages (TreeAnnounce, LookupResponse) @@ -529,7 +530,7 @@ maintaining control over their own identities and peering relationships. | Document | Description | |----------|-------------| -| [fips-session-protocol.md](fips-session-protocol.md) | End-to-end session flow, Noise KK encryption | +| [fips-session-protocol.md](fips-session-protocol.md) | End-to-end session flow, Noise IK encryption | | [fips-wire-protocol.md](fips-wire-protocol.md) | Link-layer transport, Noise IK handshake | | [fips-gossip-protocol.md](fips-gossip-protocol.md) | TreeAnnounce, FilterAnnounce, Lookup formats | | [fips-routing.md](fips-routing.md) | Bloom filters, discovery, greedy routing | diff --git a/docs/design/fips-routing.md b/docs/design/fips-routing.md index cf65728..2f99f3e 100644 --- a/docs/design/fips-routing.md +++ b/docs/design/fips-routing.md @@ -92,7 +92,7 @@ node's npub, truncated or used directly as the filter key. Each node maintains a Bloom filter for each peer direction: ```rust -peer_filters: HashMap +peer_filters: HashMap ``` The filter for peer P answers: "Which destinations are reachable through P?" @@ -248,7 +248,7 @@ Note: Coordinates are ordered self-to-root, so common ancestry is a suffix. ### Greedy Routing Algorithm ```rust -fn greedy_next_hop(&self, dest_coords: &[NodeId]) -> PeerId { +fn greedy_next_hop(&self, dest_coords: &[NodeId]) -> NodeId { // Check if we are the destination if dest_coords[0] == self.node_id { return LOCAL_DELIVERY; @@ -257,7 +257,7 @@ fn greedy_next_hop(&self, dest_coords: &[NodeId]) -> PeerId { // Check if destination is a direct peer for peer in &self.peers { if peer.node_id == dest_coords[0] { - return peer.id; + return peer.node_id; } } @@ -265,7 +265,7 @@ fn greedy_next_hop(&self, dest_coords: &[NodeId]) -> PeerId { self.peers .iter() .min_by_key(|p| tree_distance(&p.coords, dest_coords)) - .map(|p| p.id) + .map(|p| p.node_id) .expect("no peers") } ``` @@ -331,7 +331,7 @@ struct SessionSetup { // Crypto session establishment (see fips-session-protocol.md §6) // Opaque to routers; only processed by destination - handshake_payload: Option>, // Noise KK message 1 + handshake_payload: Option>, // Noise IK message 1 } struct SessionFlags { @@ -346,7 +346,7 @@ struct SessionAck { src_coords: Vec, // Acknowledger's coords (for return caching) // Crypto session response (see fips-session-protocol.md §6) - handshake_payload: Option>, // Noise KK message 2 + handshake_payload: Option>, // Noise IK message 2 } /// Minimal data packet diff --git a/docs/design/fips-session-protocol.md b/docs/design/fips-session-protocol.md index 19d796e..d7c681e 100644 --- a/docs/design/fips-session-protocol.md +++ b/docs/design/fips-session-protocol.md @@ -169,7 +169,7 @@ Payloads within a session are: 1. **Encrypted** with the session key (provides confidentiality) 2. **Authenticated** via AEAD tag (session keys bound to npub identities) -Authentication derives from the Noise KK handshake binding session keys to +Authentication derives from the Noise IK handshake binding session keys to both parties' static keys. See §6 for cryptographic details. ### 3.2 Session Establishment Trigger @@ -203,10 +203,9 @@ paths. ### 3.4 Session Establishment Flow -FIPS uses Noise KK for session establishment. Both parties know each other's -static keys: the initiator from DNS lookup, the responder from the source -address in the SessionSetup. The KK pattern provides mutual authentication -from the first message. +FIPS uses Noise IK for session establishment. The initiator knows the +destination's npub; the responder learns the initiator's identity from the +handshake. This is the same asymmetry as link-layer connections. The handshake is carried inside SessionSetup/SessionAck messages (see §5.5), which also establish routing session state at intermediate nodes. @@ -268,7 +267,7 @@ FIPS uses two distinct session concepts at different layers: ### 5.1 Crypto Session - Established between two npub identities -- Provides confidentiality and authenticity via Noise KK +- Provides confidentiality and authenticity via Noise IK - Survives route changes and transport failover - Keyed by: `(local_npub, remote_npub)` @@ -291,14 +290,14 @@ crypto handshake, minimizing round-trips. 2. SessionSetup + Crypto Init └─► Source sends SessionSetup containing: - src/dest coordinates (for router caching) - - Noise KK handshake initiation (for destination) + - Noise IK handshake initiation (for destination) └─► Routers cache coordinates as packet transits └─► Destination receives crypto init, begins handshake 3. SessionAck + Crypto Response └─► Destination sends SessionAck containing: - Its coordinates (for reverse path caching) - - Noise KK handshake response + - Noise IK handshake response └─► Routers cache reverse path └─► Source completes crypto handshake @@ -321,7 +320,7 @@ FIPS uses two independent Noise Protocol handshakes at different layers: | Layer | Scope | Pattern | Purpose | |---------|-------------|----------|-------------------------------------------| | Link | Hop-by-hop | Noise IK | Authenticate peers, encrypt link | -| Session | End-to-end | Noise KK | Authenticate endpoints, encrypt payload | +| Session | End-to-end | Noise IK | Authenticate endpoints, encrypt payload | Both use `Noise_IK_secp256k1_ChaChaPoly_SHA256` with the same cryptographic primitives, but with separate keys and sessions. @@ -336,21 +335,21 @@ nodes forward opaque ciphertext without being able to read the contents. ### 6.2 Session Noise Handshake -The session-layer Noise KK handshake is carried inside `SessionSetup`/`SessionAck` +The session-layer Noise IK handshake is carried inside `SessionSetup`/`SessionAck` messages, which themselves travel through the link-encrypted channel: ```text Initiator knows destination npub (from DNS lookup) │ ▼ -SessionSetup { coords, handshake_payload: Noise KK msg1 } +SessionSetup { coords, handshake_payload: Noise IK msg1 } │ ▼ (travels through link-encrypted hops) │ Responder processes msg1, learns initiator identity │ ▼ -SessionAck { coords, handshake_payload: Noise KK msg2 } +SessionAck { coords, handshake_payload: Noise IK msg2 } │ ▼ Session keys established (independent of link keys) @@ -386,7 +385,7 @@ SessionSetup { dest_addr: Ipv6Addr, // Crypto portion (opaque to routers, processed by destination) - handshake_payload: Vec, // Noise KK message 1 + handshake_payload: Vec, // Noise IK message 1 } SessionAck { @@ -394,7 +393,7 @@ SessionAck { src_coords: Vec, // Responder's coordinates // Crypto portion - handshake_payload: Vec, // Noise KK message 2 + handshake_payload: Vec, // Noise IK message 2 } ``` @@ -427,13 +426,12 @@ The ephemeral keys (`e` in Noise notation) provide forward secrecy: Lightning's adaptation of Noise for secp256k1 (BOLT 8) provides a proven reference implementation: -- Uses Noise XK pattern (different from our KK) +- Uses Noise XK pattern (different from our IK) - Same secp256k1 + ChaCha20-Poly1305 + SHA-256 stack - Handles the secp256k1 ECDH correctly - Open source implementations available in multiple languages -FIPS can reference BOLT 8's cryptographic details while using the KK pattern -appropriate for our mutual-knowledge scenario. +FIPS can reference BOLT 8's cryptographic details while using the IK pattern. ### 6.9 Data Packet Authentication diff --git a/docs/design/spanning-tree-dynamics.md b/docs/design/spanning-tree-dynamics.md index f45df36..17d364a 100644 --- a/docs/design/spanning-tree-dynamics.md +++ b/docs/design/spanning-tree-dynamics.md @@ -196,7 +196,7 @@ D receives and merges: ``` D adds B's node_id to its bloom filter -D sends BloomUpdate to parent A +D sends FilterAnnounce to parent A A merges D's bloom filter with its view of D's subtree A now knows "B is reachable through D" (probabilistically)