How EndpointId, PublicKey, and SecretKey Work Together in iroh
In iroh, EndpointId is a type alias for PublicKey, which is cryptographically derived from a SecretKey using Ed25519 signatures, creating a deterministic identity chain where the secret key authenticates the endpoint and its public derivative serves as the network identifier.
The iroh networking library establishes peer identity through a strict cryptographic hierarchy. Understanding the relationship between EndpointId, PublicKey, and SecretKey is essential for implementing secure node authentication, as these three types form the backbone of identity and verification in the n0-computer/iroh protocol.
The Cryptographic Hierarchy
iroh implements a one-way derivation chain: SecretKey → PublicKey → EndpointId. This design ensures that endpoint identities are self-verifiable and cryptographically secure.
SecretKey (the private signing key)
The SecretKey struct holds the private Ed25519 signing key used to authenticate connections and sign protocol messages. Defined in iroh-base/src/key.rs, this type provides the generate() method for creating cryptographically secure random keys, and the public() method for deriving the corresponding public key.
PublicKey (derived from SecretKey)
The PublicKey represents the public counterpart to the secret key. According to the source code in iroh-base/src/key.rs at lines 98-101, calling SecretKey::public() derives the public key deterministically using Ed25519 key generation algorithms. This public key serves as the cryptographic identity that other peers use to verify signatures.
EndpointId (type alias for PublicKey)
EndpointId is defined as a direct type alias for PublicKey in iroh-base/src/key.rs at lines 58-70. This means every endpoint's network identifier is exactly its public key, with no additional encoding or transformation layer. Because EndpointId is just the public key, any two endpoints sharing the same EndpointId must possess the same underlying SecretKey.
Implementation in the iroh Source Code
When constructing an Endpoint, the builder either accepts a user-provided SecretKey or generates one automatically using SecretKey::generate(). As implemented in iroh/src/endpoint.rs at lines 24-31, the builder extracts the endpoint's ID via secret_key.public() and stores it in the internal EndpointInner struct.
The Endpoint::id() method defined at lines 66-72 in iroh/src/endpoint.rs simply returns this pre-computed value, while Endpoint::secret_key() (lines 61-64) provides access to the original secret key for persistence or cryptographic operations.
Practical Usage Examples
Manual Key Generation and Identity Verification
The following example demonstrates the direct relationship between the three types:
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 using the high-level Endpoint API, the relationship is managed automatically:
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(())
}
Summary
SecretKeyholds the private Ed25519 signing key and serves as the root of identity.PublicKeyis deterministically derived fromSecretKeyvia thepublic()method defined iniroh-base/src/key.rs.EndpointIdis a type alias forPublicKey, meaning the endpoint's network address is exactly its public key.- The
Endpointbuilder iniroh/src/endpoint.rsstores the secret key and exposes its public derivative through theid()method. - Because
EndpointIdequalsPublicKey, possessing theSecretKeyproves cryptographic ownership of theEndpointId.
Frequently Asked Questions
Is EndpointId just a wrapper around PublicKey?
No, EndpointId is not a wrapper but a direct type alias for PublicKey defined in iroh-base/src/key.rs at lines 58-70. This means the two types are identical and can be used interchangeably without conversion overhead or runtime cost.
How do I retrieve the EndpointId from an existing Endpoint?
Call the Endpoint::id() method implemented in iroh/src/endpoint.rs at lines 66-72. This method returns the pre-computed public key that was derived from the endpoint's secret key during the builder's bind() phase.
Can I use an existing SecretKey to create an Endpoint with a specific EndpointId?
Yes. When building an Endpoint, provide your existing SecretKey to the builder. The resulting endpoint will have an EndpointId equal to secret_key.public(), ensuring deterministic identity across sessions. If you don't provide a secret key, the builder generates a random one via SecretKey::generate().
What happens if two endpoints use the same SecretKey?
Since EndpointId is derived deterministically from SecretKey, two endpoints using the same secret key will have identical EndpointId values. This creates a cryptographic identity collision where both endpoints claim the same network address, which can cause routing conflicts in peer-to-peer discovery systems like pkarr or DNS.
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 →