a70e68c7bd
* Smolmix documentation * Add smolmix docs: landing page, tutorials, and developer page links * Add Exit Gateway services page (NR vs IPR) and link from existing docs * Update auto-generated command and API outputs * Reorg of tutorials and architecture pages * License information + remove TODO from docs.rs visibile comment + reorg readme * Add versions file for doc-wide versioning * Relative -> absolute links * Relative -> absolute links * Update license + add old tutorial code as examples * Streamline smolmix docs * Clippy * Clean up doc comments * Last pass * Add larger file download to list * set new versions * Clippy * Remove blake pin from docs + add version range to root Cargo.toml * Format example logging * Remove crate blocked component * Loose whitespace * Add doc verification script for inline mdx * Formatting * Components regen * Reorg + tighten text * Voicing cohesion pass + remove bloated examples * Voicing cont. * Reduce max download size * Small suggested clarifications * Max/docs voicing consistency (#6769) * Reduce max download size * voicing consistency across docs * New landing order w smolmix * Tweaks * Final tweaks
91 lines
3.8 KiB
Plaintext
91 lines
3.8 KiB
Plaintext
---
|
|
title: "Nym Client Message Queue and Cover Traffic"
|
|
description: "How the Nym client queues messages, sends cover traffic via Poisson processes, and manages Sphinx packet streams to prevent timing attacks."
|
|
schemaType: "TechArticle"
|
|
section: "Developers"
|
|
lastUpdated: "2026-03-15"
|
|
---
|
|
|
|
import { Callout } from 'nextra/components'
|
|
|
|
# Message Queue
|
|
|
|
<Callout type="info">
|
|
Useful for understanding how the Nym Client works internally, but only of practical interest if you are using the [`Mixnet`](/developers/rust/mixnet) module of the Rust SDK and interacting with the client at a low level. The [`Stream`](/developers/rust/stream) module (`AsyncRead + AsyncWrite` channels) abstracts most of this away.
|
|
</Callout>
|
|
|
|
## Sphinx Packet Streams
|
|
Clients, once connected to the Mixnet, **are always sending traffic into the Mixnet**; as well as the packets that you as a developer are sending from your application logic, they send [cover traffic](/network/mixnet-mode/cover-traffic) at a constant rate defined by a Poisson process. This is part of the network's mitigation of timing attacks.
|
|
|
|
There are two constant streams of sphinx packets leaving the client at the rate defined by the Poisson process.
|
|
- one that is solely cover traffic
|
|
- one that sends a mixture of cover and 'real' traffic
|
|
|
|
|
|
```mermaid
|
|
---
|
|
config:
|
|
theme: neo-dark
|
|
layout: elk
|
|
|
|
title: Cover Traffic Stream
|
|
---
|
|
sequenceDiagram
|
|
box Local Machine
|
|
participant App Logic
|
|
participant Nym Client
|
|
end
|
|
participant Entry Gateway
|
|
|
|
loop Cover Traffic Stream
|
|
Nym Client->>Nym Client: Delay
|
|
Nym Client->>Entry Gateway: Cover traffic
|
|
end
|
|
|
|
|
|
```
|
|
|
|
```mermaid
|
|
---
|
|
config:
|
|
theme: neo-dark
|
|
layout: elk
|
|
|
|
title: Mixed Stream
|
|
---
|
|
sequenceDiagram
|
|
box Local Machine
|
|
participant App Logic
|
|
participant Nym Client
|
|
end
|
|
participant Entry Gateway
|
|
|
|
loop Cover + Real Traffic Stream
|
|
Nym Client->>Nym Client: Check internal queue + delay
|
|
Nym Client->>Entry Gateway: Cover traffic
|
|
alt Packets with App Payload
|
|
App Logic-->>Nym Client: Send(bytes): add to internal queue
|
|
Nym Client->>Nym Client: Check internal queue: bytes to send
|
|
Nym Client->>Nym Client: Encrypt & packetise bytes
|
|
Nym Client->>Entry Gateway: Real Packets
|
|
Nym Client->>Nym Client: Check internal queue: bytes to send
|
|
Nym Client->>Nym Client: Encrypt & packetise bytes
|
|
Nym Client->>Entry Gateway: Real Packets
|
|
Nym Client->>Nym Client: Check internal queue: queue empty
|
|
end
|
|
Nym Client->>Nym Client: Delay
|
|
Nym Client->>Entry Gateway: Cover traffic
|
|
end
|
|
```
|
|
|
|
> Since Sphinx packets are indistinguishable to an external observer, the only difference between 'real' and cover traffic is whether the payload is empty or not. This can be only known to the eventual receiver of the packet.
|
|
|
|
## What does `send()` do then?
|
|
|
|
When passing a message to a client (however you do it, either piping messages from an app to a standalone client or via one of the `send` functions exposed by the SDKs), you are **putting that message into the queue** to be source encrypted and sent in the future, in order to ensure that traffic leaving the client does so in a manner that to an external observer is uniform / does not create any 'burst' or change in traffic timings that could aid traffic analysis.
|
|
|
|
## Note on Client Shutdown
|
|
Accidentally dropping a client before your message has been sent is possible and should be avoided (see the [troubleshooting guide](/developers/rust/mixnet/troubleshooting) for more on this). To avoid it:
|
|
- keep your client process alive, even if you are not expecting a reply to your message
|
|
- (with the SDKs) disconnect your client properly so that the message queue is flushed of Sphinx packets with real payloads.
|