casebench
test cases straight onto the board.
git clone https://owenrusk.dev/casebench.git
commit 1f4702d0b6bf1723a5435af631fec938240a47d9 parent 8ee9741288e34bbe0785a872acf8d982fec33b90 author Owen Rusk <owen@papermothgames.com> date 2025-10-22 11:39:55 -0500
lock: cap the combinations at 64 four lines of four alternates took a few seconds to hash. that's 256; nobody needs that.
| casebench/lock.py | +7 | -0 |
| tests/test_lock.py | +4 | -0 |
diff --git a/casebench/lock.py b/casebench/lock.py index c4d2ad8..475800c 100644 --- a/casebench/lock.py +++ b/casebench/lock.py @@ -1,11 +1,16 @@ import hashlib import hmac import itertools +import math import os from dataclasses import dataclass, replace from datetime import datetime, timedelta +# each combination is a scrypt, at lock time. past this, write fewer alternates. +MAX_COMBINATIONS = 64 + + @dataclass(frozen=True) class Rest: after: int @@ -49,6 +54,8 @@ def make(answers: list[str], rest: Rest, text: str = "locked.") -> Lock: choices = [[a for a in (normalize(part) for part in line.split("|")) if a] for line in answers] if not choices or not all(choices): raise ValueError("a lock needs an answer on every line") + if math.prod(len(choice) for choice in choices) > MAX_COMBINATIONS: + raise ValueError(f"more than {MAX_COMBINATIONS} combinations of answers") salt = os.urandom(16) hashes = sorted(digest(list(combination), salt) for combination in itertools.product(*choices)) return Lock(text, len(answers), salt, tuple(hashes), rest) diff --git a/tests/test_lock.py b/tests/test_lock.py index 2eb2a4d..c97df15 100644 --- a/tests/test_lock.py +++ b/tests/test_lock.py @@ -67,6 +67,10 @@ class AttemptTest(unittest.TestCase): self.assertEqual(lock.attempt(either, typed, T0)[0], "open") self.assertEqual(lock.attempt(either, ["grey", "hat"], T0)[0], "wrong") + def test_too_many_combinations(self): + with self.assertRaisesRegex(ValueError, "combinations"): + lock.make(["a|b|c|d"] * 4, lock.Rest(3, 60)) + def test_empty_line(self): with self.assertRaises(ValueError): lock.make(["a", " | "], lock.Rest(3, 60))