3.8 KiB
entropy
(no submodules)
Purpose
estimateEntropy(password, opts?) returns the upper-bound entropy of a candidate password as log2(charsetSize) * password.length, where charsetSize is the cardinality of the union of every detected built-in class (lowercase / uppercase / digits / symbols) plus any caller-supplied opts.extraClasses whose characters appear in the password. estimatePassphraseEntropy(words, wordlistSize) returns log2(wordlistSize) * words.length for Diceware-style passphrases. assertStrength(password, minBits, opts?) consumes estimateEntropy and throws PWGEN.STRENGTH_INSUFFICIENT when the computed bits are below the floor.
The entropy formulas assume uniform sampling and ignore patterns — "AAAAAAAA" is reported as the same entropy as "hG83mP9k" if both contain the same charset classes. Pattern-aware scoring (zxcvbn-style) is intentionally out of scope and lives in the separate @suaveplan/password-strength package.
Features
- Detects class membership in a single pass over the password.
extraClassesopt-in lets callers report custom-charset passwords (emoji unions, hex-only PINs).assertStrengththrows on insufficient entropy with a structured error code.- Zod-validated
EntropyOptions; mismatch →PWGEN.INVALID_OPTIONS.
Usage: Basic Example
import { estimateEntropy } from "@suaveplan/password-generator";
const { bits, charsetSize } = estimateEntropy("Abc123Xy");
// charsetSize === 62, bits === log2(62) * 8 ≈ 47.6
Usage: Advanced Example
import {
assertStrength,
estimateEntropy,
estimatePassphraseEntropy,
} from "@suaveplan/password-generator";
// Server-side guard before persisting a vault item
function persistVaultItem(pw: string): void {
assertStrength(pw, 80); // throws PWGEN.STRENGTH_INSUFFICIENT if < 80 bits
// ... persist
}
// Custom emoji-augmented class
const e = estimateEntropy("emoji👍2025", { extraClasses: ["👍🎉🚀"] });
// Diceware reporting
const words = ["correct", "horse", "battery", "staple", "alpha", "beta"];
const passEntropy = estimatePassphraseEntropy(words, 7776); // ≈ 77.55 bits
API Reference
estimateEntropy(password: string, opts?: EntropyOptions): EntropyEstimate
Returns { bits, charsetSize }. bits is 0 when the password is empty.
estimatePassphraseEntropy(words: readonly string[], wordlistSize: number): number
Returns log2(wordlistSize) * words.length. Throws PWGEN.INVALID_OPTIONS for non-positive integer wordlistSize.
assertStrength(password: string, minBits: number, opts?: EntropyOptions): void
Returns void on success. Throws PwgenError(PWGEN.STRENGTH_INSUFFICIENT) when the computed bits are strictly less than minBits.
EntropyOptions
extraClasses?: readonly string[]— additional character classes the password may draw from.
Implementation Notes
Class detection is a single forward pass over the password, tracking four boolean flags for the built-in classes plus a Set<number> of seen extraClasses indices. The charsetSize accumulator only adds a class's cardinality when the first matching character is seen, which keeps the cost O(password.length * extraClasses.length) worst-case.
The formula deliberately reports an upper bound. A consumer comparing this number to a cracking-time chart should treat it as a ceiling: real-world passwords contain dictionary patterns, keyboard walks, and date stamps that reduce the effective entropy substantially. Use @suaveplan/password-strength for adversarial-aware estimates. assertStrength is a deliberately blunt instrument — it answers "does this password meet the floor on the most generous estimator?" — and is intended as a server-side guardrail against drastically weak inputs, not a substitute for proper strength scoring.