New: a threat-model-first guide to choosing your network defence, plus the nym-smoldvpn dVPN package and nym-swizzle sender hygiene.
Network
Worked Examples
Private Messaging

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.

L1Directory observer
VantageReads a public contact directory (registered handles, public group listings).
SeesPublic account handles and listed group memberships.
Cannot seeMessage content, who messages whom, or message timing.

The invariants the app must hold:

InvariantStatementDepends on
A. Social graphThe 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 timingArrival 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.

Sees

  • Real client IP
  • Your account and every message recipient
  • The arrival time of every message

Residual / countermeasure

  • The social graph is reconstructed with no adversarial effort. This is the baseline network protection must improve on.

Sees

  • That you are connected to the chat server
  • Your request and response rhythm, which reveals a live conversation

Can't see

  • Which other user you are conversing with (pairing two clients needs both endpoints)

Sees

  • Both endpoints, so it pairs the two conversing clients by correlated timing

Cons / mitigations

  • Needs IP hiding, then network-layer timing protection and metadata-private delivery

Fit

  • Baseline only: offers no protection

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.

Sees

  • Exit gateway IP
  • Your account and every message recipient
  • The arrival time of every message

Can't see

  • Client IP

Residual / countermeasure

  • Hiding your IP removes one identifier. The server still authenticates your account and delivers each message to a named recipient, so it reconstructs the social graph from account metadata regardless of transport.
  • Message and reply timing at the server still reveals a live conversation. Only end-to-end delivery (no untrusted server) or a metadata-private protocol removes this leak.

Sees

  • Constant-size packets at a Poisson rate with cover traffic
  • That the client uses the Nym mixnet

Can't see

  • Whether you are in a conversation, the volume, or the activity

Residual / countermeasure

  • Cover traffic hides even that you are conversing from a local observer. This is the layer the mixnet actually protects for messaging.

Sees

  • Per-packet timing across both endpoints (hampered by mixing delays and cover traffic)

Residual / countermeasure

  • Mixing degrades the timing correlation that pairs the two conversing clients, but long-running conversations of many messages weaken that resistance (an open question).

Pros

  • Client IP hidden; mixing hides the conversation from a local observer and degrades global timing correlation

Cons / mitigations

  • The chat server still learns who you message and when
  • Slow (5-hop and mixing delays)

Fit

  • Hides the conversation from the network, not from the server
  • For server-side metadata privacy, run end-to-end instead
⚠️

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.