smolmix
smolmix is a TCP/UDP tunnel over the Nym mixnet. It uses a userspace network stack smoltcp (opens in a new tab) to provide TcpStream and UdpSocket types that work with the async tokio (opens in a new tab) Rust ecosystem e.g. tokio-rustls (opens in a new tab), hyper (opens in a new tab), tokio-tungstenite (opens in a new tab), etc.
The TcpStream type implements tokio's AsyncRead/AsyncWrite traits and UdpSocket provides send_to/recv_from for datagrams.
┌──────────────────────────────────────────────────────────────┐
│ Your application (TLS, HTTP, WebSocket, DNS, etc.) │
│ └─ smolmix::TcpStream / UdpSocket │
│ └─ smoltcp (userspace TCP/IP) │
│ └─ Nym mixnet → IPR exit gateway → internet │
└──────────────────────────────────────────────────────────────┘Traffic exits the mixnet at an IPR (Internet Packet Router) exit gateway. The exit IP is the gateway's, not yours.
Runtime and platform support
Other runtimes
smolmix currently requires tokio. The internal pipeline is tokio-based: the bridge task that shuttles packets to the mixnet, the Nym SDK's MixnetClient, and the tokio-smoltcp (opens in a new tab) reactor that drives the userspace TCP/IP stack all run on the tokio runtime.
This means smolmix is not directly compatible with alternative async runtimes like smol (opens in a new tab) or async-std (opens in a new tab). If you need to use smolmix from another runtime, the async-compat (opens in a new tab) crate can bridge the gap.
The WebAssembly build (browsers and WebViews)
The WebAssembly build of smolmix powers the mix-* packages mix-tunnel, mix-fetch, mix-dns, and mix-websocket. The wasm is inlined into mix-tunnel, so apps install one of those packages rather than building the crate themselves.
It runs in any JavaScript runtime that provides WebSocket, Web Workers, and WebAssembly. That means desktop browsers and mobile WebViews alike, so hybrid app shells (Capacitor, Ionic, Cordova, react-native-webview) are in scope, not just web pages. It does not run in a bare Node.js or React Native Hermes/JSC runtime, which lack Web Workers (and, for Hermes, WebAssembly). For native mobile or server targets, compile the Rust crate itself rather than using the wasm packages.
Installation
Add smolmix to your Cargo.toml:
[dependencies]
smolmix = "1.21.1"
nym-bin-common = { version = "1.21.1", features = ["basic_tracing"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }tokio is a transitive dependency of smolmix, but you need to enable rt-multi-thread (the default runtime spun up by #[tokio::main]) and macros (for the #[tokio::main] attribute itself).
nym-bin-common is optional but recommended: it sets up tracing (opens in a new tab) logging so you can see mixnet connection progress.
Minimum Rust version: 1.87+
smolmix's API may still change between minor releases. Pin a version rather than tracking the latest, and read the changelog before bumping.
From Git
For unreleased changes, import directly from the repository:
smolmix = { git = "https://github.com/nymtech/nym", branch = "develop" }When to use smolmix
| smolmix | Stream module | mixFetch | SOCKS client | |
|---|---|---|---|---|
| Layer | Transport (TCP/UDP) | Message (multiplexed streams) | HTTP | TCP (SOCKS proxy) |
| Controls both sides? | No (proxy mode) | Yes (E2E) | No (proxy mode) | No (proxy mode) |
| API | TcpStream, UdpSocket | AsyncRead + AsyncWrite | fetch() replacement | SOCKS4/5 protocol |
| Composability | Full: TLS, HTTP, WebSocket, DNS, etc. stack on top | Byte streams only | HTTP(S) only | Application-dependent |
| Best for | Reaching external services from Rust with standard networking | Peer-to-peer / E2E protocols between Nym clients | Browser HTTP requests | Legacy apps with SOCKS support |
Security model
Traffic is Sphinx-encrypted inside the mixnet. Past the Exit Gateway, it travels over the public internet to the destination, the same as any other server-initiated connection. Protect the payload at the application layer with TLS (rustls (opens in a new tab)), Noise Protocol (snow (opens in a new tab)), or equivalent, as you would on a direct connection.
The mixnet hides your identity from the destination and your destination from the network, but the IPR exit gateway sees the destination IP and port, and sees your payload only if you didn't encrypt it. If you connect with TLS (as in the TCP example (opens in a new tab)), the IPR only sees ciphertext addressed to the destination, not its contents. Plaintext HTTP is fully readable at the exit.
The full model (what each hop sees, trust boundaries, and a comparison with Tor and VPNs) is on Exit security.
Examples
Runnable examples in smolmix/core/examples/ (opens in a new tab). Each is self-contained; read the //! doc comments at the top of each file for a walkthrough.
cargo run -p smolmix --example <name>All examples accept --ipr <ADDRESS> to target a specific exit node (pass a Recipient address to Tunnel::builder().ipr_address()).
| Example | Source | What it demonstrates |
|---|---|---|
| UDP | udp.rs (opens in a new tab) | DNS lookup via hickory-proto (opens in a new tab), sending a raw UDP query to 1.1.1.1:53 through the mixnet. Runs a clearnet hickory-resolver (opens in a new tab) lookup alongside it to compare resolved IPs and latency |
| TCP | tcp.rs (opens in a new tab) | HTTPS request via hyper (opens in a new tab) + tokio-rustls (opens in a new tab). Fetches Cloudflare's /cdn-cgi/trace to show that the exit IP differs from clearnet |
| WebSocket | websocket.rs (opens in a new tab) | WebSocket echo against ws.postman-echo.com via tokio-tungstenite (opens in a new tab) + tokio-rustls (opens in a new tab). Runs the same stack over clearnet first, so the only thing that changes between runs is the underlying TCP stream |
| TCP download | tcp_download.rs (opens in a new tab) | DNS-over-mixnet + multi-request HTTP/1.1 download over a single keep-alive connection, the full real-world pattern |
Architecture
The internal stack (smoltcp reactor, device adapter, bridge task, packet flow) is documented in ARCHITECTURE.md (opens in a new tab). This is also the crate-level documentation on docs.rs.
API reference
Full API documentation is available on docs.rs/smolmix (opens in a new tab).