Threat model first

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.

Layer architecture

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.

  1. L8ApplicationUI, contacts, notifications, map
  2. L7Mediacall negotiation, ICE, SRTP, SFrame, Opus/AV1
  3. L6Payloadtyped versioned messages; CBOR; capability-gated
  4. L5Deliverystore-carry-forward, fragmentation, acks, bearer handoff
  5. L4Sessionhandshake and ratchet; forward secrecy; group keying
  6. L3Identitykeypairs, tiers, contact exchange, verification
  7. L2OverlayDHT lookup, onion circuits, relay mailboxes
  8. L1Obfuscationframing, padding, pluggable transports
  9. 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.

Cryptography policy

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.

Post-quantum

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.

Identity

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.