Update design docs for session 142 implementation changes

Comprehensive documentation review across 12 files to reflect:
- Noise XK at FSP (was IK), 3-message handshake, SessionMsg3 wire format
- Epoch exchange in Noise handshakes for peer restart detection
- Per-link MTU, min_mtu/path_mtu in lookup packets
- MtuExceeded (0x22) error signal wire format and behavior
- LookupResponse proof now covers target_coords
- Discovery reverse-path routing as primary (not greedy)
- Control socket architecture and fipsctl binary
- FSP handshake state machine (Initiating/AwaitingMsg3/Established)
- Root timeout framing updated for heartbeat cascading
This commit is contained in:
Johnathan Corgan
2026-02-22 23:03:00 +00:00
parent 2293f7d2d5
commit dc89edf60b
12 changed files with 440 additions and 148 deletions
+59 -31
View File
@@ -89,10 +89,15 @@ FMP signals routing failures asynchronously:
- **PathBroken**: Greedy routing reached a dead end. FSP responds by sending
a standalone CoordsWarmup (rate-limited), re-discovering the destination's
current coordinates, and resetting the warmup counter.
- **MtuExceeded**: A transit node cannot forward a SessionDatagram because
the packet exceeds the next-hop link MTU. FSP uses the reported bottleneck
MTU to adjust its session-layer path MTU estimate. MtuExceeded is the
reactive complement to the proactive `path_mtu` field in SessionDatagram.
Both signals are generated by transit nodes (not the destination) and travel
back to the source inside a new SessionDatagram. They are plaintext (not
end-to-end encrypted) because transit nodes have no session with the source.
All three signals are generated by transit nodes (not the destination) and
travel back to the source inside a new SessionDatagram. They are plaintext
(not end-to-end encrypted) because transit nodes have no session with the
source.
### Local Delivery
@@ -106,18 +111,29 @@ node, FMP delivers it to FSP for session-layer processing.
Sessions are established on demand when the first datagram needs to be sent to
a destination with no existing session.
FSP uses Noise IK for session key agreement. The initiator knows the
destination's npub (from DNS lookup or native API); the responder learns the
initiator's identity from the handshake. This is the same asymmetry as
link-layer peer connections.
FSP uses Noise XK for session key agreement. The initiator knows the
destination's npub (required for XK's pre-message `s` token); the
responder learns the initiator's identity from msg3 (not msg1, unlike
IK at the link layer). This provides stronger initiator identity hiding
— the initiator's static key is encrypted under the established shared
secret rather than under only the responder's static key.
The handshake is carried in SessionSetup and SessionAck messages:
The handshake is a three-message flow carried in SessionSetup, SessionAck,
and SessionMsg3:
1. **Initiator** sends SessionSetup containing Noise IK msg1 and both
parties' tree coordinates
2. **Responder** processes msg1, learns initiator identity, sends SessionAck
containing Noise IK msg2 and both parties' tree coordinates
3. Both parties derive identical symmetric session keys
1. **Initiator** sends SessionSetup containing Noise XK msg1 (ephemeral key
only) and both parties' tree coordinates
2. **Responder** processes msg1, sends SessionAck containing Noise XK msg2
(ephemeral key + encrypted epoch) and both parties' tree coordinates.
The responder transitions to AwaitingMsg3 state.
3. **Initiator** processes msg2, sends SessionMsg3 containing the encrypted
static key and encrypted epoch. Both parties derive identical symmetric
session keys and the session is established.
Each side's epoch (an 8-byte random value generated at startup) is
exchanged encrypted in msg2 and msg3. On subsequent handshakes, an epoch
mismatch indicates the peer has restarted, triggering session
re-establishment.
Packets that trigger session establishment are queued (with bounded buffer)
and transmitted after the session is established.
@@ -187,22 +203,30 @@ transport addresses or routing paths. A session survives:
## End-to-End Encryption
### Noise IK Pattern
### Noise XK Pattern
FSP uses the same Noise IK pattern as FMP link encryption, but with
independent keys and sessions. The full Noise descriptor is
`Noise_IK_secp256k1_ChaChaPoly_SHA256`.
FSP uses Noise XK for session encryption, distinct from the Noise IK
pattern used at the link layer. The full Noise descriptor is
`Noise_XK_secp256k1_ChaChaPoly_SHA256`.
The IK pattern:
The XK pattern (pre-message: `← s`):
- **msg1** (`→ e, es, s, ss`): Initiator sends ephemeral key, encrypts static
key to responder. Four DH operations establish session keys.
- **msg2** (`← e, ee, se`): Responder sends ephemeral key. Both parties now
share identical session keys.
- **msg1** (`→ e, es`): Initiator sends ephemeral key only. The initiator's
static identity is not revealed in this message.
- **msg2** (`← e, ee`): Responder sends ephemeral key and encrypted epoch.
- **msg3** (`→ s, se`): Initiator sends encrypted static key and encrypted
epoch. Both parties now share identical session keys.
After the handshake, Noise produces two directional symmetric keys
(`send_key`, `recv_key`) used with ChaCha20-Poly1305 for all subsequent data.
The XK pattern requires the initiator to know the responder's static key
in advance (the `← s` pre-message), which is satisfied by the discovery
or DNS lookup that precedes session establishment. In exchange, XK
provides stronger initiator identity protection than IK — the initiator's
static key is encrypted under the full shared secret (after three DH
operations) rather than under only the responder's static key.
### Cryptographic Primitives
| Component | Choice | Notes |
@@ -218,7 +242,7 @@ These choices prioritize compatibility with the Nostr cryptographic stack.
### secp256k1 Parity Normalization
Nostr npubs encode x-only public keys (32 bytes, no y-coordinate parity). The
Noise IK pre-message mixes the responder's static key as a 33-byte compressed
Noise XK pre-message mixes the responder's static key as a 33-byte compressed
key, and the default secp256k1 ECDH hash includes a parity-dependent version
byte.
@@ -229,12 +253,14 @@ actual key parity.
### Privacy Note
Noise IK does not provide initiator anonymity if the responder's static key is
compromised. An attacker who obtains the responder's nsec can decrypt the
initiator's identity from captured handshake messages. Noise XK would protect
initiator identity in this scenario but requires an additional round-trip (3
handshake messages vs. 2). The privacy/latency tradeoff may be revisited with
deployment experience.
Noise XK provides stronger initiator identity protection than IK. In XK, the
initiator's static key is encrypted in msg3 under the full shared secret
(derived from three DH operations), so an attacker who compromises only the
responder's nsec cannot decrypt the initiator's identity from captured
handshake messages (they would also need the responder's ephemeral key).
This is the primary reason FSP uses XK rather than IK — session-layer
traffic traverses untrusted intermediate nodes, making initiator identity
protection more valuable than at the link layer.
### Data Packet Authentication
@@ -460,7 +486,7 @@ feedback:
1. The source sets `path_mtu` in each SessionDatagram envelope to its
outbound link MTU.
2. Each transit node applies `min(current, transport.mtu())` before
2. Each transit node applies `min(current, transport.link_mtu(addr))` before
forwarding.
3. The destination receives the forward-path minimum and sends a
PathMtuNotification (2-byte body: u16 LE path_mtu) back to the source.
@@ -492,7 +518,9 @@ MMP session metrics session=npub1tdwa...84le rtt=4.3ms loss=0.6% jitter=0.2ms go
| Feature | Status |
| ------- | ------ |
| Session establishment (Noise IK) | **Implemented** |
| Session establishment (Noise XK) | **Implemented** |
| Peer restart detection (epoch exchange) | **Implemented** |
| MtuExceeded handling | **Implemented** |
| End-to-end encryption (ChaCha20-Poly1305) | **Implemented** |
| Explicit counter replay protection | **Implemented** |
| Hybrid coordinate warmup (CP + CoordsWarmup) | **Implemented** |