Files
skills/docs/security-stack/security/password-strength/src/matchers/dictionary/l33t-table.md
2026-05-29 08:20:56 +01:00

3.0 KiB

l33t-table — default substitution table

Purpose

Provides the default character → letter substitution table used by the dictionaryMatch matcher to recognise l33t-encoded variants of dictionary tokens (e.g. p4ssw0rd for password). The table follows Wheeler §3.1 and mirrors the dropbox/zxcvbn reference impl's data/l33t_table.coffee. The companion inverseL33tTable utility flips the table for the matcher's enumeration pass — given a substitute character, it returns the set of letters that character could represent.

Features

  • Frozen default table covering twelve high-frequency substitutions
  • Inverse lookup helper for matcher enumeration
  • Pure data; safe to import in any tier (no runtime deps)
  • Caller-pluggable: assess accepts an alternative table via options

Usage: Basic Example

import { DEFAULT_L33T_TABLE, inverseL33tTable } from "@suaveplan/password-strength/matchers/dictionary";

const inverse = inverseL33tTable(DEFAULT_L33T_TABLE);
console.log(inverse["4"]); // ["a"]
console.log(inverse["1"]); // ["i", "l"]

Usage: Advanced Example

import { DEFAULT_L33T_TABLE, inverseL33tTable, dictionaryMatch } from "@suaveplan/password-strength/matchers/dictionary";

const customTable = {
 ...DEFAULT_L33T_TABLE,
 a: ["4", "@", "/-\\"],
};
const matches = dictionaryMatch("p4ssword", { passwords: new Map([["password", 1]]) }, customTable);
console.log(matches);

API Reference

  • DEFAULT_L33T_TABLE: L33tTable — frozen default substitution map.
  • inverseL33tTable(table: L33tTable): Record<string, string[]> — return the inverse map of substitute character → array of letters it can stand in for.

Implementation Notes

The table is intentionally conservative: every substitute character maps to real letters that appear in the breach-corpus literature. Adding more substitutions inflates the enumeration cost quadratically per password length, so callers who extend the table should benchmark against assess_dictionary_heavy. The frozen Object.freeze wrapper prevents inadvertent mutation by consumers.

Additional Implementation Notes

The implementation follows the canonical zxcvbn algorithm from Wheeler 2016 with the suaveplan-style additions described in the package proposal: structured error codes via the defineCodes registry, Zod boundaries at every public entry point, OTel histograms and counters keyed to low-cardinality attributes, and a strict input-length guard at 200 characters. Consumers integrate with their existing observability stack by installing a meter provider before importing the package, and with their i18n stack via the MessageResolver callback type declared in @suaveplan/types. The bundled data tables are intentionally small to keep the package bundle compact; production deployments should swap in fuller frequency-ranked tables via loadDictionaries. The default English dictionary set is a frozen DictionarySet that the matcher never mutates; caller-supplied dictionaries override defaults by name.