snow
A pure-Rust implementation of the Noise Protocol Framework for building secure, encrypted handshakes and transport channels.
Repository Health
Technical Analysis
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
BuilderAPI for constructing initiator/responderHandshakeStateobjects 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
CryptoResolvertrait with a pure-Rust default resolver and an optionalring-accelerated resolver TransportStatefor reliable transports andStatelessTransportStatefor unreliable transports with caller-managed countersno_std+allocsupport 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_stdenvironments
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.