How EndpointId, PublicKey, and SecretKey Work in iroh: Identity and Authentication Explained

In iroh, EndpointId is a type alias for PublicKey, which is cryptographically derived from SecretKey, forming a chain where the secret key authenticates the endpoint and the public key identifies it.

In the iroh networking crate, identity and authentication rely on a tightly coupled trio of types: SecretKey, PublicKey, and EndpointId. Understanding the relationship between these three concepts is essential for building secure peer-to-peer applications with iroh. This article breaks down how these types connect in the source code and how they function in practice.

The Cryptographic Relationship Between SecretKey, PublicKey, and EndpointId

SecretKey as the Private Foundation

The SecretKey holds the private Ed25519 signing key used to authenticate the endpoint. According to the iroh source code, this type is defined in iroh-base/src/key.rs and provides the cryptographic root of trust for any endpoint.

PublicKey as the Verifiable Identity

Derived directly from the SecretKey via the public() method, the PublicKey represents the public portion of the key pair. In iroh-base/src/key.rs at lines 98-101, the SecretKey::public() method returns a PublicKey that can be used to verify signatures generated by the secret key.

EndpointId as the Network Identifier

EndpointId is defined as a type alias for PublicKey in iroh-base/src/key.rs at lines 58-70. This means every endpoint's identifier is exactly the public key of its secret key, ensuring that network identity is cryptographically bound to the authentication key.

How the Connection Is Implemented in iroh

When building an Endpoint, the builder either accepts a user-provided SecretKey or generates one automatically using SecretKey::generate(). The builder then extracts the endpoint's ID via secret_key.public() and stores it in EndpointInner as shown in iroh/src/endpoint.rs at lines 24-31.

The Endpoint::id() method simply forwards this stored value, as implemented in iroh/src/endpoint.rs at lines 66-72. Similarly, Endpoint::secret_key() provides access to the secret key at lines 61-64.

The flow follows this exact chain:

  1. SecretKey generates or accepts the private key material.
  2. PublicKey derives from SecretKey::public().
  3. EndpointId aliases PublicKey, making them identical types for network identification.

Practical Usage Examples

Manual Key Generation and Relationship Verification

use iroh_base::{SecretKey, EndpointId};

fn main() {
    // Generate a new secret key
    let secret = SecretKey::generate();
    
    // Derive the public key
    let public = secret.public();
    
    // EndpointId is exactly this public key
    let endpoint_id: EndpointId = public;
    
    // Verify the relationship
    assert_eq!(endpoint_id, secret.public());
    println!("Endpoint ID: {}", endpoint_id);
}

Using the Endpoint Builder with Auto-Generated Keys

use iroh::{Endpoint, endpoint::presets};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Builder generates SecretKey internally if not provided
    let ep = Endpoint::builder(presets::N0).bind().await?;
    
    // Access the generated keys
    let secret = ep.secret_key();
    let id = ep.id();
    
    // Verify ID is the public component of the secret
    assert_eq!(id, secret.public());
    println!("Endpoint ID: {}", id);
    Ok(())
}

Summary

  • SecretKey holds the private Ed25519 signing key and serves as the root of authentication.
  • PublicKey derives from SecretKey via SecretKey::public() and acts as the verifiable identity.
  • EndpointId is a type alias for PublicKey, meaning the endpoint's network identifier is exactly its public key.
  • The Endpoint builder in iroh/src/endpoint.rs manages this relationship automatically, storing the secret key and exposing the ID via endpoint.id().

Frequently Asked Questions

Is EndpointId just a PublicKey?

Yes. In the iroh source code, EndpointId is defined as a type alias for PublicKey in iroh-base/src/key.rs at lines 58-70. They are the same type, meaning any function accepting an EndpointId can accept a PublicKey directly without conversion.

Can I use a custom SecretKey when creating an Endpoint?

Yes. The Endpoint builder accepts a user-provided SecretKey. If none is provided, the builder automatically generates one using SecretKey::generate() during the bind() process, as seen in iroh/src/endpoint.rs at lines 24-31.

How does the Builder handle SecretKey generation?

When building an endpoint without an explicit secret key, the implementation in iroh/src/endpoint.rs calls SecretKey::generate() to create a random Ed25519 key pair. It then stores this in EndpointInner and derives the EndpointId from secret_key.public().

Where are these types defined in the source code?

The SecretKey, PublicKey, and EndpointId types are defined in iroh-base/src/key.rs. The Endpoint integration that connects these types to the networking stack is implemented in iroh/src/endpoint.rs, specifically in the builder pattern and the id() accessor methods.

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 →