An inclusion proof that reconstructs nothing is refused #175

Merged
paulhitt merged 1 commits from test/inclusion-refuses-a-malformed-proof into main 2026-09-22 15:40:35 +00:00
paulhitt commented 2026-09-22 15:20:16 +00:00 (Migrated from gitlab.com)

Six refusals were disabled one at a time. Five died: the three §20
identity checks, downgrade, signature and substitution, and both key-log
fork checks. This one survived all 719 engine and 473 client tests.

verifyInclusion ends with rootFromInclusion(...) ?: return false.
That line is what turns "this proof reconstructs nothing" into a
refusal, and flipping it to ?: return true broke nothing.

It hid because the suite does assert the null cases, on
rootFromInclusion directly:

assertNull(KeyLog.rootFromInclusion(leaf, size, size, proof))
assertNull(KeyLog.rootFromInclusion(leaf, -1, size, proof))

The primitive was tested and the wrapper everything calls was not. With
that line wrong, a proof whose shape is wrong, a bad index, a truncated
path, a spare node, would have verified, which is the §19.2 refusal
itself.

The new test drives verifyInclusion with all four shapes and asserts
the published proof still verifies first, so the refusals cannot be
satisfied by a verifier that always says no.

scripts/mutate.py ships the harness, as in the engine and the relay.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com

Six refusals were disabled one at a time. Five died: the three §20 identity checks, downgrade, signature and substitution, and both key-log fork checks. This one survived all 719 engine and 473 client tests. `verifyInclusion` ends with `rootFromInclusion(...) ?: return false`. That line is what turns "this proof reconstructs nothing" into a refusal, and flipping it to `?: return true` broke nothing. It hid because the suite does assert the null cases, on `rootFromInclusion` directly: assertNull(KeyLog.rootFromInclusion(leaf, size, size, proof)) assertNull(KeyLog.rootFromInclusion(leaf, -1, size, proof)) The primitive was tested and the wrapper everything calls was not. With that line wrong, a proof whose shape is wrong, a bad index, a truncated path, a spare node, would have verified, which is the §19.2 refusal itself. The new test drives `verifyInclusion` with all four shapes and asserts the published proof still verifies first, so the refusals cannot be satisfied by a verifier that always says no. `scripts/mutate.py` ships the harness, as in the engine and the relay. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
paulhitt commented 2026-09-22 15:20:16 +00:00 (Migrated from gitlab.com)

assigned to @paulhitt

assigned to @paulhitt
paulhitt commented 2026-09-22 15:40:36 +00:00 (Migrated from gitlab.com)

mentioned in commit 8b50ffe765

mentioned in commit 8b50ffe765f3439a373aff4679851d7adfbb8697
paulhitt (Migrated from gitlab.com) merged commit 8b50ffe765 into main 2026-09-22 15:40:36 +00:00
Sign in to join this conversation.