# iroh SecretKey, PublicKey, and EndpointId: Understanding the Relationship

> Understand the n0-computer iroh SecretKey, PublicKey, and EndpointId relationship. Learn how EndpointId is derived from SecretKey, forming a direct identity chain for your node.

- Repository: [number zero/iroh](https://github.com/n0-computer/iroh)
- Tags: deep-dive
- Published: 2026-06-21

---

**In iroh, `EndpointId` is a type alias for `PublicKey`, which is cryptographically derived from the `SecretKey` via `SecretKey::public()`, creating a direct identity chain where the endpoint's public identifier is exactly its Ed25519 public key.**

The iroh networking library uses Ed25519 cryptography to establish peer identity. In the `n0-computer/iroh` repository, the relationship between `SecretKey`, `PublicKey`, and `EndpointId` forms the foundation of endpoint authentication and network identification.

## How iroh SecretKey, PublicKey, and EndpointId Form a Cryptographic Chain

Iroh implements a strict hierarchical relationship between these three types. The **secret key** holds the private Ed25519 signing material, the **public key** represents the verifiable public counterpart, and the **endpoint ID** serves as the network-visible identifier.

### SecretKey as the Root of Identity

The `SecretKey` struct in [`iroh-base/src/key.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/key.rs) holds the private Ed25519 signing key. This key authenticates the endpoint and cryptographically signs all messages. When you need to prove identity or establish secure connections, the secret key provides the cryptographic material.

### PublicKey and the EndpointId Type Alias

The `PublicKey` is derived directly from the `SecretKey` using the `SecretKey::public()` method. According to the source code in [`iroh-base/src/key.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/key.rs) lines 98-101, this method returns the public counterpart of the signing key.

Critically, `EndpointId` is defined as a type alias for `PublicKey` in [`iroh-base/src/key.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/key.rs) lines 58-70. This means:

- Every endpoint's identifier **is exactly the public key** of its secret key
- No conversion or transformation occurs between `PublicKey` and `EndpointId`
- Two endpoints sharing the same `EndpointId` must possess the same underlying secret key pair

## Implementation in the iroh Crates

The relationship is implemented across the core `iroh-base` and `iroh` crates, with specific file locations handling different aspects of the identity chain.

### iroh-base: Key Generation and Aliasing

In [`iroh-base/src/key.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/key.rs), the library defines the fundamental types:

- **`SecretKey::public()`** (lines 98-101): Derives the public key from the secret
- **`EndpointId` alias** (lines 58-70): Declares `EndpointId` as equivalent to `PublicKey`

When you call `SecretKey::generate()`, the library creates a new random Ed25519 keypair. The public portion is immediately accessible without additional computation.

### iroh: Endpoint Construction and Identity Binding

In [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs), the `Endpoint` builder integrates these cryptographic primitives:

- **Lines 24-31**: The builder stores the `SecretKey` in `EndpointInner` during construction
- **Lines 66-72**: The `Endpoint::id()` method returns the stored public key/endpoint ID
- **Lines 61-64**: The `Endpoint::secret_key()` accessor retrieves the original secret key
- **Lines 24-27**: When no secret key is provided, the builder calls `SecretKey::generate()` automatically

## Practical Usage Examples

### Generating Keys and Deriving EndpointId

When working with iroh directly, you can observe the relationship between these types:

```rust
use iroh_base::{SecretKey, EndpointId};

fn main() {
    // 1. Create a new secret key (randomly)
    let secret = SecretKey::generate();

    // 2. Derive its public key
    let public = secret.public();

    // 3. The endpoint identifier is exactly this public key
    let endpoint_id: EndpointId = public; // type alias, no conversion needed

    // 4. All three are linked
    assert_eq!(endpoint_id, secret.public());
    println!("SecretKey:   {:?}", secret);
    println!("EndpointId:  {}", endpoint_id); // prints hex representation
}

```

### Endpoint Builder Integration

When constructing an endpoint, the builder handles the secret key generation and ID extraction internally:

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

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Builder generates a random SecretKey internally
    let ep = Endpoint::builder(presets::N0).bind().await?;

    // The generated secret key can be inspected
    let secret = ep.secret_key();
    let id = ep.id();               // <-- this is the public key of `secret`
    assert_eq!(id, secret.public());

    println!("Endpoint ID (public key): {}", id);
    Ok(())
}

```

The builder extracts the endpoint ID via `secret_key.public()` and stores it in `EndpointInner`, making the identity available through the `Endpoint::id()` method.

## Summary

- **SecretKey** holds the private Ed25519 signing material in [`iroh-base/src/key.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/key.rs)
- **PublicKey** is derived via `SecretKey::public()` and represents the cryptographic public identity
- **EndpointId** is a type alias for `PublicKey` (lines 58-70 in [`iroh-base/src/key.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/key.rs)), meaning the endpoint's network ID is exactly its public key
- The **Endpoint builder** in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) (lines 24-31) automatically generates or accepts a secret key and exposes the ID via `Endpoint::id()`
- Because `EndpointId` is the public key, any two endpoints with the same ID must share the same underlying secret key pair

## Frequently Asked Questions

### What is the exact relationship between EndpointId and PublicKey in iroh?

`EndpointId` is a type alias for `PublicKey` defined in [`iroh-base/src/key.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/key.rs) lines 58-70. This means they are the same type with different names—`EndpointId` serves as the network identifier while `PublicKey` describes the cryptographic function. No conversion is necessary between them.

### How do I generate a SecretKey and retrieve the corresponding EndpointId?

Call `SecretKey::generate()` to create a random Ed25519 keypair, then use `SecretKey::public()` to retrieve the public key, which is also the `EndpointId`. In [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) lines 24-27, the endpoint builder performs this automatically when binding to a network interface.

### Can two different endpoints have the same EndpointId?

No. Because `EndpointId` is exactly the `PublicKey` derived from the `SecretKey`, and Ed25519 public keys are uniquely determined by their private keys, two endpoints can only share an `EndpointId` if they possess the same `SecretKey`. This cryptographic relationship ensures unique endpoint identification across the network.

### Where is the EndpointId stored in the iroh source code?

The `EndpointId` is stored in `EndpointInner` during endpoint construction, as seen in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) lines 24-31. The `Endpoint::id()` method (lines 66-72) forwards this value, while the underlying `SecretKey` remains accessible via `Endpoint::secret_key()` (lines 61-64).