What this defends against, written down
Everything in the design follows from the threat model, so it is stated explicitly — including the parts where the answer is we do not defend against that. Claiming protection that does not exist is worse than claiming none, because a reader stops looking.
In scope
We defend against
- Relay and infrastructure operators. They see padded, opaque blobs. No plaintext, no sender or recipient identity, no social graph, no group membership.
- DHT participants. Nodes servicing lookups cannot determine who or what is being looked up.
- Peer carriers. A device relaying someone else's message learns neither sender nor recipient — only an opaque, rotating mailbox ID — and cannot read the payload.
- Compromise of any single node, including a relay we run ourselves.
- Local device seizure, to the extent achievable: encrypted at rest, forward secrecy, no plaintext key material at rest.
- Passive local network observers, partially. They see encrypted traffic to unremarkable endpoints, but timing is not defended.
Out of scope
We explicitly do not
- A global passive adversary correlating traffic worldwide. Defeating this requires a mixnet, which makes voice unusable.
- Endpoint compromise. A rooted phone with a keylogger defeats every design.
- A user who chooses a low-anonymity identity tier and is then deanonymised through that channel. This is a disclosed tradeoff, not an accident.
- Traffic-volume analysis. A watching adversary can tell you sent something large.
One tension is kept visible rather than smoothed over: SMS as a bearer hands the carrier a record that two phone numbers communicated — precisely the metadata the rest of the system exists to hide. It stays in the design as a censorship-resistant last resort, and it is never an automatic fallback.
Nine layers, narrow interfaces
Every algorithm and transport carries a versioned registry ID negotiated per session. Nothing is hardcoded, so any layer can be replaced without a flag day.
- L8ApplicationUI, contacts, notifications, map
- L7Mediacall negotiation, ICE, SRTP, SFrame, Opus/AV1
- L6Payloadtyped versioned messages; CBOR; capability-gated
- L5Deliverystore-carry-forward, fragmentation, acks, bearer handoff
- L4Sessionhandshake and ratchet; forward secrecy; group keying
- L3Identitykeypairs, tiers, contact exchange, verification
- L2OverlayDHT lookup, onion circuits, relay mailboxes
- L1Obfuscationframing, padding, pluggable transports
- L0BearerQUIC, BLE, Wi-Fi Direct, LoRa, QR, SMS
The interface that matters most
Two overlay profiles, declared by the payload
LowLatency is interactive, best-effort, and may be direct — used for voice and video. Private is high-latency tolerant, store-and-forward and metadata-protected — used for everything else.
This single split is what lets text run over onion-routed paths while a call still sounds good. Designs that skip it ship an elegant specification and an unusable phone call.
Overlay privacy
Rotating blinded lookup keys
A naive Kademlia DHT is a metadata leak machine: the nodes you query learn what you are looking for. Lookup keys are instead derived from the identity key blinded by the current time period, following Tor's v3 onion service directories.
A node storing or serving a descriptor cannot determine whose it is; only a party who already knows the identity key can compute the blinded key for a period; descriptors are encrypted to the requesting contact; and lookups traverse onion circuits, so the serving node does not learn the querier's address.
Adopt where a standard exists and fits. Implement only where none does.
Novel cryptographic construction is a cost, not a feature — every hand-rolled scheme is one nobody else has analysed.
| Component | Choice | Rationale |
|---|---|---|
| Primitives | RustCrypto / dalek — X25519, Ed25519, ChaCha20-Poly1305, SHA-2/3, HKDF, ML-KEM | Audited, permissively licensed. Hand-rolled versions fail silently through side channels. |
| 1:1 handshake | PQXDH-style hybrid — X25519 + ML-KEM, from the published spec | Harvest-now-decrypt-later is live for a tool positioned like this. |
| 1:1 ratchet | Double Ratchet, implemented from Signal's published spec | The spec is public; implementing it avoids libsignal's AGPL-3.0. |
| Group keying | MLS (RFC 9420) via openmls | Standardised and formally analysed. Reimplementing it would be a research project with no upside. |
| Seed backup | BIP39 phrases, SLIP-39 for Shamir | Standard, interoperable, well-tested wordlists. |
| Media E2EE | SFrame | Lets a selective forwarding unit forward without decrypting. |
| NAT traversal | ICE (RFC 8445), client-side via library | Standard, and the hard part is well solved. |
| Encoding | CBOR | Compact, with deterministic profiles available. JSON is disqualified on size alone. |
| QR framing | RaptorQ fountain codes (RFC 6330) | The receiver needs any K frames plus a little, not specific ones. |
Implemented here, because nothing fits
DHT blinding, modelled on Tor's rend-spec-v3 blinded descriptors. The device sigchain, modelled on Keybase's design. Anonymous relay allocation, because standard TURN's credential model is actively wrong for this threat model. And the bearer policy engine, the delivery layer and payload adaptation, where there is no prior art at this combination.
Every primitive stays swappable by negotiated ciphersuite ID. That is non-negotiable regardless of what is adopted — it is what makes a future migration a version bump rather than a flag day.
Hybrid, not post-quantum only
Classical and post-quantum algorithms concatenated, so the construction holds if either survives. ML-KEM and ML-DSA are recently standardised and comparatively young; lattice cryptanalysis is an active field, and a classical break would be catastrophic for a PQ-only design. Pure post-quantum is a bet on lattices. Hybrid is not.
The symmetric side is satisfied by construction: Grover's algorithm gives only a quadratic speedup, so the 256-bit keys already in use retain roughly 128-bit security against a quantum adversary. The work is entirely in key encapsulation and signatures.
The cost, stated plainly
A hybrid Ed25519 + ML-DSA-65 signature is about 3.4 KB against 64 bytes classical — a fiftyfold increase. On IP, BLE and Wi-Fi bearers this is irrelevant. On the constrained bearers it is emphatically not.
| Bearer | Effective rate | One hybrid PQ signature |
|---|---|---|
| QUIC / BLE / Wi-Fi | ≥100 kbps | negligible |
| LoRa, US 915 | ≈680 B/s | ≈5 s |
| Acoustic AFSK 1200 | ≈150 B/s | ≈23 s |
| LoRa, EU 868 — 1% duty | ≈7 B/s | ≈8 minutes |
What makes it viable: signatures appear at setup, never in steady state
The Double Ratchet authenticates messages with symmetric MACs rather than signatures, so post-quantum cost is paid at identity creation, session establishment, and the rare sigchain entry for adding or revoking a device — and on no ordinary message at all. A text sent over EU LoRa carries no post-quantum signature, because the session that authenticates it was established earlier over a fatter bearer. The airtime accounting already handles the setup case: it refuses to run a fresh handshake over EU 868 and defers it until a better bearer appears.
You choose how findable you are
Tiers are per-identity, and one install may hold several personas that share no linkage between them.
| Tier | Mechanism | Discoverability | Anonymity |
|---|---|---|---|
| 0 | Ephemeral key, QR or in person only | None | Maximum |
| 1 | Persistent key plus a shareable contact blob | Only via blobs you hand out | High |
| 2 | Tier 1 plus a claimed nickname in a decentralised registry | Searchable by nickname | Medium |
| 3 | Tier 2 plus private set intersection on a hashed identifier | Findable by contacts who know your phone or email | Lower |
Tier choice must not be observable on the wire
If only 5% of users pick Tier 0, being Tier 0 is itself an identifying signal — anonymity loves company. So all tiers produce byte-identical handshakes and message framing; the differences exist only in what a user opts to publish to discovery mechanisms; and the registry and lookup services are strictly additive, never part of the message path.
Tier 0 is single-device by construction and has no backup. An ephemeral identity that can be restored is not ephemeral, so this falls out of the design rather than being special-cased.
Multi-device
A signed chain, not a synchronised list
The device set is a sigchain with checkpoints to bound its growth and explicit rollback rejection. Fork response is user-selectable rather than decided for you, and verification is a safety number drawn from the PGP word list — a list chosen because the words are meant to be read aloud over a voice channel and compared.
Backup
A warning that has to be specific
Backup is a BIP39 phrase, with SLIP-39 Shamir sharing for splitting it. What a phrase does and does not restore has to be said precisely, because a vague warning is the same as none: the compensating control is that the consequences are spelled out at the point of writing the phrase down, not in documentation the user will not read.
The design is written down, and so is what it leaves open
The decisions above are recorded with their reasoning, and the questions still being worked through are numbered and carry deadlines rather than sitting as ambient future work. This is early software, and it should be read and run rather than relied on.