tests/test_verifier.py
3.4 KB · 103 lines · python Raw
1 """Tests for the CommitmentVerifier end-to-end flow."""
2
3 from __future__ import annotations
4
5 import pytest
6
7 from pqc_training_data import (
8 CommitmentBuilder,
9 CommitmentSigner,
10 CommitmentVerifier,
11 DataRecord,
12 TrainingCommitment,
13 )
14 from pqc_training_data.errors import CommitmentVerificationError
15
16
17 def _build_signed(
18 signer: CommitmentSigner, records: list[DataRecord]
19 ) -> tuple[CommitmentBuilder, TrainingCommitment]:
20 builder = CommitmentBuilder("verifier-ds", "1.0.0")
21 builder.add_records(records)
22 commitment = signer.sign(builder.build())
23 return builder, commitment
24
25
26 def test_verify_success_for_valid_record(
27 signer: CommitmentSigner,
28 sample_records: list[DataRecord],
29 ) -> None:
30 builder, commitment = _build_signed(signer, sample_records)
31 proof = builder.tree.inclusion_proof(2)
32 result = CommitmentVerifier.verify(sample_records[2], proof, commitment)
33 assert result.fully_verified is True
34 assert result.error is None
35
36
37 def test_verify_fails_when_record_not_in_tree(
38 signer: CommitmentSigner,
39 sample_records: list[DataRecord],
40 ) -> None:
41 builder, commitment = _build_signed(signer, sample_records)
42 proof = builder.tree.inclusion_proof(2)
43 bogus_record = DataRecord(content=b"never-was-added", metadata={"doc_id": 999})
44 result = CommitmentVerifier.verify(bogus_record, proof, commitment)
45 assert result.fully_verified is False
46 assert result.leaf_matches_record is False
47
48
49 def test_verify_fails_when_proof_tampered(
50 signer: CommitmentSigner,
51 sample_records: list[DataRecord],
52 ) -> None:
53 builder, commitment = _build_signed(signer, sample_records)
54 proof = builder.tree.inclusion_proof(2)
55 # Tamper with a sibling hash
56 tampered_siblings = list(proof.siblings)
57 first = tampered_siblings[0]
58 tampered_siblings[0] = ("f" if first[0] != "f" else "0") + first[1:]
59 tampered_proof = type(proof)(
60 leaf_hash=proof.leaf_hash,
61 index=proof.index,
62 tree_size=proof.tree_size,
63 root=proof.root,
64 siblings=tampered_siblings,
65 directions=list(proof.directions),
66 )
67 result = CommitmentVerifier.verify(sample_records[2], tampered_proof, commitment)
68 assert result.fully_verified is False
69 assert result.proof_valid is False
70
71
72 def test_verify_fails_when_commitment_unsigned(
73 sample_records: list[DataRecord],
74 ) -> None:
75 builder = CommitmentBuilder("unsigned-ds", "1.0.0")
76 builder.add_records(sample_records)
77 commitment = builder.build() # no .sign() call
78 proof = builder.tree.inclusion_proof(0)
79 result = CommitmentVerifier.verify(sample_records[0], proof, commitment)
80 assert result.signature_valid is False
81 assert result.fully_verified is False
82
83
84 def test_verify_or_raise_raises_on_mismatch(
85 signer: CommitmentSigner,
86 sample_records: list[DataRecord],
87 ) -> None:
88 builder, commitment = _build_signed(signer, sample_records)
89 proof = builder.tree.inclusion_proof(0)
90 wrong_record = DataRecord(content=b"nope", metadata={})
91 with pytest.raises(CommitmentVerificationError):
92 CommitmentVerifier.verify_or_raise(wrong_record, proof, commitment)
93
94
95 def test_verify_or_raise_silent_on_success(
96 signer: CommitmentSigner,
97 sample_records: list[DataRecord],
98 ) -> None:
99 builder, commitment = _build_signed(signer, sample_records)
100 proof = builder.tree.inclusion_proof(4)
101 # Should not raise
102 CommitmentVerifier.verify_or_raise(sample_records[4], proof, commitment)
103