back

by elesiuta·3y ago·view on hn ↗
> It would be fun to work out mathematically how much they're limiting the password space with these rules.

Alright, you nerd sniped me, but I'm lazy so I just simulated it, this cuts down the password space by ~35%. I didn't take into account passwords with leading 0s in my sampling, but this shouldn't change the result by much.

    from collections import Counter
    from random import randint
    def is_valid(password: str) -> bool:
        # cannot have the same number 3 times in a row
        if any(password[i] == password[i + 1] == password[i + 2] for i in range(len(password) - 2)):
            return False
        # cannot have 4 ascending numbers
        if any(all(password[i] == str(int(password[i + j]) - j) for j in range(4)) for i in range(len(password) - 3)):
            return False
        # cannot have 4 descending numbers
        if any(all(password[i] == str(int(password[i + j]) + j) for j in range(4)) for i in range(len(password) - 3)):
            return False
        # cannot have the same number appear more than 5 times
        if max(Counter(password).values()) > 5:
            return False
        # cannot have pairs next to each other if the second pair is one number higher
        if any(int(password[i:i+2]) == int(password[i+2:i+4]) - 1 for i in range(len(password) - 3)):
            return False
        return True
    total_valid = 0
    samples = 10**5
    for i in range(samples):
        password = str(randint(10**6, 10**20 - 1))
        if is_valid(password):
            total_valid += 1
    print(f"valid passwords: {total_valid}")
    print(f"valid percentage: {total_valid / samples * 100:.2f}%")
valid passwords: 65045

valid percentage: 65.05%

2 comments
I'm glad I sniped you before I sniped myself!

I still question the interpretation of:

> cannot have pairs next to each other if the second pair is one number higher

But I think the outcome would be the same either way.

Really the only place the amount of excluded password space matters is at the minimum length, which is conveniently brute forceable. Without padding 0's that comes to 91.63% valid, with padding 0's 91.42%. Smaller spaces are going to hit the repeat rules less often so the wide difference in percentages should be no surprise.