MoonBit port of Dropbox zxcvbn password strength estimator: attack-model scoring (guesses/entropy), dictionary/l33t/keyboard/date/sequence/repeat pattern matching, crack-time estimation.
Dropbox zxcvbn 密码强度估计器的 MoonBit 移植。 输入密码字符串,输出 0–4 强度分 + 熵值(guesses/log10)+ 四场景破解时间 + 命中的模式明细 + 改进建议。
| 密码 | 典型 LUDS 打分 | 本库 zxcvbn | 真实情况 |
|---|---|---|---|
| Password1! | 4(4 类齐全、长度 10) | 1 | Password 是 rank 2 的高频词典词,大小写与符号几乎不增加成本 |
| correcthorsebatterystaple | 3(仅小写、无数字符号) | 4 | 4 个普通英文词、无任何模式,真正的离线破解下限是 2.7e14 次猜测 |
| qwerty123456 | 3(长度 12、含数字) | 1 | 键盘直行(qwerty)+ 数字序列(123456),1851 次即可命中 |
| Tr0ub4dor&3 | 4 | 4 | 确实强(1e11 次暴力破解),但这是"碰巧",不是规则算出来的 |
pub fn zxcvbn(
password : String,
user_inputs : Array[String],
reference_year? : Int = 2026,
) -> Entropy
pub struct Entropy {
password : String
/// 保守估计的猜测次数(Double:长密码会达到 1e10^n 甚至上溢)
guesses : Double
/// log10(guesses)
guesses_log10 : Double
/// 0..4,阈值 1e3 / 1e6 / 1e8 / 1e10(与上游一致)
score : Int
/// 四场景破解秒数
crack_times_seconds : CrackTimes
/// 人类可读破解时间
crack_times_display : CrackTimesDisplay
/// 最优匹配序列
sequence : Array[Match]
feedback : Feedback
}
/// 一次模式匹配(按模式拆成 enum + 每模式 struct,仿 zxcvbn-rs 的强类型范式)
pub enum Match {
Bruteforce(BruteforceMatch)
Dictionary(DictionaryMatch)
Spatial(SpatialMatch)
Repeat(RepeatMatch)
Sequence(SequenceMatch)
Regex(RegexMatch)
Date(DateMatch)
}
pub fn Match::start_index(self) -> Int // 闭区间起点
pub fn Match::end_index(self) -> Int // 闭区间终点
pub fn Match::token(self) -> String // 命中的原文字符串
pub fn Match::pattern(self) -> String // "dictionary" / "spatial" / ...
pub fn Match::guesses(self) -> Doublepub fn dictionary_match(Array<Char>, Array<(Dictionary, Map<String, Int])>, Int) -> Array<Match>
pub fn reverse_dictionary_match(Array<Char>, Array<(Dictionary, Map<String, Int])>, Int) -> Array[Match]
pub fn l33t_match(Array<Char], Array<(Dictionary, Map<String, Int])], Map<Char, Array<Char]], Int) -> Array<Match>
pub fn spatial_match(Array<Char], Array<(String, Map<Char, Array<(Char, Char)?]])>) -> Array[Match]
pub fn repeat_match(Array<Char], Array<(Dictionary, Map<String, Int])], Int, Map<Char, Array<Char]], Int) -> Array[Match]
pub fn sequence_match(Array<Char]) -> Array<Match>
pub fn regex_match(Array[Char]) -> Array<Match]
pub fn date_match(Array<Char>, Int) -> Array<Match>moon check # 0 error,0 warning
moon test # 53/53(默认 wasm 后端)
# 三个后端都全绿(验证“纯计算、无 IO 依赖”的声明)
moon test --target wasm # 53/53
moon test --target wasm-gc # 53/53
moon test --target js # 53/53
moon run cmd/main -- "correct horse battery staple"moon check # 静态检查
moon info # 更新 .mbti 接口
moon fmt # 格式化
moon test # 测试
moon run cmd/main -- "password"
python3 tools/gen_dictionaries.py # 从 data/upstream 重新生成词典数据模块
python3 tools/gen_adjacency_graphs.py # 从数据/upstream 重新生成键盘邻接图模块
# 两个生成器的产物需再跑一次 moon fmt(生成器不保证 fmt-clean,CI 的 fmt 门禁会校验)let result = @zxcvbn.zxcvbn("Tr0ub4dor&3", ["bob", "bob@example.com"])
result.score // 0..4
result.guesses // conservative attack-model lower bound (Double)
result.sequence // optimal non-overlapping matches
result.feedback // warning + suggestionspub struct AttackTimes {
crack_times_seconds : CrackTimes
crack_times_display : CrackTimesDisplay
score : Int
} derive(Eq, Debug)pub struct DictionaryMatch {
i : Int
j : Int
token : String
matched_word : String
rank : Int
dictionary_name : Dictionary
reversed : Bool
l33t : Bool
sub : Array[(Char, Char)]
guesses : Double
guesses_log10 : Double
} derive(Eq, Debug)pub struct Entropy {
password : String
guesses : Double
guesses_log10 : Double
score : Int
crack_times_seconds : CrackTimes
crack_times_display : CrackTimesDisplay
sequence : Array[Match]
feedback : Feedback
} derive(Eq, Debug)pub enum Match {
Bruteforce(BruteforceMatch)
Dictionary(DictionaryMatch)
Spatial(SpatialMatch)
Repeat(RepeatMatch)
Sequence(SequenceMatch)
Regex(RegexMatch)
Date(DateMatch)
} derive(Eq, Debug)pub struct Omnimatcher {
dictionaries : Array[(Dictionary, Map[String, Int])]
max_word_length : Int
reference_year : Int
} derive(Eq, Debug)fn guesses_to_score(guesses : Double) -> Intlet keypad_average_degree : Doublefn most_guessable_match_sequence(password : String, matches : Array[Match], reference_year : Int, exclude_additive? : Bool) -> MatchSequenceg = l! * Prod(m.guesses for m in sequence) + D^(l - 1)Install
Download zipMoonBit port of Dropbox zxcvbn password strength estimator: attack-model scoring (guesses/entropy), dictionary/l33t/keyboard/date/sequence/repeat pattern matching, crack-time estimation.