One function
verify_solution in altcha-org/altcha-lib-py
The author described this change as “fix: enforce key_prefix in PoW v2 fallback verification”. It counts as a record because the check below fails on the code as it stood at 7fc795f0e and passes on 2f70cdbfb, with nothing else changed between the two runs.
Projectaltcha-org/altcha-lib-py
Fix saved2026-07-27
Sharing licenceMIT · LICENSE
Change size+5 −2
What the code was meant to do, written into the code itself as a docstring
Verify a v2 challenge solution. Checks (in order): 1. Whether the challenge has expired. 2. Whether the challenge signature is present. 3. Whether the challenge signature is valid (tamper check). 4. Whether the solution is correct — via key signature (fast) or re-derivation (slow). Args: payload: Base64-encoded JSON payload string or a :class:`Payload` object. hmac_secret: Secret used to verify the challenge signature. derive_key: KDF function for re-derivation. Defaults to built-in for the algorithm. hmac_key_secret: Secret used to verify the derived-key signature (fast path). hmac_algorithm: HMAC digest algorithm. Defaults to `'SHA-256'`. Returns: A :class:`VerifySolutionResult` describing the outcome.
The change
| 102 | 102 | verified=valid, | |
| 103 | 103 | ) | |
| 104 | 104 | ||
| 105 | - | # 4b. Slow path: re-derive the key from the counter and compare. | |
| 105 | + | # 4b. Slow path: re-derive the key from the counter and compare, and | |
| 106 | + | # require it to satisfy the signed key prefix. | |
| 106 | 107 | if derive_key is None: | |
| 107 | 108 | derive_key = _select_derive_key(params.algorithm) | |
| 108 | 109 | ||
| ⋯ | |||
| 111 | 112 | password = _make_password(nonce_bytes, solution.counter) | |
| 112 | 113 | recomputed = derive_key(params, salt_bytes, password) | |
| 113 | 114 | recomputed_hex = recomputed.hex() | |
| 114 | - | invalid = not _constant_time_equal(recomputed_hex, solution.derived_key) | |
| 115 | + | key_matches = _constant_time_equal(recomputed_hex, solution.derived_key) | |
| 116 | + | prefix_matches = recomputed_hex.startswith(params.key_prefix) | |
| 117 | + | invalid = not (key_matches and prefix_matches) | |
| 115 | 118 | ||
| 116 | 119 | return VerifySolutionResult( | |
| 117 | 120 | expired=False, | |
The check that tells the two apart
fail→pass·tests/test_altcha_v2.py::TestVerifySolution::test_slow_path_enforces_key_prefix
Check file tests/test_altcha_v2.py, taken without changes from the fix and copied onto the older code, so the exact same check runs against both versions.
Origin and history
The code before it7fc795f0e8a0a9d8dc077f168dddc99041865aef
Broken version dated2026-07-27
Modulealtcha.v2
Units changedverify_solution
Fingerprint99e8e6e0b16fb43c
Checked2026-08-18 by goldset/0.1
Every field above is generated by our program. None of it is written by hand.