> **Nostr Agent Onboarding** · [start here](https://npub1d70emggs6jzun5lhvqnfqsd9reqmaarn2qjf6q3r02gryyl4v8sqjn44xe.nsite.lol/start.md) · [index](https://npub1d70emggs6jzun5lhvqnfqsd9reqmaarn2qjf6q3r02gryyl4v8sqjn44xe.nsite.lol/llms.txt) · source: `nostr-dev/docs/sources/fips.md` · snapshot 2026-10-10
>
> Paths such as `~/Documents/…`, `~/Production Environment/…`, `repos/…` and services on `localhost` refer to the author's workstation and are **not available to you** — read them as worked examples of a setup you can recreate.

# FIPS — Free Internetworking Peering System

**Spec home:** <https://fips.network>
**Source:** <https://github.com/jmcorgan/fips> (Rust, MIT)
**Local clone:** `~/Documents/nostr-dev/repos/fips/` (offline reference, gitignored from this repo)
**Local build:** binaries in `~/Documents/nostr-dev/repos/fips/target/release/` and copied to `~/.cargo/bin/{fips,fipsctl,fipstop,fips-gateway}` after `cargo install`.

## Why it lives in the workspace docs

FIPS is the cleanest worked example of the workspace's central design idea
(see [`docs/design-synthesis.md`](https://npub1d70emggs6jzun5lhvqnfqsd9reqmaarn2qjf6q3r02gryyl4v8sqjn44xe.nsite.lol/docs/design/design-synthesis.md) §1) applied **outside** Nostr's own
event/relay surface. Where Nostr decouples authentication from event
storage, FIPS decouples it from **packet routing** — it uses the same
secp256k1 keypair, the same npub identity space, and the same Nostr-relay
infrastructure for peer discovery, then runs an encrypted mesh on top of
arbitrary transports.

If you're designing anything that wants "Nostr keypair as identity" but
isn't itself a Nostr application, FIPS is the most fully-developed
reference architecture available. The 13 design specs in
`repos/fips/docs/design/` are worth reading on their own as a layered
protocol design exercise.

## What FIPS is, in one paragraph

A distributed mesh-routing protocol where each node is identified by a
Nostr secp256k1 keypair. Nodes self-organize into a spanning tree across
**arbitrary transports** (UDP, TCP, Ethernet, Bluetooth, Tor, serial),
forwarding packets hop-by-hop with bloom-filter-aided routing. Every
packet gets dual encryption: hop-by-hop (Noise IK) at the link layer
and end-to-end (Noise XK) at the session layer. An IPv6 adapter maps
npubs to `fd00::/8` ULA addresses and serves a `.fips` DNS namespace, so
unmodified IP applications (curl, ssh, a Nostr relay, anything) work
over the mesh without modification.

## Layered design

| Layer | Protocol | Job |
|---|---|---|
| **Transport** | platform-specific (UDP / TCP / Ethernet / BLE / Tor / serial) | Uniform datagram interface over heterogeneous media |
| **Mesh (FMP)** | Noise IK + spanning tree | Peer authentication, hop-by-hop link encryption, forwarding |
| **Session (FSP)** | Noise XK | End-to-end encryption between any two nodes, session lifecycle |
| **IPv6 adapter** | TUN + DNS resolver | Maps npubs ↔ `fd00::/8` addresses; `.fips` DNS for app interop |

Each layer's spec is one markdown file in `repos/fips/docs/design/`.

## The Nostr integration — kinds and tags

FIPS uses three Nostr kinds in production. **All three are interesting examples for [`docs/kind-cheatsheet.md`](https://npub1d70emggs6jzun5lhvqnfqsd9reqmaarn2qjf6q3r02gryyl4v8sqjn44xe.nsite.lol/docs/design/kind-cheatsheet.md)** because two of them are in the wild but not (yet) in the canonical NIPs registry.

### Kind 37195 — overlay advert (addressable)

> The digits visually spell "FIPS" — 7=F, 1=I, 9=P, 5=S. (Cute.)

A node publishes its currently-reachable transport endpoints as a kind 37195 event signed by its FIPS identity key (= its Nostr identity key). Peers that know the npub fetch the advert from the node's configured relays and append the advertised endpoints to their dial list.

- **Class:** addressable (range 30000–39999). Latest event per `(pubkey, kind, d-tag)` is what matters.
- **`d` tag:** application namespace, default `fips-overlay-v1`. Lets multiple FIPS deployments coexist on the same relays without crosstalk.
- **Tag content:** transport endpoints (`udp:host:port`, `tcp:host:port`, `tor:onion:port`, the special `udp:nat` rendezvous token), TTLs, capabilities.
- **Unpublication:** standard NIP-9 kind:5 delete, addressed at the kind 37195 event id.

This is a textbook case of "addressable kind in the wild, not in the registry." Per the kind-cheatsheet's Step 2, anyone considering kind 37195 for their own use should `nak req -k 37195 -l 3 wss://relay.damus.io wss://nos.lol` and discover that someone is already there. Coordinate via the FIPS project rather than collide.

### Kind 21059 — encrypted offer/answer (ephemeral, gift-wrapped)

For NAT hole-punching. When two nodes are both behind UDP NAT, they exchange STUN-derived candidate pairs through Nostr using NIP-59 gift-wrap. The outer wrap is kind 1059 (NIP-59 standard); the inner sealed event is kind 21059 (FIPS-specific, ephemeral 20000–29999 range).

- **Class:** ephemeral. The event has no value once the punch attempt completes.
- **Routing:** to the recipient's NIP-65 inbox relays (with fallback to `dm_relays` from the FIPS YAML config).

Another good real-world example — ephemeral kinds are uncommon outside NIP-46 / NIP-42 / NIP-98 (the core auth-flow kinds), so seeing one for application-specific live signaling is instructive.

### Kind 10002 — relay list (replaceable, NIP-65)

FIPS reuses NIP-65 unmodified for "where do my offer/answer messages get delivered." A FIPS node looking up a peer for hole-punch first fetches the peer's kind 10002 event, then publishes the kind 21059 gift-wrap to those inbox relays.

This is the right move — invent kinds only when an existing one doesn't fit.

## Binaries

| Binary | What |
|---|---|
| `fips` | Main daemon: TUN adapter, transports, mesh + session protocols. Needs root for TUN. |
| `fipsctl` | CLI: query node status, peers, links, sessions, metrics. Doesn't need root. |
| `fipstop` | TUI dashboard, like `htop` for a FIPS node. |
| `fips-gateway` | Optional daemon: lets unmodified LAN hosts reach mesh destinations via DNS-allocated virtual IPs and kernel NAT. |

In this workspace they're built at `repos/fips/target/release/` and installed to `~/.cargo/bin/`. The agent has them on PATH but no daemon is running.

## Why no `fips` daemon is running on this machine

By design choice — same posture as the other "potentially-internet-facing service" decisions in this workspace:

- `fips` requires **root** to load the TUN driver. Different threat model than localhost-bound containers.
- A FIPS node's value depends on a **persistent identity** (npub), since its routing state is anchored to that key. The workspace's `/dev/shm` ephemeral key would invalidate adverts on every reboot — pointless for a real mesh node.
- Running a node binds **UDP 2121** and **TCP 8443** outbound by default and joins a live mesh. Operationally meaningful; not appropriate as a default.
- The `nostr-discovery` feature is **off by default** in stock configs; an operator opts in deliberately. We respect that default.

If you want to run one, `repos/fips/packaging/` has Debian, AUR, OpenWrt, macOS, and Windows packagers. The minimal operator-facing flow:

```bash
# Install the .deb (or use the cargo-built binaries)
sudo cp ~/Documents/nostr-dev/repos/fips/target/release/fips /usr/local/bin/
sudo mkdir -p /etc/fips && sudo cp <your-config>.yaml /etc/fips/fips.yaml
# (config needs a persistent identity — generate or supply an nsec)
sudo /usr/local/bin/fips
# In another terminal:
fipsctl show status
fipstop
```

Don't do this with the workspace's ephemeral session key.

## Spec docs (offline at `repos/fips/docs/design/`)

| File | Topic |
|---|---|
| `fips-intro.md` | Goals, layered architecture, problem statement |
| `fips-transport-layer.md` | Datagram interface over arbitrary media |
| `fips-mesh-layer.md` | FMP — peer auth, link encryption, forwarding |
| `fips-session-layer.md` | FSP — end-to-end encryption, session lifecycle |
| `fips-ipv6-adapter.md` | TUN + DNS adapter mapping npubs ↔ `fd00::/8` |
| `fips-mesh-operation.md` | Routing, discovery, error recovery |
| `fips-wire-formats.md` | Message wire formats |
| `fips-nostr-discovery.md` | **The Nostr integration** — read this if you only read one |
| `fips-spanning-tree.md` | Root discovery, parent selection, coordinates |
| `fips-bloom-filters.md` | FPR analysis, size classes, split-horizon |
| `fips-configuration.md` | YAML configuration reference |
| `fips-gateway.md` | LAN gateway adapter |
| `spanning-tree-dynamics.md` | Walkthroughs of convergence scenarios |

## How this informs the workspace's design knowledge

- **§1 of [`design-synthesis.md`](https://npub1d70emggs6jzun5lhvqnfqsd9reqmaarn2qjf6q3r02gryyl4v8sqjn44xe.nsite.lol/docs/design/design-synthesis.md)** (the "single load-bearing idea") — FIPS is the worked example showing that "signatures decouple authentication from storage" generalizes beyond event databases to **packet routing**.
- **[`kind-cheatsheet.md`](https://npub1d70emggs6jzun5lhvqnfqsd9reqmaarn2qjf6q3r02gryyl4v8sqjn44xe.nsite.lol/docs/design/kind-cheatsheet.md)** — kind 37195 is a real-world reminder to probe `nak req -k <N> ... wss://relay.damus.io wss://nos.lol` before allocating any kind, because the registry is incomplete.
- **[`patterns/grasp-as-structural-layer.md`](https://npub1d70emggs6jzun5lhvqnfqsd9reqmaarn2qjf6q3r02gryyl4v8sqjn44xe.nsite.lol/docs/patterns/grasp-as-structural-layer.md)** — different pattern but same underlying lesson: Nostr identity is the anchor; the structural layer is the part you choose. FIPS chose "decentralized routing"; the archive project chose "Git tree."
