# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference) # Canonical Residual: https://corpusfetch.com/c/how-must-an-instance-verify-provenance-without-the-original-data-only-hashes.md # Remnant Warrant: https://corpusfetch.com/c/how-must-an-instance-verify-provenance-without-the-original-data-only-hashes.warrant.json # Markdown SHA-256: bec923d223a85e6fa709eb9413ace8feb6abb4fac42186e62fbecc5782431d63 # Code AST SHA-256: e9141c99b933993db1b3049470f49eea63ccc09ab9abebe93c304f8d79b7e92e # Verified Classes: HashProvenanceVerdict, HashProvenanceLink, ProvenanceClaim, HashPolicy, HashProvenanceManifest, HashOnlyProvenanceGuard # Defensive Guards: 0 fail-closed invariants (zero external deps) from dataclasses import dataclass from enum import Enum, auto import hashlib import json class HashProvenanceVerdict(Enum): DATA_AVAILABLE = auto() HASH_VERIFICATION_SUFFICIENT = auto() HASH_VERIFICATION_LIMITED = auto() INSUFFICIENT_HASH_EVIDENCE = auto() @dataclass(frozen=True) class HashProvenanceLink: input_hash: str process_hash: str output_hash: str determinism_attested: bool process_owner_signature: str | None @dataclass(frozen=True) class ProvenanceClaim: claim_id: str data_available: bool links: tuple[HashProvenanceLink, ...] hash_collision_resistance_bits: int @dataclass(frozen=True) class HashPolicy: min_collision_resistance_bits: int require_determinism_attestation: bool @dataclass(frozen=True) class HashProvenanceManifest: verdict: HashProvenanceVerdict directive: str manifest_digest: str class HashOnlyProvenanceGuard: @staticmethod def _hash(data: str) -> str: return hashlib.sha256(data.encode("utf-8")).hexdigest() @classmethod def evaluate_provenance( cls, claim: ProvenanceClaim, policy: HashPolicy ) -> HashProvenanceManifest: # Gate 1: Data available if claim.data_available: digest = cls._hash(json.dumps({ "claim": claim.claim_id, "type": "DATA_AVAILABLE" }, sort_keys=True)) return HashProvenanceManifest( verdict=HashProvenanceVerdict.DATA_AVAILABLE, directive=f"PROCEED: Data available for claim {claim.claim_id}, verify directly.", manifest_digest=digest ) # Gate 2: Hash chain presence if not claim.links: return HashProvenanceManifest( verdict=HashProvenanceVerdict.INSUFFICIENT_HASH_EVIDENCE, directive=f"HALT: No hash chain for claim {claim.claim_id}.", manifest_digest=cls._hash(f"NO_CHAIN:{claim.claim_id}") ) # Gate 3: Collision resistance if claim.hash_collision_resistance_bits < policy.min_collision_resistance_bits: return HashProvenanceManifest( verdict=HashProvenanceVerdict.HASH_VERIFICATION_LIMITED, directive=f"HALT: Hash collision resistance {claim.hash_collision_resistance_bits} < {policy.min_collision_resistance_bits}.", manifest_digest=cls._hash(f"WEAK_HASH:{claim.claim_id}") ) # Gate 4: Determinism attestation if policy.require_determinism_attestation: unattested = [l for l in claim.links if not l.determinism_attested or not l.process_owner_signature] if unattested: return HashProvenanceManifest( verdict=HashProvenanceVerdict.HASH_VERIFICATION_LIMITED, directive=f"HALT: {len(unattested)} links lack determinism attestation.", manifest_digest=cls._hash(f"NO_ATTEST:{len(unattested)}") ) # Gate 5: Sufficient digest = cls._hash(json.dumps({ "claim": claim.claim_id, "chain_length": str(len(claim.links)), "collision_resistance": str(claim.hash_collision_resistance_bits), "links": tuple( {"input": l.input_hash, "process": l.process_hash, "output": l.output_hash} for l in claim.links ) }, sort_keys=True)) return HashProvenanceManifest( verdict=HashProvenanceVerdict.HASH_VERIFICATION_SUFFICIENT, directive=f"PROCEED: {len(claim.links)}-link hash chain verified with determinism attestation.", manifest_digest=digest )