End-to-end encryption for video conferences, in Rust. Key management and codec-aware media protection, with no server in the trust boundary and no coordinator among the participants.
[dependencies]
chorus = "0.1"use chorus::{Codec, Conference, Policy, Recipient};
// Alice starts a conference.
let (mut alice, _bootstrap) = Conference::create(Policy::leaderless(2))?;
// Bob generates identity material out of band and hands over his package.
let bob = chorus::Joining::new(Policy::leaderless(2))?;
let out = alice.invite(&bob.key_package())?;
let welcome = out.iter()
.find(|m| m.to == Recipient::Peer(bob.identity()))
.expect("welcome");
let (mut bob, _) = bob.accept(&welcome.payload)?;
// Media.
let frame = [0, 0, 0, 1, 0x65, 0xDE, 0xAD];
let sealed = alice.protect(Codec::H264, &frame, true)?;
let (from, plain) = bob.open(&sealed)?;A continuous group key agreement with a media layer. Participants publish signed operations into a causal graph; contributions carry fresh entropy sealed individually to each recipient; the group key is derived from the graph's frontier. Anyone can contribute, admit, evict or repair at any time.
| property | how |
|---|---|
| forward secrecy | prekey secrets destroyed once channels open; chain keys overwritten every step |
| post-compromise security | rotate a prekey, contribute once |
| leaderless | no coordinator, no tree root, no distinguished participant |
| agreement | the key version is a pure function of the operations received |
| malicious insiders | equivocation produces transferable proof and eviction |
| untrusted servers | servers may drop, reorder, duplicate, partition and inject |
Media encryption is codec aware: frames are encrypted in place, so NAL headers, OBU headers and the VP8 uncompressed chunk stay readable and authenticated. A selective forwarding unit keeps routing and dropping frames without holding any key, and cannot alter a byte of what it reads.
| crate | contents |
|---|---|
chorus |
the Conference type: one participant's whole view of a call |
chorus-core |
the key management construction |
chorus-media |
codec-aware frame protection |
chorus-crypto |
primitives, all from established crates |
Each is usable alone.
Nothing here is homemade.
| role | primitive | crate |
|---|---|---|
| AEAD | AEGIS-256 | aegis |
| hash, KDF, MAC | BLAKE3 | blake3 |
| key agreement | X25519 | x25519-dalek |
| signature | Ed25519 | ed25519-dalek |
KEM (pq) |
ML-KEM-768 | ml-kem |
| erasure | — | zeroize |
| constant time | — | subtle |
The AEGIS-256 implementation is pinned to the official CFRG draft test vectors
in chorus-crypto, so a dependency update that changes the cipher fails the
build rather than the call.
| feature | effect |
|---|---|
std (default) |
standard library; without it the crates are no_std + alloc |
hwaes (default) |
AEGIS-256 with hardware AES; needs a C compiler |
portable |
AEGIS-256 in pure Rust, no C toolchain |
pq |
X25519 + ML-KEM-768 hybrid |
One hundred participants, single machine, release build
(cargo run -p chorus --release --example scale):
| operation | messages | upload | per recipient |
|---|---|---|---|
| rotation | 1 | 20.9 kB | 20.9 kB |
| join | 4 | 887 kB | 870 kB (welcome) |
| eviction, quorum of two | 4 | 41.7 kB | — |
| heal (rotate + rekey) | 2 | 20.9 kB | — |
Media: 33 µs to protect a 40 kB H.264 frame, about 9.6 Gbit/s, with 45 bytes of overhead per frame.
cargo test --workspace # 165 tests
cargo test -p chorus --release # includes the randomized suite
cargo +nightly fuzz run codec_canonical # six coverage-guided targets
cargo run -p chorus --release --example scaleThe randomized suite runs a hostile network — loss, reordering, partition,
eviction, bit-flipped injection — and checks five invariants after every step.
The default sweep is 12 seeds; CHORUS_FUZZ_SEEDS and CHORUS_FUZZ_STEPS
raise it. A 120-seed, 90-step sweep performs about 220 000 checks.
docs/protocol.md— how the construction works, and the wire formatdocs/security.md— threat model, properties, and what is not provideddocs/integration.md— wiring it to WebRTC and to a forwarding unit
Read docs/security.md before deploying. It is explicit about the limits,
including history growth and the absence of history compaction.
Apache-2.0.