Skip to content

Verification & Proofs

Proof Hashes

Every verified delta produces a proof hash that is deterministic, tamper-evident, and chain-linked.

When PacSpace verifies a delta, it produces a proof hash — a cryptographic value that lets you independently confirm your data was recorded accurately. Every proof hash has three fundamental properties.

Three Properties of Proof Hashes

Deterministic

Given the same input data, the proof hash is always the same. There's no randomness, no timestamps mixed into the hash, no server-specific variation. You can recompute it yourself and get the exact same result every time.

Same delta payload → Same content hash → Same proof hash

This means verification is repeatable. Today, tomorrow, a year from now — the math always checks out.

Tamper-Evident

Change a single byte of the original data and the proof hash is completely different. There's no way to make a "small" change that preserves the hash. This property makes it immediately obvious if data has been altered after verification.

Original:  { "amount": 42.50 }  → 0x8f3a9b...
Tampered:  { "amount": 42.51 }  → 0xd17c4e...  ← completely different

Chain-Linked

Each proof hash includes a reference to the previous proof hash. This creates a sequential chain where every delta is cryptographically tied to the one before it. You can't insert, remove, or reorder deltas without breaking the chain.

proofHash₀ ← proofHash₁ ← proofHash₂ ← proofHash₃

If someone tampers with delta 1, then delta 2's previousProofHash no longer matches — and the break is detectable all the way forward.

Independent Verification

You don't need to trust PacSpace. When you receive a delta.verified webhook, you get everything needed to verify the proof yourself. Here's how:

Step 1: Recompute the content hash

Take the original delta payload, canonicalize it, and hash it using the same algorithm PacSpace uses (see the Merkle Specification for exact details).

javascript
import { createHash } from 'crypto';

function computeContentHash(deltaPayload) {
  const canonical = JSON.stringify(deltaPayload, Object.keys(deltaPayload).sort());
  const prefixed = 'pacspace:item:v1:' + canonical;
  return keccak256(prefixed);
}

const myHash = computeContentHash({
  customerId: 'cust_8xKj2m',
  amount: -42.50,
  reason: 'usage_charge',
  referenceId: 'inv_20260211_001',
  metadata: { plan: 'growth' }
});

Step 2: Confirm your content hash is in the batch

Check that your computed content hash appears in the itemHashes array from the webhook payload. This proves your delta was included in the batch.

javascript
const { itemHashes, contentHash } = webhookData.proof;

// Your recomputed hash should match the contentHash from the webhook
assert(myHash === contentHash, 'Content hash mismatch — data may have been altered');

// And the contentHash should be present in the batch
assert(itemHashes.includes(contentHash), 'Content hash not found in batch');

Step 3: Recompute the Merkle root

Build a Merkle tree from the full itemHashes array using the Merkle Specification rules, and compute the root.

javascript
const recomputedRoot = computeMerkleRoot(itemHashes);

Step 4: Confirm it matches the proof hash

Compare your recomputed root against the proofHash from the webhook. If they match, the batch is verified.

javascript
const { proofHash } = webhookData.proof;

assert(
  recomputedRoot === proofHash,
  'Proof hash mismatch — batch integrity check failed'
);

If you stored the previous delta's proof hash, confirm it matches previousProofHash to verify chain continuity.

javascript
const { previousProofHash } = webhookData.proof;

assert(
  previousProofHash === storedPreviousProofHash,
  'Chain broken — previous proof hash does not match'
);

Verification Summary

CheckWhat it proves
Content hash recomputationYour original data is unchanged
Presence in itemHashesYour delta was included in the batch
Merkle root recomputationThe batch hasn't been tampered with
Proof hash comparisonThe committed proof matches the batch
Chain link validationNo deltas were inserted, removed, or reordered

Next Steps

Was this page helpful?

Last updated February 11, 2026