Web Wallet vs Native Wallets
Which transports run where. The dividing line is one question: can the platform open a raw UDP WireGuard socket? The browser sandbox can’t; desktop and mobile can.
| Capability | WebBrowser sandbox | DesktopRust native app | MobileiOS (Swift) / Android (Kotlin) |
|---|---|---|---|
| dVPN / nym-smol-dvpn (WireGuard) | ❌no raw UDP socket in the sandbox | ✅ | ✅via uniffi bindings |
| nym-smolmix | ❌ | ✅ | ✅via uniffi bindings |
| mixFetch / mixWS (mixnet HTTP) | ✅tx broadcast | ✅ | ✅ |
| ★ Hybrid (dVPN sync + mixnet broadcast) | ❌needs dVPN — unavailable | ✅ | ✅ |
Why dVPN is native-only
Web wallets — mixnet only
A web wallet is therefore limited to the mixnet-only path (mixFetch / mixWS) for transaction broadcast and cannot use the hybrid — it gets the sensitive-broadcast half but not the fast dVPN sync half. It still owes the Layer-2 baseline hygiene (V2 broadcast delays, V3 start-height obfuscation) exactly like a native wallet: mixFetch protects in-transit timing against L3L/L3G, but the destination still sees arrival timing, so the wallet must add its own delays.
Mobile — Swift / Kotlin via uniffi
iOS (Swift) and Android (Kotlin) wallets are native and can open UDP sockets, so they get the full hybrid. Rather than reimplement the stack, they reuse the nym-smolmix and nym-smol-dvpn Rust crates through uniffi (Mozilla), which generates the Swift and Kotlin bindings — one Rust core, native frontends. As on every platform, the Layer-2 baseline hygiene remains the app's responsibility, implemented in the Swift/Kotlin/Rust app code, not in the crates' transport.
The sandbox removes a transport option; it does not remove the wallet’s Layer-2 duties. See Baseline hygiene and the recommended architecture.