Docs · verification spec v1
Verify a stamp without trusting us
Everything needed is public: the proof bundle at GET /api/v1/verify/<stamp-id> (or /api/v1/verify/by-seq?stream=<uuid>&seq=<n>) and any RPC endpoint of the anchoring ledger (Base). All hashes are lowercase hex; all hashing is SHA-256.
1 · Canonical payload
A payload has exactly one byte encoding — canonical JSON, UTF-8:
- object keys NFC-normalized, sorted by UTF-16 code unit, no duplicates;
- strings NFC-normalized, escaped exactly as ECMA-262
JSON.stringify; - numbers are integers only; quantities travel as decimal strings
-?(0|[1-9][0-9]*)(.[0-9]*[1-9])?; - no whitespace; arrays keep order; timestamps are
YYYY-MM-DDTHH:MM:SSZ.
2 · Commitment
commit_hash = SHA256( canonical_payload_utf8 || salt ) # salt: 32 bytes, published at reveal
While a stamp is sealed, only its inclusion and chain position are verifiable — that is the point of sealed commitments.
3 · Append-only chain
prev equals the previous stamp's commit_hash in the same stream (32 zero bytes for seq 1); seq increases by exactly one. Hiding any record breaks every later commitment.
4 · Merkle inclusion
leaf = SHA256(0x00 || commit_hash)
node = SHA256(0x01 || left || right)
acc = leaf
for step in proof.path:
acc = SHA256(0x01 || step.hash || acc) if step.side == "left"
acc = SHA256(0x01 || acc || step.hash) if step.side == "right"
assert acc == merkle_root5 · Ledger anchor
tx = eth_getTransactionByHash(tx_hash) assert tx.input == "0x" + merkle_root block = eth_getBlockByNumber(tx.blockNumber) assert block.timestamp == anchored_at # the authoritative timestamp
Reference verifier
A complete reference implementation (Node, zero dependencies, no Presaid imports) ships in the repository as docs/verify-independently.mjs:
node verify-independently.mjs https://presaid.io/api/v1/verify/<id> \
--rpc https://mainnet.base.org --chainA stamp is verified when the commitment recomputes (once revealed), the chain links, the Merkle path folds to the root, and the ledger transaction carries that root. Any failing step means the record does not hold.