zxcvbn-rs
A Rust port of Dropbox's zxcvbn password strength estimator, scoring passwords 0-4 with pattern matching instead of arbitrary composition rules.
Repository Health
Technical Analysis
zxcvbn is a Rust implementation of Dropbox’s widely-used zxcvbn password strength estimation algorithm. Rather than enforcing rigid composition rules like “must contain three of {lowercase, uppercase, digit, symbol}”, it estimates how guessable a password actually is by pattern-matching against roughly 30,000 common passwords, common first and last names from US census data, popular English words drawn from Wikipedia and US television/film, and structural patterns such as dates, character repeats, keyboard sequences, and l33t-speak substitutions.
The crate exposes a single primary function, zxcvbn, which takes a password and an optional list of user-supplied inputs (username, email, city, etc.) and returns an Entropy struct containing an integer strength score (0-4), estimated crack times across several attack scenarios, the guess count and its base-10 log magnitude, verbal feedback for weak passwords, and the matched pattern sequence that produced the score. An optional ser feature adds Serde (de)serialization for the result types, and the crate compiles for WASM targets including custom WASM runtimes via the custom_wasm_env feature.
What You Get
- A single
zxcvbn(password, user_inputs)function returning a 0-4 strength score plus detailed entropy and crack-time estimates - Pattern matching against ~30k common passwords, US census names, and popular English words drawn from Wikipedia and TV/film
- Structural pattern detection for dates, repeated characters, keyboard sequences, and l33t-speak substitutions
- Verbal feedback (
feedbackmodule) with actionable, human-readable guidance for weak passwords - Crack-time estimates across multiple attack scenarios (online throttled, online unthrottled, offline slow hash, offline fast hash)
- Optional
serfeature flag for Serde serialization/deserialization of results - WASM compatibility, including a
custom_wasm_envfeature for embedding in non-browser WASM runtimes
Common Use Cases
- Real-time password strength meters in signup and password-change forms
- Replacing rigid password composition policies with a flexible, usability-friendly complexity check
- Rejecting passwords that reuse a user’s own username, email, or other profile data via the
user_inputsparameter - Estimating attacker crack times to communicate risk to end users
- Server-side password policy enforcement in Rust web backends and CLI tools
Under The Hood
Architecture
The crate is organized around a three-stage pipeline: matching::omnimatch runs a battery of pattern matchers (dictionary, reversed dictionary, l33t-substitution, spatial/keyboard-adjacency, repeat, sequence, regex, and date matchers, in src/matching/mod.rs) over the input password and returns every overlapping Match found; scoring::most_guessable_match_sequence (src/scoring.rs) then performs a dynamic-programming search over that match set to find the minimum-guess decomposition of the whole password, à la the reference zxcvbn algorithm’s optimal-partition approach; finally time_estimates::estimate_attack_times converts the resulting guess count into a Score enum and per-scenario crack-time estimates, and feedback::get_feedback derives human-readable suggestions from the winning match sequence. The public zxcvbn() function in src/lib.rs is a thin orchestrator over these three stages, truncating input to 100 characters to bound worst-case cost. Swapping any one stage (e.g. a different scoring heuristic) would require touching only that module, since the Match/Entropy types form clean boundaries between them.
Tech Stack
Pure Rust (edition 2021, MSRV 1.66) with a deliberately small dependency surface: fancy-regex and regex for pattern matchers, itertools for iterator combinators, lazy_static for the large static frequency/adjacency tables, time for date handling, and an optional derive_builder behind the default builder feature. WASM targets pull in wasm-bindgen, web-sys, and chrono for timing without a native std::time::Instant. Serde support is entirely opt-in via the ser feature so non-serializing consumers pay no cost. Benchmarks use criterion, and the crate ships as a standard cargo library with no build-time code generation.
Code Quality
The crate has substantial test coverage: unit tests live alongside the matchers in matching/mod.rs and matching/patterns.rs, plus dedicated modules in scoring.rs, feedback.rs, and time_estimates.rs, and lib.rs adds quickcheck-based property tests asserting the top-level zxcvbn() function never panics on arbitrary input (including empty strings and multi-byte Unicode) and that Serde round-tripping preserves entropy values. CI (.github/workflows/zxcvbn.yml) runs rustfmt --check and clippy --all-features --tests --benches on every PR, plus a build-and-test matrix across Ubuntu and Windows, so both style and correctness are enforced automatically. Public types carry doc comments enforced by #![warn(missing_docs)], and there’s no evidence of swallowed errors — the API surface returns owned structs rather than Results because the crate deliberately avoids fallible states (a documented breaking change from an earlier version that used to allow errors).
What Makes It Unique
Unlike password policies that check for presence of character classes, zxcvbn estimates actual guessability by combining large, real-world frequency corpora (common passwords, census names, dictionary words) with structural pattern detection (l33t substitutions, keyboard walks, date formats) and a dynamic-programming search for the cheapest way an attacker could guess the password — the same approach as Dropbox’s original JavaScript zxcvbn, reimplemented natively in Rust rather than wrapped via FFI or a JS runtime. Accepting user_inputs lets it flag passwords built from a user’s own username or email, something pure composition-rule checks can’t do, and the saturating u64 guess count paired with an unsaturated guesses_log10 avoids silently truncating strength estimates for extremely strong passwords.