Skip to content
LogoLogo

The context tree

The context is THE object policies judge. It is a fixed-shape set of Poseidon2 binary trees whose leaves are Fields:

shared_root          = merkle_64(shared leaves)                 (63 hashes)
payload_root         = H(CTX_PAYLOAD, payload_schema_id, merkle_128(payload leaves))
sender_private_root  = merkle_64(sender_private leaves)         (63 hashes)
payment_root         = H(CTX_PAYMENT, schema_id, shared_root, sender_private_root)
context_root         = H(CTX_PHASE, payment_root, merkle_16(phase leaves))

payload_root is itself one of the shared leaves. Four regions, chosen so each party can recompute exactly what it knows:

RegionWho knows the leavesContents
shared (64 leaves)sender, recipient, recipient FI, sender FIrecipient note fields, refund_commitment, payload_root, recipient_fi_index, deadline_bucket, nonce, reserved
payload (128 leaves, nested)same as sharedtravel-rule record, identifiers, remittance, purpose code, evidence hashes, reserved
sender_private (64 leaves)sender, sender FIchange note fields, the two input notes and their leaf indices, nk commitment, refund note preimage (sender pk_d, rho_refund), reserved
phase (16 leaves)pool-welded, per transitionphase, time_bucket, registry_root, chain_id, pool_address, attestation_in, fi_index (the proving FI), counterparty_fi_index, reserved

Rules:

  • Schema is data. schema_id and payload_schema_id name JSON schema files (protocol/schema/context-v1.json, payload-v1.json) that assign each leaf index a name, a type (field | u128 | bool | address | bytes31), and a region. The circuits know only the tree shapes and region boundaries. Changing a tree shape is a protocol version.
  • Additive evolution. A schema bump may only assign previously reserved slots; existing indices never move or change type. Absent fields are 0. A policy circuit witnesses schema_id and asserts schema_id >= COMPILED_SCHEMA, so a policy compiled against schema N proves against any payment at schema ≥ N without rebuilding. This is what Goal 4 means.
  • Multi-limb values (names, addresses) occupy consecutive leaves; the schema declares limb counts.
  • The initiate circuit computes payment_root from plaintext it holds and publishes it. The hold stores it. The resolve and reclaim circuits take it as a public and recompute it from the opened envelope plus the opaque sender_private_root carried in the envelope.
  • The wrapper computes context_root in circuit from payment_root and the phase leaves it receives as publics or witnesses, so the pool never hashes.
  • A policy at phase 1/2 structurally cannot read sender_private leaves: it only receives sender_private_root as an opaque field. This is a type-level guarantee (§5.2).
  • refund_commitment is in shared so the recipient side can publish it on reject, but its preimage is in sender_private, so the recipient side never learns the sender's address. The initiate circuit welds the two.

Opening mode: v1 always opens a knowable region in full (all leaves witnessed, root recomputed once). Path openings are a v2 optimization, pending the benchmark in §12.