Difference Between iroh EndpointId, PublicKey, and SecretKey Explained
In iroh, EndpointId is simply a type alias for PublicKey, which is cryptographically derived from the SecretKey using Ed25519 key pairs, forming a direct identity chain where the secret key signs messages and the public key identifies the endpoint on the network.
The n0-computer/iroh distributed systems framework implements a strict cryptographic hierarchy for peer identity. Understanding the difference between these three types is essential for secure peer-to-peer networking, as they collectively handle authentication, signing, and network addressing within the iroh protocol stack.
The Cryptographic Hierarchy
The relationship between SecretKey, PublicKey, and EndpointId follows a deterministic one-way derivation implemented in the iroh-base crate:
- SecretKey – Holds the private Ed25519 signing key used to authenticate messages and establish identity.
- PublicKey – The public counterpart derived deterministically from the secret key via elliptic curve cryptography.
- EndpointId – A type alias for
PublicKeythat semantically represents the network-facing identifier of an endpoint.
This architecture ensures that every endpoint's network identity is exactly the public key of its underlying secret key pair, with no additional abstraction layer or hashing involved.
SecretKey: The Private Signing Authority
The SecretKey contains the sensitive cryptographic material that proves ownership of an endpoint. In iroh-base/src/key.rs, lines 98-101, the SecretKey::public() method performs the Ed25519 derivation to generate the corresponding public key. When an endpoint is constructed without an explicit key, the builder automatically generates a random secret key using SecretKey::generate() as seen in iroh/src/endpoint.rs, lines 24-27.
PublicKey: The Verifiable Identity
The PublicKey allows other peers to verify signatures and confirm message authenticity without accessing private material. This type represents the raw cryptographic identity that can be shared freely across the network. According to the source code in iroh-base/src/key.rs, lines 98-101, the public key is computed deterministically from the secret key using standard Ed25519 derivation.
EndpointId: The Network Alias
EndpointId is defined in iroh-base/src/key.rs, lines 58-70, as a direct type alias for PublicKey. This design choice provides semantic clarity—distinguishing between a generic public key and one specifically used as an endpoint identifier—while maintaining zero-cost interoperability. Because it is merely an alias, any PublicKey can be used as an EndpointId without conversion or runtime overhead.
Implementation in the iroh Source Code
The connection between these types is enforced at the API level in both the cryptographic primitives and the endpoint builder.
Key Derivation in iroh-base
The iroh-base/src/key.rs file defines the core relationship. Lines 58-70 establish the EndpointId alias, while lines 98-101 implement the SecretKey::public() method that performs the actual cryptographic derivation. This ensures that the three concepts remain tightly coupled at the type system level.
Endpoint Builder Integration
When constructing an Endpoint in iroh/src/endpoint.rs, the builder stores the secret key in EndpointInner (lines 24-31). The Endpoint::id() method (lines 66-72) simply returns the pre-computed public key, while Endpoint::secret_key() (lines 61-64) provides access to the private material. This implementation guarantees that ep.id() is always exactly ep.secret_key().public().
Practical Code Examples
Generating Keys and Accessing the EndpointId
use iroh_base::{SecretKey, EndpointId};
fn main() {
// Generate a new random Ed25519 secret key
let secret = SecretKey::generate();
// Derive the public key (zero-cost operation)
let public = secret.public();
// EndpointId is exactly the public key
let endpoint_id: EndpointId = public;
// All three references point to the same identity
assert_eq!(endpoint_id, secret.public());
println!("Endpoint ID: {}", endpoint_id);
}
Using the Endpoint Builder
use iroh::{Endpoint, endpoint::presets};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Builder generates SecretKey automatically if not provided
let ep = Endpoint::builder(presets::N0).bind().await?;
// Access the generated secret and its public identifier
let secret = ep.secret_key();
let id = ep.id(); // Returns the PublicKey as EndpointId
// Verify the relationship
assert_eq!(id, secret.public());
println!("Endpoint ID: {}", id);
Ok(())
}
Summary
- SecretKey contains the private Ed25519 signing material and must remain confidential to the node.
- PublicKey is cryptographically derived from
SecretKeyvia thepublic()method defined iniroh-base/src/key.rs. - EndpointId is a type alias for
PublicKey, meaning the endpoint's network identity is exactly its public key with no additional encoding. - The implementation in
iroh/src/endpoint.rsenforces thatEndpoint::id()always returnssecret_key.public(), ensuring cryptographic consistency.
Frequently Asked Questions
Can two endpoints have the same EndpointId with different SecretKeys?
No. Because EndpointId is exactly the PublicKey, and the public key is deterministically derived from the SecretKey via Ed25519, two endpoints sharing the same EndpointId must possess identical underlying secret key pairs. This cryptographic binding ensures that endpoint identity is unforgeable without access to the private key material.
Why does iroh use a type alias for EndpointId instead of a wrapper struct?
The type alias defined in iroh-base/src/key.rs, lines 58-70, provides semantic clarity for API consumers while maintaining zero-cost interoperability with PublicKey operations. This design allows functions to accept EndpointId specifically when an endpoint identifier is semantically required, while avoiding conversion overhead or wrapper indirection that would occur with a distinct struct type.
How do I persist a SecretKey between application restarts?
The SecretKey type implements serialization traits that allow you to export the private key bytes. Store these bytes securely using OS-level secret management (such as keychains or encrypted configuration files), then deserialize and provide the key to Endpoint::builder() when reconstructing the endpoint. Never log the secret key or transmit it over the network, as possession of the secret key grants complete control over the endpoint's identity.
Is EndpointId used for encryption or just identification?
The EndpointId (being the public key) is primarily used for identification and signature verification. While Ed25519 keys can be used in X25519 key exchange protocols for encryption, in iroh the EndpointId serves as the stable network address and authentication credential. It identifies which peer sent a message and verifies that message's cryptographic signature, but does not directly encrypt payload data.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →