spake2
Pure Rust implementation of the SPAKE2 password-authenticated key exchange protocol using Curve25519.
Repository Health
Technical Analysis
spake2 is a pure Rust, no_std-compatible implementation of the SPAKE2 password-authenticated key exchange (PAKE) protocol, part of the RustCrypto PAKEs workspace. It lets two parties who share a weak password derive a strong, symmetric session key over an untrusted channel without ever transmitting the password itself — an eavesdropper learns nothing, and an active attacker gets exactly one guess per protocol run.
Built on curve25519-dalek’s Ed25519 group, the crate exposes both asymmetric roles (start_a/start_b, for client-server pairings) and a symmetric mode (start_symmetric, for peer-to-peer exchanges with no fixed roles). It compiles without the standard library, ships an optional getrandom feature for pulling entropy from the OS RNG, and derives session keys through HKDF-SHA256, making it a building block for pairing flows, device onboarding, and PAKE-based login schemes.
What You Get
- Asymmetric start_a / start_b APIs for classic client-server PAKE flows, where each side knows which role it is playing.
- A start_symmetric mode for peer-to-peer exchanges where no side is designated client or server.
- A single built-in Ed25519Group parameter set offering roughly 128-bit symmetric security with 33-byte protocol messages.
- An optional getrandom feature for pulling session randomness straight from the OS CSPRNG, plus support for supplying your own RNG.
- HKDF-SHA256-derived output keys ready to feed into an AEAD cipher or HMAC for the encrypted channel that follows.
Common Use Cases
- Device pairing — introducing two devices via a short one-time code, similar to the original Firefox Sync J-PAKE flow.
- Password-authenticated login — letting client and server confirm they hold the same password without sending it over the wire.
- Secure session bootstrapping — establishing a strong shared key that seeds an authenticated-encryption channel for everything that follows.
- Zero-knowledge credential confirmation — proving password knowledge between two parties before any other data is exchanged.
Under The Hood
Architecture The crate is a small, flat library organized around a single generic entry point: Spake2<G: Group> in src/lib.rs, parameterized over a Group trait (src/group.rs) that abstracts the underlying algebraic group — currently only Ed25519Group (src/ed25519.rs) is provided, built on curve25519-dalek. Construction happens through start_a/start_b/start_symmetric associated functions that consume a Password and Identity newtype pair and return both a mutable protocol state and the outbound wire message; finish() then consumes that state together with the inbound message to yield the derived key, enforcing single-use semantics at the type level. Errors are centralized in a small Error enum (src/error.rs: BadSide, CorruptMessage, WrongLength) surfaced through a crate-wide Result alias. There is no dependency injection or layering beyond the Group trait boundary — the design’s core commitment is algorithm/parameter separation, so swapping the underlying group means implementing Group rather than touching the protocol state machine, which is the crate’s one clear extension point.
Tech Stack The crate targets a recent Rust edition and MSRV and is no_std by default (alloc only), gaining std only behind an explicit feature flag. Cryptographic primitives come from curve25519-dalek (Edwards point / scalar arithmetic), sha2 and hkdf for HKDF-SHA256 key derivation, and rand_core for the RNG trait boundary; an optional getrandom feature wires in the OS CSPRNG for callers who don’t want to supply their own. Dev-dependencies include a benchmarking crate and test-vector helpers. There is no async runtime, network layer, or persistence — this is a pure computation library meant to be embedded in a caller’s own transport and storage. It ships as part of the RustCrypto/PAKEs Cargo workspace alongside sibling crates srp and aucpace, each built and tested by its own scoped GitHub Actions workflow.
Code Quality Testing lives in an integration test file covering matching keys, password mismatch, and reflected/corrupted messages, plus inline doctests embedded in the crate-level documentation, all exercised in CI. CI builds against both the MSRV and stable toolchains across multiple no_std targets with warnings treated as errors, and a separate security-audit workflow runs dependency vulnerability scanning with dependabot keeping versions current. Error handling is fully typed through the Error enum rather than panics or swallowed Results, unsafe code is forbidden at the crate root, and documentation/idiom lints are enforced in CI. Coverage is adequate for the protocol’s happy and mismatch paths but not exhaustive — there is no fuzzing or property-based testing evident in the repo, and the crate’s own README discloses it has not received a formal third-party security audit.
API Design The public API is deliberately small and hard to misuse: Password and Identity are dedicated newtypes rather than raw byte slices, preventing accidental argument swaps, and the state-consuming start_*/finish() flow makes protocol single-use enforced by the type system rather than by documentation alone. The split between a getrandom-gated convenience constructor and an explicit RNG-taking variant lets no_std or embedded callers supply their own randomness source without pulling in OS entropy. Where the API asks more of callers than average is the Group trait: extending the crate to a new curve or adding a planned augmented variant requires implementing several low-level field/group operations by hand, and the crate-level docs disclose real gaps up front — no constant-time guarantees, no serialization of in-flight state, and no independent security audit — which is transparent but does raise the bar for production login use versus more turnkey PAKE offerings.