Design documentation illustration pass and FLP→FMP rename

Rename FIPS Link Protocol (FLP) to FIPS Mesh Protocol (FMP)

  The "Link Protocol" name understated the layer's scope — spanning tree
  construction, bloom filter routing, greedy forwarding, and mesh-wide
  coordination go well beyond link-level concerns. Rename fips-link-layer.md
  to fips-mesh-layer.md, update FLP→FMP throughout docs and source code
  (FLP_VERSION→FMP_VERSION, wire.rs, rx_loop.rs, spanning_tree.rs).

New SVG illustrations

  - Protocol stack: color-coded layer diagram replacing ASCII art
  - OSI mapping: side-by-side comparison with traditional networking layers
  - Bloom filter propagation: 6-node tree with sender-colored filter boxes
    showing split-horizon computation per link
  - Routing decision flowchart: 5-step priority chain with candidate ranking
    by tree distance and link performance
  - Coordinate discovery: sequence diagram showing LookupRequest propagation,
    response caching, and SessionSetup cache warming

Redesigned existing SVGs

  - Architecture overview: uniform node layout, U-shaped encrypted link
    connectors, separate end-to-end session line
  - Node architecture: split Router Core into FSP and FMP layers, reorganize
    transports into Overlay/Shared Medium/Point-to-Point categories
  - Identity derivation: wider boxes, visible encode arrow, dashed npub line

fips-intro.md revisions

  - Add inline references to prior work: Yggdrasil/Ironwood for coordinate
    routing, Noise Protocol Framework for IK handshakes, WireGuard for
    index-based session dispatch, Wikipedia for bloom filters, split-horizon,
    and greedy embedding
  - Add explanatory paragraphs after bloom filter diagram describing
    split-horizon filter computation and candidate selection behavior
  - Simplify transport abstraction language, remove I2P/LoRa references
  - Fix LookupRequest wording ("propagates" not "floods"), note intermediate
    node coordinate caching on lookup responses
  - Rewrite architecture overview prose to match redesigned diagrams
This commit is contained in:
Johnathan Corgan
2026-02-21 22:05:44 +00:00
parent 19efe06622
commit 0a72317b59
27 changed files with 997 additions and 502 deletions
+2 -2
View File
@@ -16,7 +16,7 @@ specific topics.
| -------- | ----------- |
| [fips-intro.md](fips-intro.md) | Protocol introduction: goals, architecture, layer model |
| [fips-transport-layer.md](fips-transport-layer.md) | Transport layer: datagram delivery over arbitrary media |
| [fips-link-layer.md](fips-link-layer.md) | FIPS Link Protocol (FLP): peer authentication, link encryption, forwarding |
| [fips-mesh-layer.md](fips-mesh-layer.md) | FIPS Mesh Protocol (FMP): peer authentication, link encryption, forwarding |
| [fips-session-layer.md](fips-session-layer.md) | FIPS Session Protocol (FSP): end-to-end encryption, sessions |
| [fips-ipv6-adapter.md](fips-ipv6-adapter.md) | IPv6 adaptation: TUN interface, DNS, MTU enforcement |
@@ -58,7 +58,7 @@ specific topics.
fips-transport-layer fips-mesh- fips-software-
│ operation architecture
▼ │ │
fips-link-layer ◄────────┤ ▼
fips-mesh-layer ◄────────┤ ▼
│ │ fips-state-machines
▼ │
fips-session-layer ├──► fips-spanning-tree
+92 -101
View File
@@ -1,122 +1,113 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 420" font-family="monospace" font-size="13">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 455" font-family="monospace" font-size="13">
<style>
rect.node { fill: #1a1a2e; stroke: #e0e0e0; stroke-width: 1.5; rx: 4; }
rect.app { fill: #2a2a4e; stroke: #e0e0e0; stroke-width: 1; rx: 2; }
rect.fips { fill: #2e3a5e; stroke: #e0e0e0; stroke-width: 1; rx: 2; }
rect.xport { fill: #3a2e2e; stroke: #e0e0e0; stroke-width: 1; rx: 2; }
rect.app { fill: #1a3a2a; stroke: #40a060; stroke-width: 1; rx: 2; }
rect.fips { fill: #2e3a5e; stroke: #5080c0; stroke-width: 1; rx: 2; }
rect.xport { fill: #2a1a1a; stroke: #c06040; stroke-width: 1; rx: 2; }
text { fill: #e0e0e0; }
text.label { font-size: 14px; font-weight: bold; }
text.npub { font-size: 11px; fill: #90a0b0; }
text.label { font-size: 15px; font-weight: bold; }
text.role { font-size: 11px; fill: #90a0b0; }
text.layer { font-size: 12px; }
text.transport-label { font-size: 11px; fill: #c0c0c0; }
line.link { stroke: #70a0d0; stroke-width: 2; }
line.session { stroke: #d0a040; stroke-width: 2; stroke-dasharray: 6,3; }
text.link-label { font-size: 11px; fill: #70a0d0; }
text.session-label { font-size: 12px; fill: #d0a040; }
text.caption { font-size: 13px; fill: #808090; font-style: italic; }
path.link { fill: none; stroke: #5080c0; stroke-width: 2; }
text.link-label { font-size: 12px; fill: #5080c0; font-weight: bold; }
text.link-enc { font-size: 10px; fill: #5080c0; }
line.session { stroke: #d0a040; stroke-width: 2; stroke-dasharray: 8,4; }
text.session-label { font-size: 13px; fill: #d0a040; }
text.legend { font-size: 12px; }
</style>
<!-- Background -->
<rect width="900" height="420" fill="#0d1117" rx="8"/>
<rect width="880" height="420" fill="#0d1117" rx="8"/>
<!-- Node positions: x = 60, 230, 400, 570, 740 width=100 -->
<!-- ============ NODES ============ -->
<!-- Node A (source) -->
<text x="100" y="30" text-anchor="middle" class="label">Node A</text>
<text x="100" y="46" text-anchor="middle" class="role">(source)</text>
<rect x="50" y="56" width="100" height="130" class="node"/>
<rect x="60" y="66" width="80" height="28" class="app"/>
<text x="100" y="85" text-anchor="middle" class="layer">App</text>
<rect x="60" y="102" width="80" height="28" class="fips"/>
<text x="100" y="121" text-anchor="middle" class="layer">FIPS</text>
<rect x="60" y="138" width="80" height="28" class="xport"/>
<text x="100" y="157" text-anchor="middle" class="layer">WiFi</text>
<!-- Node A -->
<text x="110" y="30" text-anchor="middle" class="label">Node A</text>
<text x="110" y="46" text-anchor="middle" class="npub">npub1aaa...</text>
<text x="110" y="60" text-anchor="middle" class="role">(source)</text>
<rect x="60" y="70" width="100" height="130" class="node"/>
<rect x="70" y="80" width="80" height="30" class="app"/>
<text x="110" y="100" text-anchor="middle" class="layer">App</text>
<rect x="70" y="118" width="80" height="30" class="fips"/>
<text x="110" y="138" text-anchor="middle" class="layer">FIPS</text>
<rect x="70" y="156" width="80" height="30" class="xport"/>
<text x="110" y="176" text-anchor="middle" class="layer">WiFi</text>
<!-- Node B -->
<!-- Node B (transit) -->
<text x="280" y="30" text-anchor="middle" class="label">Node B</text>
<text x="280" y="46" text-anchor="middle" class="npub">npub1bbb...</text>
<text x="280" y="60" text-anchor="middle" class="role">(relay)</text>
<rect x="230" y="70" width="100" height="130" class="node"/>
<rect x="240" y="118" width="80" height="30" class="fips"/>
<text x="280" y="138" text-anchor="middle" class="layer">FIPS</text>
<rect x="240" y="156" width="37" height="30" class="xport"/>
<text x="258" y="176" text-anchor="middle" class="layer">WiFi</text>
<rect x="283" y="156" width="37" height="30" class="xport"/>
<text x="302" y="176" text-anchor="middle" class="layer">Eth</text>
<text x="280" y="46" text-anchor="middle" class="role">(transit)</text>
<rect x="230" y="56" width="100" height="130" class="node"/>
<rect x="240" y="102" width="80" height="28" class="fips"/>
<text x="280" y="121" text-anchor="middle" class="layer">FIPS</text>
<rect x="240" y="138" width="36" height="28" class="xport"/>
<text x="258" y="157" text-anchor="middle" class="layer">WiFi</text>
<rect x="284" y="138" width="36" height="28" class="xport"/>
<text x="302" y="157" text-anchor="middle" class="layer">Eth</text>
<!-- Node C -->
<text x="450" y="30" text-anchor="middle" class="label">Node C</text>
<text x="450" y="46" text-anchor="middle" class="npub">npub1ccc...</text>
<text x="450" y="60" text-anchor="middle" class="role">(relay)</text>
<rect x="400" y="70" width="100" height="130" class="node"/>
<rect x="410" y="118" width="80" height="30" class="fips"/>
<text x="450" y="138" text-anchor="middle" class="layer">FIPS</text>
<rect x="410" y="156" width="37" height="30" class="xport"/>
<text x="428" y="176" text-anchor="middle" class="layer">Eth</text>
<rect x="453" y="156" width="37" height="30" class="xport"/>
<text x="472" y="176" text-anchor="middle" class="layer">UDP</text>
<!-- Node C (transit) -->
<text x="460" y="30" text-anchor="middle" class="label">Node C</text>
<text x="460" y="46" text-anchor="middle" class="role">(transit)</text>
<rect x="410" y="56" width="100" height="130" class="node"/>
<rect x="420" y="102" width="80" height="28" class="fips"/>
<text x="460" y="121" text-anchor="middle" class="layer">FIPS</text>
<rect x="420" y="138" width="36" height="28" class="xport"/>
<text x="438" y="157" text-anchor="middle" class="layer">Eth</text>
<rect x="464" y="138" width="36" height="28" class="xport"/>
<text x="482" y="157" text-anchor="middle" class="layer">UDP</text>
<!-- Node D -->
<text x="620" y="30" text-anchor="middle" class="label">Node D</text>
<text x="620" y="46" text-anchor="middle" class="npub">npub1ddd...</text>
<text x="620" y="60" text-anchor="middle" class="role">(relay)</text>
<rect x="570" y="70" width="100" height="130" class="node"/>
<rect x="580" y="118" width="80" height="30" class="fips"/>
<text x="620" y="138" text-anchor="middle" class="layer">FIPS</text>
<rect x="580" y="156" width="37" height="30" class="xport"/>
<text x="598" y="176" text-anchor="middle" class="layer">UDP</text>
<rect x="623" y="156" width="37" height="30" class="xport"/>
<text x="642" y="176" text-anchor="middle" class="layer">Tor</text>
<!-- Node D (transit) -->
<text x="640" y="30" text-anchor="middle" class="label">Node D</text>
<text x="640" y="46" text-anchor="middle" class="role">(transit)</text>
<rect x="590" y="56" width="100" height="130" class="node"/>
<rect x="600" y="102" width="80" height="28" class="fips"/>
<text x="640" y="121" text-anchor="middle" class="layer">FIPS</text>
<rect x="600" y="138" width="36" height="28" class="xport"/>
<text x="618" y="157" text-anchor="middle" class="layer">UDP</text>
<rect x="644" y="138" width="36" height="28" class="xport"/>
<text x="662" y="157" text-anchor="middle" class="layer">Tor</text>
<!-- Node E -->
<text x="790" y="30" text-anchor="middle" class="label">Node E</text>
<text x="790" y="46" text-anchor="middle" class="npub">npub1eee...</text>
<text x="790" y="60" text-anchor="middle" class="role">(dest)</text>
<rect x="740" y="70" width="100" height="130" class="node"/>
<rect x="750" y="80" width="80" height="30" class="app"/>
<text x="790" y="100" text-anchor="middle" class="layer">App</text>
<rect x="750" y="118" width="80" height="30" class="fips"/>
<text x="790" y="138" text-anchor="middle" class="layer">FIPS</text>
<rect x="750" y="156" width="80" height="30" class="xport"/>
<text x="790" y="176" text-anchor="middle" class="layer">Tor</text>
<!-- Node E (destination) -->
<text x="800" y="30" text-anchor="middle" class="label">Node E</text>
<text x="800" y="46" text-anchor="middle" class="role">(destination)</text>
<rect x="750" y="56" width="100" height="130" class="node"/>
<rect x="760" y="66" width="80" height="28" class="app"/>
<text x="800" y="85" text-anchor="middle" class="layer">App</text>
<rect x="760" y="102" width="80" height="28" class="fips"/>
<text x="800" y="121" text-anchor="middle" class="layer">FIPS</text>
<rect x="760" y="138" width="80" height="28" class="xport"/>
<text x="800" y="157" text-anchor="middle" class="layer">Tor</text>
<!-- Link lines (from bottom of transport boxes) -->
<!-- WiFi: A(110) -> B-WiFi(258) -->
<line x1="110" y1="200" x2="110" y2="240" class="link"/>
<line x1="110" y1="240" x2="258" y2="240" class="link"/>
<line x1="258" y1="240" x2="258" y2="200" class="link"/>
<text x="184" y="256" text-anchor="middle" class="link-label">WiFi</text>
<!-- ============ LINK CONNECTIONS (U-shaped, all same depth) ============ -->
<!-- WiFi: A ↔ B -->
<path d="M 100 186 L 100 240 L 258 240 L 258 186" class="link"/>
<text x="179" y="256" text-anchor="middle" class="link-label">WiFi</text>
<text x="179" y="268" text-anchor="middle" class="link-enc">encrypted FMP link</text>
<!-- Ethernet: B-Eth(302) -> C-Eth(428) -->
<line x1="302" y1="200" x2="302" y2="270" class="link"/>
<line x1="302" y1="270" x2="428" y2="270" class="link"/>
<line x1="428" y1="270" x2="428" y2="200" class="link"/>
<text x="365" y="286" text-anchor="middle" class="link-label">Ethernet</text>
<!-- Ethernet: B ↔ C -->
<path d="M 302 186 L 302 240 L 438 240 L 438 186" class="link"/>
<text x="370" y="256" text-anchor="middle" class="link-label">Ethernet</text>
<text x="370" y="268" text-anchor="middle" class="link-enc">encrypted FMP link</text>
<!-- UDP/IP: C-UDP(472) -> D-UDP(598) -->
<line x1="472" y1="200" x2="472" y2="300" class="link"/>
<line x1="472" y1="300" x2="598" y2="300" class="link"/>
<line x1="598" y1="300" x2="598" y2="200" class="link"/>
<text x="535" y="316" text-anchor="middle" class="link-label">UDP/IP</text>
<!-- UDP/IP: C ↔ D -->
<path d="M 482 186 L 482 240 L 618 240 L 618 186" class="link"/>
<text x="550" y="256" text-anchor="middle" class="link-label">UDP/IP</text>
<text x="550" y="268" text-anchor="middle" class="link-enc">encrypted FMP link</text>
<!-- Tor: D-Tor(642) -> E(790) -->
<line x1="642" y1="200" x2="642" y2="330" class="link"/>
<line x1="642" y1="330" x2="790" y2="330" class="link"/>
<line x1="790" y1="330" x2="790" y2="200" class="link"/>
<text x="716" y="346" text-anchor="middle" class="link-label">Tor</text>
<!-- Tor: D ↔ E -->
<path d="M 662 186 L 662 240 L 800 240 L 800 186" class="link"/>
<text x="731" y="256" text-anchor="middle" class="link-label">Tor</text>
<text x="731" y="268" text-anchor="middle" class="link-enc">encrypted FMP link</text>
<!-- End-to-end session (dashed) -->
<line x1="110" y1="380" x2="790" y2="380" class="session"/>
<text x="450" y="375" text-anchor="middle" class="session-label">End-to-end encrypted session (A ↔ E)</text>
<!-- ============ END-TO-END SESSION (below links, no intersection) ============ -->
<line x1="100" y1="305" x2="800" y2="305" class="session"/>
<text x="450" y="298" text-anchor="middle" class="session-label">End-to-end FSP session encryption (A ↔ E)</text>
<!-- Link labels -->
<text x="184" y="405" text-anchor="middle" class="link-label">Link</text>
<line x1="110" y1="395" x2="258" y2="395" class="link" stroke-dasharray="3,2"/>
<text x="365" y="405" text-anchor="middle" class="link-label">Link</text>
<line x1="302" y1="395" x2="428" y2="395" class="link" stroke-dasharray="3,2"/>
<text x="535" y="405" text-anchor="middle" class="link-label">Link</text>
<line x1="472" y1="395" x2="598" y2="395" class="link" stroke-dasharray="3,2"/>
<text x="716" y="405" text-anchor="middle" class="link-label">Link</text>
<line x1="642" y1="395" x2="790" y2="395" class="link" stroke-dasharray="3,2"/>
<!-- ============ LEGEND ============ -->
<line x1="60" y1="345" x2="120" y2="345" class="session"/>
<text x="132" y="349" class="legend" fill="#d0a040">FSP session encryption (end-to-end)</text>
<path d="M 60 370 L 60 380 L 120 380 L 120 370" class="link"/>
<text x="132" y="381" class="legend" fill="#5080c0">FMP link encryption (hop-by-hop)</text>
<!-- Caption -->
<text x="440" y="443" text-anchor="middle" class="caption">Multi-transport architecture — each link encrypted independently, session spans the full path</text>
</svg>

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

+147
View File
@@ -0,0 +1,147 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 840 620" font-family="monospace" font-size="12">
<style>
rect.callout { fill: #151520; stroke: #505040; stroke-width: 1; rx: 3; }
rect.bloom { fill: #1a1a2e; stroke-width: 1; rx: 3; }
text { fill: #e0e0e0; }
text.title { font-size: 16px; font-weight: bold; }
text.subtitle { font-size: 12px; fill: #909090; }
text.nlabel { font-size: 14px; font-weight: bold; }
text.bloom-t { font-size: 11px; fill: #b0b0c0; }
text.sender { font-size: 12px; font-weight: bold; }
text.op { font-size: 10px; fill: #b0b0b0; font-style: italic; }
text.caption { font-size: 13px; fill: #808090; font-style: italic; }
line.link { stroke: #404860; stroke-width: 2; }
</style>
<!-- Background -->
<rect width="840" height="620" fill="#0d1117" rx="8"/>
<!-- Title -->
<text x="420" y="28" text-anchor="middle" class="title">Bloom Filter Propagation</text>
<text x="420" y="46" text-anchor="middle" class="subtitle">Each link carries two filters — one in each direction (split-horizon)</text>
<!--
Node colors (sender-coded):
R: #d0a040 (amber) B: #40a0a0 (teal)
C: #a060c0 (purple) D: #c07050 (coral)
E: #50a060 (green) F: #5090d0 (sky)
Filter contents (tree-only, no mesh links):
D to B = {D} B to D = {B C E F R}
E to B = {E} B to E = {B C D F R}
F to C = {F} C to F = {B C D E R}
B to R = {B D E} R to B = {C F R}
C to R = {C F} R to C = {B D E R}
-->
<!-- ═══ Edges (drawn first so nodes/boxes overlay) ═══ -->
<line x1="400" y1="120" x2="232" y2="252" class="link"/>
<line x1="440" y1="120" x2="610" y2="252" class="link"/>
<line x1="192" y1="272" x2="130" y2="412" class="link"/>
<line x1="228" y1="272" x2="290" y2="412" class="link"/>
<line x1="630" y1="272" x2="630" y2="412" class="link"/>
<!-- ═══ Nodes (colored per-node) ═══ -->
<rect x="388" y="92" width="64" height="36" fill="#2e3020" stroke="#d0a040" stroke-width="2" rx="6"/>
<text x="420" y="115" text-anchor="middle" class="nlabel" fill="#d0a040">R</text>
<rect x="178" y="248" width="64" height="36" fill="#1e3030" stroke="#40a0a0" stroke-width="2" rx="6"/>
<text x="210" y="271" text-anchor="middle" class="nlabel" fill="#40a0a0">B</text>
<rect x="598" y="248" width="64" height="36" fill="#2a1e30" stroke="#a060c0" stroke-width="2" rx="6"/>
<text x="630" y="271" text-anchor="middle" class="nlabel" fill="#a060c0">C</text>
<rect x="78" y="408" width="64" height="36" fill="#2e2018" stroke="#c07050" stroke-width="2" rx="6"/>
<text x="110" y="431" text-anchor="middle" class="nlabel" fill="#c07050">D</text>
<rect x="278" y="408" width="64" height="36" fill="#1a2e1a" stroke="#50a060" stroke-width="2" rx="6"/>
<text x="310" y="431" text-anchor="middle" class="nlabel" fill="#50a060">E</text>
<rect x="598" y="408" width="64" height="36" fill="#1a2030" stroke="#5090d0" stroke-width="2" rx="6"/>
<text x="630" y="431" text-anchor="middle" class="nlabel" fill="#5090d0">F</text>
<!-- ═══════════════════════════════════════════════════════ -->
<!-- Filter boxes colored by sender node. -->
<!-- Every filter: self + merge(all inbound except recipient's) -->
<!-- ═══════════════════════════════════════════════════════ -->
<!-- ─── R—B link ─── -->
<!-- B to R -->
<text x="210" y="120" class="sender" fill="#40a0a0">B to R</text>
<rect x="210" y="124" width="80" height="26" class="bloom" stroke="#40a0a0"/>
<text x="218" y="142" class="bloom-t">B D E</text>
<!-- R to B -->
<text x="210" y="166" class="sender" fill="#d0a040">R to B</text>
<rect x="210" y="170" width="80" height="26" class="bloom" stroke="#d0a040"/>
<text x="218" y="188" class="bloom-t">C F R</text>
<!-- ─── R—C link ─── -->
<!-- C to R -->
<text x="560" y="120" class="sender" fill="#a060c0">C to R</text>
<rect x="560" y="124" width="80" height="26" class="bloom" stroke="#a060c0"/>
<text x="568" y="142" class="bloom-t">C F</text>
<!-- R to C -->
<text x="560" y="166" class="sender" fill="#d0a040">R to C</text>
<rect x="560" y="170" width="80" height="26" class="bloom" stroke="#d0a040"/>
<text x="568" y="188" class="bloom-t">B D E R</text>
<!-- ─── B—D link ─── -->
<!-- D to B -->
<text x="52" y="320" class="sender" fill="#c07050">D to B</text>
<rect x="52" y="324" width="80" height="26" class="bloom" stroke="#c07050"/>
<text x="60" y="342" class="bloom-t">D</text>
<!-- B to D -->
<text x="52" y="366" class="sender" fill="#40a0a0">B to D</text>
<rect x="52" y="370" width="80" height="26" class="bloom" stroke="#40a0a0"/>
<text x="60" y="388" class="bloom-t">B C E F R</text>
<!-- ─── B—E link ─── -->
<!-- E to B -->
<text x="298" y="320" class="sender" fill="#50a060">E to B</text>
<rect x="298" y="324" width="80" height="26" class="bloom" stroke="#50a060"/>
<text x="306" y="342" class="bloom-t">E</text>
<!-- B to E -->
<text x="298" y="366" class="sender" fill="#40a0a0">B to E</text>
<rect x="298" y="370" width="80" height="26" class="bloom" stroke="#40a0a0"/>
<text x="306" y="388" class="bloom-t">B C D F R</text>
<!-- ─── C—F link ─── -->
<!-- F to C -->
<text x="668" y="320" class="sender" fill="#5090d0">F to C</text>
<rect x="668" y="324" width="80" height="26" class="bloom" stroke="#5090d0"/>
<text x="676" y="342" class="bloom-t">F</text>
<!-- C to F -->
<text x="668" y="366" class="sender" fill="#a060c0">C to F</text>
<rect x="668" y="370" width="80" height="26" class="bloom" stroke="#a060c0"/>
<text x="676" y="388" class="bloom-t">B C D E R</text>
<!-- ═══ Merge annotations ═══ -->
<text x="248" y="271" class="op">merges D + E + self, sends to R</text>
<text x="592" y="271" text-anchor="end" class="op">merges F + self, sends to R</text>
<!-- ═══ Legend ═══ -->
<rect x="40" y="462" width="760" height="36" class="callout"/>
<text x="60" y="486" font-size="12" font-weight="bold" fill="#e0e0e0">X to Y</text>
<rect x="116" y="474" width="54" height="20" class="bloom" stroke="#e0e0e0"/>
<text x="180" y="488" class="bloom-t">filter X sends to Y — box color matches sender node</text>
<!-- ═══ Callout: candidate selection ═══ -->
<rect x="40" y="512" width="760" height="62" class="callout"/>
<text x="56" y="532" font-size="11" font-weight="bold" fill="#d0a040">Candidate selection</text>
<text x="56" y="548" font-size="10" fill="#c0c0c0">At any node, each peer's filter answers: "can you maybe reach destination X?"</text>
<text x="56" y="564" font-size="10" fill="#c0c0c0">Example: D wants to reach F. D checks the filter from B: B C E F R — F present, so B is a candidate.</text>
<!-- Caption -->
<text x="420" y="604" text-anchor="middle" class="caption">At steady state, every node knows full network reachability through each of its peers</text>
</svg>

After

Width:  |  Height:  |  Size: 7.2 KiB

+1 -1
View File
@@ -166,7 +166,7 @@ configurable.
### Link-Layer MMP (`node.mmp.*`)
Metrics Measurement Protocol for per-peer link measurement. See
[fips-link-layer.md](fips-link-layer.md) for behavioral details.
[fips-mesh-layer.md](fips-mesh-layer.md) for behavioral details.
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
+156
View File
@@ -0,0 +1,156 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 860 680" font-family="monospace" font-size="12">
<style>
rect.node { fill: #2e3a5e; stroke: #5080c0; stroke-width: 2; rx: 6; }
rect.cache { fill: #151520; stroke: #404060; stroke-width: 1; rx: 3; }
rect.phase { fill: none; stroke: none; }
text { fill: #e0e0e0; }
text.title { font-size: 16px; font-weight: bold; }
text.subtitle { font-size: 12px; fill: #909090; }
text.nlabel { font-size: 13px; font-weight: bold; }
text.nrole { font-size: 10px; fill: #909090; }
text.plabel { font-size: 13px; font-weight: bold; fill: #909090; }
text.annot { font-size: 10px; fill: #909090; font-style: italic; }
text.alabel { font-size: 11px; }
text.clabel { font-size: 9px; fill: #c0c0c0; }
text.caption { font-size: 11px; fill: #707080; font-style: italic; }
line.sep { stroke: #303040; stroke-width: 1; stroke-dasharray: 6,4; }
line.life { stroke: #303040; stroke-width: 1; stroke-dasharray: 2,3; }
line.disco { stroke: #5080c0; stroke-width: 2; }
line.resp { stroke: #d0a040; stroke-width: 2; stroke-dasharray: 6,3; }
line.data { stroke: #40a060; stroke-width: 2; }
polygon.disco { fill: #5080c0; }
polygon.resp { fill: #d0a040; }
polygon.data { fill: #40a060; }
</style>
<!-- Background -->
<rect width="860" height="680" fill="#0d1117" rx="8"/>
<!-- Title -->
<text x="430" y="28" text-anchor="middle" class="title">Coordinate Discovery and Caching</text>
<text x="430" y="46" text-anchor="middle" class="subtitle">LookupRequest/Response warms caches along the path</text>
<!-- ═══ Node headers ═══ -->
<!-- Node positions: A=160, B=340, C=520, D=700 -->
<!-- Node A — Source -->
<rect x="110" y="68" width="100" height="42" class="node"/>
<text x="160" y="88" text-anchor="middle" class="nlabel">A</text>
<text x="160" y="101" text-anchor="middle" class="nrole">Source</text>
<!-- Node B — Transit -->
<rect x="290" y="68" width="100" height="42" class="node"/>
<text x="340" y="88" text-anchor="middle" class="nlabel">B</text>
<text x="340" y="101" text-anchor="middle" class="nrole">Transit</text>
<!-- Node C — Transit -->
<rect x="470" y="68" width="100" height="42" class="node"/>
<text x="520" y="88" text-anchor="middle" class="nlabel">C</text>
<text x="520" y="101" text-anchor="middle" class="nrole">Transit</text>
<!-- Node D — Destination -->
<rect x="650" y="68" width="100" height="42" class="node"/>
<text x="700" y="88" text-anchor="middle" class="nlabel">D</text>
<text x="700" y="101" text-anchor="middle" class="nrole">Destination</text>
<!-- ═══ Lifelines ═══ -->
<line x1="160" y1="110" x2="160" y2="620" class="life"/>
<line x1="340" y1="110" x2="340" y2="620" class="life"/>
<line x1="520" y1="110" x2="520" y2="620" class="life"/>
<line x1="700" y1="110" x2="700" y2="620" class="life"/>
<!-- ═══════════════════════════════════════════════ -->
<!-- Phase 1 — Discovery (y: 130290) -->
<!-- ═══════════════════════════════════════════════ -->
<text x="40" y="148" text-anchor="middle" class="plabel">Phase 1</text>
<text x="40" y="164" text-anchor="middle" class="annot">Discovery</text>
<!-- A → B LookupRequest -->
<line x1="170" y1="170" x2="328" y2="170" class="disco"/>
<polygon points="326,165 336,170 326,175" class="disco"/>
<text x="250" y="163" text-anchor="middle" class="alabel" fill="#5080c0">LookupRequest</text>
<!-- B → C LookupRequest -->
<line x1="350" y1="200" x2="508" y2="200" class="disco"/>
<polygon points="506,195 516,200 506,205" class="disco"/>
<text x="430" y="193" text-anchor="middle" class="alabel" fill="#5080c0">LookupRequest</text>
<!-- C → D LookupRequest -->
<line x1="530" y1="230" x2="688" y2="230" class="disco"/>
<polygon points="686,225 696,230 686,235" class="disco"/>
<text x="610" y="223" text-anchor="middle" class="alabel" fill="#5080c0">LookupRequest</text>
<!-- Bloom filter annotation -->
<text x="430" y="260" text-anchor="middle" class="annot">guided by bloom filters at each hop</text>
<!-- ═══ Phase separator ═══ -->
<line x1="70" y1="285" x2="830" y2="285" class="sep"/>
<!-- ═══════════════════════════════════════════════ -->
<!-- Phase 2 — Response (y: 295460) -->
<!-- ═══════════════════════════════════════════════ -->
<text x="40" y="318" text-anchor="middle" class="plabel">Phase 2</text>
<text x="40" y="334" text-anchor="middle" class="annot">Response</text>
<!-- D → C LookupResponse -->
<line x1="690" y1="340" x2="532" y2="340" class="resp"/>
<polygon points="534,335 524,340 534,345" class="resp"/>
<text x="610" y="333" text-anchor="middle" class="alabel" fill="#d0a040">LookupResponse + coords</text>
<!-- Cache box at C -->
<rect x="490" y="358" width="60" height="22" class="cache"/>
<text x="520" y="373" text-anchor="middle" class="clabel">cache D</text>
<!-- C → B LookupResponse -->
<line x1="510" y1="395" x2="352" y2="395" class="resp"/>
<polygon points="354,390 344,395 354,400" class="resp"/>
<text x="430" y="388" text-anchor="middle" class="alabel" fill="#d0a040">LookupResponse + coords</text>
<!-- Cache box at B -->
<rect x="310" y="413" width="60" height="22" class="cache"/>
<text x="340" y="428" text-anchor="middle" class="clabel">cache D</text>
<!-- B → A LookupResponse -->
<line x1="330" y1="448" x2="172" y2="448" class="resp"/>
<polygon points="174,443 164,448 174,453" class="resp"/>
<text x="250" y="441" text-anchor="middle" class="alabel" fill="#d0a040">LookupResponse + coords</text>
<!-- ═══ Phase separator ═══ -->
<line x1="70" y1="475" x2="830" y2="475" class="sep"/>
<!-- ═══════════════════════════════════════════════ -->
<!-- Phase 3 — Efficient routing (y: 485610) -->
<!-- ═══════════════════════════════════════════════ -->
<text x="40" y="508" text-anchor="middle" class="plabel">Phase 3</text>
<text x="40" y="524" text-anchor="middle" class="annot">Routing</text>
<!-- A → B Data -->
<line x1="170" y1="530" x2="328" y2="530" class="data"/>
<polygon points="326,525 336,530 326,535" class="data"/>
<text x="250" y="523" text-anchor="middle" class="alabel" fill="#40a060">Data</text>
<!-- Cached coords note at B -->
<text x="340" y="553" text-anchor="middle" class="annot">cached coords</text>
<!-- B → C Data -->
<line x1="350" y1="565" x2="508" y2="565" class="data"/>
<polygon points="506,560 516,565 506,570" class="data"/>
<text x="430" y="558" text-anchor="middle" class="alabel" fill="#40a060">Data</text>
<!-- Cached coords note at C -->
<text x="520" y="588" text-anchor="middle" class="annot">cached coords</text>
<!-- C → D Data -->
<line x1="530" y1="600" x2="688" y2="600" class="data"/>
<polygon points="686,595 696,600 686,605" class="data"/>
<text x="610" y="593" text-anchor="middle" class="alabel" fill="#40a060">Data</text>
<!-- Efficient forwarding annotation -->
<text x="430" y="622" text-anchor="middle" class="annot">cached coords enable efficient forwarding — no re-discovery needed</text>
<!-- ═══ Caption ═══ -->
<text x="430" y="660" text-anchor="middle" class="caption">Each transit node caches coordinates from the LookupResponse return path</text>
</svg>

After

Width:  |  Height:  |  Size: 7.8 KiB

+26 -27
View File
@@ -1,4 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 370" font-family="monospace" font-size="12">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 840 370" font-family="monospace" font-size="12">
<style>
rect.box { rx: 4; stroke-width: 1.5; }
rect.source { fill: #1a3a2a; stroke: #40a060; }
@@ -22,11 +22,11 @@
</style>
<!-- Background -->
<rect width="800" height="370" fill="#0d1117" rx="8"/>
<rect width="840" height="370" fill="#0d1117" rx="8"/>
<!-- Title -->
<text x="400" y="28" text-anchor="middle" class="title">FIPS Identity Derivation</text>
<text x="400" y="46" text-anchor="middle" class="subtitle">From Nostr keypair to protocol identifiers</text>
<text x="420" y="28" text-anchor="middle" class="title">FIPS Identity Derivation</text>
<text x="420" y="46" text-anchor="middle" class="subtitle">From Nostr keypair to protocol identifiers</text>
<!-- ═══ Source: pubkey ═══ -->
<rect x="280" y="70" width="240" height="50" class="box source"/>
@@ -36,8 +36,8 @@
<!-- ═══ Left branch: bech32 encoding → npub ═══ -->
<!-- Arrow: pubkey left edge → npub -->
<line x1="280" y1="95" x2="180" y2="95" class="encode"/>
<polygon points="182,91 172,95 182,99" class="ehead"/>
<line x1="280" y1="95" x2="188" y2="95" class="encode"/>
<polygon points="190,91 180,95 190,99" class="ehead"/>
<text x="226" y="87" text-anchor="middle" class="op">encode</text>
<!-- npub box -->
@@ -46,14 +46,13 @@
<text x="105" y="106" text-anchor="middle" class="detail">human-readable form</text>
<!-- npub use box -->
<rect x="20" y="144" width="170" height="50" class="use"/>
<rect x="10" y="144" width="190" height="54" class="use"/>
<text x="105" y="162" text-anchor="middle" class="use-text">Display &amp; configuration</text>
<text x="105" y="176" text-anchor="middle" class="use-text">User-facing identifiers</text>
<text x="105" y="190" text-anchor="middle" class="use-text">DNS queries (npub.fips)</text>
<!-- npub → use arrow -->
<line x1="105" y1="120" x2="105" y2="144" class="arrow"/>
<polygon points="101,142 105,150 109,142" class="head"/>
<!-- npub → use connection -->
<line x1="105" y1="120" x2="105" y2="144" stroke="#606080" stroke-width="1" stroke-dasharray="3,3"/>
<!-- ═══ Right branch: pubkey → session encryption ═══ -->
@@ -62,10 +61,10 @@
<polygon points="618,91 628,95 618,99" class="head"/>
<!-- pubkey use box -->
<rect x="620" y="70" width="160" height="50" class="use"/>
<text x="700" y="88" text-anchor="middle" class="use-text">Endpoint authentication</text>
<text x="700" y="102" text-anchor="middle" class="use-text">Link &amp; session encryption</text>
<text x="700" y="116" text-anchor="middle" class="use-text">Known only to endpoints</text>
<rect x="620" y="66" width="200" height="58" class="use"/>
<text x="720" y="86" text-anchor="middle" class="use-text">Endpoint authentication</text>
<text x="720" y="100" text-anchor="middle" class="use-text">Link &amp; session encryption</text>
<text x="720" y="114" text-anchor="middle" class="use-text">Known only to endpoints</text>
<!-- ═══ Down: pubkey → one-way hash → node_addr ═══ -->
@@ -86,10 +85,10 @@
<polygon points="618,197 628,201 618,205" class="head"/>
<!-- node_addr use box -->
<rect x="620" y="176" width="160" height="50" class="use"/>
<text x="700" y="194" text-anchor="middle" class="use-text">Packet header addressing</text>
<text x="700" y="208" text-anchor="middle" class="use-text">Spanning tree coordinates</text>
<text x="700" y="222" text-anchor="middle" class="use-text">Bloom filter entries</text>
<rect x="620" y="172" width="200" height="58" class="use"/>
<text x="720" y="192" text-anchor="middle" class="use-text">Packet header addressing</text>
<text x="720" y="206" text-anchor="middle" class="use-text">Spanning tree coordinates</text>
<text x="720" y="220" text-anchor="middle" class="use-text">Bloom filter entries</text>
<!-- ═══ Down: node_addr → derive → IPv6 address ═══ -->
@@ -110,17 +109,17 @@
<polygon points="618,303 628,307 618,311" class="head"/>
<!-- IPv6 use box -->
<rect x="620" y="282" width="160" height="50" class="use"/>
<text x="700" y="298" text-anchor="middle" class="use-text">TUN interface (fips0)</text>
<text x="700" y="312" text-anchor="middle" class="use-text">Unmodified IP applications</text>
<text x="700" y="326" text-anchor="middle" class="use-text">ping, curl, ssh, etc.</text>
<rect x="620" y="278" width="200" height="58" class="use"/>
<text x="720" y="298" text-anchor="middle" class="use-text">TUN interface (fips0)</text>
<text x="720" y="312" text-anchor="middle" class="use-text">Unmodified IP applications</text>
<text x="720" y="326" text-anchor="middle" class="use-text">ping, curl, ssh, etc.</text>
<!-- ═══ Left: privacy annotation ═══ -->
<rect x="20" y="218" width="230" height="62" fill="#151520" stroke="#505040" stroke-width="1" rx="3"/>
<text x="135" y="236" text-anchor="middle" font-size="11" font-weight="bold" fill="#d0a040">Privacy boundary</text>
<text x="135" y="252" text-anchor="middle" class="use-text">Intermediate routers see only</text>
<text x="135" y="266" text-anchor="middle" class="use-text">node_addr — never the pubkey.</text>
<rect x="10" y="218" width="245" height="62" fill="#151520" stroke="#505040" stroke-width="1" rx="3"/>
<text x="132" y="236" text-anchor="middle" font-size="11" font-weight="bold" fill="#d0a040">Privacy boundary</text>
<text x="132" y="252" text-anchor="middle" class="use-text">Intermediate routers see only</text>
<text x="132" y="266" text-anchor="middle" class="use-text">node_addr — never the pubkey.</text>
<!-- Dashed line connecting privacy box to node_addr -->
<line x1="250" y1="249" x2="280" y2="201" stroke="#505040" stroke-width="1" stroke-dasharray="3,3"/>
<line x1="255" y1="249" x2="280" y2="201" stroke="#505040" stroke-width="1" stroke-dasharray="3,3"/>
</svg>

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

+108 -156
View File
@@ -14,12 +14,17 @@ as an IPv6 endpoint for compatibility with existing IP-based applications.
## Why FIPS?
**Self-sovereign identity**: FIPS nodes generate their own addresses, node IDs,
and security credentials without coordination with any central authority. The
identity system uses Nostr keypairs (secp256k1), so existing npub/nsec pairs
work directly.
**Infrastructure independence**: The internet depends on centralized
infrastructure — ISPs, backbone providers, DNS, certificate authorities. FIPS
works over any transport that can carry packets: a LoRa radio link between
mountain towns, a serial cable between air-gapped systems, onion-routed
connections through Tor, or the existing internet as an overlay. When the
internet is unavailable, unreliable, or untrusted, the mesh still works.
works over any transport that can carry packets: a serial cable between
air-gapped systems, onion-routed connections through Tor, radio links between
remote sites, or the existing internet as an overlay. When the internet is
unavailable, unreliable, or untrusted, the mesh still works.
**End-to-end security**: FIPS provides secure, authenticated, and encrypted
communication between any two nodes in the mesh, independent of the mix of
@@ -33,11 +38,6 @@ exposure is limited to direct peers only.
automatically. Connect to one peer and you can reach the entire mesh. The
network self-heals around failures and adapts to changing topology.
**Self-sovereign identity**: FIPS nodes generate their own addresses, node IDs,
and security credentials without coordination with any central authority. The
identity system uses Nostr keypairs (secp256k1), so existing npub/nsec pairs
work directly.
## A Self-Organizing Mesh
Traditional networks are built top-down. A central authority assigns addresses,
@@ -86,62 +86,16 @@ FIPS is organized in three protocol layers, each with distinct responsibilities
and clean service boundaries. Understanding these layers is key to understanding
how FIPS works.
```text
┌─────────────────────────────────────────────────────────────┐
│ Applications │
│ (native FIPS API / IPv6 adapter) │
├─────────────────────────────────────────────────────────────┤
│ │
│ FIPS Session Protocol (FSP) │
│ End-to-end authenticated encryption between endpoints │
│ Session lifecycle, coordinate caching, replay protection │
│ │
├─────────────────────────────────────────────────────────────┤
│ │
│ FIPS Link Protocol (FLP) │
│ Hop-by-hop link encryption, peer authentication │
│ Spanning tree, bloom filters, routing, forwarding │
│ │
├─────────────────────────────────────────────────────────────┤
│ │
│ Transport Layer │
│ Datagram delivery over arbitrary media │
│ UDP, Ethernet, LoRa, Tor, serial, ... │
│ │
└─────────────────────────────────────────────────────────────┘
```
![Protocol Stack](fips-protocol-stack.svg)
### Mapping to Traditional Networking
Readers familiar with the OSI model or TCP/IP networking may find it helpful to
see how FIPS concepts relate to traditional layers:
```text
Traditional FIPS Key Difference
─────────────────────────────────────────────────────────────────────
Application Applications Same role — user-facing
(IPv6 adapter) software
─────────────────────────────────────────────────────────────────────
Transport (TCP/UDP) (not present) FIPS provides datagrams,
not reliable streams
─────────────────────────────────────────────────────────────────────
Session FSP End-to-end encryption
and session management
─────────────────────────────────────────────────────────────────────
Network (IP) FLP Routing, forwarding,
address resolution —
but self-organizing
─────────────────────────────────────────────────────────────────────
Link (Ethernet/WiFi) FLP (link encryption) Peer authentication
and hop-by-hop crypto
─────────────────────────────────────────────────────────────────────
Physical (PHY) Transport layer Abstracted — FIPS
(UDP, radio, serial) treats all media the
same way
─────────────────────────────────────────────────────────────────────
```
![OSI Mapping](fips-osi-mapping.svg)
Note that FLP spans what would traditionally be separate link and network
Note that FMP spans what would traditionally be separate link and network
layers. This is intentional — in a self-organizing mesh, the same layer that
authenticates peers also makes routing decisions, because routing depends on
authenticated peer state (spanning tree positions, bloom filters).
@@ -152,27 +106,28 @@ authenticated peer state (spanning tree positions, bloom filters).
medium. Each transport type (UDP socket, Ethernet interface, radio modem)
implements the same abstract interface: send and receive datagrams, report MTU.
The transport layer knows nothing about FIPS identities, routing, or encryption.
It provides raw datagram delivery to FLP above.
It provides raw datagram delivery to FMP above.
See [fips-transport-layer.md](fips-transport-layer.md) for the transport layer
specification.
**FIPS Link Protocol (FLP)**: Manages peer connections, authenticates peers via
Noise IK handshakes, and encrypts all traffic on each link. FLP is where the
**FIPS Mesh Protocol (FMP)**: Manages peer connections, authenticates peers via
Noise IK handshakes, and encrypts all traffic on each link. FMP is where the
mesh organizes itself — nodes exchange spanning tree announcements and bloom
filters with their direct peers, and FLP makes forwarding decisions for transit
traffic. FLP provides authenticated, encrypted forwarding to FSP above.
filters with their direct peers, and FMP makes forwarding decisions for transit
traffic. FMP provides authenticated, encrypted forwarding to FSP above.
See [fips-link-layer.md](fips-link-layer.md) for the FLP specification and
[fips-mesh-operation.md](fips-mesh-operation.md) for how FLP's routing and
See [fips-mesh-layer.md](fips-mesh-layer.md) for the FMP specification and
[fips-mesh-operation.md](fips-mesh-operation.md) for how FMP's routing and
self-organization work in practice.
**FIPS Session Protocol (FSP)**: Provides end-to-end authenticated encryption
between any two nodes, regardless of how many intermediate hops separate them.
FSP manages session lifecycle (setup, data transfer, teardown), caches
destination coordinates for efficient routing, and handles the warmup strategy
that keeps transit node caches populated. FSP provides a datagram service to
applications above.
that keeps transit node caches populated. Session dispatch uses index-based
routing inspired by [WireGuard](https://www.wireguard.com/), enabling O(1)
packet demultiplexing. FSP provides a datagram service to applications above.
See [fips-session-layer.md](fips-session-layer.md) for the FSP specification.
@@ -187,48 +142,38 @@ See [fips-ipv6-adapter.md](fips-ipv6-adapter.md) for the IPv6 adapter.
## Architecture Overview
![Architecture Overview](fips-architecture-overview.svg)
Each node is a self-contained protocol stack with a strict layered architecture.
No layer depends on the specifics of the layers above or below it — transport
plugins know nothing about sessions, the routing layer knows nothing about
application addressing, and applications know nothing about which physical
media carry their traffic. This separation means new transports, protocol
features, and application interfaces can be added independently.
Each link uses a different transport, but the end-to-end session encryption is
independent of the transport mix. Intermediate nodes decrypt the link layer to
make routing decisions, then re-encrypt for the next hop. They cannot read the
session-layer payload.
```text
Application ──────────── End-to-end FSP session ──────────── Application
│ │
▼ ▼
┌─────────┐ FLP link ┌─────────┐ FLP link ┌─────────┐
│ Node A │◄──────────────►│ Node B │◄──────────────►│ Node C │
└────┬────┘ (Noise IK) └────┬────┘ (Noise IK) └────┬────┘
│ │ │
UDP/IP Ethernet LoRa
transport transport transport
```
Each FLP link operates over its own transport type, with independent link-layer
encryption. The FSP session spans the entire path, providing end-to-end
confidentiality that is independent of the transport mix along the route.
Two application interfaces sit at the top of the stack: a native datagram API
addressed by npub, and an IPv6 TUN adapter that maps npubs to `fd::/8`
addresses so unmodified IP applications can use the network transparently. Below
them, FSP manages end-to-end encrypted sessions while FMP handles mesh routing,
peer authentication, and hop-by-hop link encryption. At the bottom, transport
plugins abstract the physical diversity — each implements the same interface, so
the router treats UDP, Ethernet, Tor, and serial links identically.
![Node Architecture](fips-node-architecture.svg)
Internally, each node is organized in the three protocol layers. At the top,
two application interfaces provide access to the mesh: a native datagram API
addressed by npub, and an IPv6 TUN adapter that maps npubs to `fd::/8`
addresses so unmodified IP applications can use the network transparently. The
FSP and FLP layers in the middle implement session management, routing, and
encryption. At the bottom, transport plugins handle the physical diversity —
each plugin implements the same interface, so the router treats UDP, Ethernet,
LoRa, Tor, and serial links identically. Adding a new transport requires no
changes to the routing or session layers.
The mesh routes application traffic across heterogeneous transports
transparently. A packet may traverse WiFi, Ethernet, UDP/IP, and Tor links on
its way from source to destination — the application never needs to know which
transports are involved. Each hop is independently encrypted at the link layer,
while a single end-to-end session protects the payload across the entire path.
![Architecture Overview](fips-architecture-overview.svg)
---
## Identity System
FIPS uses Nostr keypairs (secp256k1) as node identities. The public key
identifies the node; the private key signs protocol messages and establishes
encrypted sessions.
FIPS uses [Nostr](https://github.com/nostr-protocol/nips) keypairs (secp256k1)
as node identities. The public key identifies the node; the private key signs
protocol messages and establishes encrypted sessions.
The FIPS address (synonymous with the pubkey) is the primary means for
application-layer software to identify communication endpoints. The
@@ -238,7 +183,7 @@ native API to the FIPS node software, or through an IPv6 adaptation layer that
converts the node identity into an IPv6 address and provides DNS resolution
from npub to this address for traditional software.
### Node Address Derivation
### FIPS Identity Handling
![Identity Derivation](fips-identity-derivation.svg)
@@ -250,44 +195,23 @@ Intermediate routers see only node_addrs — they can forward traffic without
learning the Nostr identities of the endpoints. An observer can verify "does
this node_addr belong to pubkey X?" but cannot enumerate which pubkeys are
communicating by inspecting traffic. The IPv6 address prepends `fd` to the
first 15 bytes of the node_addr, providing an overlay address for unmodified
first 15 bytes of the node_addr, providing a ULA overlay address for unmodified
IP applications via the TUN interface.
### Address Format
When using the IPv6 adaptation layer, FIPS addresses use the IPv6 Unique Local
Address (ULA) prefix `fd00::/8`, providing 120 bits from the node_addr hash.
These are overlay identifiers — they appear in the TUN interface for application
compatibility but are not routable on the underlying transport. The fd prefix
ensures no collision with addresses that may be in use on the transport network.
Below the FIPS identity layer, each transport uses its own native addressing —
IP:port tuples, MAC addresses, .onion identifiers. These **link addresses** are
opaque to everything above FMP and discarded once link authentication completes.
### Identity Verification
The Noise Protocol Framework is used to mutually authenticate both peer-to-peer
link connections (at FLP) and end-to-end session traffic (at FSP), proving each
The Noise Protocol Framework mutually authenticates both peer-to-peer link
connections (at FMP) and end-to-end session traffic (at FSP), proving each
party controls the private key for their claimed identity.
See [fips-link-layer.md](fips-link-layer.md) for peer authentication and
See [fips-mesh-layer.md](fips-mesh-layer.md) for peer authentication and
[fips-session-layer.md](fips-session-layer.md) for end-to-end session
establishment.
### Terminology: Addresses and Identifiers
FIPS uses several related but distinct identifiers at different protocol layers:
| Term | Layer | Visible To | Description |
| ---- | ----- | ---------- | ----------- |
| **FIPS address / pubkey** | Application/FSP | Endpoints only | 32-byte secp256k1 public key — the endpoint identity |
| **npub** | (encoding) | Human readers | Bech32 encoding of pubkey for display/config |
| **node_addr** | FLP (routing) | Routing nodes | SHA-256(pubkey) truncated to 128 bits — cannot be reversed to pubkey |
| **link_addr** | Transport | Direct peers | IP:port, MAC, .onion — transport-specific |
| **IPv6 address** | IPv6 adapter | Applications | fd::/8 derived from node_addr — optional compatibility |
**Privacy property**: The pubkey (FIPS address / Nostr identity) is never
exposed to intermediate routing nodes. They see only the node_addr, a one-way
hash. An observer can verify "does this node_addr belong to pubkey X?" but
cannot derive the pubkey from traffic.
---
## Two-Layer Encryption
@@ -296,14 +220,14 @@ FIPS uses independent encryption at two protocol layers:
| Layer | Scope | Pattern | Purpose |
| ----- | ----- | ------- | ------- |
| **FLP (Link)** | Hop-by-hop | Noise IK | Encrypt all traffic on each peer link |
| **FMP (Mesh)** | Hop-by-hop | Noise IK | Encrypt all traffic on each peer link |
| **FSP (Session)** | End-to-end | Noise IK | Encrypt application payload between endpoints |
### Link Layer (Hop-by-Hop)
When two nodes establish a direct connection, they perform a Noise IK
handshake. This authenticates both parties and establishes symmetric keys for
encrypting all traffic on that link. Every packet between direct peers is
When two nodes establish a direct connection, they perform a
[Noise IK](https://noiseprotocol.org/) handshake. This authenticates both
parties and establishes symmetric keys for encrypting all traffic on that link. Every packet between direct peers is
encrypted — gossip messages, routing queries, and forwarded session datagrams
alike.
@@ -331,20 +255,20 @@ twice: once by the session layer (end-to-end) and once by the link layer
A packet from A to adjacent peer B:
1. A encrypts payload with A↔B session key (FSP)
2. A wraps in SessionDatagram, encrypts with A↔B link key (FLP), sends to B
2. A wraps in SessionDatagram, encrypts with A↔B link key (FMP), sends to B
3. B decrypts link layer, then decrypts session layer to get payload
A packet from A to D through intermediate node B:
1. A encrypts payload with A↔D session key (FSP)
2. A wraps in SessionDatagram, encrypts with A↔B link key (FLP), sends to B
2. A wraps in SessionDatagram, encrypts with A↔B link key (FMP), sends to B
3. B decrypts link layer, reads destination, re-encrypts with B↔D link key
4. D decrypts link layer, then decrypts session layer to get payload
Intermediate nodes can route based on destination node_addr but cannot read
session-layer payloads.
See [fips-link-layer.md](fips-link-layer.md) for link encryption and
See [fips-mesh-layer.md](fips-mesh-layer.md) for link encryption and
[fips-session-layer.md](fips-session-layer.md) for session encryption.
---
@@ -363,7 +287,9 @@ mechanisms provide the information each node needs.
Nodes self-organize into a spanning tree rooted at a deterministically-elected
node (the one with the smallest node_addr). Each node selects a single parent
from among its direct peers, and the resulting tree gives every node a
**coordinate** — its path from itself to the root.
**coordinate** — its path from itself to the root. This coordinate-based
approach is adapted from [Yggdrasil](https://yggdrasil-network.github.io/)'s
[Ironwood](https://github.com/Arceliar/ironwood) routing library.
These coordinates enable distance calculations between any two nodes: the
distance is the number of hops from each node to their lowest common ancestor
@@ -382,10 +308,13 @@ walkthroughs.
### Bloom Filters: Candidate Selection
Each node maintains bloom filters summarizing which destinations are reachable
through each of its peers. Bloom filters propagate via gossip, with each node
computing outbound filters by merging the filters received from its other
peers. At steady state, filters represent the entire reachable network.
Each node maintains [bloom filters](https://en.wikipedia.org/wiki/Bloom_filter)
summarizing which destinations are reachable through each of its peers. Bloom
filters propagate via gossip, with each node computing outbound filters by
merging the filters received from its other peers (a
[split-horizon](https://en.wikipedia.org/wiki/Split_horizon_route_advertisement)
technique borrowed from distance-vector routing). At steady state, filters
represent the entire reachable network.
Bloom filters answer a single question: "can peer P possibly reach destination
D?" The answer is either "no" (definitive) or "maybe" (probabilistic — false
@@ -396,17 +325,35 @@ decision requires tree coordinates to rank those candidates by distance.
See [fips-bloom-filters.md](fips-bloom-filters.md) for filter parameters and
mathematical properties.
![Bloom filter propagation on a spanning tree](fips-bloom-propagation.svg)
Every filter is computed identically regardless of link type: the outbound filter
for peer Q merges this node's identity with all inbound filters except Q's
(split-horizon exclusion). The protocol makes no distinction between tree parents,
tree children, or mesh peers — the asymmetry visible in the diagram is a
consequence of tree topology, not a different operation.
A node with multiple peers receives genuinely different filters from each. In the
diagram, R receives {B, D, E} from B and {C, F} from C — two disjoint subtrees.
When R needs to reach F, only C's filter matches. This is where bloom filters
provide real candidate selection: a node with several peers can narrow the
forwarding choice before consulting tree coordinates. Leaf nodes like D have only
one peer, so their single inbound filter is necessarily near-complete (everything
except themselves) and offers no selection — but leaf nodes have no choice to make
anyway.
### Routing Decisions
At each hop, FLP makes a local forwarding decision using the following priority
At each hop, FMP makes a local forwarding decision using the following priority
chain:
1. **Local delivery** — the destination is this node
2. **Direct peer** — the destination is an authenticated neighbor
3. **Bloom-guided candidate selection** — bloom filters identify peers that can
reach the destination; tree coordinates rank them by distance
4. **Greedy tree routing** — fallback when bloom filters haven't converged;
forward to the peer that minimizes tree distance to the destination
4. **[Greedy routing](https://en.wikipedia.org/wiki/Greedy_embedding)** —
fallback when bloom filters haven't converged; forward to the peer that
minimizes tree distance to the destination
5. **No route** — destination unreachable; send error signal to source
All multi-hop routing depends on knowing the destination's tree coordinates.
@@ -414,17 +361,23 @@ These are cached at each node after being learned through discovery
(LookupRequest/LookupResponse) or session establishment (SessionSetup). The
coordinate cache is the critical piece that enables efficient forwarding.
![Per-hop routing decision flowchart](fips-routing-decision.svg)
### Coordinate Caching and Discovery
When a node first needs to reach an unknown destination, it sends a
LookupRequest that floods through the network guided by bloom filters. The
destination responds with its coordinates, which the source caches. Subsequent
traffic routes efficiently using the cached coordinates.
LookupRequest that propagates through the network guided by bloom filters and
loop prevention. The
destination responds with its coordinates, which the source and intermediate
nodes along the return path cache. Subsequent traffic routes efficiently using
the cached coordinates.
Session establishment (SessionSetup) also carries coordinates, warming transit
node caches along the path so that data packets can be forwarded without
individual discovery at each hop.
![Coordinate discovery and cache warming sequence](fips-coordinate-discovery.svg)
### Error Recovery
When routing fails — because cached coordinates are stale or a path has
@@ -446,13 +399,13 @@ and mesh behavior description.
## Transport Abstraction
FIPS is transport-agnostic. The protocol operates identically whether peers
connect over UDP, Ethernet, LoRa radio, serial cables, or Tor hidden services.
connect over UDP, Bluetooth, or whatever transport is available.
A **transport** is a physical or logical interface: a UDP socket, an Ethernet
NIC, a Tor client, a radio modem. A **link** is a peer connection established
over a transport. Transport addresses (IP:port, MAC address, .onion) are opaque
to all layers above FLP — they are used only to deliver datagrams and are
discarded once FLP has authenticated the peer.
to all layers above FMP — they are used only to deliver datagrams and are
discarded once FMP has authenticated the peer.
A node with multiple transports automatically bridges between networks. Peers
from all transports feed into a single spanning tree; the router selects the
@@ -461,10 +414,9 @@ automatically routes through alternatives.
| Category | Examples | Characteristics |
| -------- | -------- | --------------- |
| Overlay | UDP/IP, TCP/TLS, WebSocket | Internet connectivity, NAT traversal |
| Shared medium | Ethernet, WiFi, Bluetooth, LoRa | Local discovery, broadcast |
| Point-to-point | Serial, dialup | Static config, no discovery |
| Anonymity | Tor, I2P | High latency, strong privacy |
| Overlay | UDP/IP, Tor | Internet connectivity, NAT traversal |
| Shared medium | Ethernet, WiFi, Bluetooth, Radio | Local discovery, broadcast |
| Point-to-point | Serial | Static config, no discovery |
> **Implementation status**: UDP/IP is the only implemented transport. All
> others are future directions.
@@ -565,8 +517,8 @@ approach, enabling O(1) packet routing without relying on source addresses.
| Document | Description |
| -------- | ----------- |
| [fips-transport-layer.md](fips-transport-layer.md) | Transport layer: abstraction, types, services provided to FLP |
| [fips-link-layer.md](fips-link-layer.md) | FLP: peer authentication, link encryption, forwarding |
| [fips-transport-layer.md](fips-transport-layer.md) | Transport layer: abstraction, types, services provided to FMP |
| [fips-mesh-layer.md](fips-mesh-layer.md) | FMP: peer authentication, link encryption, forwarding |
| [fips-session-layer.md](fips-session-layer.md) | FSP: end-to-end encryption, session lifecycle |
| [fips-ipv6-adapter.md](fips-ipv6-adapter.md) | IPv6 adaptation: DNS, TUN interface, MTU enforcement |
+3 -3
View File
@@ -155,7 +155,7 @@ transport path MTU for the IPv6 adapter is therefore:
1280 + 106 = 1386 bytes
```
Transports with smaller MTUs (LoRa at ~250 bytes, serial at 256 bytes) cannot
Transports with smaller MTUs (radio at ~250 bytes, serial at 256 bytes) cannot
support the IPv6 adapter — applications on those transports must use the
native FIPS datagram API.
@@ -227,7 +227,7 @@ The TUN reader receives raw IPv6 packets from applications and processes them:
4. Retrieve NodeAddr and PublicKey from cache
5. Look up or establish FSP session
6. Encrypt payload with session keys
7. Route through FLP toward destination
7. Route through FMP toward destination
### Writer Thread
@@ -295,7 +295,7 @@ TUN device creation requires `CAP_NET_ADMIN`. Options:
Two complementary mechanisms support full PMTUD:
1. **Proactive**: The `path_mtu` field (2 bytes) in the SessionDatagram envelope
is implemented at the FLP level. The source sets it to its outbound link MTU
is implemented at the FMP level. The source sets it to its outbound link MTU
minus overhead; each transit node applies
`min(current, own_outbound_mtu - overhead)`. The destination receives the
forward-path minimum. PathMtuNotification is handled at the session layer;
@@ -1,49 +1,49 @@
# FIPS Link Protocol (FLP)
# FIPS Mesh Protocol (FMP)
The FIPS Link Protocol is the middle layer of the FIPS protocol stack. It sits
The FIPS Mesh Protocol is the middle layer of the FIPS protocol stack. It sits
between the transport layer below and the FIPS Session Protocol (FSP) above.
FLP is where anonymous transport addresses become authenticated peers, where
FMP is where anonymous transport addresses become authenticated peers, where
the mesh self-organizes, and where forwarding decisions are made.
## Role
FLP manages direct peer connections over transports. When a transport delivers
a datagram from an unknown address, FLP authenticates the sender through a
FMP manages direct peer connections over transports. When a transport delivers
a datagram from an unknown address, FMP authenticates the sender through a
Noise IK handshake, establishing a cryptographic link. Once authenticated, the
link carries all inter-peer communication: spanning tree gossip, bloom filter
updates, coordinate discovery, and forwarded session datagrams — all encrypted
per-hop.
FLP is the boundary between opaque transport addresses and identified peers.
Below FLP, everything is transport-specific addresses (IP:port, MAC, .onion).
Above FLP, everything is peers identified by public keys and routable by
FMP is the boundary between opaque transport addresses and identified peers.
Below FMP, everything is transport-specific addresses (IP:port, MAC, .onion).
Above FMP, everything is peers identified by public keys and routable by
node_addr. The transport layer never sees FIPS-level structure; FSP never sees
transport addresses or routing details.
## Services Provided to FSP
From the session layer's perspective, FLP is a black box providing three
From the session layer's perspective, FMP is a black box providing three
services. FSP knows nothing about transports, links, peers, spanning trees,
coordinates, bloom filters, hop counts, or network topology.
### Datagram Forwarding
FLP accepts a datagram addressed by source and destination node_addr and
FMP accepts a datagram addressed by source and destination node_addr and
delivers it best-effort toward the destination. The datagram travels hop by
hop — at each node, FLP decrypts the link layer, reads the destination
hop — at each node, FMP decrypts the link layer, reads the destination
node_addr, makes a local forwarding decision, and re-encrypts onto the
next-hop link.
FSP provides: source node_addr, destination node_addr, hop limit, and an
opaque payload (the session-layer encrypted message).
FLP provides: best-effort delivery. No acknowledgment, no retransmission, no
FMP provides: best-effort delivery. No acknowledgment, no retransmission, no
ordering guarantee. Datagrams may be dropped, duplicated, or delivered out of
order.
### Error Signaling
When forwarding fails, FLP signals the source endpoint asynchronously:
When forwarding fails, FMP signals the source endpoint asynchronously:
- **CoordsRequired**: A transit node lacks the destination's tree coordinates
and cannot make a forwarding decision. The source should re-initiate
@@ -60,21 +60,21 @@ storms during topology changes.
### Local Delivery
When a datagram arrives with a destination node_addr matching the local node,
FLP delivers it up to FSP for session-layer processing.
FMP delivers it up to FSP for session-layer processing.
## Services Required from Transport Layer
FLP requires the following from each transport:
FMP requires the following from each transport:
### Datagram Delivery
Send and receive raw datagrams to/from transport addresses. The transport
handles all medium-specific details. FLP sees only "send bytes to address" and
handles all medium-specific details. FMP sees only "send bytes to address" and
"bytes arrived from address."
### MTU Reporting
The maximum datagram size for a given link. FLP needs this to determine how
The maximum datagram size for a given link. FMP needs this to determine how
much payload fits in a single packet after link encryption overhead (37 bytes
for the encrypted frame wrapper: 16-byte outer header + 5-byte inner header +
16-byte AEAD tag).
@@ -82,13 +82,13 @@ for the encrypted frame wrapper: 16-byte outer header + 5-byte inner header +
### Connection Lifecycle
For connection-oriented transports, the transport must establish the underlying
connection before FLP can begin the Noise IK handshake. For connectionless
connection before FMP can begin the Noise IK handshake. For connectionless
transports, datagrams can flow immediately.
### Endpoint Discovery (Optional)
When a transport discovers a FIPS-capable endpoint (via beacon, query, or
other transport-specific mechanism), it notifies FLP so that link setup can
other transport-specific mechanism), it notifies FMP so that link setup can
be initiated. Transports without discovery support provide peer addresses
through configuration.
@@ -124,14 +124,14 @@ handshake completion:
### Reconnection
When a Noise IK msg1 arrives from a peer that already has an authenticated
link, FLP accepts the new handshake alongside the existing session. If the new
link, FMP accepts the new handshake alongside the existing session. If the new
handshake completes successfully, it replaces the old session. This handles
legitimate reconnection (network change, process restart, NAT rebinding)
without disrupting ongoing traffic until the new session is confirmed.
### Auto-Reconnect
When MMP's liveness detection removes a peer (dead timeout exceeded), FLP
When MMP's liveness detection removes a peer (dead timeout exceeded), FMP
automatically re-initiates the connection if the peer is configured for it.
The auto-reconnect path:
@@ -256,7 +256,7 @@ authenticity.
When an encrypted packet successfully decrypts, the sender is the
authenticated peer regardless of what transport address the packet arrived
from. FLP updates the peer's current address to the packet's source address,
from. FMP updates the peer's current address to the packet's source address,
and subsequent outbound packets use the updated address.
This allows peers to change transport addresses (IP:port for UDP, connection
@@ -294,7 +294,7 @@ Handshake initiation (msg1) is the primary attack surface for unauthenticated
traffic. Each msg1 requires Noise DH operations (~200µs on modern CPUs),
state allocation, and response generation.
FLP uses a global token bucket rate limiter:
FMP uses a global token bucket rate limiter:
- **Burst capacity**: Handles legitimate connection storms (e.g., node restart
with many configured peers)
- **Sustained rate**: Limits steady-state new connections per second
@@ -310,13 +310,13 @@ Additional protections:
## Disconnect
FLP supports orderly link teardown via a Disconnect message carrying a reason
FMP supports orderly link teardown via a Disconnect message carrying a reason
code (shutdown, restart, protocol error, transport failure, resource
exhaustion, security violation, configuration change, timeout).
On receiving Disconnect, FLP immediately cleans up state: removes the peer
On receiving Disconnect, FMP immediately cleans up state: removes the peer
from the peer table, frees the session index, removes the link, and cleans up
address mappings. If the departed peer was the tree parent, FLP triggers parent
address mappings. If the departed peer was the tree parent, FMP triggers parent
reselection.
Disconnect is best-effort — if the transport is broken, the message won't
@@ -328,7 +328,7 @@ stopped.
## Liveness Detection
FLP detects link liveness through a combination of explicit heartbeats and
FMP detects link liveness through a combination of explicit heartbeats and
traffic observation.
### Heartbeat
@@ -357,7 +357,7 @@ event-driven, and MMP reports require at least one side running Full mode).
## Link Message Types
FLP defines eight message types carried inside encrypted frames:
FMP defines eight message types carried inside encrypted frames:
| Type | Name | Purpose |
| ---- | ---- | ------- |
@@ -392,7 +392,7 @@ routing layer for link-cost decisions.
### Metrics Tracked
MMP computes the following metrics from the per-frame counter and timestamp
fields in the FLP wire format:
fields in the FMP wire format:
- **SRTT** — Smoothed round-trip time (Jacobson/RFC 6298, α=1/8). Derived
from timestamp-echo in ReceiverReports with dwell-time compensation.
@@ -426,7 +426,7 @@ formula is `clamp(2 × SRTT, 100ms, 2000ms)`.
### Spin Bit and RTT
The SP (spin bit) flag in the FLP inner header follows the QUIC spin bit
The SP (spin bit) flag in the FMP inner header follows the QUIC spin bit
pattern: reflected on receive, toggled on send when the reflected value
matches the last sent value. The spin bit state machine runs for TX
reflection, but **RTT samples from the spin bit are discarded**. In a mesh
@@ -437,7 +437,7 @@ bit RTT measurements unpredictably. Timestamp-echo from ReceiverReports
### CE Echo
The CE (Congestion Experienced) echo flag (bit 1 in the FLP flags byte) is
The CE (Congestion Experienced) echo flag (bit 1 in the FMP flags byte) is
reserved for ECN signaling. The transport trait does not currently expose
ECN marking, so the CE echo flag is never set. One-way delay trend serves
as the sole pre-loss congestion indicator.
@@ -515,8 +515,8 @@ an attacker sends invalid packets to elicit responses.
## References
- [fips-intro.md](fips-intro.md) — Protocol overview and architecture
- [fips-transport-layer.md](fips-transport-layer.md) — Transport layer (below FLP)
- [fips-session-layer.md](fips-session-layer.md) — FSP (above FLP)
- [fips-mesh-operation.md](fips-mesh-operation.md) — How FLP's routing and
- [fips-transport-layer.md](fips-transport-layer.md) — Transport layer (below FMP)
- [fips-session-layer.md](fips-session-layer.md) — FSP (above FMP)
- [fips-mesh-operation.md](fips-mesh-operation.md) — How FMP's routing and
self-organization work in practice
- [fips-wire-formats.md](fips-wire-formats.md) — Byte-level wire format reference
+2 -2
View File
@@ -136,7 +136,7 @@ FPR calculations, and size class folding.
## Routing Decision Process
At each hop, FLP makes a local forwarding decision using the `find_next_hop()`
At each hop, FMP makes a local forwarding decision using the `find_next_hop()`
priority chain. This is the core routing algorithm.
### Priority Chain
@@ -585,7 +585,7 @@ recovery).
## References
- [fips-intro.md](fips-intro.md) — Protocol overview
- [fips-link-layer.md](fips-link-layer.md) — FLP specification
- [fips-mesh-layer.md](fips-mesh-layer.md) — FMP specification
- [fips-spanning-tree.md](fips-spanning-tree.md) — Tree algorithms and data
structures
- [fips-bloom-filters.md](fips-bloom-filters.md) — Filter parameters and math
+77 -91
View File
@@ -1,10 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 520" font-family="monospace" font-size="12">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 560" font-family="monospace" font-size="12">
<style>
rect.outer { fill: #151525; stroke: #505070; stroke-width: 2; rx: 6; }
rect.layer { rx: 4; }
rect.api { fill: #1a3a2a; stroke: #40a060; stroke-width: 1.5; }
rect.tun { fill: #1a2a3a; stroke: #4080c0; stroke-width: 1.5; }
rect.router { fill: #2a2040; stroke: #8060c0; stroke-width: 1.5; }
rect.fsp { fill: #2a2040; stroke: #8060c0; stroke-width: 1.5; }
rect.fmp { fill: #2e3a5e; stroke: #5080c0; stroke-width: 1.5; }
rect.xport { fill: #2a1a1a; stroke: #c06040; stroke-width: 1.5; }
rect.cat { fill: none; stroke: #404060; stroke-width: 1; stroke-dasharray: 4,3; rx: 3; }
text { fill: #e0e0e0; }
@@ -18,21 +19,17 @@
</style>
<!-- Background -->
<rect width="800" height="520" fill="#0d1117" rx="8"/>
<rect width="800" height="560" fill="#0d1117" rx="8"/>
<!-- Title -->
<text x="400" y="28" text-anchor="middle" class="title">FIPS Node Architecture</text>
<text x="400" y="46" text-anchor="middle" class="subtitle">Application interfaces, router core, and transport abstraction layer</text>
<text x="400" y="46" text-anchor="middle" class="subtitle">Application interfaces, protocol layers, and transport abstraction</text>
<!-- Outer node box -->
<rect x="40" y="60" width="720" height="310" class="outer"/>
<rect x="40" y="60" width="720" height="350" class="outer"/>
<text x="56" y="80" class="sub">FIPS Node</text>
<!-- === Application layer (centered) === -->
<!-- Router core center = 390, gap = 20, each box = 200 wide -->
<!-- Left box: 390 - 10 - 200 = 180..380, center = 280 -->
<!-- Right box: 390 + 10 = 400..600, center = 500 -->
<!-- === Application layer === -->
<!-- FIPS-native API (left) -->
<rect x="180" y="90" width="200" height="50" class="layer api"/>
<text x="280" y="108" text-anchor="middle" class="label">FIPS-Native API</text>
@@ -53,122 +50,111 @@
<line x1="280" y1="78" x2="280" y2="90" class="conn"/>
<line x1="500" y1="78" x2="500" y2="90" class="conn"/>
<!-- === Router Core === -->
<rect x="80" y="170" width="620" height="60" class="layer router"/>
<text x="390" y="196" text-anchor="middle" class="label">Router Core</text>
<text x="390" y="212" text-anchor="middle" class="sub">Spanning tree · Bloom filters · Greedy routing · Session management · Noise IK</text>
<!-- === FSP Layer === -->
<rect x="80" y="170" width="620" height="50" class="layer fsp"/>
<text x="390" y="191" text-anchor="middle" class="label">FIPS Session Protocol (FSP)</text>
<text x="390" y="205" text-anchor="middle" class="sub">End-to-end encryption · Session lifecycle · Path discovery · In-band metrics</text>
<!-- Connections: API/TUN → Router -->
<!-- Connections: API/TUN → FSP -->
<line x1="280" y1="140" x2="280" y2="170" class="conn"/>
<line x1="500" y1="140" x2="500" y2="170" class="conn"/>
<!-- === Router → Transport connections (single trunk, branching to groups) === -->
<!-- === FMP Layer === -->
<rect x="80" y="240" width="620" height="50" class="layer fmp"/>
<text x="390" y="261" text-anchor="middle" class="label">FIPS Mesh Protocol (FMP)</text>
<text x="390" y="275" text-anchor="middle" class="sub">Link encryption · Spanning tree · Bloom filters · Routing · Peer management</text>
<!-- Single vertical trunk from router bottom center -->
<line x1="390" y1="230" x2="390" y2="252" class="conn"/>
<!-- Connection: FSP → FMP -->
<line x1="390" y1="220" x2="390" y2="240" class="conn"/>
<!-- === FMP → Transport connections === -->
<!-- Single vertical trunk from FMP bottom center -->
<line x1="390" y1="290" x2="390" y2="312" class="conn"/>
<!-- Horizontal bar at branch point -->
<line x1="160" y1="252" x2="690" y2="252" class="conn"/>
<line x1="155" y1="312" x2="625" y2="312" class="conn"/>
<!-- Vertical drops to each category group outline -->
<line x1="160" y1="252" x2="160" y2="276" class="conn"/>
<line x1="400" y1="252" x2="400" y2="276" class="conn"/>
<line x1="580" y1="252" x2="580" y2="276" class="conn"/>
<line x1="690" y1="252" x2="690" y2="276" class="conn"/>
<line x1="155" y1="312" x2="155" y2="336" class="conn"/>
<line x1="390" y1="312" x2="390" y2="336" class="conn"/>
<line x1="625" y1="312" x2="625" y2="336" class="conn"/>
<!-- === Transport layer === -->
<!-- Overlay transports -->
<rect x="60" y="276" width="200" height="80" class="cat"/>
<text x="160" y="289" text-anchor="middle" class="cat">Overlay</text>
<rect x="80" y="336" width="150" height="60" class="cat"/>
<text x="155" y="349" text-anchor="middle" class="cat">Overlay</text>
<rect x="72" y="296" width="56" height="36" class="layer xport"/>
<text x="100" y="312" text-anchor="middle" font-size="10" font-weight="bold" fill="#e0e0e0">UDP</text>
<text x="100" y="324" text-anchor="middle" class="sub">IP</text>
<rect x="92" y="356" width="60" height="30" class="layer xport"/>
<text x="122" y="371" text-anchor="middle" font-size="10" font-weight="bold" fill="#e0e0e0">UDP</text>
<text x="122" y="381" text-anchor="middle" class="sub">IP</text>
<rect x="134" y="296" width="56" height="36" class="layer xport"/>
<text x="162" y="312" text-anchor="middle" font-size="10" font-weight="bold" fill="#e0e0e0">QUIC</text>
<text x="162" y="324" text-anchor="middle" class="sub">IP</text>
<rect x="196" y="296" width="56" height="36" class="layer xport"/>
<text x="224" y="312" text-anchor="middle" font-size="10" font-weight="bold" fill="#e0e0e0">WS</text>
<text x="224" y="324" text-anchor="middle" class="sub">TCP</text>
<rect x="158" y="356" width="60" height="30" class="layer xport"/>
<text x="188" y="371" text-anchor="middle" font-size="10" font-weight="bold" fill="#e0e0e0">Tor</text>
<text x="188" y="381" text-anchor="middle" class="sub">.onion</text>
<!-- Shared medium transports -->
<rect x="270" y="276" width="260" height="80" class="cat"/>
<text x="400" y="289" text-anchor="middle" class="cat">Shared Medium</text>
<rect x="240" y="336" width="300" height="60" class="cat"/>
<text x="390" y="349" text-anchor="middle" class="cat">Shared Medium</text>
<rect x="282" y="296" width="56" height="36" class="layer xport"/>
<text x="310" y="312" text-anchor="middle" font-size="10" font-weight="bold" fill="#e0e0e0">Ether</text>
<text x="310" y="324" text-anchor="middle" class="sub">802.3</text>
<rect x="254" y="356" width="60" height="30" class="layer xport"/>
<text x="284" y="371" text-anchor="middle" font-size="10" font-weight="bold" fill="#e0e0e0">Ether</text>
<text x="284" y="381" text-anchor="middle" class="sub">802.3</text>
<rect x="344" y="296" width="56" height="36" class="layer xport"/>
<text x="372" y="312" text-anchor="middle" font-size="10" font-weight="bold" fill="#e0e0e0">WiFi</text>
<text x="372" y="324" text-anchor="middle" class="sub">802.11</text>
<rect x="320" y="356" width="60" height="30" class="layer xport"/>
<text x="350" y="371" text-anchor="middle" font-size="10" font-weight="bold" fill="#e0e0e0">WiFi</text>
<text x="350" y="381" text-anchor="middle" class="sub">802.11</text>
<rect x="406" y="296" width="56" height="36" class="layer xport"/>
<text x="434" y="312" text-anchor="middle" font-size="10" font-weight="bold" fill="#e0e0e0">BT</text>
<text x="434" y="324" text-anchor="middle" class="sub">RFCOMM</text>
<rect x="386" y="356" width="60" height="30" class="layer xport"/>
<text x="416" y="371" text-anchor="middle" font-size="10" font-weight="bold" fill="#e0e0e0">BT</text>
<text x="416" y="381" text-anchor="middle" class="sub">RFCOMM</text>
<rect x="468" y="296" width="56" height="36" class="layer xport"/>
<text x="496" y="312" text-anchor="middle" font-size="10" font-weight="bold" fill="#e0e0e0">LoRa</text>
<text x="496" y="324" text-anchor="middle" class="sub">radio</text>
<rect x="452" y="356" width="60" height="30" class="layer xport"/>
<text x="482" y="371" text-anchor="middle" font-size="10" font-weight="bold" fill="#e0e0e0">Radio</text>
<text x="482" y="381" text-anchor="middle" class="sub">Sat, ...</text>
<!-- Point-to-point transports -->
<rect x="540" y="276" width="80" height="80" class="cat"/>
<text x="580" y="289" text-anchor="middle" class="cat">P-to-P</text>
<rect x="550" y="336" width="150" height="60" class="cat"/>
<text x="625" y="349" text-anchor="middle" class="cat">Point-to-Point</text>
<rect x="552" y="296" width="56" height="36" class="layer xport"/>
<text x="580" y="312" text-anchor="middle" font-size="10" font-weight="bold" fill="#e0e0e0">Serial</text>
<text x="580" y="324" text-anchor="middle" class="sub">UART</text>
<rect x="562" y="356" width="60" height="30" class="layer xport"/>
<text x="592" y="371" text-anchor="middle" font-size="10" font-weight="bold" fill="#e0e0e0">Serial</text>
<text x="592" y="381" text-anchor="middle" class="sub">UART</text>
<!-- Anonymity transports -->
<rect x="630" y="276" width="120" height="80" class="cat"/>
<text x="690" y="289" text-anchor="middle" class="cat">Anonymity</text>
<rect x="642" y="296" width="46" height="36" class="layer xport"/>
<text x="665" y="312" text-anchor="middle" font-size="10" font-weight="bold" fill="#e0e0e0">Tor</text>
<text x="665" y="324" text-anchor="middle" class="sub">.onion</text>
<rect x="694" y="296" width="46" height="36" class="layer xport"/>
<text x="717" y="312" text-anchor="middle" font-size="10" font-weight="bold" fill="#e0e0e0">I2P</text>
<text x="717" y="324" text-anchor="middle" class="sub">tunnel</text>
<rect x="628" y="356" width="60" height="30" class="layer xport"/>
<text x="658" y="371" text-anchor="middle" font-size="10" font-weight="bold" fill="#e0e0e0">...</text>
<text x="658" y="381" text-anchor="middle" class="sub"></text>
<!-- === Peer networks below node box === -->
<text x="155" y="436" text-anchor="middle" class="sub">Internet / Overlay Peers</text>
<line x1="155" y1="410" x2="155" y2="426" class="peer"/>
<!-- Overlay peers -->
<text x="160" y="396" text-anchor="middle" class="sub">Internet Peers</text>
<line x1="160" y1="370" x2="160" y2="386" class="peer"/>
<text x="390" y="436" text-anchor="middle" class="sub">Local / Radio Peers</text>
<line x1="390" y1="410" x2="390" y2="426" class="peer"/>
<!-- Shared medium peers -->
<text x="400" y="396" text-anchor="middle" class="sub">Local / Radio Peers</text>
<line x1="400" y1="370" x2="400" y2="386" class="peer"/>
<!-- Point-to-point peers -->
<text x="580" y="396" text-anchor="middle" class="sub">Wired Peer</text>
<line x1="580" y1="370" x2="580" y2="386" class="peer"/>
<!-- Anonymity peers -->
<text x="690" y="396" text-anchor="middle" class="sub">Anonymous Peers</text>
<line x1="690" y1="370" x2="690" y2="386" class="peer"/>
<text x="625" y="436" text-anchor="middle" class="sub">Wired Peers</text>
<line x1="625" y1="410" x2="625" y2="426" class="peer"/>
<!-- === Legend === -->
<rect x="40" y="420" width="720" height="85" fill="#151520" stroke="#404060" stroke-width="1" rx="4"/>
<rect x="40" y="458" width="720" height="88" fill="#151520" stroke="#404060" stroke-width="1" rx="4"/>
<rect x="60" y="438" width="24" height="14" class="layer api"/>
<text x="92" y="450" class="sub">Application interface</text>
<rect x="60" y="476" width="24" height="14" class="layer api"/>
<text x="92" y="488" class="sub">Application interface</text>
<rect x="60" y="460" width="24" height="14" class="layer tun"/>
<text x="92" y="472" class="sub">IPv6 compatibility layer</text>
<rect x="60" y="496" width="24" height="14" class="layer tun"/>
<text x="92" y="508" class="sub">IPv6 compatibility layer</text>
<rect x="60" y="482" width="24" height="14" class="layer router"/>
<text x="92" y="494" class="sub">Router core (protocol engine)</text>
<rect x="300" y="476" width="24" height="14" class="layer fsp"/>
<text x="332" y="488" class="sub">FSP — end-to-end session encryption</text>
<rect x="300" y="438" width="24" height="14" class="layer xport"/>
<text x="332" y="450" class="sub">Transport plugin</text>
<rect x="300" y="496" width="24" height="14" class="layer fmp"/>
<text x="332" y="508" class="sub">FMP — mesh routing and link encryption</text>
<rect x="300" y="460" width="24" height="14" fill="none" stroke="#404060" stroke-width="1" stroke-dasharray="4,3" rx="2"/>
<text x="332" y="472" class="sub">Transport category grouping</text>
<rect x="590" y="476" width="24" height="14" class="layer xport"/>
<text x="622" y="488" class="sub">Transport plugin</text>
<text x="300" y="494" class="sub">All transports use the same Router Core interface</text>
<rect x="590" y="496" width="24" height="14" fill="none" stroke="#404060" stroke-width="1" stroke-dasharray="4,3" rx="2"/>
<text x="622" y="508" class="sub">Transport category</text>
<text x="300" y="536" class="sub">All transports use the same FMP protocol</text>
</svg>

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

+64
View File
@@ -0,0 +1,64 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 820 400" font-family="monospace" font-size="15">
<style>
text { fill: #e0e0e0; }
text.header { font-size: 16px; font-weight: bold; fill: #e0e0e0; }
text.layer { font-size: 15px; fill: #e0e0e0; }
text.fips { font-size: 15px; fill: #80b0e0; }
text.diff { font-size: 14px; fill: #a0a0b0; }
line.rule { stroke: #404050; stroke-width: 1; }
line.top { stroke: #606070; stroke-width: 1.5; }
</style>
<!-- Background -->
<rect width="800" height="360" fill="#0d1117" rx="8"/>
<!-- Column headers -->
<text x="40" y="35" class="header">Traditional</text>
<text x="280" y="35" class="header">FIPS</text>
<text x="560" y="35" class="header">Key Difference</text>
<line x1="20" y1="48" x2="780" y2="48" class="top"/>
<!-- Application -->
<text x="40" y="75" class="layer">Application</text>
<text x="280" y="75" class="fips">Application</text>
<text x="560" y="75" class="diff">Same role</text>
<line x1="20" y1="90" x2="780" y2="90" class="rule"/>
<!-- Transport -->
<text x="40" y="117" class="layer">Transport</text>
<text x="280" y="117" class="fips">(not present)</text>
<text x="560" y="117" class="diff">Datagrams, not streams</text>
<line x1="20" y1="132" x2="780" y2="132" class="rule"/>
<!-- Session -->
<text x="40" y="159" class="layer">Session</text>
<text x="280" y="159" class="fips">FIPS Session Protocol</text>
<text x="560" y="159" class="diff">End-to-end encryption</text>
<text x="280" y="177" class="fips">(FSP)</text>
<text x="560" y="177" class="diff">and session management</text>
<line x1="20" y1="192" x2="780" y2="192" class="rule"/>
<!-- Network -->
<text x="40" y="219" class="layer">Network (IP)</text>
<text x="280" y="219" class="fips">FIPS Mesh Protocol</text>
<text x="560" y="219" class="diff">Self-organizing routing</text>
<text x="280" y="237" class="fips">(FMP)</text>
<text x="560" y="237" class="diff">and forwarding</text>
<line x1="20" y1="252" x2="780" y2="252" class="rule"/>
<!-- Link -->
<text x="40" y="279" class="layer">Link</text>
<text x="280" y="279" class="fips">FMP (link encryption)</text>
<text x="560" y="279" class="diff">Hop-by-hop crypto</text>
<line x1="20" y1="294" x2="780" y2="294" class="rule"/>
<!-- Physical -->
<text x="40" y="321" class="layer">Physical</text>
<text x="280" y="321" class="fips">Transport layer</text>
<text x="560" y="321" class="diff">Abstracted — all media</text>
<text x="280" y="339" class="fips">(UDP, radio, serial)</text>
<text x="560" y="339" class="diff">treated the same</text>
<!-- Caption -->
<text x="400" y="393" text-anchor="middle" font-size="14" fill="#808090" font-style="italic">Mapping FIPS protocol layers to the traditional networking model</text>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

+49
View File
@@ -0,0 +1,49 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 895 620" font-family="monospace" font-size="15">
<style>
rect.layer { rx: 5; }
rect.app { fill: #1a3a2a; stroke: #40a060; stroke-width: 2; }
rect.fsp { fill: #2a2040; stroke: #8060c0; stroke-width: 2; }
rect.fmp { fill: #2e3a5e; stroke: #5080c0; stroke-width: 2; }
rect.xport { fill: #2a1a1a; stroke: #c06040; stroke-width: 2; }
text { fill: #e0e0e0; }
text.name { font-size: 23px; font-weight: bold; }
text.desc { font-size: 18px; fill: #a0a0b0; }
text.scope { font-size: 17px; fill: #707080; font-style: italic; }
text.caption { font-size: 18px; fill: #808090; font-style: italic; }
</style>
<!-- Background -->
<rect width="875" height="560" fill="#0d1117" rx="10"/>
<!-- Applications layer -->
<rect x="50" y="25" width="775" height="100" class="layer app"/>
<text x="75" y="58" class="name">Application Layer Interface</text>
<text x="75" y="78" class="desc">Native FIPS API — for FIPS-aware applications</text>
<text x="75" y="98" class="desc">IPv6 Shim — for traditional IP application backward compatibility</text>
<!-- FSP layer -->
<rect x="50" y="150" width="775" height="120" class="layer fsp"/>
<text x="75" y="183" class="name">FIPS Session Protocol (FSP)</text>
<text x="75" y="205" class="desc">End-to-end authenticated encryption between endpoints</text>
<text x="75" y="225" class="desc">Session lifecycle, path discovery, in-band metrics</text>
<text x="75" y="245" class="desc">Replay protection, forward secrecy, identity privacy</text>
<text x="800" y="183" class="scope" text-anchor="end">end-to-end</text>
<!-- FMP layer -->
<rect x="50" y="295" width="775" height="120" class="layer fmp"/>
<text x="75" y="328" class="name">FIPS Mesh Protocol (FMP)</text>
<text x="75" y="350" class="desc">Hop-by-hop peer authentication, link encryption, liveness detection</text>
<text x="75" y="370" class="desc">Spanning tree, bloom filters, routing, forwarding, repair</text>
<text x="75" y="390" class="desc">Link quality monitoring, maintenance, optional discovery</text>
<text x="800" y="328" class="scope" text-anchor="end">hop-by-hop</text>
<!-- Transport layer -->
<rect x="50" y="440" width="775" height="95" class="layer xport"/>
<text x="75" y="473" class="name">Transport Layer</text>
<text x="800" y="473" class="scope" text-anchor="end">(overlay, shared medium, point-to-point)</text>
<text x="75" y="495" class="desc">Datagram delivery over arbitrary media</text>
<text x="75" y="515" class="desc">UDP, Ethernet, WiFi, Bluetooth, Tor, serial, ...</text>
<!-- Caption -->
<text x="438" y="585" text-anchor="middle" class="caption">FIPS protocol layer stack — three layers with clean service boundaries</text>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

+153
View File
@@ -0,0 +1,153 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 720 920" font-family="monospace" font-size="12">
<style>
text { fill: #e0e0e0; }
text.title { font-size: 16px; font-weight: bold; }
text.subtitle { font-size: 12px; fill: #909090; }
text.step { font-size: 11px; fill: #5080c0; font-weight: bold; }
text.decision { font-size: 12px; }
text.action { font-size: 12px; }
text.branch { font-size: 11px; fill: #a0a0b0; }
text.caption { font-size: 13px; fill: #808090; font-style: italic; }
polygon.diamond { fill: #1a1a2e; stroke: #5080c0; stroke-width: 1.5; }
rect.start { fill: #2e3a5e; stroke: #5080c0; stroke-width: 1.5; }
rect.outcome { fill: #1a3a2a; stroke: #40a060; stroke-width: 1.5; rx: 4; }
rect.error { fill: #2a1a1a; stroke: #c06040; stroke-width: 1.5; rx: 4; }
rect.interim { fill: #1a2a3a; stroke: #4080c0; stroke-width: 1.5; rx: 4; }
line.arrow { stroke: #606080; stroke-width: 1.5; }
marker { fill: #606080; }
</style>
<defs>
<marker id="arrowhead" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto">
<polygon points="0 0, 8 3, 0 6" fill="#606080"/>
</marker>
</defs>
<!-- Background -->
<rect width="720" height="920" fill="#0d1117" rx="8"/>
<!-- Title -->
<text x="360" y="30" text-anchor="middle" class="title">Routing Decision Chain</text>
<text x="360" y="48" text-anchor="middle" class="subtitle">Per-hop forwarding priority at each FMP router</text>
<!-- ============================================================ -->
<!-- START: Packet arrives -->
<!-- ============================================================ -->
<rect x="260" y="74" width="200" height="36" rx="18" class="start"/>
<text x="360" y="97" text-anchor="middle" class="action">Packet arrives</text>
<!-- Arrow: start → decision 1 -->
<line x1="360" y1="110" x2="360" y2="140" class="arrow" marker-end="url(#arrowhead)"/>
<!-- ============================================================ -->
<!-- STEP 1: Local delivery? -->
<!-- ============================================================ -->
<text x="240" y="155" text-anchor="end" class="step">1</text>
<polygon points="360,140 440,180 360,220 280,180" class="diamond"/>
<text x="360" y="176" text-anchor="middle" class="decision">Local</text>
<text x="360" y="190" text-anchor="middle" class="decision">delivery?</text>
<!-- Yes → right to outcome -->
<line x1="440" y1="180" x2="520" y2="180" class="arrow" marker-end="url(#arrowhead)"/>
<text x="475" y="172" text-anchor="middle" class="branch">Yes</text>
<rect x="528" y="162" width="160" height="36" class="outcome"/>
<text x="608" y="185" text-anchor="middle" class="action">Deliver to application</text>
<!-- No → down -->
<line x1="360" y1="220" x2="360" y2="260" class="arrow" marker-end="url(#arrowhead)"/>
<text x="372" y="244" class="branch">No</text>
<!-- ============================================================ -->
<!-- STEP 2: Direct peer? -->
<!-- ============================================================ -->
<text x="240" y="275" text-anchor="end" class="step">2</text>
<polygon points="360,260 440,300 360,340 280,300" class="diamond"/>
<text x="360" y="296" text-anchor="middle" class="decision">Direct</text>
<text x="360" y="310" text-anchor="middle" class="decision">peer?</text>
<!-- Yes → right to outcome -->
<line x1="440" y1="300" x2="520" y2="300" class="arrow" marker-end="url(#arrowhead)"/>
<text x="475" y="292" text-anchor="middle" class="branch">Yes</text>
<rect x="528" y="282" width="160" height="36" class="outcome"/>
<text x="608" y="305" text-anchor="middle" class="action">Forward to peer</text>
<!-- No → down -->
<line x1="360" y1="340" x2="360" y2="380" class="arrow" marker-end="url(#arrowhead)"/>
<text x="372" y="364" class="branch">No</text>
<!-- ============================================================ -->
<!-- STEP 3: Bloom filter hit? -->
<!-- ============================================================ -->
<text x="240" y="395" text-anchor="end" class="step">3</text>
<polygon points="360,380 440,420 360,460 280,420" class="diamond"/>
<text x="360" y="416" text-anchor="middle" class="decision">Bloom filter</text>
<text x="360" y="430" text-anchor="middle" class="decision">hit?</text>
<!-- Yes → right to interim step -->
<line x1="440" y1="420" x2="520" y2="420" class="arrow" marker-end="url(#arrowhead)"/>
<text x="475" y="412" text-anchor="middle" class="branch">Yes</text>
<rect x="520" y="396" width="176" height="48" class="interim"/>
<text x="608" y="412" text-anchor="middle" class="action">Rank candidates by</text>
<text x="608" y="426" text-anchor="middle" class="action">tree distance and</text>
<text x="608" y="440" text-anchor="middle" class="action">link performance</text>
<!-- Arrow from interim → final outcome -->
<line x1="608" y1="444" x2="608" y2="470" class="arrow" marker-end="url(#arrowhead)"/>
<rect x="528" y="478" width="160" height="36" class="outcome"/>
<text x="608" y="501" text-anchor="middle" class="action">Forward to 'best'</text>
<!-- No → down -->
<line x1="360" y1="460" x2="360" y2="530" class="arrow" marker-end="url(#arrowhead)"/>
<text x="372" y="500" class="branch">No</text>
<!-- ============================================================ -->
<!-- STEP 4: Coords known? -->
<!-- ============================================================ -->
<text x="240" y="545" text-anchor="end" class="step">4</text>
<polygon points="360,530 440,570 360,610 280,570" class="diamond"/>
<text x="360" y="566" text-anchor="middle" class="decision">Coords</text>
<text x="360" y="580" text-anchor="middle" class="decision">known?</text>
<!-- Yes → right to outcome -->
<line x1="440" y1="570" x2="520" y2="570" class="arrow" marker-end="url(#arrowhead)"/>
<text x="475" y="562" text-anchor="middle" class="branch">Yes</text>
<rect x="528" y="552" width="160" height="36" class="outcome"/>
<text x="608" y="575" text-anchor="middle" class="action">Greedy tree forward</text>
<!-- No → down -->
<line x1="360" y1="610" x2="360" y2="660" class="arrow" marker-end="url(#arrowhead)"/>
<text x="372" y="640" class="branch">No</text>
<!-- ============================================================ -->
<!-- STEP 5: No route → error signal -->
<!-- ============================================================ -->
<text x="240" y="683" text-anchor="end" class="step">5</text>
<rect x="260" y="668" width="200" height="36" class="error"/>
<text x="360" y="691" text-anchor="middle" class="action">No route → error signal</text>
<!-- ============================================================ -->
<!-- Legend -->
<!-- ============================================================ -->
<rect x="40" y="740" width="640" height="120" fill="#151520" stroke="#404060" stroke-width="1" rx="4"/>
<rect x="60" y="762" width="24" height="14" rx="7" fill="#2e3a5e" stroke="#5080c0" stroke-width="1"/>
<text x="92" y="774" font-size="11" fill="#a0a0b0">Start / entry point</text>
<polygon points="64,800 72,793 80,800 72,807" fill="#1a1a2e" stroke="#5080c0" stroke-width="1"/>
<text x="88" y="804" font-size="11" fill="#a0a0b0">Routing decision (checked in priority order)</text>
<rect x="60" y="822" width="24" height="14" rx="4" fill="#1a3a2a" stroke="#40a060" stroke-width="1"/>
<text x="92" y="834" font-size="11" fill="#a0a0b0">Forwarding action (packet delivered or sent)</text>
<rect x="410" y="762" width="24" height="14" rx="4" fill="#1a2a3a" stroke="#4080c0" stroke-width="1"/>
<text x="442" y="774" font-size="11" fill="#a0a0b0">Intermediate processing step</text>
<rect x="410" y="793" width="24" height="14" rx="4" fill="#2a1a1a" stroke="#c06040" stroke-width="1"/>
<text x="442" y="805" font-size="11" fill="#a0a0b0">Terminal error (no route available)</text>
<line x1="410" y1="831" x2="434" y2="831" stroke="#606080" stroke-width="1.5" marker-end="url(#arrowhead)"/>
<text x="442" y="835" font-size="11" fill="#a0a0b0">Control flow direction</text>
<!-- Caption -->
<text x="360" y="896" text-anchor="middle" class="caption">Each hop evaluates destinations in priority order 14, falling through on miss</text>
</svg>

After

Width:  |  Height:  |  Size: 8.5 KiB

+11 -11
View File
@@ -1,7 +1,7 @@
# FIPS Session Protocol (FSP)
The FIPS Session Protocol is the top protocol layer in the FIPS stack. It sits
above the FIPS Link Protocol (FLP) and below applications (native FIPS API or
above the FIPS Mesh Protocol (FMP) and below applications (native FIPS API or
IPv6 adapter). FSP provides end-to-end authenticated, encrypted datagram
delivery between any two FIPS nodes, regardless of how many intermediate hops
separate them.
@@ -34,7 +34,7 @@ Applications access the FIPS mesh through two interfaces, both served by FSP:
Applications address destinations directly by npub or public key. The FIPS
stack resolves the destination's node_addr, establishes or reuses a session,
encrypts the payload, and routes through FLP. No DNS involvement.
encrypts the payload, and routes through FMP. No DNS involvement.
### IPv6 Adapter
@@ -66,21 +66,21 @@ layer.
TCP over IPv6 get TCP's congestion control; native API applications must
manage their own sending rate.
## Services Required from FLP
## Services Required from FMP
FSP treats FLP as a black box providing three services. FSP knows nothing about
FSP treats FMP as a black box providing three services. FSP knows nothing about
transports, transport addresses, links, peers, spanning trees, coordinates,
bloom filters, hop counts, or network topology.
### SessionDatagram Forwarding
FLP accepts a SessionDatagram (source node_addr, destination node_addr, TTL,
FMP accepts a SessionDatagram (source node_addr, destination node_addr, TTL,
path MTU, payload) and delivers it best-effort toward the destination. Delivery
may traverse multiple hops, each with independent link encryption.
### Error Signaling
FLP signals routing failures asynchronously:
FMP signals routing failures asynchronously:
- **CoordsRequired**: A transit node lacks the destination's tree coordinates.
FSP responds by sending a standalone CoordsWarmup (0x14) message
@@ -97,7 +97,7 @@ end-to-end encrypted) because transit nodes have no session with the source.
### Local Delivery
When a SessionDatagram arrives with a destination node_addr matching the local
node, FLP delivers it to FSP for session-layer processing.
node, FMP delivers it to FSP for session-layer processing.
## Session Lifecycle
@@ -189,7 +189,7 @@ transport addresses or routing paths. A session survives:
### Noise IK Pattern
FSP uses the same Noise IK pattern as FLP link encryption, but with
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`.
@@ -386,7 +386,7 @@ Cache population mechanisms:
The coordinate cache maps `NodeAddr → TreeCoordinate` and is the critical
data structure that enables efficient multi-hop routing. Without cached
coordinates for a destination, FLP cannot make forwarding decisions and must
coordinates for a destination, FMP cannot make forwarding decisions and must
either fall back to bloom-filter-only routing or signal CoordsRequired.
### Unified Cache
@@ -506,13 +506,13 @@ MMP session metrics session=npub1tdwa...84le rtt=4.3ms loss=0.6% jitter=0.2ms go
| Simultaneous initiation tie-breaker | **Implemented** |
| Flush coord cache on parent change | **Implemented** |
| Rekey | Planned |
| Path MTU tracking (FLP SessionDatagram field) | **Implemented** |
| Path MTU tracking (FMP SessionDatagram field) | **Implemented** |
| Path MTU notification (end-to-end echo) | **Implemented** |
## References
- [fips-intro.md](fips-intro.md) — Protocol overview and architecture
- [fips-link-layer.md](fips-link-layer.md) — FLP specification (below FSP)
- [fips-mesh-layer.md](fips-mesh-layer.md) — FMP specification (below FSP)
- [fips-ipv6-adapter.md](fips-ipv6-adapter.md) — IPv6 adaptation layer (above FSP)
- [fips-mesh-operation.md](fips-mesh-operation.md) — Routing, discovery, and
error recovery
+5 -5
View File
@@ -93,7 +93,7 @@ FIPS uses independent Noise IK encryption at two layers:
| Layer | Scope | What It Protects |
| ----- | ----- | ---------------- |
| FLP (link) | Hop-by-hop | All traffic on each peer link |
| FMP (mesh) | Hop-by-hop | All traffic on each peer link |
| FSP (session) | End-to-end | Application payload between endpoints |
**Why two layers instead of one**:
@@ -163,7 +163,7 @@ MMP is instantiated at two independent layers, each with its own
configuration and state:
- **Link layer**: One `MmpPeerState` per `ActivePeer`. Measures per-hop
quality using the FLP counter and timestamp fields that already exist on
quality using the FMP counter and timestamp fields that already exist on
every encrypted frame. No additional message overhead beyond periodic
SenderReport/ReceiverReport exchanges.
@@ -224,13 +224,13 @@ increase in bloom filter occupancy).
## Transport Opacity
Transport addresses are opaque byte vectors above FLP. The transport layer
Transport addresses are opaque byte vectors above FMP. The transport layer
interprets them (e.g., UDP parses "ip:port" strings); all layers above treat
them as handles passed back to the transport for sending.
**Architectural boundary**: Adding a new transport type (e.g., BLE) requires
implementing the transport trait and potentially a new `TransportHandle`
variant. No changes to FLP, FSP, or any routing logic. The transport trait
variant. No changes to FMP, FSP, or any routing logic. The transport trait
defines the interface:
- `send(addr, data)` — send a datagram
@@ -300,7 +300,7 @@ The `TransportHandle` enum provides async dispatch for methods that need it
## References
- [fips-intro.md](fips-intro.md) — Protocol overview
- [fips-link-layer.md](fips-link-layer.md) — FLP specification
- [fips-mesh-layer.md](fips-mesh-layer.md) — FMP specification
- [fips-session-layer.md](fips-session-layer.md) — FSP specification
- [fips-state-machines.md](fips-state-machines.md) — Phase-based state
machine pattern
+32 -34
View File
@@ -8,14 +8,14 @@ session management — is built on the services the transport layer provides.
## Role
A **transport** is a driver for a particular communication medium: a UDP
socket, an Ethernet interface, a LoRa radio, a serial line, a Tor circuit.
socket, an Ethernet interface, a serial line, a Tor circuit, a radio modem.
The transport layer's job is simple: accept a datagram and a transport
address, deliver the datagram to that address, and push inbound datagrams up
to the FIPS Link Protocol (FLP) above.
to the FIPS Mesh Protocol (FMP) above.
The transport layer deals exclusively in **transport addresses** — IP:port
tuples, MAC addresses, LoRa device addresses, .onion identifiers. These are
opaque to every layer above FLP. The mapping from transport address to FIPS
tuples, MAC addresses, .onion identifiers, radio device addresses. These are
opaque to every layer above FMP. The mapping from transport address to FIPS
identity happens at the link layer after the Noise IK handshake completes.
The word "peer" belongs to the link layer and above; the transport layer
knows only about remote endpoints identified by transport addresses.
@@ -23,29 +23,29 @@ knows only about remote endpoints identified by transport addresses.
A single transport instance can serve multiple remote endpoints
simultaneously — a UDP socket exchanges datagrams with many remote
addresses, an Ethernet interface communicates with many MAC addresses on the
same segment. Each endpoint may become a separate FLP link, but the
same segment. Each endpoint may become a separate FMP link, but the
transport layer itself maintains no per-endpoint state.
## Services Provided to FLP
## Services Provided to FMP
The transport layer provides four services to the FIPS Link Protocol above:
The transport layer provides four services to the FIPS Mesh Protocol above:
### Datagram Delivery
Send and receive datagrams to/from transport addresses. The transport
handles all medium-specific details: socket management, framing for stream
transports, radio configuration. FLP sees only "send bytes to address" and
transports, radio configuration. FMP sees only "send bytes to address" and
"bytes arrived from address."
Inbound datagrams are pushed to FLP through a channel. The transport spawns
Inbound datagrams are pushed to FMP through a channel. The transport spawns
a receive task that pushes arriving datagrams (along with the source
transport address and transport identifier) onto a bounded channel. FLP
transport address and transport identifier) onto a bounded channel. FMP
reads from this channel and dispatches based on the source address and
packet content.
### MTU Reporting
Report the maximum datagram size for a given link. FLP needs this to
Report the maximum datagram size for a given link. FMP needs this to
determine how much payload can fit in a single packet after link-layer
encryption overhead.
@@ -63,7 +63,7 @@ link individually.
### Connection Lifecycle
For connection-oriented transports, manage the underlying connection: TCP
handshake, Tor circuit establishment, Bluetooth pairing. FLP cannot begin
handshake, Tor circuit establishment, Bluetooth pairing. FMP cannot begin
the Noise IK handshake until the transport-layer connection is established.
Connectionless transports (UDP, raw Ethernet) skip this — datagrams can flow
@@ -71,7 +71,7 @@ immediately to any reachable address.
### Discovery (Optional)
Notify FLP when FIPS-capable endpoints are discovered on the local medium.
Notify FMP when FIPS-capable endpoints are discovered on the local medium.
This is an optional capability — transports that don't support it simply
don't provide discovery events.
@@ -94,7 +94,6 @@ for internet connectivity:
| TCP/IP | IP:port | Stream | Reliable | Requires length-prefix framing |
| WebSocket | URL | Stream | Reliable | Browser-compatible |
| Tor | .onion | Stream | Reliable | High latency, strong anonymity |
| I2P | Destination | ~32K | Unreliable | Datagram mode |
**Shared medium transports** operate over broadcast- or multicast-capable
media:
@@ -105,7 +104,7 @@ media:
| WiFi | MAC | 1500 | Unreliable | Infrastructure mode = Ethernet |
| Bluetooth | BD_ADDR | 67264K | Reliable | L2CAP |
| BLE | BD_ADDR | 23517 | Reliable | Negotiated ATT_MTU |
| LoRa | Device addr | 51222 | Unreliable | Low bandwidth, long range |
| Radio | Device addr | 51222 | Unreliable | Low bandwidth, long range |
**Point-to-point transports** connect exactly two endpoints:
@@ -114,9 +113,9 @@ media:
| Serial | None (P2P) | 2561500 | Reliable | SLIP/COBS framing |
| Dialup | None (P2P) | 1500 | Reliable | PPP framing |
### Properties That Matter to FLP
### Properties That Matter to FMP
**MTU**: Determines how much data FLP can pack into a single datagram after
**MTU**: Determines how much data FMP can pack into a single datagram after
accounting for link encryption overhead. Heterogeneous MTUs across the mesh
are normal — the IPv6 minimum (1280 bytes) is the safe baseline for FIPS
packet sizing.
@@ -129,19 +128,19 @@ and duplication at the routing layer.
**Connection model**: Connectionless transports (UDP, raw Ethernet) allow
immediate datagram exchange. Connection-oriented transports (TCP, Tor, BLE)
require connection setup before FLP can begin the Noise IK handshake,
require connection setup before FMP can begin the Noise IK handshake,
adding startup latency.
**Stream vs. datagram**: Datagram transports have natural packet boundaries.
Stream transports (TCP, WebSocket, Tor) require framing to delineate FIPS
packets within the byte stream. The FLP common prefix includes a payload
packets within the byte stream. The FMP common prefix includes a payload
length field that provides this framing directly, replacing the need for a
separate length-prefix layer.
**Addressing opacity**: Transport addresses are opaque byte vectors. FLP
**Addressing opacity**: Transport addresses are opaque byte vectors. FMP
doesn't interpret them — it just passes them back to the transport when
sending. This means adding a new transport type with a novel address format
requires no changes to FLP or FSP.
requires no changes to FMP or FSP.
## Connection Model
@@ -154,13 +153,12 @@ are lightweight — a transport address is sufficient to begin communication.
| --------- | ----- |
| UDP/IP | Stateless datagrams; NAT state is implicit |
| Ethernet | Send to MAC address directly |
| LoRa | Raw packets to device address |
| I2P | Datagram mode |
| Radio | Raw packets to device address |
### Connection-Oriented Transports
Explicit connection setup is required before FIPS traffic can flow. The link
must complete transport-layer connection before FLP authentication can
must complete transport-layer connection before FMP authentication can
proceed.
| Transport | Connection Setup |
@@ -185,7 +183,7 @@ circuit). Peer timeout configuration must account for transport-specific
setup times.
**Framing**: Stream transports must delimit FIPS packets within the byte
stream. The FLP common prefix includes a payload length field that provides
stream. The FMP common prefix includes a payload length field that provides
integrated framing. Datagram transports preserve packet boundaries naturally.
## UDP/IP: The Primary Internet Transport
@@ -248,14 +246,14 @@ discovery; a FIPS-specific announcement or response is.
Discovery is an optional transport capability. Transports that don't support
it (configured UDP endpoints, TCP) simply don't provide discovery events.
FLP handles both cases uniformly: with discovery, it waits for events then
FMP handles both cases uniformly: with discovery, it waits for events then
initiates link setup; without discovery, it initiates link setup directly to
configured addresses.
### Local/Medium Discovery *(future direction)*
For transports where endpoints share a physical or link-layer medium — LAN
broadcast, LoRa, BLE — discovery uses beacon and query mechanisms:
broadcast, radio, BLE — discovery uses beacon and query mechanisms:
- **Beacon**: A node periodically broadcasts its FIPS presence on the shared
medium. Content is a FIPS-defined discovery frame carrying enough
@@ -264,13 +262,13 @@ broadcast, LoRa, BLE — discovery uses beacon and query mechanisms:
respond. Responses arrive on the same channel as beacon events.
Both produce the same result: "FIPS endpoint available at transport address
X." FLP does not need to distinguish beacons from query responses.
X." FMP does not need to distinguish beacons from query responses.
| Transport | Discovery | Notes |
| --------- | --------- | ----- |
| UDP (LAN) | Broadcast/multicast | On local network segment |
| Ethernet | Broadcast | Custom EtherType, ff:ff:ff:ff:ff:ff |
| LoRa | Beacon | Shared RF channel, natural fit |
| Radio | Beacon | Shared RF channel, natural fit |
| BLE | Advertising | GATT service UUID |
### Nostr Relay Discovery *(future direction)*
@@ -290,7 +288,7 @@ Key properties:
is authenticated
- Relay selection acts as scoping — which relays a node publishes to and
subscribes on determines its discovery neighborhood
- Can only advertise IP-reachable endpoints (not LoRa, BLE, serial)
- Can only advertise IP-reachable endpoints (not radio, BLE, serial)
- Higher latency than local discovery (relay propagation delays)
### Current State
@@ -333,7 +331,7 @@ Each inbound datagram carries:
### Transport Metadata
Transport types carry static metadata that FLP can query:
Transport types carry static metadata that FMP can query:
```text
TransportType {
@@ -373,7 +371,7 @@ transitions through `Starting` to `Up` (operational). `stop()` moves to
| WiFi | Future direction | Infrastructure mode = Ethernet driver |
| Tor | Future direction | High latency, .onion addressing |
| BLE | Future direction | ATT_MTU negotiation, per-link MTU |
| LoRa | Future direction | Constrained MTU (51222 bytes) |
| Radio | Future direction | Constrained MTU (51222 bytes) |
| Serial | Future direction | SLIP/COBS framing, point-to-point |
## Design Considerations
@@ -399,7 +397,7 @@ traffic automatically routes through alternatives. A node with both UDP and
Ethernet transports bridges between internet-connected and local-only
networks transparently.
Multiple links to the same peer over different transports are possible. FLP
Multiple links to the same peer over different transports are possible. FMP
manages these independently — each link has its own Noise session, its own
MTU, and its own liveness tracking.
@@ -413,7 +411,7 @@ consider transport quality. This is a potential area for future optimization.
## References
- [fips-intro.md](fips-intro.md) — Protocol overview and layer architecture
- [fips-link-layer.md](fips-link-layer.md) — FLP specification (the layer above)
- [fips-mesh-layer.md](fips-mesh-layer.md) — FMP specification (the layer above)
- [fips-wire-formats.md](fips-wire-formats.md) — Transport framing details
- [fips-software-architecture.md](fips-software-architecture.md) — Transport
trait implementation details
+4 -4
View File
@@ -32,7 +32,7 @@ tag). No separate length prefix is needed.
## Link-Layer Formats
All FLP packets begin with a **4-byte common prefix** that identifies the
All FMP packets begin with a **4-byte common prefix** that identifies the
protocol version, session lifecycle phase, per-packet flags, and payload
length.
@@ -663,11 +663,11 @@ Layer 3: Session encryption (FSP)
FSP header (12 bytes) + AEAD(inner_hdr (6) + payload (1024)) + AEAD tag (16)
= 1058 bytes
Layer 2: SessionDatagram envelope (FLP routing)
Layer 2: SessionDatagram envelope (FMP routing)
msg_type (1) + ttl (1) + path_mtu (2) + src_addr (16) + dest_addr (16) + payload (1058)
= 1094 bytes
Layer 1: Link encryption (FLP per-hop)
Layer 1: Link encryption (FMP per-hop)
outer header (16) + encrypted(inner_hdr (5) + datagram (1094)) + AEAD tag (16)
= 1131 bytes
@@ -754,7 +754,7 @@ endpoint session keys).
## References
- [fips-link-layer.md](fips-link-layer.md) — FLP behavioral specification
- [fips-mesh-layer.md](fips-mesh-layer.md) — FMP behavioral specification
- [fips-session-layer.md](fips-session-layer.md) — FSP behavioral specification
- [fips-transport-layer.md](fips-transport-layer.md) — Transport framing
- [fips-mesh-operation.md](fips-mesh-operation.md) — How messages work together
+1 -1
View File
@@ -2,7 +2,7 @@
//!
//! Measures link quality between adjacent peers: RTT, loss, jitter,
//! throughput, one-way delay trend, and ETX. Operates on the per-frame
//! hooks (counter, timestamp, flags) introduced by the FLP wire format
//! hooks (counter, timestamp, flags) introduced by the FMP wire format
//! revision.
//!
//! Three operating modes trade measurement fidelity for overhead:
+4 -4
View File
@@ -2,7 +2,7 @@
use crate::node::{Node, NodeError};
use crate::transport::ReceivedPacket;
use crate::node::wire::{CommonPrefix, PHASE_ESTABLISHED, PHASE_MSG1, PHASE_MSG2, FLP_VERSION, COMMON_PREFIX_SIZE};
use crate::node::wire::{CommonPrefix, PHASE_ESTABLISHED, PHASE_MSG1, PHASE_MSG2, FMP_VERSION, COMMON_PREFIX_SIZE};
use std::time::Duration;
use tracing::{debug, info};
@@ -110,11 +110,11 @@ impl Node {
None => return, // Malformed prefix
};
if prefix.version != FLP_VERSION {
if prefix.version != FMP_VERSION {
debug!(
version = prefix.version,
transport_id = %packet.transport_id,
"Unknown FLP version, dropping"
"Unknown FMP version, dropping"
);
return;
}
@@ -133,7 +133,7 @@ impl Node {
debug!(
phase = prefix.phase,
transport_id = %packet.transport_id,
"Unknown FLP phase, dropping"
"Unknown FMP phase, dropping"
);
}
}
+1 -1
View File
@@ -144,7 +144,7 @@ impl FspCommonPrefix {
/// ```
///
/// The full 12-byte header is used as AAD for the AEAD construction.
/// No receiver_idx — unlike FLP, FSP is end-to-end (dispatched by src_addr
/// No receiver_idx — unlike FMP, FSP is end-to-end (dispatched by src_addr
/// from the SessionDatagram envelope, not by index).
#[derive(Clone, Debug)]
pub struct FspEncryptedHeader {
+2 -2
View File
@@ -204,7 +204,7 @@ pub(super) fn print_tree_snapshot(label: &str, nodes: &[TestNode]) {
///
/// Returns the number of packets processed.
pub(super) async fn process_available_packets(nodes: &mut [TestNode]) -> usize {
use crate::node::wire::{CommonPrefix, FLP_VERSION, PHASE_ESTABLISHED, PHASE_MSG1, PHASE_MSG2, COMMON_PREFIX_SIZE};
use crate::node::wire::{CommonPrefix, FMP_VERSION, PHASE_ESTABLISHED, PHASE_MSG1, PHASE_MSG2, COMMON_PREFIX_SIZE};
let mut count = 0;
for node in nodes.iter_mut() {
@@ -213,7 +213,7 @@ pub(super) async fn process_available_packets(nodes: &mut [TestNode]) -> usize {
continue;
}
if let Some(prefix) = CommonPrefix::parse(&packet.data) {
if prefix.version != FLP_VERSION {
if prefix.version != FMP_VERSION {
continue;
}
match prefix.phase {
+10 -10
View File
@@ -1,6 +1,6 @@
//! Wire Format Parsing and Serialization
//!
//! Defines the FIPS link-layer wire format (FLP) for packet dispatch.
//! Defines the FIPS mesh-layer wire format (FMP) for packet dispatch.
//! All packets begin with a 4-byte common prefix followed by phase-specific fields.
//!
//! ## Common Prefix (4 bytes)
@@ -24,8 +24,8 @@ use crate::noise::{HANDSHAKE_MSG1_SIZE, HANDSHAKE_MSG2_SIZE, TAG_SIZE};
// Constants
// ============================================================================
/// FLP protocol version (4 high bits of byte 0).
pub const FLP_VERSION: u8 = 0;
/// FMP protocol version (4 high bits of byte 0).
pub const FMP_VERSION: u8 = 0;
/// Phase value for established (encrypted) frames.
pub const PHASE_ESTABLISHED: u8 = 0x0;
@@ -70,7 +70,7 @@ pub const FLAG_SP: u8 = 0x04;
// Common Prefix
// ============================================================================
/// Parsed common packet prefix (first 4 bytes of every FLP packet).
/// Parsed common packet prefix (first 4 bytes of every FMP packet).
///
/// Wire format:
/// ```text
@@ -156,7 +156,7 @@ impl EncryptedHeader {
let version = data[0] >> 4;
let phase = data[0] & 0x0F;
if version != FLP_VERSION || phase != PHASE_ESTABLISHED {
if version != FMP_VERSION || phase != PHASE_ESTABLISHED {
return None;
}
@@ -222,7 +222,7 @@ impl Msg1Header {
let version = data[0] >> 4;
let phase = data[0] & 0x0F;
if version != FLP_VERSION || phase != PHASE_MSG1 {
if version != FMP_VERSION || phase != PHASE_MSG1 {
return None;
}
@@ -278,7 +278,7 @@ impl Msg2Header {
let version = data[0] >> 4;
let phase = data[0] & 0x0F;
if version != FLP_VERSION || phase != PHASE_MSG2 {
if version != FMP_VERSION || phase != PHASE_MSG2 {
return None;
}
@@ -317,7 +317,7 @@ pub fn build_msg1(sender_idx: SessionIndex, noise_msg1: &[u8]) -> Vec<u8> {
let payload_len = (4 + noise_msg1.len()) as u16; // sender_idx + noise_msg1
let mut packet = Vec::with_capacity(MSG1_WIRE_SIZE);
packet.push(CommonPrefix::ver_phase_byte(FLP_VERSION, PHASE_MSG1));
packet.push(CommonPrefix::ver_phase_byte(FMP_VERSION, PHASE_MSG1));
packet.push(0x00); // flags must be zero
packet.extend_from_slice(&payload_len.to_le_bytes());
packet.extend_from_slice(&sender_idx.to_le_bytes());
@@ -334,7 +334,7 @@ pub fn build_msg2(sender_idx: SessionIndex, receiver_idx: SessionIndex, noise_ms
let payload_len = (4 + 4 + noise_msg2.len()) as u16; // sender + receiver + noise
let mut packet = Vec::with_capacity(MSG2_WIRE_SIZE);
packet.push(CommonPrefix::ver_phase_byte(FLP_VERSION, PHASE_MSG2));
packet.push(CommonPrefix::ver_phase_byte(FMP_VERSION, PHASE_MSG2));
packet.push(0x00); // flags must be zero
packet.extend_from_slice(&payload_len.to_le_bytes());
packet.extend_from_slice(&sender_idx.to_le_bytes());
@@ -353,7 +353,7 @@ pub fn build_established_header(
payload_len: u16,
) -> [u8; ESTABLISHED_HEADER_SIZE] {
let mut header = [0u8; ESTABLISHED_HEADER_SIZE];
header[0] = CommonPrefix::ver_phase_byte(FLP_VERSION, PHASE_ESTABLISHED);
header[0] = CommonPrefix::ver_phase_byte(FMP_VERSION, PHASE_ESTABLISHED);
header[1] = flags;
header[2..4].copy_from_slice(&payload_len.to_le_bytes());
header[4..8].copy_from_slice(&receiver_idx.to_le_bytes());
+1 -1
View File
@@ -268,7 +268,7 @@ impl CipherState {
/// Encrypt plaintext with Additional Authenticated Data (AAD).
///
/// The AAD is authenticated but not encrypted. Used for the FLP
/// The AAD is authenticated but not encrypted. Used for the FMP
/// established frame format where the 16-byte outer header is
/// bound to the AEAD tag.
pub fn encrypt_with_aad(
+1 -1
View File
@@ -118,7 +118,7 @@ impl NoiseSession {
/// Decrypt with explicit counter, replay protection, and AAD.
///
/// This is the primary decryption method for the FLP transport phase
/// This is the primary decryption method for the FMP transport phase
/// with AAD binding. The AAD (typically the 16-byte outer header) must
/// match what was used during encryption.
pub fn decrypt_with_replay_check_and_aad(
+2 -2
View File
@@ -565,7 +565,7 @@ impl SessionAck {
/// Session-layer sender report (msg_type 0x11).
///
/// Mirrors the FLP `SenderReport` fields but carried as an FSP session
/// Mirrors the FMP `SenderReport` fields but carried as an FSP session
/// message inside the AEAD envelope. The msg_type is in the FSP inner
/// header, so the body starts with reserved bytes.
///
@@ -634,7 +634,7 @@ impl SessionSenderReport {
/// Session-layer receiver report (msg_type 0x12).
///
/// Mirrors the FLP `ReceiverReport` fields but carried as an FSP session
/// Mirrors the FMP `ReceiverReport` fields but carried as an FSP session
/// message inside the AEAD envelope.
///
/// ## Wire Format (66 bytes body, after inner header stripped)
+5 -5
View File
@@ -69,22 +69,22 @@ const MAX_ORIGINAL_PACKET: usize = MIN_IPV6_MTU - IPV6_HEADER_LEN - ICMPV6_HEADE
/// Breakdown (traced through the actual send path):
///
/// ```text
/// FLP outer header (cleartext AAD) 16
/// FMP outer header (cleartext AAD) 16
/// common prefix (4) + receiver_idx (4) + counter (8)
/// FLP AEAD ciphertext:
/// timestamp (4) + msg_type (1) 5 [FLP inner header]
/// FMP AEAD ciphertext:
/// timestamp (4) + msg_type (1) 5 [FMP inner header]
/// ttl (1) + path_mtu (2) + src (16) + dst (16) 35 [SessionDatagram body]
/// FSP header (4 prefix + 8 counter) 12 [cleartext AAD]
/// FSP AEAD ciphertext:
/// timestamp (4) + msg_type (1) + flags (1) 6 [FSP inner header]
/// <application data>
/// Poly1305 tag 16 [FSP AEAD]
/// FLP Poly1305 tag 16 [FLP AEAD]
/// FMP Poly1305 tag 16 [FMP AEAD]
/// ────
/// 106
/// ```
///
/// Note: the FLP inner header msg_type byte IS the SessionDatagram msg_type
/// Note: the FMP inner header msg_type byte IS the SessionDatagram msg_type
/// byte (shared, not double-counted). The "35 bytes" is the SessionDatagram
/// body after msg_type is consumed by the dispatch layer.
pub const FIPS_OVERHEAD: u16 = 16 + 16 + 5 + 35 + 12 + 6 + 16; // 106 bytes