How to Use Post-Quantum Key Exchange with Iroh

Enable post-quantum key exchange in Iroh by building the tls-aws-lc-rs feature and configuring the aws-lc-rs cryptographic provider to advertise the X25519MLKEM768 key exchange group.

Iroh leverages rustls for all TLS traffic, allowing you to swap cryptographic providers to enable post-quantum security. By activating the tls-aws-lc-rs feature and configuring the key exchange groups (kx_groups), you can secure connections against quantum computing threats while maintaining compatibility with classical peers. This guide explains the exact patterns implemented in the n0-computer/iroh repository.

Understanding Iroh's Cryptographic Providers

Iroh supports pluggable cryptographic providers through rustls. The provider you choose determines which key exchange algorithms are available during the TLS handshake.

The Default Ring Provider

By default, Iroh uses the ring cryptographic provider. This provider supports classical key exchange groups including X25519 and SECP256R1, but does not implement any post-quantum algorithms. If you build Iroh without the tls-aws-lc-rs feature, all connections use classical cryptography only.

The AWS-LC-RS Provider for Post-Quantum Support

To enable post-quantum key exchange, you must use the aws-lc-rs provider. This backend implements X25519MLKEM768, a hybrid post-quantum key exchange group that combines X25519 elliptic curve cryptography with the ML-KEM-768 (Kyber) lattice-based algorithm. When configured correctly, this provider negotiates post-quantum security automatically during the TLS handshake.

Configuring Post-Quantum Key Exchange

Implementing post-quantum security requires three specific steps: enabling the correct feature flag, constructing a custom cryptographic provider, and injecting it into your endpoint builder.

Step 1: Enable the tls-aws-lc-rs Feature

You must compile Iroh with the tls-aws-lc-rs feature flag to access the AWS-LC-RS provider. Add this to your Cargo.toml or pass it during compilation:

cargo run --example prefer-pq-key-exchange --features=tls-aws-lc-rs

Without this feature, the aws-lc-rs modules are not available, and you cannot construct a post-quantum capable provider.

Step 2: Construct the Crypto Provider

Create a CryptoProvider from aws_lc_rs::default_provider() and modify its kx_groups vector to control algorithm preference. The provider's kx_groups list determines which algorithms are advertised during the TLS handshake, ordered by preference.

In iroh/src/endpoint.rs (lines 761-767), the Endpoint::builder method accepts a custom provider via the crypto_provider() method, which is then consumed by the TLS configuration logic in iroh/src/tls.rs (lines 49-79).

Step 3: Inject the Provider into the Endpoint Builder

Use Endpoint::builder(...).crypto_provider(Arc::new(provider)) to apply your custom configuration. The builder pattern ensures that all TLS connections—including relay HTTPS, PKARR publishing, and direct peer connections—use your specified cryptographic policy.

Implementation Patterns

Iroh ships with two reference implementations demonstrating different post-quantum security policies. Choose the pattern that matches your security requirements.

Prefer Post-Quantum (with Fallback)

This configuration advertises the post-quantum group first but maintains classical algorithms as fallbacks. It ensures maximum compatibility while preferring quantum-resistant connections when both peers support them.

use std::sync::Arc;
use iroh::endpoint::{Endpoint, presets::N0};
use rustls::crypto::aws_lc_rs::{self, kx_group};

const ALPN: &[u8] = b"iroh-example/prefer-pq-key-exchange/0";

#[tokio::main]
async fn main() -> n0_error::Result<()> {
    // Build a provider that offers the PQ group first.
    let mut provider = aws_lc_rs::default_provider();
    provider.kx_groups = vec![
        kx_group::X25519MLKEM768, // PQ group – tried first
        kx_group::X25519,
        kx_group::SECP256R1,
        kx_group::SECP384R1,
    ];
    let pq = Arc::new(provider);

    // Server side
    let server = Endpoint::builder(N0)
        .crypto_provider(pq.clone())
        .alpns(vec![ALPN.to_vec()])
        .bind()
        .await?;
    let server_addr = server.addr();

    // Client side (same provider, so both prefer PQ)
    let client = Endpoint::builder(N0).crypto_provider(pq).bind().await?;
    let conn = client.connect(server_addr, ALPN).await?;
    // … send/receive data …
    Ok(())
}

See the complete implementation in iroh/examples/prefer-pq-key-exchange.rs.

Post-Quantum Only (Strict Mode)

This configuration enforces exclusive use of the X25519MLKEM768 group. Any peer that does not support this algorithm will fail to complete the TLS handshake, creating a quantum-resistant-only network segment.

use std::sync::Arc;
use iroh::{endpoint::{Endpoint, presets::Empty}, RelayMode};
use rustls::crypto::aws_lc_rs;

const ALPN: &[u8] = b"iroh-example/pq-key-exchange/0";

#[tokio::main]
async fn main() -> n0_error::Result<()> {
    let pq = pq_only_provider();

    // Server – only the PQ group is offered.
    let server = Endpoint::builder(Empty)
        .crypto_provider(pq.clone())
        .alpns(vec![ALPN.to_vec()])
        .relay_mode(RelayMode::Disabled)
        .bind()
        .await?;
    let server_addr = server.addr();

    // Client – uses the same provider, so the handshake succeeds.
    let client = Endpoint::builder(Empty)
        .crypto_provider(pq)
        .relay_mode(RelayMode::Disabled)
        .bind()
        .await?;
    let conn = client.connect(server_addr, ALPN).await?;
    // … exchange data …
    Ok(())
}

// Helper that creates a provider offering **only** the PQ group.
fn pq_only_provider() -> Arc<rustls::crypto::CryptoProvider> {
    let mut p = aws_lc_rs::default_provider();
    p.kx_groups = vec![aws_lc_rs::kx_group::X25519MLKEM768];
    Arc::new(p)
}

See the complete implementation in iroh/examples/pq-only-key-exchange.rs.

Key Source Files

The following files in the n0-computer/iroh repository contain the implementation details for post-quantum key exchange:

Summary

  • Post-quantum key exchange requires the tls-aws-lc-rs feature and the aws-lc-rs cryptographic provider.
  • Configure the kx_groups vector to control whether you prefer PQ (with classical fallback) or require PQ exclusively.
  • Use Endpoint::builder(...).crypto_provider(...) to inject your configured provider into the Iroh stack.
  • Both communicating peers must support the chosen key exchange groups to successfully complete the handshake.
  • Reference implementations are available in the iroh/examples/ directory for both "prefer" and "strict" post-quantum modes.

Frequently Asked Questions

What is the X25519MLKEM768 key exchange group?

X25519MLKEM768 is a hybrid post-quantum key exchange mechanism that combines X25519 (elliptic curve Diffie-Hellman) with ML-KEM-768 (Module Lattice-based Key Encapsulation Mechanism, formerly Kyber). This hybrid approach provides protection against attacks by quantum computers while maintaining the security guarantees of well-established classical cryptography. The AWS-LC-RS provider implements this group, allowing Iroh to negotiate quantum-resistant TLS connections.

Do both peers need the aws-lc-rs provider to use post-quantum key exchange?

Yes, both peers must support the X25519MLKEM768 group to complete a post-quantum handshake. If you configure "prefer PQ" mode (with fallback to classical groups), Iroh will negotiate classical algorithms with peers that lack post-quantum support. However, if you configure "PQ-only" mode, the handshake will fail immediately when connecting to peers using the default ring provider or other implementations that do not support ML-KEM-768.

Can I use post-quantum key exchange with Iroh's public relay servers?

Only if the relay infrastructure is also built with the tls-aws-lc-rs feature. Since the cryptographic provider is shared across all TLS connections—including relay HTTPS and PKARR publishing—any Iroh component that shares the same crypto_provider must support the configured key exchange groups. If you use a PQ-only configuration, you must ensure that any n0 public relays or discovery services you connect to are also built with post-quantum support enabled.

Is there a performance impact when using post-quantum cryptography?

Yes, but it is generally minimal for the key exchange phase. ML-KEM-768 operations are computationally inexpensive compared to traditional RSA operations, though they involve slightly larger key sizes and handshake messages compared to pure X25519. The hybrid X25519MLKEM768 group performs both classical and post-quantum key exchanges simultaneously, adding negligible latency to connection establishment while providing quantum resistance. For most Iroh use cases, the security benefits outweigh the minor performance overhead.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →