Verifier Design

The offline verifier is a deterministic program that validates an evidence bundle and emits a structured verdict. It must be simple, auditable, and produce consistent results across implementations.

What are the core verifier responsibilities?

The verifier performs a strict sequence of validation steps. Each step must pass before proceeding. Failure at any step produces a specific error code.

  1. 1.Unpack bundle: Read ZIP contents without network access
  2. 2.Validate manifest checksums: SHA-256 of each file must match declared hash
  3. 3.Verify policy artifact: Recompute policy_id, validate issuer signature
  4. 4.Validate receipts: Schema, receipt_id, this_receipt_hash, signature per receipt
  5. 5.Check chain continuity: Counter gaps, prev_hash linkage, chain_head match
  6. 6.Verify policy consistency: All receipts reference same policy_id
  7. 7.Check required events: POLICY_LOADED, ENFORCED, etc. present if mandated
  8. 8.Emit verdict: PASS, PASS_WITH_CAVEATS, or FAIL with structured report

What verdict types exist?

The verifier emits one of three verdicts. Each verdict has specific semantics and triggers.

PASS

All validation steps succeeded. The bundle is internally consistent, properly signed, chain is intact, and policy was enforced as declared.

PASS_WITH_CAVEATS

All cryptographic validations passed, but some optional features are degraded. For example: local timestamps used instead of TSA, merkle anchoring skipped.

FAIL

One or more validation steps failed. The bundle should not be trusted. Report includes specific error_code and path identifying the failure.

What error codes are defined?

Error codes are machine-readable identifiers for specific failure conditions. Each code maps to a specific validation step failure.

// Manifest errors
BUNDLE_CHECKSUM_MISMATCH     // File hash doesn't match manifest
MANIFEST_PARSE_ERROR         // Manifest JSON is invalid

// Policy errors
POLICY_ID_MISMATCH           // Computed policy_id != declared
POLICY_SIGNATURE_INVALID     // Issuer signature verification failed

// Receipt errors
RECEIPT_SCHEMA_INVALID       // Receipt missing required fields
RECEIPT_ID_MISMATCH          // Computed receipt_id != declared
RECEIPT_HASH_MISMATCH        // this_receipt_hash computation failed
RECEIPT_SIGNATURE_INVALID    // Receipt signature verification failed

// Chain errors
COUNTER_GAP                  // Non-sequential counter values
CHAIN_PREV_HASH_MISMATCH     // prev_hash != previous this_hash
CHAIN_HEAD_MISMATCH          // chain_head doesn't match last receipt

// Policy consistency errors
POLICY_MISMATCH              // Receipt references different policy
REQUIRED_EVENT_MISSING       // Mandated event type not in chain

// Enforcement errors
ENFORCEMENT_POLICY_MISMATCH  // Action doesn't match policy mapping

What does the report output look like?

The verifier emits a structured report in JSON format. The report is deterministic: same bundle bytes produce identical report bytes.

{
  "verdict": "PASS",
  "report_hash": "sha256:abc123...",
  "timestamp": "2024-01-15T10:30:00Z",
  "bundle_hash": "sha256:def456...",
  "checks": {
    "manifest": "OK",
    "policy_signature": "OK",
    "receipts": {
      "status": "OK",
      "count": 42,
      "validated": 42
    },
    "chain": "OK",
    "drift_detected": true,
    "enforcement_executed": true,
    "merkle": "SKIPPED",
    "anchor": "SKIPPED"
  },
  "caveats": [],
  "errors": []
}

What are the implementation requirements?

Verifier implementations must meet specific requirements to ensure interoperability and trust.

  • No network calls: Zero external dependencies during verification
  • Deterministic output: Same input bytes produce same output bytes
  • Bounded resources: O(n) time and space where n is bundle size
  • Minimal dependencies: Only crypto primitives and ZIP library
  • Auditable code: Implementation should be readable and reviewable

Frequently asked questions

Can I use any programming language?

Yes. The specification is language-agnostic. Reference implementations exist in JavaScript, Python, and Go. Choose based on your deployment environment and security review capacity.

How do I handle very large bundles?

Stream processing is recommended. Read and validate receipts one at a time without loading the entire chain into memory. The chain is designed for sequential validation.

What if my implementation produces different results?

Run the conformance test suite. Differences typically stem from canonicalization bugs or signature verification edge cases. The test vectors will identify the divergence.