Evidence packs
Public verification surfaces deliberately withhold the values a fingerprint
commits to. That is correct for privacy and incomplete for verification: a
Class V verifier reading a public certificate
record can recompute the disclosure_hash, but not the certificate
fingerprint itself, because business_id and subject_hash are not
published.
An evidence pack closes that gap. It is a single JSON document containing exactly the committed facts, handed to a party who is already entitled to see them — the subject, the recipient, an auditor under engagement, or opposing counsel under discovery — and verifiable entirely offline.
Why the public record cannot simply publish more
Section titled “Why the public record cannot simply publish more”The obvious “fix” is to publish subject_hash alongside the fingerprint. SP/1
forbids this.
subject_hash is SHA-256 over the canonical JSON of the submitted fields, and
those fields are low-entropy: a name, an email, a phone number. Publishing the
hash creates a confirmation oracle — anyone who can guess a person’s exact
field values can confirm them against the published digest, turning a privacy
surface into a lookup. Hubs MUST NOT publish subject_hash, and MUST NOT
publish any digest computed over subject values alone.
Verification of the full fingerprint is therefore an entitled operation, not a public one. The evidence pack is how that entitlement is exercised.
Pack format
Section titled “Pack format”A pack is a JSON object. pack_version is "sp1-evidence/1".
{ "pack_version": "sp1-evidence/1", "kind": "consent_certificate", "issued_by": "https://api.pryvc.com", "exported_at": "2026-07-30T12:00:00.000Z", "record": { "cert_id": "cc_...", "business_id": "biz_...", "business_name": "Example Co", "entities": ["Example Co", "Example Partners LLC"], "purpose": "Discuss insurance options", "origin_domain": "example.com", "page_url": "https://example.com/quote", "timestamp": "2026-01-15T12:00:00.000Z", "disclosure_text": "I agree to be contacted by ...", "subject_fields": { "email": "jane@example.com", "first_name": "Jane" } }, "derived": { "disclosure_hash": "375bcf...", "subject_hash": "a7e5df...", "fingerprint": "93aa61..." }, "policies": [ { "kind": "privacy", "url": "https://example.com/privacy", "captured_at": "2026-01-15T12:00:02.000Z", "content_hash": "…", "content_text": "…" } ], "anchor": { "ledger": "engrave", "tx_id": 4, "idx": 0, "value_hash": "sha256:…", "root": "sha256:…", "tree_size": 21, "anchored_at": "2026-01-15T12:15:00.000Z" }, "chain": { "expected_first_prev_hash": "…", "rows": [{ "prev_hash": "…", "event": {}, "row_hash": "…" }] }}Requirements
Section titled “Requirements”recordMUST contain every field the relevant fingerprint composition commits to, under the same key names the fingerprint spec uses. A pack that omits a committed fact is malformed, not merely incomplete.derivedMUST be present. A verifier MUST recompute every value in it and MUST NOT trust the supplied values — they exist so a mismatch localizes the discrepancy, not so verification can be skipped.policies[].content_textMUST be the exact captured text whose SHA-256 iscontent_hash.chainis OPTIONAL. When present,rowsMUST be contiguous and ordered, andexpected_first_prev_hashMUST be either the genesis value or a row hash the verifier can independently corroborate — typically one covered byanchor.anchoris OPTIONAL but SHOULD be present. Inclusion proofs MUST be verified against the ledger’s signed tree head with a pinned key, never by asking the ledger to attest to itself (see anchoring).- Packs MUST NOT contain hub credentials, API keys, or session material.
Verification procedure
Section titled “Verification procedure”A conforming Class V verifier, given only the pack:
- Recompute
disclosure_hashfromrecord.disclosure_text; compare toderived.disclosure_hash. - Recompute
subject_hashasSHA256(canonical_json(record.subject_fields)); compare toderived.subject_hash. - Rebuild the fingerprint composition from
record— sortingentities, and substituting the two recomputed hashes — thenSHA256(canonical_json(composition))and compare toderived.fingerprint. - For each policy, recompute
SHA256(content_text)and compare tocontent_hash. - If
chainis present, verify continuity and everyrow_hash. - If
anchoris present, verify the inclusion proof against a pinned tree head.
Every step is local. No network access is required at any point, which is the property that makes a pack usable years later, in a proceeding, after the issuing hub has changed hands or ceased to exist.
Distribution
Section titled “Distribution”Hubs MUST make packs available to the subject of a record and to the recipient that holds it, authenticated. Hubs MAY offer auditor-scoped export. Hubs MUST NOT expose pack export on an unauthenticated surface, for the confirmation-oracle reason above.
A pack is a disclosure of personal data to whoever receives it. Hubs SHOULD record pack export as an audit event.
Reference tooling
Section titled “Reference tooling”The conformance suite ships a pack verifier:
python -m sp1verify pack evidence-pack.jsonIt performs every step above and reports which facts were checked and which were absent — a pack that verifies its fingerprint but carries no anchor is a different evidentiary object from one that carries both, and a verifier should say so rather than print a single green tick.