# Iroh Key Derivation and Signing: Working with SecretKey and PublicKey

> Learn how Iroh uses SecretKey for signing and PublicKey for verification and identification. Work with Iroh key derivation and signing easily.

- Repository: [number zero/iroh](https://github.com/n0-computer/iroh)
- Tags: how-to-guide
- Published: 2026-07-11

---

**Iroh uses a single Ed25519 key pair per endpoint where `SecretKey` handles signing and `PublicKey` (aliased as `EndpointId`) serves as the unique identifier and verification key.**

The `n0-computer/iroh` repository implements a robust identity system based on Ed25519 cryptography. Understanding Iroh key derivation and signing with SecretKey/PublicKey is essential for building secure peer-to-peer applications, as these keys authenticate every endpoint and sign all network messages.

## Core Key Types in Iroh

### SecretKey Structure and Generation

Located in [`iroh-base/src/key.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/key.rs), the `SecretKey` struct wraps a `SigningKey` from the `ed25519_dalek` crate:

```rust
#[derive(Clone, zeroize::ZeroizeOnDrop)]
pub struct SecretKey(SigningKey);

```

The `ZeroizeOnDrop` derive ensures sensitive key material is cleared from memory when the key is dropped. The `SecretKey::generate` method uses the OS RNG to produce 32 random bytes and construct a new signing key.

### PublicKey and EndpointId

The public counterpart uses `CompressedEdwardsY` for efficient representation:

```rust
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct PublicKey(CompressedEdwardsY);

```

Iroh defines `EndpointId` as a direct alias to `PublicKey`:

```rust
pub type EndpointId = PublicKey;

```

This means your public key doubles as your network address, eliminating the need for separate identity and transport identifiers.

## Key Derivation and Signing Implementation

### Generating Cryptographically Secure Keys

Call `SecretKey::generate()` to create fresh key material. This method in [`iroh-base/src/key.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/key.rs) (lines 18-20) sources entropy from the operating system and initializes the `SigningKey` with 32 random bytes.

### Deriving the Public Identifier

The `public()` method (lines 99-101 in [`iroh-base/src/key.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/key.rs)) derives the `PublicKey` from the secret key by calling `self.0.verifying_key()`. This deterministic derivation ensures that each secret key maps to exactly one endpoint ID.

### Signing Messages and Verification

Sign data using `SecretKey::sign` (lines 23-26), which delegates to `self.0.sign(msg)`:

```rust
pub fn sign(&self, msg: &[u8]) -> Signature {
    self.0.sign(msg)
}

```

Verification uses `PublicKey::verify` (lines 33-35), which calls `ed25519_dalek::VerifyingKey::verify_strict` to enforce strict signature verification and prevent signature malleability.

## Practical Code Examples

### Generating a New Key Pair

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

let secret_key = SecretKey::generate();          // 32-byte random secret
let endpoint_id: PublicKey = secret_key.public(); // unique endpoint identifier
println!("Endpoint ID: {}", endpoint_id.fmt_short());

```

### Signing and Verifying Messages

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

let secret = SecretKey::generate();
let msg = b"hello iroh";

// Signing
let signature: Signature = secret.sign(msg);

// Verification with the derived public key
let pub_key = secret.public();
pub_key.verify(msg, &signature).expect("signature must be valid");

```

### Integrating with the Endpoint Builder

In [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs), the `Endpoint` builder consumes the secret key to establish identity:

```rust
use iroh::Endpoint;

let secret_key = SecretKey::generate();
let ep = Endpoint::builder()
    .secret_key(secret_key)
    .bind_port(0)
    .run()
    .await?;
println!("Running as {}", ep.secret_key().public().fmt_short());

```

### Publishing PKARR Records

The PKARR publisher in [`iroh/src/address_lookup/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/pkarr.rs) uses the public key as the record owner:

```rust
use iroh::address_lookup::pkarr::PkarrPublisher;

let secret = SecretKey::generate();
let publisher = PkarrPublisher::builder()
    .secret_key(secret.clone())
    .build(/* TLS config */);
publisher.publish("example.com", secret.public()).await?;

```

## Key Files and Architecture

The implementation spans several critical files:

- **[`iroh-base/src/key.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/key.rs)**: Core definitions for `SecretKey` and `PublicKey`, including `generate`, `public`, `sign`, and `verify` methods.
- **[`iroh/src/tls/resolver.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls/resolver.rs)**: Constructs self-signed TLS certificates using `self.key.public().as_bytes()` (line 67) for the certificate subject.
- **[`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs)**: High-level API that stores the secret key and exposes its public ID via `secret_key().public()`.
- **[`iroh/src/address_lookup/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/pkarr.rs)**: Publishes DNS-like records signed with the secret key and indexed by the public key.
- **[`iroh-relay/src/server/http_server.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/server/http_server.rs)**: Relay server that identifies clients using `key.public()`.

## Summary

- Iroh uses a single Ed25519 key pair per endpoint, with `SecretKey` for signing and `PublicKey` as the identifier.
- The `SecretKey::generate` method creates cryptographically secure keys using OS entropy.
- `SecretKey::public()` deterministically derives the `PublicKey`, which doubles as the `EndpointId`.
- Signing occurs via `SecretKey::sign`, while `PublicKey::verify` uses strict verification to prevent malleability.
- These keys underpin TLS certificates, PKARR publishing, and relay authentication throughout the Iroh stack.

## Frequently Asked Questions

### How does Iroh generate secure secret keys?

Iroh's `SecretKey::generate` method in [`iroh-base/src/key.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-base/src/key.rs) uses the operating system's RNG to produce 32 random bytes, feeding them into the Ed25519 `SigningKey` constructor. The `ZeroizeOnDrop` trait ensures keys are securely cleared from memory when no longer needed.

### What is the relationship between PublicKey and EndpointId 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). This design means your cryptographic public key serves as your network address, ensuring that endpoint identification and cryptographic verification use the same 32-byte identifier.

### How does Iroh prevent signature malleability attacks?

The `PublicKey::verify` method delegates to `ed25519_dalek::VerifyingKey::verify_strict`, which enforces strict verification standards. This prevents attackers from generating alternative valid signatures for the same message and public key.

### Where is the secret key used in Iroh's TLS implementation?

In [`iroh/src/tls/resolver.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls/resolver.rs) (line 67), the secret key's public component is converted to bytes via `self.key.public().as_bytes()` to create the subject field of self-signed TLS certificates, binding the TLS identity to the Ed25519 public key.