Skip to content

Iroh: Peer-to-Peer QUIC Networking & Content-Addressed Data

A source-grounded survey of iroh's Rust implementation — n0's stack for authenticated peer-to-peer QUIC connectivity and content-addressed data transfer — read at workspace v1.0.1 (commit 22cac742ca) to inform a clean-room native D reimplementation running on sparkles:event-horizon (single-threaded, completion-first io_uring/kqueue/IOCP, fibers + algebraic effects). Each subsystem was read against its pinned tree, cited to real path:lines, and written up as an independent deep-dive; this page is the map that ties them together.

This survey answers eight questions:

  1. What is a peer, and how does it prove who it is? — every endpoint is a single Ed25519 keypair whose 32-byte public key is its EndpointId, authenticated in an RFC 7250 raw-public-key TLS 1.3 handshake carried in QUIC CRYPTO frames — no PKI, no X.509. See Identity & Cryptography (shared vocabulary in Concepts).
  2. How does every iroh value become bytes? — exactly one application codec (postcard), base32-wrapped tickets, and an ALPN registry. See Wire Formats & Serialization.
  3. What carries the connection, and what must a port rebuild?noq, n0's sans-io fork of quinn extended with QUIC Multipath, QUIC Address Discovery, and an in-QUIC NAT-traversal protocol. See QUIC Transport (noq); the app-facing connect/accept + protocol-router shell is Endpoint & Protocol Router.
  4. How does one logical connection ride many changing network paths? — the multipath Socket (the module formerly called magicsock) that fans QUIC datagrams across direct, IPv6, and relay carriers under one noq::AsyncUdpSocket.
  5. How do two NATed peers get a direct path, and what happens when they cannot? — QUIC-native simultaneous-open NAT Traversal & Address Discovery (the DISCO UDP side-protocol and STUN are gone); the always-reachable Relay is rendezvous and fallback; Net Report measures the local vantage point via netwatch / portmapper.
  6. How do you reach a peer knowing only its key?Address Lookup: BEP-44-signed records published and resolved over pkarr relays and the DNS.
  7. How is application data moved, verified, synced, and broadcast? — content-addressed Blobs over BLAKE3 verified streaming, multi-writer Document Sync, and epidemic Gossip.
  8. What concurrency runs all of this, and how does it collapse onto a single-threaded loop? — a complete Tokio Concurrency Inventory feeding the D Architecture Migration onto sparkles:event-horizon.

NOTE

Scope. This is the master index for the iroh research tree. Each row below links to a deep-dive that was written and fact-checked independently against its pinned source tree; where this index summarizes a subsystem, the deep-dive is the source of truth. The workspace is pinned at iroh v1.0.1 (22cac742ca); companion crates at iroh-blobs 0.103.0, iroh-docs 0.101.0, iroh-gossip 0.101.0, noq 1.0.1 (noq-v1.0.1), bao-tree 0.16.0, iroh-util 0.6.0, and irpc 0.17.0. iroh 1.0 is a major restructure of the 0.x APImagicsock → the socket layer, "discovery" → address_lookup, NodeIdEndpointId, and the DISCO UDP side-protocol + STUN replaced by QUIC-native NAT traversal + QUIC Address Discovery inside noq-proto. NodeAddr-era folklore does not compile; treat pre-1.0 material with suspicion.

Last reviewed: July 6, 2026


Master Catalog

One row per subsystem, grouped by layer. ALPN / role gives the wire-bearing ALPN string where the subsystem owns one, otherwise its function. Versions are the pinned tags read; per-path:line provenance lives in each deep-dive's Sources block.

Foundations

SubsystemCrate(s)VersionALPN / roleWhat it doesLink
Identity & Cryptographyiroh-base, iroh (tls/*)iroh 1.0.1 (22cac742ca)none — raw-public-key TLS 1.3 identityEd25519 keypair = EndpointId; RFC 7250 handshake; BLAKE3 auxiliary MACs; no PKI, no ECDHDeep-dive →
Wire Formats & Serializationiroh-tickets, iroh-base, postcardiroh-tickets 1.0.0 / iroh-base 1.0.1owns the ALPN registryone non-self-describing postcard codec, base32 tickets, five base codecs, per-protocol framingDeep-dive →
QUIC Transport (noq)noq, noq-proto, noq-udpnoq-v1.0.1 (340e9c7)none — transport is ALPN-agnosticsans-io QUIC v1 state machine + Multipath + Address Discovery + in-QUIC NAT traversal (≈48k LoC)Deep-dive →

Connectivity

SubsystemCrate(s)VersionALPN / roleWhat it doesLink
Endpoint & Protocol Routeriroh (endpoint, protocol, runtime)iroh 1.0.1 (22cac742ca)app-chosen (e.g. b"iroh-example/echo/0")cheaply-clonable Endpoint over noq; Router multiplexes inbound connections onto ProtocolHandlersDeep-dive →
The Multipath Socketiroh (socket, ex-magicsock)iroh 1.0.1 (22cac742ca)none — sits below QUIC/TLSone AsyncUdpSocket over IP + relay + custom carriers; synthetic-IPv6 mapped addrs; path selectionDeep-dive →
NAT Traversal & Address Discoverynoq-proto, noq, iroh, iroh-relaynoq-v1.0.1 / iroh 1.0.1/iroh-qad/0 (QAD server); QNT rides the app connectionsimultaneous-open ADD_ADDRESS/REACH_OUT/REMOVE_ADDRESS over the encrypted 1-RTT dataplaneDeep-dive →
The Relay Protocoliroh-relay, iroh (relay transport)iroh-relay 1.0.1WS subprotocol iroh-relay-v2; QAD ALPN /iroh-qad/0authenticated WebSocket packet-forwarder keyed on EndpointId + a bare QAD QUIC endpoint (port 7842)Deep-dive →
Address Lookup (Discovery)iroh, iroh-dns, iroh-dns-serveriroh 1.0.1 / iroh-dns 1.0.1none — DNS + pkarr HTTP(S)EndpointId → dialable addresses via BEP-44-signed DNS packets over pkarr relays and the DNSDeep-dive →
Net Report, Watching & Port Mappingiroh (net_report), netwatch, portmapperiroh 1.0.1 / netwatch 0.19.1 / portmapper 0.19.1/iroh-qad/0 probe; HTTPS fallbackmeasures UDP reachability, public address, NAT type, home relay; interface watching + UPnP/PCP/NAT-PMPDeep-dive →

Protocols

SubsystemCrate(s)VersionALPN / roleWhat it doesLink
Blobs: Content-Addressed Transferiroh-blobs, iroh-util, irpc, bao-treeiroh-blobs 0.103.0/iroh-bytes/4request/response BLAKE3 verified-stream transfer; crash-consistent store; resumable multi-provider downloaderDeep-dive →
BLAKE3 Verified Streaming (bao-tree)bao-treebao-tree 0.16.0n/a — a codec, not a wire protocolexposes BLAKE3's internal Merkle tree as an incrementally-verifiable stream (16 KiB chunk groups)Deep-dive →
Document Sync (iroh-docs)iroh-docsiroh-docs 0.101.0/iroh-sync/1multi-writer eventually-consistent KV store; recursive range-fingerprint set reconciliationDeep-dive →
Epidemic Broadcast (iroh-gossip)iroh-gossipiroh-gossip 0.101.0/iroh-gossip/1 (per-instance overridable)HyParView partial-view membership + Plumtree eager/lazy-push broadcast tree, as an IO-less state machineDeep-dive →

D migration

SubsystemCrate(s)VersionALPN / roleWhat it doesLink
Tokio Concurrency Inventoryn0-future, n0-watcher, irpc, allworkspace 1.0.1 (irpc 0.17.0)none — process-internal plumbingcensus of every task, channel, lock, select! loop, spawn_blocking, timer; protocol-inherent vs Send + Sync artifactDeep-dive →

NOTE

Two catalog entries are cross-cutting rather than subsystems: Concepts & Vocabulary (the shared glossary every page references) and D Architecture Migration (the capstone that maps the whole stack onto event-horizon). Both are in Quick Navigation, not the Master Catalog.


Taxonomy

Three re-cuts of the same fourteen subsystems, one axis each. Every row links back to a deep-dive.

By layer

The catalog's grouping: where a subsystem sits from the identity root up to the runtime that drives it. Higher layers depend on lower ones.

LayerConcernSubsystems
FoundationsIdentity, bytes, and the transport state machine everything ridesIdentity & Cryptography, Wire Formats, QUIC Transport
ConnectivityGetting an authenticated QUIC path to a peer, wherever it isEndpoint, Socket, NAT Traversal, Relay, Address Lookup, Net Report
ProtocolsApplication services built on top of a connectionBlobs, bao-tree, Document Sync, Gossip
D migrationPorting artifacts — the concurrency census and the architecture planConcurrency Inventory, D Architecture Migration

By network role

The same set cut by what job it does on the wire rather than where it sits in the stack.

RoleQuestion it answersSubsystems
Identity & encodingWho is this peer, and how do its values serialize?Identity & Cryptography, Wire Formats
TransportHow is an authenticated, multiplexed byte pipe established?QUIC Transport, Endpoint
Connectivity / NATHow do we reach a peer, and stay reached as the net changes?Socket, NAT Traversal, Relay, Address Lookup, Net Report
Data protocolsWhat application semantics ride the connection?Blobs, bao-tree, Document Sync, Gossip
RuntimeWhat schedules all of the above?Concurrency Inventory

By port difficulty

The axis that matters most for the D reimplementation: how a subsystem should be acquired. A subsystem can appear in more than one class — Socket, for instance, is both policy to re-implement and raw OS surface to bind.

ClassWhat the port doesSubsystems
Reuse a sans-io coreThe logic is already a pure (state, event) → effects machine with no OS or runtime coupling; re-derive the state machine and drive it from a fiberQUIC Transport (noq-proto), Gossip (proto/), Document Sync (range reconciler), bao-tree, Wire Formats (postcard)
Reimplement policy / glueModerate protocol and policy logic over a sans-io core; no exotic OS or crypto surfaceEndpoint, Socket (routing fabric), NAT Traversal (orchestration), Relay, Address Lookup, Blobs (protocol/store/downloader), Concurrency substrate
Needs an OS bindingMust bind raw per-OS surfaces the language runtime does not provideNet Report (netwatch netlink/AF_ROUTE//proc/net/route/IP Helper/getifaddrs; portmapper UPnP/PCP/NAT-PMP), Socket (UDP send/recv, GSO/GRO, rebind)
Needs a crypto primitiveDepends on cryptographic primitives that must be spec-exact and constant-timeIdentity & Cryptography (Ed25519, TLS 1.3 raw-public-key, BLAKE3 keyed_hash/derive_key), bao-tree & Blobs (BLAKE3), Relay (TLS keying-material export, RFC 5705)

NOTE

The single largest reuse-a-sans-io-core item, noq-proto, is ≈48k lines of protocol logic — deterministic and portable, but the dominant effort of the whole port. Its own crate root flags it as of interest to anyone who wants "a different event loop than the one tokio provides" — precisely event-horizon's brief. See QUIC Transport § Mapping to event-horizon.


Milestones: the 0.x → 1.0 restructure

iroh 1.0 is not an increment; it deletes whole subsystems and QUIC-natively absorbs their jobs. The table below is the evolution the survey documents, subsystem by subsystem.

NOTE

The pinned trees carry no dated changelog of the 0.x release line, and this survey trusts only the pinned sources — so only the 1.0-era tag dates are absolute: noq noq-v1.0.1 released 2026-06-29 (340e9c7); iroh v1.0.1 committed 2026-07-03 (22cac742ca). The "iroh 0.x" column describes the prior architecture each deep-dive contrasts against, not a dated release; treat the ordering as logical, not chronological.

Capabilityiroh 0.xiroh 1.0Surveyed in
NAT-traversal signallingDISCO — a bespoke UDP ping/pong side-protocol using NaCl crypto_box (node key → Curve25519)QUIC-native (QNT)ADD_ADDRESS/REACH_OUT/REMOVE_ADDRESS frames on the encrypted 1-RTT dataplaneNAT Traversal, Identity
Reflexive-address discoverySTUN against relay serversQUIC Address Discovery (/iroh-qad/0) on the main endpoint — no STUN code remainsNet Report, Relay
Connectivity modulemagicsock (MagicSock)socket (Socket, pub(crate))Socket
Path modelDuplicate each datagram onto UDP and relay; DISCO ping/pong picks a winnerRelay and every direct address are concurrent QUIC multipath paths on one connection; switching = flipping a path's PathStatusSocket, QUIC
QUIC libraryquinnnoq fork — adds Multipath, Address Discovery, in-QUIC NAT traversalQUIC Transport
Identity vocabularyNodeId / NodeAddr / NodeTicketEndpointId / EndpointAddr / EndpointTicket — old node… tickets are unparseableIdentity, Wire
Address directorydiscovery (Discovery / DiscoveryItem)address_lookup (AddressLookup / Item); pkarr/DNS-centricAddress Lookup
Relay wire formatDERP-era bespoke framing / magic stringsBinary WebSocket subprotocol iroh-relay-v2 (v1 legacy); the Health frame is removed in v2Relay
Blobs store contractA Store / Map trait hierarchy"Whatever handles the Command enum" over irpcBlobs
Blobs downloaderDial queues, retry backoff, request dedup baked in~550-line re-planning orchestrator + a generic ConnectionPool; those concerns pushed to consumersBlobs
Blobs transfer ALPN/iroh-bytes/4/iroh-bytes/4unchanged across the rename (a deliberate interop-stability point)Blobs
Gossip ALPN/iroh-gossip/0/iroh-gossip/1, now per-instance overridable via Builder::alpnGossip

Quick Navigation

Suggested reading paths

Overview & synthesis

  • Concepts & Vocabulary — the shared glossary: EndpointId, EndpointAddr, tickets, ALPN, path, relay, the 0.x → 1.0 rename map every page relies on.
  • Tokio Concurrency Inventory — the exhaustive census of tasks, channels, locks, select! loops, and blocking work, classified protocol-inherent vs Send + Sync artifact.
  • D Architecture Migration — the capstone: Rust constructs beside proposed D equivalents on event-horizon, the bottlenecks (CPU-bound BLAKE3 on the loop thread, the missing cross-fiber channel primitive), and the sans-io reuse strategy.

Cross-tree

  • event-horizon spec — the D runtime the port targets: completion-first loop, fibers, Scope/race/JoinHandle structured concurrency, capability effects, IoResult!/Outcome!.
  • async-io survey — the prior-art runtime survey; Tokio, Glommio, and monoio are the directly-relevant deep-dives.
  • algebraic-effects corpus — the effect-handler background behind event-horizon's capability layer.

Sources

Each deep-dive carries its own primary-source citations to exact path:lines in the pinned trees; this index's classifications derive from them. The pinned upstream artifacts are: