Skip to main content
The entire trust layer is a single Move module, carry::access, deployed on Sui testnet. It holds the access policy, mints Receipt proof objects, and recomputes the authorization verdict on-chain.

Objects

AccessPolicy

A shared object: the agent × namespace grants table, plus the receipt-chain head (receipt_count, chain_head).

OwnerCap

An owned capability. Only the holder can change grants on its policy.

Receipt

An owned, Display-enabled proof object minted on each anchor.

AccessPolicy

The policy is default-allow: is_allowed returns true unless a namespace was explicitly revoked for an agent. receipt_count and chain_head track the tamper-evident receipt chain.

Granting and revoking

Only the OwnerCap holder can change access:
is_allowed is a public, read-only function — anchor_receipt calls it on-chain to recompute a proof’s verdict, and the walletless verifier calls it via devInspect (no gas, no signing) to re-check any proof against the live policy.

Anchoring a receipt

anchor_receipt is the heart of the proof layer. It recomputes the verdict, extends the hash chain, mints the Receipt, and transfers it to the signer:
anchor_receipt takes the policy as &mut and is callable by anyone — the receipt chain is append-only. Only set_access requires the OwnerCap.

Display metadata

In init, the module claims a Publisher and registers a Display<Receipt> so wallets and explorers render each proof as a “Carry Proof # rather than a raw object.

Tests

The Move tests assert the behavior that matters:
  • blake2b256_abc_golden — pins the hash so it matches the TypeScript verifier byte-for-byte.
  • gate_defaults_allow_then_revokes — default-allow, then revoke flips is_allowed.
  • anchor_mints_receipt_and_chains — anchoring creates a Receipt, increments seq, and chains correctly.