Private Messaging
A messaging app sends every message through a chat server. The server delivers each message to a named recipient, so it is the party the client must talk to directly. That makes it the primary adversary.
What must not leak
Message content is the obvious secret, and end-to-end encryption already protects it. The harder secret is the social graph: who talks to whom, and when. That metadata survives content encryption, and it is often more revealing than the words.
The threat model
The primary adversary is L2, the chat server, alongside L3 network observers. The dominant vector is V2 timing: request and response bursts pair the two conversing clients, and the server routes by account.
The messaging app also faces an application-specific public observer.
| L1 | Directory observer |
|---|---|
| Vantage | Reads a public contact directory (registered handles, public group listings). |
| Sees | Public account handles and listed group memberships. |
| Cannot see | Message content, who messages whom, or message timing. |
The invariants the app must hold:
| Invariant | Statement | Depends on |
|---|---|---|
| A. Social graph | The adversary cannot reconstruct who communicates with whom. | P1 everywhere, but that alone is not enough: a server routing by account learns the graph regardless of transport. Only end-to-end or a metadata-private protocol removes it. |
| B. Conversation timing | Arrival timing must not reveal that two accounts are in a live conversation. | V2 timing discipline at the network layer; metadata-private delivery against the server. |
Unprotected: the conversation is in the open
The client talks to the chat server directly. The server sees the client IP, the account, every recipient and every timestamp. A global network observer pairs the two conversing clients by their request and response bursts.
Protected: the mixnet hides the conversation from the network
Fixed-size Sphinx packets take three mix layers with per-hop delays, Poisson sending and cover traffic. The exit gateway forwards to the chat server. Mixing breaks the timing correlation a network observer relied on.
Read the verdicts together. The local observer (L3L) gets P1 yes: cover traffic hides even that you are conversing. The global observer (L3G) drops to partial: mixing degrades the end-to-end timing that pairs the two clients. The server (L2) still gets P2 no: it authenticates your account and routes each message to a named recipient. So it reconstructs the social graph regardless of transport.
Hiding your IP removes one identifier. It does not hide the account graph, because the server needs the recipient to deliver the message. The mixnet's real win here is against the network, not against the server. To remove the server-side social graph, run end to end so that no untrusted server exists.
Where to go next
- Choose a Defence picks a configuration for your case.
- Build it maps the configuration you picked to a package, for Rust and for the browser.
- The two-layer model explains why transport alone is never the whole answer.
- Packet Mixing shows how per-hop delays and cover traffic break timing correlation.