Files
nym/smolmix/core/src/ARCHITECTURE.md
mfahampshire a70e68c7bd Max/smolmix docs (#6716)
* 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
2026-05-13 11:19:44 +00:00

4.4 KiB

Architecture

smolmix tunnels TCP and UDP over the Nym mixnet. It exposes TcpStream and UdpSocket types compatible with the async Rust ecosystem (tokio-rustls, hyper, tokio-tungstenite), with all traffic routed through the mixnet so a network observer cannot correlate source and destination.

Stack

┌─────────────────────────────────────────────────────────────────┐
│  User code                                                      │
│  tunnel.tcp_connect() → TcpStream (AsyncRead + AsyncWrite)      │
│  tunnel.udp_socket()  → UdpSocket (send_to / recv_from)         │
├─────────────────────────────────────────────────────────────────┤
│  tokio-smoltcp::Net                                             │
│  Owns the smoltcp Interface + SocketSet + async poll loop.      │
│  Manages TCP state machines, retransmits, port allocation.      │
├─────────────────────────────────────────────────────────────────┤
│  NymAsyncDevice  (device.rs)                                    │
│  Stream + Sink adapter for raw IP packets over mpsc channels.   │
├─────────────────────────────────────────────────────────────────┤
│  NymIprBridge  (bridge.rs)                                      │
│  Background task shuttling packets between channels and the     │
│  mixnet. Bundles outgoing packets with MultiIpPacketCodec       │
│  (required by the IPR protocol).                                │
├─────────────────────────────────────────────────────────────────┤
│  IpMixStream → MixnetClient → Nym mixnet → IPR exit node        │
└─────────────────────────────────────────────────────────────────┘

Data flow

outgoing: smoltcp → NymAsyncDevice (Sink) → channel → NymIprBridge → IpMixStream → mixnet
incoming: mixnet → IpMixStream → NymIprBridge → channel → NymAsyncDevice (Stream) → smoltcp

tokio-smoltcp drives the smoltcp poll loop, TCP state machines, port allocation, and waker management. Its only requirement is a device producing and consuming raw IP packets. NymAsyncDevice satisfies that by wrapping the mpsc channel ends in the Stream and Sink traits.

Key design decisions

Single async device adapter

All traffic flows through one NymAsyncDevice. New transport types (e.g. ICMP) are added as methods on Tunnel rather than as separate devices, so neither the device nor the bridge needs to change. smoltcp already supports ICMP sockets: enable the socket-icmp feature in Cargo.toml, add a method like Tunnel::icmp_socket() that calls the appropriate Net method, and re-export the socket type from lib.rs.

Tokio-only

The bridge, SDK (IpMixStream, MixnetClient), and shutdown signalling are tokio-based. The data-plane channels use futures::channel::mpsc because UnboundedSender implements Sink, which tokio-smoltcp's AsyncDevice trait requires.

An earlier version had a sync smoltcp Device adapter for use without tokio-smoltcp, but it still required a tokio runtime underneath (for the bridge and SDK), so it provided no real runtime independence and just duplicated the bridging logic. Supporting alternative runtimes would require replacing the bridge, SDK, and channel layers, which is the scope of a separate crate rather than a feature flag on this one.

Unbounded channels

The channels between the device and bridge are unbounded. Backpressure is applied at the mixnet layer (the IPR protocol), not at the channel level. If that assumption changes, switch to bounded channels with a drop policy.

Medium::Ip (no Ethernet framing)

Raw IP packets in and out, matching what the IPR protocol expects.