PRCYCoin  2.0.0.7rc1
P2P Digital Currency
scoring.cpp
Go to the documentation of this file.
1 #include <zxcvbn/scoring.hpp>
2 
4 #include <zxcvbn/util.hpp>
5 
6 #include <numeric>
7 #include <string>
8 #include <vector>
9 
10 #include <cmath>
11 
12 namespace std {
13 
14 template<class T, class U>
15 struct hash<std::pair<T, U>> {
16  std::size_t operator()(const std::pair<T, U> & v) const {
17  return std::hash<T>()(v.first) ^ std::hash<U>()(v.second);
18  }
19 };
20 
21 }
22 
23 namespace zxcvbn {
24 
25 const auto BRUTEFORCE_CARDINALITY = static_cast<guesses_t>(10);
26 const auto MIN_GUESSES_BEFORE_GROWING_SEQUENCE = static_cast<guesses_t>(10000);
27 const auto MIN_SUBMATCH_GUESSES_SINGLE_CHAR = static_cast<guesses_t>(10);
28 const auto MIN_SUBMATCH_GUESSES_MULTI_CHAR = static_cast<guesses_t>(50);
29 
30 template<class Tret, class Tin>
31 Tret factorial(Tin n) {
32  // unoptimized, called only on small n
33  if (n < 2) return 1;
34  Tret f = 1;
35  for (Tin i = 2; i <= n; ++i) {
36  f *= i;
37  }
38  return f;
39 }
40 
41 template<class M, class K, class V>
42 static
43 void insert_or_assign(M & m, const K & k, V && v) {
44  auto p = m.insert(std::make_pair(k, std::forward<V>(v)));
45  if (!p.second) {
46  p.first->second = std::forward<V>(v);
47  }
48 }
49 
50 static
51 std::size_t token_len(const Match & m) __attribute__((pure));
52 
53 static
54 std::size_t token_len(const Match & m) {
55  std::size_t result = m.j - m.i + 1;
56  assert(result == util::character_len(m.token));
57  return result;
58 }
59 
60 // ------------------------------------------------------------------------------
61 // search --- most guessable match sequence -------------------------------------
62 // ------------------------------------------------------------------------------
63 //
64 // takes a sequence of overlapping matches, returns the non-overlapping sequence with
65 // minimum guesses. the following is a O(l_max * (n + m)) dynamic programming algorithm
66 // for a length-n password with m candidate matches. l_max is the maximum optimal
67 // sequence length spanning each prefix of the password. In practice it rarely exceeds 5 and the
68 // search terminates rapidly.
69 //
70 // the optimal "minimum guesses" sequence is here defined to be the sequence that
71 // minimizes the following function:
72 //
73 // g = l! * Product(m.guesses for m in sequence) + D^(l - 1)
74 //
75 // where l is the length of the sequence.
76 //
77 // the factorial term is the number of ways to order l patterns.
78 //
79 // the D^(l-1) term is another length penalty, roughly capturing the idea that an
80 // attacker will try lower-length sequences first before trying length-l sequences.
81 //
82 // for example, consider a sequence that is date-repeat-dictionary.
83 // - an attacker would need to try other date-repeat-dictionary combinations,
84 // hence the product term.
85 // - an attacker would need to try repeat-date-dictionary, dictionary-repeat-date,
86 // ..., hence the factorial term.
87 // - an attacker would also likely try length-1 (dictionary) and length-2 (dictionary-date)
88 // sequences before length-3. assuming at minimum D guesses per pattern type,
89 // D^(l-1) approximates Sum(D^i for i in [1..l-1]
90 //
91 // ------------------------------------------------------------------------------
92 
93 ScoringResult most_guessable_match_sequence(const std::string & password,
94  std::vector<Match> & matches,
95  bool exclude_additive) {
96  auto n = password.length();
97 
98  // partition matches into sublists according to ending index j
99  std::unordered_map<idx_t, std::vector<std::reference_wrapper<Match>>> matches_by_j;
100  for (auto & m : matches) {
101  matches_by_j[m.j].push_back(m);
102  }
103  // small detail: for deterministic output, sort each sublist by i
104  for (auto & item : matches_by_j) {
105  std::sort(item.second.begin(), item.second.end(),
106  [&] (const std::reference_wrapper<Match> & a,
107  const std::reference_wrapper<Match> & b) {
108  return a.get().i < b.get().i;
109  });
110  }
111 
112  struct {
113  // optimal.m[k][l] holds final match in the best length-l match sequence covering the
114  // password prefix up to k, inclusive.
115  // if there is no length-l sequence that scores better (fewer guesses) than
116  // a shorter match sequence spanning the same prefix, optimal.m[k][l] is undefined.
117  std::unordered_map<idx_t, std::unordered_map<idx_t, std::reference_wrapper<Match>>> m;
118 
119  // same structure as optimal.m -- holds the product term Prod(m.guesses for m in sequence).
120  // optimal.pi allows for fast (non-looping) updates to the minimization function.
121  std::unordered_map<idx_t, std::unordered_map<idx_t, guesses_t>> pi;
122 
123  // same structure as optimal.m -- holds the overall metric.
124  std::unordered_map<idx_t, std::unordered_map<idx_t, guesses_t>> g;
125  } optimal;
126 
127  // helper: considers whether a length-l sequence ending at match m is better (fewer guesses)
128  // than previously encountered sequences, updating state if so.
129  auto update = [&] (Match & m, idx_t l) {
130  auto k = m.j;
131  auto pi = estimate_guesses(m, password);
132  if (l > 1) {
133  // we're considering a length-l sequence ending with match m:
134  // obtain the product term in the minimization function by multiplying m's guesses
135  // by the product of the length-(l-1) sequence ending just before m, at m.i - 1.
136  pi *= optimal.pi[m.i - 1][l - 1];
137  }
138  // calculate the minimization func
139  auto g = factorial<guesses_t>(l) * pi;
140  if (!exclude_additive) {
141  g += std::pow(MIN_GUESSES_BEFORE_GROWING_SEQUENCE, l - 1);
142  }
143  // update state if new best.
144  // first see if any competing sequences covering this prefix, with l or fewer matches,
145  // fare better than this sequence. if so, skip it and return.
146  for (const auto & item : optimal.g[k]) {
147  auto & competing_l = item.first;
148  auto & competing_g = item.second;
149  if (competing_l > l) continue;
150  if (competing_g <= g) return;
151  }
152  // this sequence might be part of the final optimal sequence.
153  insert_or_assign(optimal.g[k], l, g);
154  insert_or_assign(optimal.m[k], l, std::ref(m));
155  insert_or_assign(optimal.pi[k], l, pi);
156  };
157 
158  // helper: make bruteforce match objects spanning i to j, inclusive.
159  // TODO: we store bruteforce matches in this vector so that we can
160  // store references in optimal.m, this is arguable hacked, so fix this
161  std::unordered_map<std::pair<idx_t, idx_t>, std::unique_ptr<Match>> bruteforces;
162  auto make_bruteforce_match = [&] (idx_t i, idx_t j) -> std::reference_wrapper<Match> {
163  auto p = bruteforces.insert(std::make_pair(std::make_pair(i, j),
164  std::make_unique<Match>
165  (i, j,
166  password.substr(i, j - i + 1),
167  BruteforceMatch{})));
168  return std::ref(*p.first->second);
169  };
170 
171  // helper: evaluate bruteforce matches ending at k.
172  auto bruteforce_update = [&] (idx_t k) {
173  // see if a single bruteforce match spanning the k-prefix is optimal.
174  auto m = make_bruteforce_match(0, k);
175  update(m, 1);
176  for (idx_t i = 1; i <= k; ++i) {
177  // generate k bruteforce matches, spanning from (i=1, j=k) up to (i=k, j=k).
178  // see if adding these new matches to any of the sequences in optimal[i-1]
179  // leads to new bests.
180  auto m2 = make_bruteforce_match(i, k);
181  for (const auto & item : optimal.m[i - 1]) {
182  auto & l = item.first;
183  auto & last_m = item.second;
184  // corner: an optimal sequence will never have two adjacent bruteforce matches.
185  // it is strictly better to have a single bruteforce match spanning the same region:
186  // same contribution to the guess product with a lower length.
187  // --> safe to skip those cases.
188  if (last_m.get().get_pattern() == MatchPattern::BRUTEFORCE) continue;
189  // try adding m to this length-l sequence.
190  update(m2, l + 1);
191  }
192  }
193  };
194 
195  // helper: step backwards through optimal.m starting at the end,
196  // constructing the final optimal match sequence.
197  auto unwind = [&] (idx_t n) {
198  std::vector<std::reference_wrapper<Match>> optimal_match_sequence;
199  if (!n) return optimal_match_sequence;
200  auto k = n - 1;
201  idx_t l = optimal.g[k].begin()->first;
202  auto g = optimal.g[k].begin()->second;
203  for (const auto & item : optimal.g[k]) {
204  auto & candidate_l = item.first;
205  auto & candidate_g = item.second;
206  if (candidate_g < g) {
207  l = candidate_l;
208  g = candidate_g;
209  }
210  }
211  while (true) {
212  auto it = optimal.m[k].find(l);
213  assert(it != optimal.m[k].end());
214  auto & m = it->second;
215  optimal_match_sequence.push_back(m);
216  if (!m.get().i) break;
217  k = m.get().i - 1;
218  l -= 1;
219  }
220  std::reverse(optimal_match_sequence.begin(), optimal_match_sequence.end());
221  return optimal_match_sequence;
222  };
223 
224  for (idx_t k = 0; k < n; ++k) {
225  for (const auto & m : matches_by_j[k]) {
226  if (m.get().i > 0) {
227  for (const auto & item : optimal.m[m.get().i - 1]) {
228  auto & l = item.first;
229  update(m, l + 1);
230  }
231  }
232  else {
233  update(m, 1);
234  }
235  }
236  bruteforce_update(k);
237  }
238  auto optimal_match_sequence = unwind(n);
239  auto optimal_l = optimal_match_sequence.size();
240 
241  guesses_t guesses;
242  // corner: empty password
243  if (password.length() == 0) {
244  guesses = 1;
245  }
246  else {
247  guesses = optimal.g[n - 1][optimal_l];
248  }
249 
250  // retrieve referenced bruteforce matches
251  std::vector<std::unique_ptr<Match>> bruteforce_matches;
252  for (const auto & ref : optimal_match_sequence) {
253  auto & m = ref.get();
254  if (m.get_pattern() != MatchPattern::BRUTEFORCE) continue;
255  auto it = bruteforces.find(std::make_pair(m.i, m.j));
256  if (it == bruteforces.end()) continue;
257  bruteforce_matches.push_back(std::move(it->second));
258  }
259 
260  return {
261  password,
262  guesses,
263  static_cast<guesses_log10_t>(std::log10(guesses)),
264  std::move(bruteforce_matches),
265  std::move(optimal_match_sequence),
266  };
267 }
268 
269 // ------------------------------------------------------------------------------
270 // guess estimation -- one function per match pattern ---------------------------
271 // ------------------------------------------------------------------------------
272 
273 guesses_t estimate_guesses(Match & match, const std::string & password) {
274  if (match.guesses) return match.guesses; // a match's guess estimate doesn't change. cache it.
275  guesses_t min_guesses = 1;
276  if (match.token.length() < password.length()) {
277  min_guesses = (token_len(match) == 1)
280  }
281 #define MATCH_FN(title, upper, lower) \
282  : match.get_pattern() == MatchPattern::upper ? lower##_guesses
283  guesses_t (*estimation_function)(const Match &) =
284  false ? nullptr MATCH_RUN() : nullptr;
285 #undef MATCH_FN
286  assert(estimation_function != nullptr);
287  auto guesses = estimation_function(match);
288  match.guesses = std::max(guesses, min_guesses);
289  match.guesses_log10 = static_cast<guesses_log10_t>(std::log10(match.guesses));
290  return match.guesses;
291 }
292 
294  assert(match.guesses);
295  return match.guesses;
296 }
297 
299  auto guesses = std::pow(BRUTEFORCE_CARDINALITY, token_len(match));
300  // small detail: make bruteforce matches at minimum one guess bigger than smallest allowed
301  // submatch guesses, such that non-bruteforce submatches over the same [i..j] take precedence.
302  auto min_guesses = (token_len(match) == 1)
305  return std::max(guesses, min_guesses);
306 }
307 
309  return match.get_repeat().base_guesses * match.get_repeat().repeat_count;
310 }
311 
313  auto second_chr_pos = util::utf8_iter(match.token.begin(), match.token.end());
314  auto first_chr = std::string(match.token.begin(), second_chr_pos);
315  guesses_t base_guesses;
316  // lower guesses for obvious starting points
317  if (first_chr == "a" || first_chr == "A" || first_chr == "z" ||
318  first_chr == "Z" || first_chr == "0" || first_chr == "1" ||
319  first_chr == "9") {
320  base_guesses = 4;
321  }
322  else {
323  if (std::regex_match(first_chr, std::regex(R"(\d)"))) {
324  base_guesses = 10; // digits
325  }
326  else {
327  // could give a higher base for uppercase,
328  // assigning 26 to both upper and lower sequences is more conservative.
329  base_guesses = 26;
330  }
331  }
332  if (!match.get_sequence().ascending) {
333  // need to try a descending sequence in addition to every ascending sequence ->
334  // 2x guesses
335  base_guesses *= 2;
336  }
337  return base_guesses * token_len(match);
338 }
339 
340 guesses_t regex_guesses(const Match & match) {
341  switch (match.get_regex().regex_tag) {
343  {
344  // conservative estimate of year space: num years from REFERENCE_YEAR.
345  // if year is close to REFERENCE_YEAR, estimate a year space of MIN_YEAR_SPACE.
346  auto pre_year_space = std::stoul(match.get_regex().regex_match.matches[0]);
347  if (pre_year_space > REFERENCE_YEAR) {
348  pre_year_space -= REFERENCE_YEAR;
349  }
350  else {
351  pre_year_space = REFERENCE_YEAR - pre_year_space;
352  }
353  guesses_t year_space = pre_year_space;
354  year_space = std::max(year_space, MIN_YEAR_SPACE);
355  return year_space;
356  }
358  auto base = [&] {
359  switch (match.get_regex().regex_tag) {
360  case RegexTag::ALPHA_LOWER: return 26;
361  case RegexTag::ALPHANUMERIC: return 62;
362  default: assert(false); return 0;
363  }
364  }();
365  return std::pow(base, token_len(match));
366  }
367  default:
368  return 0;
369  }
370 }
371 
372 guesses_t date_guesses(const Match & match) {
373  // base guesses: (year distance from REFERENCE_YEAR) * num_days * num_years
374  auto pre_year_space = match.get_date().year;
375  if (pre_year_space > REFERENCE_YEAR) {
376  pre_year_space -= REFERENCE_YEAR;
377  }
378  else {
379  pre_year_space = REFERENCE_YEAR - pre_year_space;
380  }
381 
382  guesses_t year_space = pre_year_space;
383  year_space = std::max(year_space, MIN_YEAR_SPACE);
384  auto guesses = year_space * 365;
385  // double for four-digit years
386  if (match.get_date().has_full_year) guesses *= 2;
387  // add factor of 4 for separator selection (one of ~4 choices)
388  if (match.get_date().separator.length()) guesses *= 4;
389  return guesses;
390 }
391 
393  std::size_t s;
394  guesses_t d;
395  if (match.get_spatial().graph == GraphTag::QWERTY ||
396  match.get_spatial().graph == GraphTag::DVORAK) {
399  }
400  else {
403  }
404  guesses_t guesses = 0;
405  auto L = token_len(match);
406  auto t = static_cast<decltype(L)>(match.get_spatial().turns);
407  // estimate the number of possible patterns w/ length L or less with t turns or less.
408  for (decltype(L) i = 2; i <= L; ++i) {
409  auto possible_turns = std::min(t, i - 1);
410  for (decltype(possible_turns) j = 1; j <= possible_turns; ++j) {
411  guesses += nCk(i - 1, j - 1) * s * std::pow(d, j);
412  }
413  }
414  // add extra guesses for shifted keys. (% instead of 5, A instead of a.)
415  // math is similar to extra guesses of l33t substitutions in dictionary matches.
416  if (match.get_spatial().shifted_count) {
417  auto S = match.get_spatial().shifted_count;
418  decltype(S) U = token_len(match) - match.get_spatial().shifted_count; // unshifted count
419  if (S == 0 || U == 0) {
420  guesses *= 2;
421  }
422  else {
423  auto shifted_variations = 0;
424  for (decltype(S) i = 1; i <= std::min(S, U); ++i) {
425  shifted_variations += nCk(S + U, i);
426  }
427  guesses *= shifted_variations;
428  }
429  }
430 
431  return guesses;
432 }
433 
435  auto base_guesses = match.get_dictionary().rank; // keep these as properties for display purposes
436  auto uppercase_variations_ = uppercase_variations(match);
437  auto l33t_variations_ = l33t_variations(match);
438  auto reversed_variations = match.get_dictionary().reversed ? 2 : 1;
439  return (base_guesses * uppercase_variations_ * l33t_variations_ * reversed_variations);
440 }
441 
443  auto & word = match.token;
444  if (std::regex_match(word, ALL_LOWER) || !word.size()) return 1;
445  // a capitalized word is the most common capitalization scheme,
446  // so it only doubles the search space (uncapitalized + capitalized).
447  // allcaps and end-capitalized are common enough too, underestimate as 2x factor to be safe.
448  for (const auto & regex : {START_UPPER, END_UPPER, ALL_UPPER}) {
449  if (std::regex_match(word, regex)) return 2;
450  }
451  // otherwise calculate the number of ways to capitalize U+L uppercase+lowercase letters
452  // with U uppercase letters or less. or, if there's more uppercase than lower (for eg. PASSwORD),
453  // the number of ways to lowercase U+L letters with L lowercase letters or less.
454  auto match_chr = [] (const std::string & str, const std::regex & regex) {
455  decltype(str.length()) toret = 0;
456  for (auto it = str.begin(); it != str.end();) {
457  auto it2 = util::utf8_iter(it, str.end());
458  auto s = std::string(it, it2);
459  if (std::regex_match(s, regex)) {
460  toret += 1;
461  }
462  it = it2;
463  }
464  return toret;
465  };
466  auto U = match_chr(word, std::regex(R"([A-Z])"));
467  auto L = match_chr(word, std::regex(R"([a-z])"));
468  guesses_t variations = 0;
469  for (decltype(U) i = 1; i <= std::min(U, L); ++i) {
470  variations += nCk(U + L, i);
471  }
472  return variations;
473 }
474 
476  auto & dmatch = match.get_dictionary();
477  if (!dmatch.l33t) return 1;
478  guesses_t variations = 1;
479  for (const auto & item : dmatch.sub) {
480  auto & subbed = item.first;
481  auto & unsubbed = item.second;
482  // lower-case match.token before calculating: capitalization shouldn't affect l33t calc.
483  idx_t S = 0, U = 0;
484  // XXX: using ascii_lower is okay for now since our
485  // sub dictionaries are ascii only
486  auto ltoken = util::ascii_lower(match.token);
487  for (auto it = ltoken.begin(); it != ltoken.end();) {
488  auto it2 = util::utf8_iter(it, ltoken.end());
489  auto cs = std::string(it, it2);
490  if (cs == subbed) S += 1;
491  if (cs == unsubbed) U += 1;
492  it = it2;
493  }
494  if (!S || !U) {
495  // for this sub, password is either fully subbed (444) or fully unsubbed (aaa)
496  // treat that as doubling the space (attacker needs to try fully subbed chars in addition to
497  // unsubbed.)
498  variations *= 2;
499  }
500  else {
501  // this case is similar to capitalization:
502  // with aa44a, U = 3, S = 2, attacker needs to try unsubbed + one sub + two subs
503  auto p = std::min(U, S);
504  guesses_t possibilities = 0;
505  for (decltype(p) i = 1; i <= p; ++i) {
506  possibilities += nCk(U + S, i);
507  }
508  variations *= possibilities;
509  }
510  }
511  return variations;
512 }
513 
514 }
zxcvbn::repeat_guesses
guesses_t repeat_guesses(const Match &match)
Definition: scoring.cpp:308
zxcvbn::date_guesses
guesses_t date_guesses(const Match &match)
Definition: scoring.cpp:372
zxcvbn::MIN_YEAR_SPACE
const guesses_t MIN_YEAR_SPACE
Definition: scoring.hpp:19
std::hash< std::pair< T, U > >::operator()
std::size_t operator()(const std::pair< T, U > &v) const
Definition: scoring.cpp:16
zxcvbn::most_guessable_match_sequence
ScoringResult most_guessable_match_sequence(const std::string &password, std::vector< Match > &matches, bool exclude_additive)
Definition: scoring.cpp:93
b
void const uint64_t * b
Definition: field_5x52_asm_impl.h:10
zxcvbn::Match::guesses_log10
guesses_log10_t guesses_log10
Definition: common.hpp:178
zxcvbn::regex_match
std::vector< Match > regex_match(const std::string &password, const std::vector< std::pair< RegexTag, std::regex >> &regexen)
Definition: matching.cpp:603
zxcvbn::Match::guesses
guesses_t guesses
Definition: common.hpp:177
zxcvbn::KEYBOARD_STARTING_POSITIONS
const std::size_t KEYBOARD_STARTING_POSITIONS
Definition: adjacency_graphs.hpp:47
zxcvbn::util::ascii_lower
std::string ascii_lower(const std::string &in)
Definition: util.cpp:15
zxcvbn::MATCH_RUN
MATCH_RUN()
zxcvbn::GraphTag::QWERTY
@ QWERTY
zxcvbn::ALL_UPPER
const auto ALL_UPPER
Definition: scoring.hpp:16
zxcvbn
Definition: _frequency_lists.cpp:7
zxcvbn::dictionary_guesses
guesses_t dictionary_guesses(const Match &match)
Definition: scoring.cpp:434
zxcvbn::estimate_guesses
guesses_t estimate_guesses(Match &match, const std::string &password)
Definition: scoring.cpp:273
zxcvbn::RegexTag::ALPHANUMERIC
@ ALPHANUMERIC
zxcvbn::Match::j
idx_t j
Definition: common.hpp:175
zxcvbn::spatial_guesses
guesses_t spatial_guesses(const Match &match)
Definition: scoring.cpp:392
zxcvbn::Match::token
std::string token
Definition: common.hpp:176
__attribute__
void __attribute__((sysv_abi)) secp256k1_fe_mul_inner(const uint64_t *a
zxcvbn::BRUTEFORCE_CARDINALITY
const auto BRUTEFORCE_CARDINALITY
Definition: scoring.cpp:25
zxcvbn::util::character_len
std::string::size_type character_len(const std::string &str, std::string::size_type start, std::string::size_type end)
Definition: util.cpp:84
zxcvbn::bruteforce_guesses
guesses_t bruteforce_guesses(const Match &match)
Definition: scoring.cpp:298
zxcvbn::RegexTag::RECENT_YEAR
@ RECENT_YEAR
zxcvbn::RegexTag::ALPHA_LOWER
@ ALPHA_LOWER
zxcvbn::guesses_log10_t
int guesses_log10_t
Definition: common.hpp:16
zxcvbn::END_UPPER
const auto END_UPPER
Definition: scoring.hpp:15
zxcvbn::MIN_GUESSES_BEFORE_GROWING_SEQUENCE
const auto MIN_GUESSES_BEFORE_GROWING_SEQUENCE
Definition: scoring.cpp:26
zxcvbn::START_UPPER
const auto START_UPPER
Definition: scoring.hpp:14
zxcvbn::REFERENCE_YEAR
const auto REFERENCE_YEAR
Definition: scoring.hpp:20
zxcvbn::Match::i
idx_t i
Definition: common.hpp:175
zxcvbn::util::utf8_iter
std::string::iterator utf8_iter(std::string::iterator start, std::string::iterator end)
Definition: util.cpp:74
zxcvbn::guesses_t
zxcvbn_guesses_t guesses_t
Definition: common.hpp:15
zxcvbn::MIN_SUBMATCH_GUESSES_MULTI_CHAR
const auto MIN_SUBMATCH_GUESSES_MULTI_CHAR
Definition: scoring.cpp:28
scoring.hpp
zxcvbn::ScoringResult
Definition: scoring.hpp:22
zxcvbn::ALL_LOWER
const auto ALL_LOWER
Definition: scoring.hpp:17
zxcvbn::GraphTag::DVORAK
@ DVORAK
zxcvbn::factorial
Tret factorial(Tin n)
Definition: scoring.cpp:31
zxcvbn::Match::get_pattern
MatchPattern get_pattern() const
Definition: common.hpp:216
zxcvbn::sequence_guesses
guesses_t sequence_guesses(const Match &match)
Definition: scoring.cpp:312
zxcvbn::KEYPAD_STARTING_POSITIONS
const std::size_t KEYPAD_STARTING_POSITIONS
Definition: adjacency_graphs.hpp:48
L
#define L(x0, x1, x2, x3, x4, x5, x6, x7)
Definition: jh.c:501
std
Definition: adjacency_graphs.hpp:25
zxcvbn::l33t_variations
guesses_t l33t_variations(const Match &match)
Definition: scoring.cpp:475
zxcvbn::unknown_guesses
guesses_t unknown_guesses(const Match &match)
Definition: scoring.cpp:293
zxcvbn::idx_t
std::string::size_type idx_t
Definition: common.hpp:18
zxcvbn::nCk
T nCk(T n, T k)
Definition: scoring.hpp:31
adjacency_graphs.hpp
zxcvbn::MIN_SUBMATCH_GUESSES_SINGLE_CHAR
const auto MIN_SUBMATCH_GUESSES_SINGLE_CHAR
Definition: scoring.cpp:27
zxcvbn::BruteforceMatch
Definition: common.hpp:123
zxcvbn::Match
Definition: common.hpp:133
zxcvbn::regex_guesses
guesses_t regex_guesses(const Match &match)
Definition: scoring.cpp:340
zxcvbn::KEYPAD_AVERAGE_DEGREE
const degree_t KEYPAD_AVERAGE_DEGREE
Definition: adjacency_graphs.hpp:45
util.hpp
S
#define S(x0, x1, x2, x3, cb, r)
Definition: jh.c:494
zxcvbn::uppercase_variations
guesses_t uppercase_variations(const Match &match)
Definition: scoring.cpp:442
zxcvbn::KEYBOARD_AVERAGE_DEGREE
const degree_t KEYBOARD_AVERAGE_DEGREE
Definition: adjacency_graphs.hpp:44