Files
iroh-gossip-rendezvous/README.md
T
swaitsandClaude Opus 4.7 7e39781318 Initial release: v0.1.0
Passphrase-based peer rendezvous for iroh-gossip swarms over the public
Mainline DHT. Two nodes that share a passphrase + application salt find
each other and join the same gossip topic — no bootstrap server, no
prior knowledge of peer addresses.

The algorithm is a clock-free variant of HyParView-style partition
healing on BEP 44 mutable items, with K-sharded slots, logical aging
with random-tie eviction, vouching of up to V neighbors at age 1, and
a two-layer AEAD record envelope. Full spec in PROTOCOL.md.

Ships with:

* 119 tests (unit / property / integration / doctest) all green
* 100% mutation-testing catch rate (cargo-mutants)
* cargo-fuzz harnesses for the parse surface
* Kani proofs of no-UB / no-panic on crypto::epoch_of and
  wire::decode_entries across their full symbolic input spaces
* Stateright distributed-system model: safety invariants S1 + S2
  proved exhaustively for N ≤ 6, K ≤ 3; liveness witness under weak
  fairness
* Miri green on the synchronous modules
* cargo-deny + cargo-audit clean
* criterion benches
* Full-matrix CI (Linux + macOS + Windows × stable + MSRV 1.93.0)
* Dedicated nightly lane for Miri / mutation / fuzz / Kani / Stateright

Pinned iroh 0.98.x. License MIT.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 22:52:46 -06:00

126 lines
5.3 KiB
Markdown

# iroh-gossip-rendezvous
[![crates.io](https://img.shields.io/crates/v/iroh-gossip-rendezvous.svg)](https://crates.io/crates/iroh-gossip-rendezvous)
[![docs.rs](https://img.shields.io/docsrs/iroh-gossip-rendezvous)](https://docs.rs/iroh-gossip-rendezvous)
[![CI](https://github.com/swaits/iroh-gossip-rendezvous/workflows/CI/badge.svg)](https://github.com/swaits/iroh-gossip-rendezvous/actions)
[![MSRV](https://img.shields.io/badge/MSRV-1.93.0-blue)](#msrv)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
**Zero-configuration peer rendezvous for [iroh-gossip] swarms.** Two nodes
that share a passphrase and an application label find each other over the
public [Mainline DHT] and join the same gossip topic — no bootstrap server,
no prior knowledge of peer addresses.
```rust,no_run
use iroh_gossip_rendezvous::Rendezvous;
# async fn run() -> anyhow::Result<()> {
let rendezvous = Rendezvous::join("my-shared-passphrase", "my-app/v1").await?;
// Send to the swarm.
rendezvous.broadcast(bytes::Bytes::from_static(b"hello")).await?;
// Receive swarm events.
let mut events = rendezvous.subscribe();
while let Ok(event) = events.recv().await {
println!("{event:?}");
}
# Ok(()) }
```
## How it works
The crate implements a clock-free variant of HyParView-style partition
healing on top of BEP 44 mutable items. Every `(passphrase, app_salt)` pair
deterministically derives:
- A gossip `TopicId` (via HKDF-SHA256).
- `K` independent DHT slot keys (default `K=3`), each with its own Ed25519
signing key and a per-slot AEAD wrapper key.
Nodes publish their endpoint ID to one of the `K` slots and read from a
changing subset of slots to discover peers. Records age out naturally, so
crashed or silently-departed nodes don't clutter the DHT indefinitely. A
two-layer AEAD envelope (per-record one-time key wrapped under a
seq-ratcheted per-epoch key) ensures content confidentiality against DHT
observers.
See **[PROTOCOL.md](PROTOCOL.md)** for the full algorithm specification.
See **[ARCHITECTURE.md](ARCHITECTURE.md)** for a module map.
## Correctness
The crate ships with a test suite that goes beyond unit tests:
- **Property tests** (proptest) for wire format, merge invariants, and AEAD
roundtrips.
- **Integration tests** driving multi-node scenarios over an in-memory DHT:
cold start, partition healing, asymmetric minority visibility.
- **Mutation testing** (cargo-mutants) on the algorithmic core.
- **Fuzz harnesses** (cargo-fuzz) for `decode_entries`, `crypto::open`,
merge, and wire-format roundtrip.
- **Bounded model checking** (Kani) of **absence of undefined behavior**
on pure algorithmic entry points: `crypto::epoch_of` never panics /
overflows for any `(i64 seq, u64 epoch_size ≥ 1)`; `wire::decode_entries`
never panics on arbitrary byte input. Structural invariants (merge size
bound, age bound, roundtrip) are covered by the stronger proptest +
Stateright combination — Kani's niche here is UB-absence at the
slice/iterator boundary.
- **Distributed-system model checking** (Stateright): bounded safety +
liveness witness for `N ≤ 6, K ≤ 3` under weak fairness; randomized
exploration of 10⁷ states for `N = 20`.
- **Miri** UB checks on the synchronous modules (keys, wire, crypto, merge).
The precise claim: *the record-size and age invariants always hold across
all explored reachable states up to N=6, K=3; under a weak-fairness
assumption on action scheduling, any bipartite-partitioned initial state
eventually reaches a state where both components overlap. For larger N,
randomized exploration has found no counterexample. This is not a proof for
unbounded deployments — it is the strongest tractable evidence available
short of a hand proof.*
## Security
See [SECURITY.md](SECURITY.md) for the threat model and known limitations.
Short version: the design protects against DHT observers and passive
eavesdroppers, but not against a compromise of the passphrase (no forward
secrecy) or a malicious member (no post-compromise security). For threat
models requiring those properties, layer MLS / RFC 9420 on top.
## Features
| Feature | Default | Purpose |
|---|---|---|
| `sim` | off | Discrete-event simulator (`examples/simulator.rs`) + test-support exports |
| `kani` | off | Build Kani proof harnesses (`#[kani::proof]` functions) |
| `miri-compat` | off | Skip Miri-incompatible tests (`#[cfg_attr(miri, ignore)]`) |
| `mainline-live` | off | Tests against the real public Mainline DHT (flaky, nightly-only) |
| `test-support` | off | Exposes `Builder::dht_backend` for injecting an in-memory DHT in integration tests |
## MSRV
Minimum Supported Rust Version: **1.93.0**. Enforced in CI. Bumps are minor
releases; we don't raise MSRV without releasing a new minor version.
Pinned iroh / iroh-gossip major versions: `0.98.x`. Bumping the iroh major
will be a minor version of this crate.
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md). Local testing via [`just`]:
```sh
just check # fmt + clippy + nextest + doctests (fast CI lane)
just all # everything including miri, kani, stateright
```
See the [CHANGELOG](CHANGELOG.md) for release history.
## License
MIT. See [LICENSE](LICENSE).
[iroh-gossip]: https://docs.rs/iroh-gossip
[Mainline DHT]: https://en.wikipedia.org/wiki/Mainline_DHT
[`just`]: https://just.systems/