What Is the n0-Computer/iroh Protocol? A Deep Dive into QUIC-Based P2P Networking

The n0-computer/iroh protocol is a peer-to-peer networking stack built on QUIC that uses public keys for endpoint identity, enabling automatic mutual authentication without a central PKI while providing built-in NAT traversal and encrypted relay fallback.

The n0-computer/iroh protocol serves as the network layer for the iroh library, a Rust-based toolkit for building distributed applications. By leveraging QUIC (defined in IETF RFC 9000) and eliminating traditional certificate authorities, it creates a secure, globally routable network where every peer is identified by its cryptographic public key.

Identity and Authentication via Public Keys

Instead of relying on domain names or centralized certificate authorities, the n0-computer/iroh protocol derives identity directly from cryptography. Every Endpoint holds a SecretKey, and its corresponding public key becomes the EndpointId. This ID functions as the TLS certificate's subject during the handshake, as implemented in iroh/src/endpoint.rs (lines 24-31).

This design provides automatic mutual authentication—both endpoints verify each other's public keys during the TLS handshake without requiring a separate PKI infrastructure. The EndpointId serves as both the identity and the address, making peers globally routable regardless of their underlying IP addresses.

QUIC Transport and Protocol Selection

The protocol uses the noq QUIC implementation from the noq crate for transport. When establishing connections, the library configures TLS with the endpoint's secret key and registers Application-Layer Protocol Negotiation (ALPN) strings to identify supported protocols.

In iroh/src/endpoint.rs (lines 1170-1190), the connect_with_opts method creates a QUIC client configuration that negotiates these ALPNs during the handshake. Each application protocol is identified by a specific ALPN string (such as b"/iroh/echo/1"), allowing a single endpoint to multiplex multiple protocols over one QUIC connection.

Protocol Routing with the Router

Incoming connections are dispatched through the Router, which maps ALPN strings to user-defined handlers. The ProtocolHandler trait, defined in iroh/src/protocol.rs (lines 27-45), requires implementers to handle incoming Connection objects.

To register a protocol, developers use Router::builder(endpoint).accept(ALPN, handler).spawn(), creating a clean separation between transport concerns and application logic. This architecture allows endpoints to simultaneously support multiple protocols—such as file transfer, chat, and streaming—over a single network port.

Connection Establishment: Hole-Punching and Relay Fallback

The n0-computer/iroh protocol implements sophisticated NAT traversal to establish direct connections between peers behind firewalls. After the QUIC handshake completes, peers attempt direct UDP communication via hole-punching. If this fails, the connection falls back to a relay server (the "home relay") without dropping the encrypted session.

Relays forward encrypted packets addressed to an EndpointId but cannot decrypt payload data, as all traffic remains encrypted under QUIC/TLS. The address discovery mechanism uses Pkarr/DNS to publish an endpoint's public addresses and relay information under its EndpointId, allowing peers to resolve IDs to reachable sockets before connecting. This logic is handled in iroh/src/endpoint.rs (lines 1840-1865) via the addr and watch_addr methods.

Zero-RTT Performance Optimization

For latency-sensitive applications, the protocol supports 0-RTT (Zero Round Trip Time) data transmission. The ProtocolHandler::on_accepting method, documented in iroh/src/protocol.rs (lines 28-44), allows handlers to take control of a connection before the handshake fully completes. This enables servers to begin processing requests immediately, reducing connection latency to a single packet round trip.

Security Model

The security architecture rests on three pillars:

  • Public-key authentication: No certificate authorities are required; peers authenticate via cryptographic signatures exchanged during the TLS handshake.
  • End-to-end encryption: All traffic is encrypted under QUIC/TLS, including when traversing relay servers.
  • Relay privacy: Relay servers only forward encrypted packets and cannot read payload data or identify the ultimate destination beyond the EndpointId.

Practical Implementation Example

The following example demonstrates the canonical echo protocol, showing how to create endpoints, register protocols, and establish connections:

use iroh::{
    Endpoint,
    endpoint::{presets, Connection},
    protocol::{AcceptError, ProtocolHandler, Router},
};

const ALPN: &[u8] = b"/iroh/echo/1";

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Accepting side
    let server = Endpoint::bind(presets::N0).await?;
    let router = Router::builder(server.clone())
        .accept(ALPN, Echo)
        .spawn();

    // Connecting side
    let client = Endpoint::bind(presets::N0).await?;
    let conn = client.connect(server.addr(), ALPN).await?;
    let (mut send, mut recv) = conn.open_bi().await?;
    send.write_all(b"Hello, iroh!").await?;
    send.finish()?;
    let reply = recv.read_to_end(1024).await?;
    assert_eq!(&reply, b"Hello, iroh!");

    // Cleanup
    router.shutdown().await?;
    server.close().await;
    client.close().await;
    Ok(())
}

#[derive(Debug, Clone)]
struct Echo;

impl ProtocolHandler for Echo {
    async fn accept(&self, connection: Connection) -> Result<(), AcceptError> {
        let (mut send, mut recv) = connection.accept_bi().await?;
        tokio::io::copy(&mut recv, &mut send).await?;
        send.finish()?;
        connection.closed().await;
        Ok(())
    }
}

To customize relay behavior, configure the endpoint builder:

let endpoint = Endpoint::builder(presets::N0)
    .relay_mode(RelayMode::Custom(custom_map))
    .bind()
    .await?;

For 0-RTT support, implement the on_accepting method:

impl ProtocolHandler for MyZeroRtt {
    async fn on_accepting(&self, accepting: Accepting) -> Result<Connection, AcceptError> {
        let conn = accepting.into_0rtt().await?;
        Ok(conn)
    }

    fn accept(&self, _connection: Connection) -> impl Future<Output = Result<(), AcceptError>> + Send {
        async { Ok(()) }
    }
}

Summary

  • Public-key identity: The n0-computer/iroh protocol uses EndpointId (derived from SecretKey) as the TLS certificate subject, eliminating the need for certificate authorities.
  • QUIC-based transport: Built on the noq crate with ALPN-based protocol multiplexing handled by the Router in iroh/src/protocol.rs.
  • Automatic NAT traversal: Attempts direct hole-punching first, then falls back to encrypted relay servers without compromising security.
  • Address discovery: Uses Pkarr/DNS to publish and resolve endpoint addresses under the public key identity.
  • Extensible architecture: New protocols are implemented via the ProtocolHandler trait and registered with specific ALPN strings.

Frequently Asked Questions

What transport protocol does the n0-computer/iroh protocol use?

The protocol is built on QUIC (IETF RFC 9000), using the noq Rust implementation. This provides stream multiplexing, congestion control, and built-in TLS encryption at the transport layer.

How does iroh handle peers behind NATs or firewalls?

The protocol first attempts hole-punching to establish direct UDP paths after the QUIC handshake. If direct connection fails, it transparently falls back to relay servers that forward encrypted packets without decrypting them, ensuring connectivity even when both peers are behind restrictive NATs.

What is the purpose of ALPN strings in iroh?

Application-Layer Protocol Negotiation (ALPN) strings identify specific protocols running over the QUIC connection. The Router in iroh/src/protocol.rs uses these strings to dispatch incoming connections to the appropriate ProtocolHandler implementations, enabling multiple protocols to share a single endpoint.

How does iroh ensure security without a central certificate authority?

Security relies on public-key cryptography rather than centralized trust. Each endpoint generates its own SecretKey, and the corresponding public key becomes the EndpointId. During the TLS handshake, peers mutually authenticate by verifying these public keys, creating a trust model where identity is self-certified and globally unique.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →