snow

A pure-Rust implementation of the Noise Protocol Framework for building secure, encrypted handshakes and transport channels.

Library
Cargo
v0.10.0
1,090stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
54/100Fair
Development Activity28
Maintenance20
Community80
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
78/100Good
Architecture85
Code Quality82
Innovation78
Learning Curve65

Snow is a Rust crate implementing the Noise Protocol Framework, the handshake and cryptographic transport protocol used by WireGuard, Lightning Network, and many other secure messaging systems. It exposes a Builder API that constructs a HandshakeState from a Noise pattern string (e.g. Noise_XX_25519_ChaChaPoly_BLAKE2s), walks it through the handshake, and transitions it into a TransportState (or StatelessTransportState for unreliable transports like UDP) once complete.

Cryptographic primitives are pluggable via a CryptoResolver trait: the default resolver ships pure-Rust implementations of Curve25519, AES-GCM, ChaCha20-Poly1305, SHA-2, and BLAKE2/BLAKE3, while an optional ring-backed resolver trades pure-Rust guarantees for BoringSSL-derived performance. The crate supports no_std environments with alloc, is validated against the official Noise and Cacophony test vectors, and forbids unsafe code via a crate-level lint.

What You Get

  • A Builder API for constructing initiator/responder HandshakeState objects from Noise pattern strings
  • Support for the full range of Noise handshake patterns (NN, XX, IK, and others) plus PSK and pattern modifiers
  • A swappable CryptoResolver trait with a pure-Rust default resolver and an optional ring-accelerated resolver
  • TransportState for reliable transports and StatelessTransportState for unreliable transports with caller-managed counters
  • no_std + alloc support for embedded and constrained environments
  • Conformance test suites against the official Noise and Cacophony vector sets

Common Use Cases

  • Encrypting peer-to-peer or client-server connections with mutual authentication (as WireGuard does)
  • Building secure messaging protocols that need forward secrecy without a full TLS stack
  • Adding an encrypted handshake layer over unreliable transports like UDP
  • Embedding Noise-based encryption in constrained or no_std environments

Under The Hood

Architecture Snow centers on a small state-machine pipeline: Builder (src/builder.rs) validates prerequisites (local/remote keys, PSKs, prologue) for a parsed NoiseParams pattern and produces a HandshakeState (src/handshakestate.rs), which drives SymmetricState (src/symmetricstate.rs) and CipherState/CipherStates (src/cipherstate.rs) through each message of the handshake. Once the handshake completes, into_transport_mode() consumes the HandshakeState and yields either a TransportState (src/transportstate.rs, internal nonce counter) or a StatelessTransportState (src/stateless_transportstate.rs, caller-supplied nonce) for encrypting application data. Pattern parsing and validation live in src/params/ (mod.rs, patterns.rs), which encode the Noise handshake pattern grammar as data rather than per-pattern code branches.

Tech Stack Pure Rust, edition 2024, rust-version = 1.85. Cryptography is abstracted behind the CryptoResolver trait (src/resolvers/mod.rs) with two implementations: DefaultResolver (src/resolvers/default.rs, ~1000 lines) wiring in curve25519-dalek, aes-gcm, chacha20poly1305, blake2/blake3, and sha2, each gated behind its own Cargo feature flag; and an optional ring-backed resolver (src/resolvers/ring.rs) for BoringSSL-derived performance. subtle provides constant-time comparisons used for keypair equality. #![cfg_attr(not(feature = "std"), no_std)] plus an alloc feature path gives no_std support.

Code Quality The crate carries an extensive tests/ suite: tests/general.rs exercises builder validation, handshake round-trips, PSKs, and rekeying with a deterministic counting RNG, while tests/vectors.rs replays the official Noise (tests/vectors/snow.txt, snow-extended.txt) and Cacophony (cacophony.txt) test-vector files for cross-implementation conformance. Error (src/error.rs) is a #[non_exhaustive] enum with dedicated variants (Pattern, Init, Prereq, State, Dh, Decrypt, Rng) rather than a single opaque failure type, and its doc comments explicitly warn against leaking Debug output to attackers. The crate enables #![warn(missing_docs)] and unsafe_code = "forbid" at the lint level, plus Clippy’s pedantic group with additional strict lints (shadow_reuse, missing_assert_message, as_conversions).

API Design The public surface is small and deliberately staged: Builder::new(pattern).local_private_key(..).remote_public_key(..).build_initiator() reads as a linear setup, and the type-level transition from HandshakeState to TransportState prevents calling transport methods before the handshake is done. examples/simple.rs and examples/oneway.rs show a complete TCP client/server, and crate-level rustdoc includes a runnable end-to-end example. The main ergonomic cost is Noise’s own pattern-string syntax (e.g. Noise_XX_25519_ChaChaPoly_BLAKE2s), which requires familiarity with the Noise spec rather than being fully self-describing in Rust types.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search