Skip to content

Verify subtree inclusion proofs#227

Open
phbnf wants to merge 11 commits into
transparency-dev:mainfrom
phbnf:verifysubtreeinclusion
Open

Verify subtree inclusion proofs#227
phbnf wants to merge 11 commits into
transparency-dev:mainfrom
phbnf:verifysubtreeinclusion

Conversation

@phbnf
Copy link
Copy Markdown
Contributor

@phbnf phbnf commented Jun 3, 2026

Towards #225.

This PR implements VerifySubtreeInclusion and adds relevant tests:

  • duplicates the VerifyInclusion tests
  • adds matching subtree tests by shifting the subtrees to the left (except when LeafIdx was set to 2^64-1)
  • adds boundary tests under /errors

Like in the previous PR, there's little benefit to factoring VerifyInclusion and VerifySubtreeInclusion into each other, but we can always do that later if we want to.

While I'm there, fix a error message in SubtreeInclusion.

@phbnf phbnf requested a review from AlCutter June 3, 2026 10:36
@phbnf phbnf requested a review from a team as a code owner June 3, 2026 10:36
@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 3, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 58.57%. Comparing base (4ebea17) to head (85206ca).
⚠️ Report is 127 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff             @@
##             main     #227       +/-   ##
===========================================
- Coverage   89.33%   58.57%   -30.76%     
===========================================
  Files           7        8        +1     
  Lines         497      618      +121     
===========================================
- Hits          444      362       -82     
- Misses         48      251      +203     
  Partials        5        5               

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Collaborator

@AlCutter AlCutter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll admit I've not looked at the millions of lines of json in here...

Comment thread proof/proof.go Outdated
}
if !isSubtreeValid(start, end) {
return Nodes{}, fmt.Errorf("start %d not a multiple of bit_ceil(end - start) = %d", start, end-start)
return Nodes{}, fmt.Errorf("start %d not a multiple of bit_ceil(end - start)", start)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I quite liked having the thing it wasn't a multiple of in there (although it was wrong, but that makes me think that perhaps isSubtreeValid should return an error explaining why it isn't - technically this error would be wrong/misleading if e.g. a very large l was passed in).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hehe, it was actually returning an error, but I removed it thinking this is what you were asking for yesterday, I'll put it back!

Comment thread proof/verify.go Outdated
Comment on lines +54 to +56
// VerifySubtreeInclusion verifies the correctness of the subtree inclusion
// proof for the leaf with the specified hash and index, relatively to the
// [start, end) subtree with a given subtree root hash.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// VerifySubtreeInclusion verifies the correctness of the subtree inclusion
// proof for the leaf with the specified hash and index, relatively to the
// [start, end) subtree with a given subtree root hash.
// VerifySubtreeInclusion verifies the correctness of the subtree inclusion
// proof for the leaf with the specified hash and index, relative to the
// provided subtree [start, end) and root hash.

Comment thread proof/verify.go Outdated
return fmt.Errorf("index %d out of bounds for subtree [%d, %d)", index, start, end)
}
if !isSubtreeValid(start, end) {
return fmt.Errorf("start %d not a multiple of bit_ceil(end - start)", start)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(same comment about errors here)

Comment thread proof/verify_test.go
return nil
}

if filepath.Ext(d.Name()) != ".json" {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe with strings.ToLower just in case?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure thing - this is just a copy of TestVerifyInclusionProbes, so let's maybe do that in a followup PR?

Comment thread proof/verify_test.go
Comment on lines +154 to +169
err := VerifySubtreeInclusion(rfc6962.DefaultHasher, p.LeafIdx, p.Start, p.End, p.LeafHash, p.Proof, p.Root)
if p.WantError && err == nil {
wrong = append(wrong, fmt.Sprintf("expected error but didn't get one: %s", p.Desc))
continue
}

if !p.WantError && err != nil {
wrong = append(wrong, fmt.Sprintf("unexpected error: %s, %s", p.Desc, err))
continue
}
}

if len(wrong) > 0 {
t.Errorf("errors verifying subtree inclusion probes: \n%d out of %d failures \nError messages: \n%s", len(wrong), len(probes), strings.Join(wrong, "\n"))
}
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this be more "modern" as a t.Run(p.Desc, func(t *testing.T) { ...?

Can ditch the continues and len(wrong) stuff then, and just let testing do the right reporting.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure thing - this is just a copy of TestVerifyInclusionProbes, so let's maybe do that in a followup PR?

@phbnf
Copy link
Copy Markdown
Contributor Author

phbnf commented Jun 3, 2026

I'll admit I've not looked at the millions of lines of json in here...

Reviewing individual commits will help to understand what's happening under the hood.

Comment thread proof/proof.go Outdated
Comment on lines +239 to +241
if start%bitCeil(l) != 0 {
return fmt.Errorf("start %d not a multiple of bit_ceil(end - start) = %d", start, l)
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if start%bitCeil(l) != 0 {
return fmt.Errorf("start %d not a multiple of bit_ceil(end - start) = %d", start, l)
}
if bc := bitCeil(l); start%bc != 0 {
return fmt.Errorf("start %d not a multiple of bit_ceil(end - start) = %d", start, bc)
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants