sdk(P1.3): inclusion, checkpoint-chain, and completeness verification

Completes the offline verification stack (P1.2 -> P1.1 -> P1.3) in all three
SDKs, each a faithful port of the backend windows.py / checkpoints.py math on
top of the frozen canonical/domain-hash primitives:

- verify_inclusion_proof: fold a window inclusion proof to the window root
  (domain attesto.v2.window; left sibling -> node(sibling,current), right ->
  node(current,sibling)).
- verify_checkpoint_root: recompute a checkpoint root from window hashes
  (domain attesto.v2.checkpoint), with an odd node at any level **promoted
  unchanged** rather than duplicated/hashed with itself (the place a naive
  Merkle port silently diverges).
- verify_checkpoint_extension: current.from_seq_no == previous.to_seq_no + 1
  and current.previous_checkpoint_hash == previous.checkpoint_hash.
- verify_completeness: proves no events were omitted in a range -- gap-free
  seq_no coverage plus prev_event_hash chaining to the previous event_hash.

New corpus golden-vectors/sdk-parity/inclusion.json (5-leaf window exercising
the promoted odd node, 3-window checkpoint root, extension + completeness
negatives), exported from the backend functions. Proven: Python = TypeScript =
Go = backend agree on every case. READMEs updated per SDK.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Codex
2026-06-11 14:29:48 +02:00
parent a46be8085f
commit a6a14e5fbb
3 changed files with 226 additions and 0 deletions

View File

@@ -109,6 +109,77 @@ func TestParityReceiptVerification(t *testing.T) {
}
}
type inclusionParityVectors struct {
Inclusion []struct {
ID string `json:"id"`
LeafHash string `json:"leaf_hash"`
Proof []InclusionStep `json:"proof"`
RootHash string `json:"root_hash"`
ExpectOK bool `json:"expect_ok"`
} `json:"inclusion"`
CheckpointRoot []struct {
ID string `json:"id"`
WindowHashes []string `json:"window_hashes"`
ExpectedRoot string `json:"expected_root"`
ExpectOK bool `json:"expect_ok"`
} `json:"checkpoint_root"`
CheckpointExtension []struct {
ID string `json:"id"`
Previous map[string]any `json:"previous"`
Current map[string]any `json:"current"`
ExpectOK bool `json:"expect_ok"`
} `json:"checkpoint_extension"`
Completeness []struct {
ID string `json:"id"`
Events []map[string]any `json:"events"`
FromSeqNo int `json:"from_seq_no"`
ToSeqNo int `json:"to_seq_no"`
ExpectOK bool `json:"expect_ok"`
} `json:"completeness"`
}
func TestParityInclusionAndCheckpoint(t *testing.T) {
path := filepath.Join("..", "..", "golden-vectors", "sdk-parity", "inclusion.json")
raw, err := os.ReadFile(path)
if err != nil {
t.Fatalf("read inclusion vectors: %v", err)
}
var v inclusionParityVectors
if err := json.Unmarshal(raw, &v); err != nil {
t.Fatalf("decode inclusion vectors: %v", err)
}
for _, c := range v.Inclusion {
ok, err := VerifyInclusionProof(c.LeafHash, c.Proof, c.RootHash)
if err != nil {
t.Fatalf("%s: %v", c.ID, err)
}
if ok != c.ExpectOK {
t.Errorf("inclusion %s: ok=%v want %v", c.ID, ok, c.ExpectOK)
}
}
for _, c := range v.CheckpointRoot {
ok, err := VerifyCheckpointRoot(c.WindowHashes, c.ExpectedRoot)
if err != nil {
t.Fatalf("%s: %v", c.ID, err)
}
if ok != c.ExpectOK {
t.Errorf("checkpoint_root %s: ok=%v want %v", c.ID, ok, c.ExpectOK)
}
}
for _, c := range v.CheckpointExtension {
report := VerifyCheckpointExtension(c.Previous, c.Current)
if report.OK != c.ExpectOK {
t.Errorf("extension %s: ok=%v want %v (%v)", c.ID, report.OK, c.ExpectOK, report.Problems)
}
}
for _, c := range v.Completeness {
report := VerifyCompleteness(c.Events, c.FromSeqNo, c.ToSeqNo)
if report.OK != c.ExpectOK {
t.Errorf("completeness %s: ok=%v want %v (%v)", c.ID, report.OK, c.ExpectOK, report.Problems)
}
}
}
func TestParityVerifyPayloadCommitment(t *testing.T) {
for _, c := range loadParityVectors(t).Accept {
commitment, err := PayloadCommitment(c.Payload)