Skip to main content
Carry’s proofs are tamper-evident because of two hashes computed with BLAKE2b-256: a content-binding digest and a chaining chain_digest.

Two hashes, two guarantees

digest — content binding

blake2b256 of the exact Walrus receipt blob. Proves the on-chain proof points to specific content.

chain_digest — tamper evidence

blake2b256(prev_digest ++ digest). Links each receipt to its predecessor, so reordering or deleting a receipt breaks the chain.

The fixed byte layout

Both sides agree on an exact byte layout — this is what makes cross-implementation verification possible:
  • prev first, then digest, no separator.
  • An empty prev (the first receipt) hashes the digest bytes alone.

Content binding via canonical JSON

The digest is the hash of the receipt’s canonical form — keys sorted recursively — so it’s reproducible regardless of how Walrus serialized the stored JSON:
The verifier re-canonicalizes the fetched blob before hashing, so the check is robust to key order and whitespace introduced in storage. The proof binds the content, not the exact bytes.

Cross-implementation agreement

The TypeScript verifier and the Move contract must produce identical hashes or honest proofs would fail to verify. This is pinned by a golden test vector on both sides:
  • TypeScript: @noble/hashes blake2b(bytes, { dkLen: 32 }).
  • Move: sui::hash::blake2b256(&bytes).
Both are asserted against the same constant in their test suites — so any drift fails CI, not a user’s verification.
@noble/hashes v2 exposes blake2b at the @noble/hashes/blake2.js subpath, and @mysten/sui v2.20 exposes the JSON-RPC client at @mysten/sui/jsonRpc — both are used by the verifier.