Offline Verification Checklist

Before trusting an evidence bundle, you must complete every verification step in order. This checklist defines the minimum requirements for accepting a bundle as valid.

Phase 1: Bundle Integrity

First, verify the bundle package itself hasn't been modified in transit or storage.

  • B1: Unpack ZIP without network access
  • B2: Parse bundle_manifest.json
  • B3: For each file in manifest, compute SHA-256 and compare to declared hash
  • B4: Verify file sizes match declared sizes
  • B5: Reject if any undeclared files present (optional, per implementation)

Phase 2: Policy Artifact Validation

Next, verify the policy artifact is authentic and properly formed.

  • P1: Parse policy_artifact.json
  • P2: Validate all required fields present
  • P3: Canonicalize policy (excluding issuer.signature and policy_id)
  • P4: Compute SHA-256 of canonical bytes
  • P5: Compare computed hash to declared policy_id
  • P6: Canonicalize policy (excluding issuer.signature only)
  • P7: Verify Ed25519 signature using issuer.public_key
  • P8: Validate key_id matches SHA-256 of public key bytes (first 16 hex chars)

Phase 3: Receipt Validation

Validate each receipt individually before checking chain integrity.

  • R1: Load receipts in counter order (0001.json, 0002.json, ...)
  • R2: For each receipt, validate schema (all required fields present)
  • R3: Canonicalize receipt (excluding signer.signature and receipt_id)
  • R4: Compute SHA-256, compare to declared receipt_id
  • R5: Canonicalize receipt (excluding signer.signature and this_receipt_hash)
  • R6: Compute SHA-256, compare to declared this_receipt_hash
  • R7: Verify Ed25519 signature using signer.public_key

Phase 4: Chain Continuity

Verify the receipt chain forms an unbroken, tamper-evident sequence.

  • C1: First receipt prev_receipt_hash must equal 64 zeros
  • C2: Each subsequent receipt prev_receipt_hash must equal previous receipt's this_receipt_hash
  • C3: Counter values must be monotonically increasing (1, 2, 3, ...)
  • C4: No counter gaps allowed
  • C5: All receipts reference same run_id
  • C6: Parse chain_head.json
  • C7: Verify head_receipt_hash matches last receipt's this_receipt_hash
  • C8: Verify receipt_count matches actual count

Phase 5: Policy Consistency

Verify all receipts reference the same policy and required events are present.

  • PC1: All receipts policy.policy_id must match policy artifact policy_id
  • PC2: Required event types present (POLICY_LOADED, ENFORCED, etc.)
  • PC3: If DRIFT_DETECTED, corresponding ENFORCED receipt must follow
  • PC4: Enforcement action matches policy enforcement_mapping

Phase 6: Emit Verdict

Generate the final verdict based on all checks.

  • V1: If all checks pass → verdict: PASS
  • V2: If optional features degraded but core passes → verdict: PASS_WITH_CAVEATS
  • V3: If any required check fails → verdict: FAIL with error_code
  • V4: Include report_hash in output
  • V5: Report must be deterministic (same bundle → same report)