Dragons

Docs · Verify

Verify a
receipt.

Recomputes the chain root from the receipt body, in your browser, and shows you the math. Existence proof for the auditable-labor thesis — dashboards narrate work; a hash chain records it.

01

What this verifier does

Reads the receipt body, canonicalizes it, hashes the canonical bytes with SHA-256, and compares the computed chain root against the value the receipt claims. The comparison runs entirely in your browser; no network call is made.

A pass means the math you just ran agrees with the math whoever issued the receipt ran. A fail means the receipt body, the claimed chain root, or the canonicalization rule has drifted — and the result panel surfaces all three so you can see where.

02

The widget

A receipt specimen with an unfilled chain root. Click Verify and the page computes the root from the fields above, in-tab, and reveals the canonical JSON it hashed.

Sandboxed verifier · specimen receipt · the production verifier will replace this with a signed server replay
Dragons · Receipt Specimen rcp_019e5f80a1f3a4cc2d0000000000000a
Identity
manifest_hash
lease_id
tenant_id
Chain
parent_root
evidence[0]
evidence[1]
State
organism_state running
mtboi_seconds 86400
outcome accepted
Claim
chain_root (click verify to compute)
recomputes the chain root in your browser
Show the canonical JSON I am hashing
(verify to populate)
03

The math, step by step

Canonicalization is the entire trick. Two receipts with identical content but different key orderings or whitespace would hash to different roots; the rule below removes every degree of freedom that does not carry meaning.

  1. 01

    Drop

    Drop the field being verified

    Remove the `claimed_chain_root` field from the receipt body. The chain root is the value the math is going to produce; including it in the input would let any value match itself.

  2. 02

    Sort

    Sort all object keys recursively

    Walk every object in the receipt tree and emit keys in lexicographic order. Arrays preserve their original order — arrays are sequences, not bags. Determinism lives or dies on this step.

  3. 03

    Encode

    JSON-stringify, UTF-8 encode

    Serialize with no whitespace, no Unicode escapes, no trailing commas. Encode the resulting string as UTF-8. NaN and Infinity are forbidden by JSON itself; nothing to do here.

  4. 04

    Hash

    SHA-256, lowercase hex, sha256: prefix

    Hash the UTF-8 bytes with SHA-256. Render as lowercase hexadecimal. Prefix with `sha256:` so the algorithm travels with the value and future migrations are unambiguous.

04

Reference implementation

The exact JavaScript the widget above runs. Paste this into a console with any receipt object and you reproduce the chain root by hand. The widget is not magic — it is these forty lines.

// Sort all object keys recursively. Drop `claimed_chain_root`
// (the field being verified). Arrays preserve order. Primitives
// serialize normally.
function canonicalize(value) {
  if (value === null || typeof value !== "object") return value;
  if (Array.isArray(value)) return value.map(canonicalize);
  const out = {};
  const keys = Object.keys(value)
    .filter((k) => k !== "claimed_chain_root")
    .sort();
  for (const k of keys) out[k] = canonicalize(value[k]);
  return out;
}

function canonicalJson(receipt) {
  // JSON.stringify with no whitespace, no Unicode escapes,
  // no trailing commas. UTF-8 encoding is implicit at the
  // TextEncoder step below.
  return JSON.stringify(canonicalize(receipt));
}

async function sha256Hex(text) {
  const enc = new TextEncoder().encode(text);
  const buf = await crypto.subtle.digest("SHA-256", enc);
  const bytes = new Uint8Array(buf);
  let hex = "";
  for (let i = 0; i < bytes.length; i++) {
    hex += bytes[i].toString(16).padStart(2, "0");
  }
  return hex;
}

async function chainRoot(receipt) {
  const canonical = canonicalJson(receipt);
  return "sha256:" + (await sha256Hex(canonical));
}

Drift between this snippet and the function inside src/components/ReceiptVerify.astro would be a bug. The production reference implementation, once published in the RELOS spec, becomes the single source of truth — both this snippet and the widget derive from it.

05

Limits

What this page is, and what it is not. No marketing voice — the gap between today and the production verifier is the most useful thing on this surface.

Sandboxed

The widget runs entirely in your browser. It hashes a specimen receipt the page ships with — nothing leaves the tab.

No counter-receipt

A production verifier replays the receipt server-side under a signing key and emits a counter-receipt. That service does not exist yet.

Same math

The canonicalization rule and the SHA-256 step here are the contract the production verifier will run. Today, you audit the math; tomorrow, you audit the counter-signature.

Transparency aid

This page exists so the math is auditable before there is a signed verifier to trust. It is not a replacement for one.

Next

Read the concepts.

The chain root is one field on one receipt. The four mechanisms — identity, leases, evidence, liveness — and the evidence chain itself are the rest of the surface.