<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/sanstun-a-sans-io-parallel-friendly-wireguard-implementation-in-rust-46bjc0gqm" -->

---
title: sanstun: A sans-IO, parallel-friendly WireGuard...
description: Firezone released sanstun, a sans-IO WireGuard implementation in Rust. The library separates IO, time and randomness from the WireGuard state machine. Its API...
canonical: https://daily.dev/posts/sanstun-a-sans-io-parallel-friendly-wireguard-implementation-in-rust-46bjc0gqm
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: sanstun: A sans-IO, parallel-friendly WireGuard implementation in Rust | daily.dev
og:description: Firezone released sanstun, a sans-IO WireGuard implementation in Rust. The library separates IO, time and randomness from the WireGuard state machine. Its API...
og:url: https://daily.dev/posts/sanstun-a-sans-io-parallel-friendly-wireguard-implementation-in-rust-46bjc0gqm
og:image: https://api.daily.dev/og/posts/46bjc0gQm.png
og:image:alt: sanstun: A sans-IO, parallel-friendly WireGuard implementation in Rust
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# sanstun: A sans-IO, parallel-friendly WireGuard implementation in Rust

**[Hacker News](https://daily.dev/sources/hn)** · 9 min read · 1 upvotes · 0 comments

## Summary

Firezone released sanstun, a sans-IO WireGuard implementation in Rust. The library separates IO, time and randomness from the WireGuard state machine. Its API splits packet bookkeeping from encryption, returning a Send-able PendingEncapsulate so crypto work can run on another thread. Benchmarks show the bookkeeping step takes only 2% of the time at 1280-byte packets, hinting at a potential speedup of more than 45x from offloading encryption. The boringtun fork is now deprecated, and sanstun is available on crates.io under Apache 2.0.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.firezone.dev/blog/introducing-sanstun>

## Questions this post answers

### What is sans-IO and why does it matter for a library like WireGuard?

Sans-IO is a design approach where IO and side effects, including time and randomness, are cleanly separated from a system's core state and logic. Because sans-IO components have no side effects, they compose well, are easy to test, avoid function coloring issues, and work well with Rust's ownership rules.

_Developers evaluating protocol library architectures can find deep dives like this on daily.dev._

### How does sanstun enable parallel encryption and decryption for a single WireGuard tunnel?

Sanstun separates bookkeeping from actual cryptography: calling Tunnel::begin_encapsulate checks the session, reserves a packet counter, and advances timer state without encrypting, returning a PendingEncapsulate struct. Because PendingEncapsulate implements Send, it can be moved to another thread to run the ChaCha20-Poly1305 encryption, since bookkeeping is only about 2% of the cost at 1280-byte packets, hinting at over 45x potential speedup.

_Teams optimizing Rust networking throughput track architecture write-ups like this via daily.dev._

### Why was Cloudflare's boringtun replaced with a new WireGuard implementation at Firezone?

Firezone deprecated its boringtun fork after maintaining it for more than 2 years and accumulating over 70 pull requests of patches and fixes, including making it fully sans-IO for time handling and removing internal buffering. Internal buffering in boringtun required awkward zero-length datagram calls to drain buffers and added unnecessary allocations, so sanstun removes buffering from the library entirely.

_Developers weighing a fork versus rewriting a core dependency can follow cases like this on daily.dev._

## Community take

How the wider developer community reacted, aggregated from 1 discussion and 42 comments across hackernews (as of 2026-10-31).

**TL;DR:** Discussion splits into a long, technical argument over whether framing sans-IO against async/function-coloring is accurate, alongside praise for the sans-IO architecture's testability and portability and sharp criticism of AI-sounding marketing copy on Firezone's site.

**Sentiment:** 35% positive · 40% mixed · 25% skeptical

**The case for**

- The sans-IO split makes the core easy to test, reuse across async and blocking runtimes, and compose with minimal unsafe code.
- Being able to run the implementation in no_std/embedded environments (e.g. ESP32, MCUs) is seen as a real benefit over the reference implementation.
- Several people note alternative WireGuard reimplementations (e.g. Mullvad's gotatun) already exist for good reasons, validating the approach of not relying solely on the reference implementation.

**The pushback**

- Multiple commenters pushed back hard on the claim that async causes 'function coloring' problems avoided by sans-IO, arguing async is not inherently tied to I/O and the framing is technically wrong.
- Marketing copy that reads as AI-generated drew strong criticism, with some saying it undermines trust in a security-critical VPN project.
- Some argue that proliferating independent WireGuard implementations instead of auditing the small reference implementation is risky for a security protocol.

**By community**

- hackernews (heated): A long back-and-forth debate over async/function-coloring and sans-IO semantics dominates, alongside a separate flare-up about AI-sounding website copy, while others simply welcome the portability and design of the new implementation.

**Hottest debate:** Whether describing sans-IO's avoidance of 'function coloring' is a legitimate technical claim or a fundamental misunderstanding of what async actually is.

**Open questions**

- Does the library hold up under real-world performance testing (throughput, jitter) compared to existing implementations like gotatun?
- Could Rust's evolving coroutine/generator support eventually offer the benefits of both async ergonomics and sans-IO composability?

**Highlights**

> It was all going great until I read > The design also avoids problems like function coloring and plays well with Rust's ownership rules. Async is not I/O. It can be used for I/O, but it's just a way of writing pure, deterministic state machines that keeps a logical flow together instead of scattered over a bunch of transitions. Even if you choose to manually compile your async flows into explicit state machines, you still have to deal with ‘function colouring’ (a.k.a. typing): a flow that crosses several state transitions (and may have other disjoint parts of the state updated in the meantime, via other transitions) now has to be rewritten as a (series of) state transitions, and can't be called from a blocking function. If anything, rewriting all your state machines without `async` makes the function colouring ‘problem’ worse, because multi-transition flows are even more different from normal functions.
> — [Twey on hackernews · 4 comments](https://news.ycombinator.com/item?id=50312268)

> In principle, you are right. Async is not I/O. And yes, `async` functions compile to a deterministic state machine. The problem is, the moment you use `async`, your state machine reduces down to one API: `poll`. What if I want to change some state in-between two state transitions (i.e. between two `await` points)? Now I have to wire-in a channel to supply that data at the right point or access some shared data via a Mutex. Rust's `async` implementation is great if you know everything upfront before you kick off your state machine. The moment you need to do many things concurrently, it can become a real mess. Firezone's sans-IO core handles many things concurrently: inbound IP, inbound UDP, WebSocket control messages, TURN allocations, timers, user commands, etc. Having essentially one big struct that I can just call `&mut self` functions on for any one of these inputs makes this very easy to understand, compose and test. A few things like TURN request-response handshakes might be easier as an `async` function but in reality, it is not a big deal and the composability you get from it outweighs it in my opinion.
> — [wh33zle on hackernews · 3 comments](https://news.ycombinator.com/item?id=50312375)

> From their website about their product: > Hardware does the heavy lifting. > Your operating system and network card take over the repetitive jobs whenever they can. Your CPU gets room to breathe, and your battery stays full longer. Where does this operating system run? Where does the power come from to run it if not battery? Pure rubbish ai slop. While the software might actually be ok upon inspection but this kind of ai slop nonsense copy doesn’t inspire confidence in using their software considering how security critical the vpn is.
> — [asdf88990 on hackernews · 2 comments](https://news.ycombinator.com/item?id=50311433)

> WireGuard implementations that are not Jason's reference implementation are stupid and an explicit invitation for issues. I will die on this hill. WG is like 2k LOC why the fuck do we need 30 different versions? Audit what you have.
> — [lakeviewterrace on hackernews · 2 comments](https://news.ycombinator.com/item?id=50311704)

> I can use sanstun in no_std environments like on an ESP32. Can I do that with Jason's reference implementation? Let people build. They might have reasons you haven't foreseen.
> — [clivedup on hackernews](https://news.ycombinator.com/item?id=50312282)

**Source threads**

- [hackernews](https://news.ycombinator.com/item?id=50310398) · 140 points · 42 comments

## Similar posts on daily.dev

- [The federated code forge](https://daily.dev/posts/the-federated-code-forge-zq5icukz3) · Hacker News · 0 upvotes · 0 comments
- [Built With Rust: ExpressVPN](https://daily.dev/posts/built-with-rust-expressvpn-hojjkxkqz) · Rust Foundation · 3 upvotes · 1 comments

---

Tags: [#rust](https://daily.dev/tags/rust), [#networking](https://daily.dev/tags/networking)

[View this post on daily.dev](https://daily.dev/posts/sanstun-a-sans-io-parallel-friendly-wireguard-implementation-in-rust-46bjc0gqm)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"sanstun: A sans-IO, parallel-friendly WireGuard implementation in Rust","url":"https://daily.dev/posts/sanstun-a-sans-io-parallel-friendly-wireguard-implementation-in-rust-46bjc0gqm","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/sanstun-a-sans-io-parallel-friendly-wireguard-implementation-in-rust-46bjc0gqm"},"datePublished":"2026-10-31T04:56:18.427Z","dateModified":"2026-10-31T12:12:16.787Z","description":"Firezone released sanstun, a sans-IO WireGuard implementation in Rust. The library separates IO, time and randomness from the WireGuard state machine. Its API...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/cff5608faca972f7f3bdc0a7ab8ae69a?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/cff5608faca972f7f3bdc0a7ab8ae69a?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Hacker News","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Hacker News","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/hn","url":"https://daily.dev/sources/hn"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/sanstun-a-sans-io-parallel-friendly-wireguard-implementation-in-rust-46bjc0gqm","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":1},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"rust,networking","timeRequired":"PT9M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Hacker News","item":"https://daily.dev/sources/hn"},{"@type":"ListItem","position":3,"name":"sanstun: A sans-IO, parallel-friendly WireGuard implementation in Rust"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/sanstun-a-sans-io-parallel-friendly-wireguard-implementation-in-rust-46bjc0gqm#faq","mainEntity":[{"@type":"Question","name":"What is sans-IO and why does it matter for a library like WireGuard?","acceptedAnswer":{"@type":"Answer","text":"Sans-IO is a design approach where IO and side effects, including time and randomness, are cleanly separated from a system's core state and logic. Because sans-IO components have no side effects, they compose well, are easy to test, avoid function coloring issues, and work well with Rust's ownership rules. Developers evaluating protocol library architectures can find deep dives like this on daily.dev."}},{"@type":"Question","name":"How does sanstun enable parallel encryption and decryption for a single WireGuard tunnel?","acceptedAnswer":{"@type":"Answer","text":"Sanstun separates bookkeeping from actual cryptography: calling Tunnel::begin_encapsulate checks the session, reserves a packet counter, and advances timer state without encrypting, returning a PendingEncapsulate struct. Because PendingEncapsulate implements Send, it can be moved to another thread to run the ChaCha20-Poly1305 encryption, since bookkeeping is only about 2% of the cost at 1280-byte packets, hinting at over 45x potential speedup. Teams optimizing Rust networking throughput track architecture write-ups like this via daily.dev."}},{"@type":"Question","name":"Why was Cloudflare's boringtun replaced with a new WireGuard implementation at Firezone?","acceptedAnswer":{"@type":"Answer","text":"Firezone deprecated its boringtun fork after maintaining it for more than 2 years and accumulating over 70 pull requests of patches and fixes, including making it fully sans-IO for time handling and removing internal buffering. Internal buffering in boringtun required awkward zero-length datagram calls to drain buffers and added unnecessary allocations, so sanstun removes buffering from the library entirely. Developers weighing a fork versus rewriting a core dependency can follow cases like this on daily.dev."}}]}
```

