first commit
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
# `entropy`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## 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.
|
||||
- `extraClasses` opt-in lets callers report custom-charset passwords (emoji unions, hex-only PINs).
|
||||
- `assertStrength` throws on insufficient entropy with a structured error code.
|
||||
- Zod-validated `EntropyOptions`; mismatch → `PWGEN.INVALID_OPTIONS`.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { estimateEntropy } from "@suaveplan/password-generator";
|
||||
|
||||
const { bits, charsetSize } = estimateEntropy("Abc123Xy");
|
||||
// charsetSize === 62, bits === log2(62) * 8 ≈ 47.6
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
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.
|
||||
Reference in New Issue
Block a user