Verify the anchor instead of believing it - #37
Merged
Conversation
The bundled verifier's anchored layer accepted three claims a record made about itself. It reported the digest the record stated without recomputing one from the checkpoint the record embeds, so pointing a record at a checkpoint its proof never covered cost one edit. It never opened a proof file, so a truncated proof still counted as an anchor. And it counted the status field, so a record claiming confirmed passed with no proof bytes on disk, which is the overclaim this project exists to refuse. All three now come from the evidence: the digest is recomputed and compared, a submission that reached a calendar must have non-empty proof bytes behind it, and those bytes are parsed against the submitted digest. The parser is new. It implements the proof grammar in docs/audit-format.md and is bounded against hostile input, because the file being verified is attacker-influenced by definition: caps on argument size, total size, fork depth, operation count, and working message length. RIPEMD-160 and Keccak-256 are declined rather than evaluated, matching the independent Go verifier, so neither implementation depends on how the host's crypto provider was built. The writer parses a calendar response before keeping it. Filing bytes that lead nowhere would tell an operator their evidence is corrupt when it was never a proof. Corpus: the b9, b10 and b13 divergence declarations are removed in the same commit, since the harness fails when a declared divergence stops happening. b11 stays declared. Corpus bytes are unchanged and still reproduce from the generator.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stops the bundled verifier trusting what an anchor record says about itself. Closes three of the four cases where the independent Go verifier was stricter than ours.
b13,
proof-missing. We counted thestatusfield at face value, so a record claimingconfirmedpassed with zero proof bytes on disk. A claim is now backed by bytes or it fails. This was the worst of the three: a self-reported status treated as evidence is exactly the overclaim this project exists to refuse.b9,
digest-mismatch. An anchor record states a digest and we never recomputed it. Now recomputed from the checkpoint and compared.b10,
proof-parse-error. We never parsed the OpenTimestamps proof, so a truncated one was accepted. There is now a real parser, carrying the same hostile-input caps as the Go implementation: message size, depth, and total size. The file being verified is attacker-influenced by definition, so a verifier that can be exhausted by its own input is itself an attack surface.The parser has to accept genuine proofs, not merely reject bad ones. Verified against the operator's live chain: it reads a real 137-byte pending proof and the chain still verifies exit 0 with all three layers passing.
Conformance goes to 25 agreed with one declared divergence remaining,
b11, which is closed by its own branch landing next.