Iroh Key Derivation and Signing: Working with SecretKey and PublicKey
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, the SecretKey struct wraps a SigningKey from the ed25519_dalek crate:
#[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:
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct PublicKey(CompressedEdwardsY);
Iroh defines EndpointId as a direct alias to PublicKey:
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 (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) 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):
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
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
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, the Endpoint builder consumes the secret key to establish identity:
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 uses the public key as the record owner:
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: Core definitions forSecretKeyandPublicKey, includinggenerate,public,sign, andverifymethods.iroh/src/tls/resolver.rs: Constructs self-signed TLS certificates usingself.key.public().as_bytes()(line 67) for the certificate subject.iroh/src/endpoint.rs: High-level API that stores the secret key and exposes its public ID viasecret_key().public().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: Relay server that identifies clients usingkey.public().
Summary
- Iroh uses a single Ed25519 key pair per endpoint, with
SecretKeyfor signing andPublicKeyas the identifier. - The
SecretKey::generatemethod creates cryptographically secure keys using OS entropy. SecretKey::public()deterministically derives thePublicKey, which doubles as theEndpointId.- Signing occurs via
SecretKey::sign, whilePublicKey::verifyuses 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 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. 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 (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.
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 →