The different non-deterministic outputs actually end up with the different g values.
Sorting matches_by_j fixes the non-determinism but it doesn't fix the correctness. The correct result depends on the incremental l value being computed and I don't think there is a matches_by_j sort that has a connection to the correct result. What actually should be sorted is the iteration over for l, last_m of optimal.m[k - 1] (in bruteforce_update) but it should be sorted by last_m.g, this will ensure update() is called in the right order.
I actually ran into this with the passphrase "horse_correct_battery_staple" [sic]. For one reason or another, zxcvbn-cpp provoked a different (& incorrect) result than upstream
zxcvbn.
To verify this yourself, randomize the iteration of for l, last_m of optimal.m[k - 1] for different runs of "horse_correct_battery_staple" and you'll get different result sequences with different g values.
Originally posted by @rianhunter in dropbox/zxcvbn#158 (comment)
The different non-deterministic outputs actually end up with the different g values.
Sorting
matches_by_jfixes the non-determinism but it doesn't fix the correctness. The correct result depends on the incrementallvalue being computed and I don't think there is amatches_by_jsort that has a connection to the correct result. What actually should be sorted is the iteration overfor l, last_m of optimal.m[k - 1](inbruteforce_update) but it should be sorted bylast_m.g, this will ensureupdate()is called in the right order.I actually ran into this with the passphrase "horse_correct_battery_staple" [sic]. For one reason or another, zxcvbn-cpp provoked a different (& incorrect) result than upstream
zxcvbn.
To verify this yourself, randomize the iteration of
for l, last_m of optimal.m[k - 1]for different runs of "horse_correct_battery_staple" and you'll get different result sequences with different g values.Originally posted by @rianhunter in dropbox/zxcvbn#158 (comment)