Skip to content

QUIC, in pure Zig

An IETF QUIC transport written from scratch in Zig — QUIC v1 and v2, pure-Zig TLS 1.3 with 0-RTT and post-quantum key exchange, multipath, and a handshake wire-verified against Go and Rust stacks.

Proven on the wire, not just in unit tests

Section titled “Proven on the wire, not just in unit tests”

quicz’s primary handshake and FIN-terminated stream-echo path are exercised by real UDP probes: loopback in-process, separate-process Zig, and certificate-verified clients written independently in Go and Rust.

Terminal window
$ zig-out/bin/quicz-tls13-process-echo-server 127.0.0.1 4443 2 concurrent-retry &
$ (cd examples/interop/go_echo_client && \
go run . -addr 127.0.0.1:4443 -ca ../testdata/quicz-echo-ca.pem -server-name localhost)
# quic-go client ↔ quicz server: TLS 1.3 handshake, then FIN-terminated
# "hello" / "world" echoes verified on streams 0 and 4 — certificate
# verification enabled the whole way.
  • Pure-Zig TLS 1.3 + 0-RTT — no C crypto dependency; post-quantum X25519Kyber768.
  • QUIC v1 and v2 transport — streams, flow control, connection migration, path validation, Retry, stateless reset, key update, version negotiation.
  • DATAGRAM, multipath, ECN, PMTU, GSO/GRO, connection pooling, qlog.
  • Loss recovery + NewReno / CUBIC / BBR with packet pacing.
  • HTTP/3 + QPACK static and WebTransport at a basic level.
  • Wire-verified interop with quic-go, quinn, and the QUIC-Interop-Runner.
var conn = try quicz.Connection.init(
std.heap.page_allocator, .client, .{
.initial_max_data = 65_536,
.initial_max_stream_data = 65_536,
.initial_max_streams_bidi = 16,
});
defer conn.deinit();
const id = try conn.openStream();
try conn.sendOnStream(id, "hello", true);
var buf: [1350]u8 = undefined;
const frame = (try conn.pollTx(0, &buf))
orelse return error.NoPendingFrame;

Full walkthrough in the quick start.

Peer Language / stack Probe
quic-go Go certificate-verified echo client/server
quinn Rust certificate-verified echo client
QUIC-Interop-Runner handshake, transfer, retry self-test
quicz (separate processes) Zig independent client + server over loopback UDP

Run it yourself: examples guide.

The authoritative feature matrix tracks 37 capabilities across four stacks. Headline coverage:

Metric quic-go quiche s2n-quic quicz
Transport (19 items) 19/19 14/19 14/19 19/19
Congestion (4 items) 4/4 4/4 3/4 4/4
Cipher suites (5 items) 5/5 5/5 5/5 5/5
Application layer (6 items) 6/6 3/6 0/6 2/6
Platform (3 items) 2/3 0/3 1/3 1/3
Total (37 items) 36/37 26/37 23/37 31/37

quicz leads on transport, congestion, and cipher suites; the remaining gap is application-layer breadth. See the full feature-by-feature comparison for all 37 rows and the gap analysis.

Status Capability
Basic, hardening in progress HTTP/3 connection management (GOAWAY / SETTINGS / stream lifecycle); WebTransport sessions
Not yet QPACK dynamic table; HTTP Datagrams (RFC 9297); stream reset partial delivery; FIPS 140-3; XDP zero-copy I/O

The authoritative status and acceptance evidence live in the transport task matrix. The API is stabilizing but still evolving.

  • Quick start — add quicz to your Zig build and send your first frame.
  • Feature comparison — quicz vs quic-go / quiche / s2n-quic, 37 rows.
  • Architecture — how the endpoint, connection, and TLS layers fit together.
  • Spec coverage — RFC 9000/9001/9002 section-by-section status.
  • Examples — loopback, echo server, and Go/Rust interop commands.