Core Systems

Access Control

What the chain records about a grant today, the checks a server must pass before releasing a key, and why none of it is serving reads yet.

What this layer does. It decides whether a given consumer may read a given dataset version, and if so releases the key for it. Read this page as a design with one part live: the grant's on-chain record works, and nothing yet serves an authorised read.

What is running, and what is not

PieceState
GrantAnchorRegistry — the on-chain grant recordLive on Base Sepolia. Not deployed on Base mainnet
Anchor writes, owner-calledLive on Base Sepolia, reachable through a legacy Python SDK
Anchor writes, delegated by signatureIn the source only, deployed to no chain — and no client can produce the signature yet. Both the relaying endpoint and the owner-side signing helper are outstanding
access-control-service — the server that would check a request and release a keyCode, deployed nowhere. It appears in no cluster manifest
An authorised read, end to endNot available. No deployed service releases decryption material

So a grant can be recorded and revoked on Base Sepolia now, by its owner. What cannot happen yet is presenting one and receiving a key. The registry's Sepolia address, and its absence on mainnet, are on Contract Addresses.

What the chain contributes

The GrantAnchorRegistry holds one anchor per grant id, and it holds deliberately little: the dataset version, a hash of the subject DID, when it was issued, an expiry — zero meaning perpetual — and a status of ACTIVE or REVOKED. No policy, no credential, no key — and no digest of the grant document and no list of permitted actions.

That omission decides the shape of everything else on this page. The grant itself is an off-chain verifiable credential, and because the anchor commits to neither its contents nor what it permits, a valid anchor is a necessary condition and never a sufficient one. A server that released a key on the strength of the anchor alone would be honouring a document the chain never saw.

Two properties the anchor does give:

  • A fail-closed condition. A grant that is missing, REVOKED, or past its expiry can be refused without consulting anything off-chain. Note that a perpetual anchor carries no expiry to fail on, so on chain revocation is its only withdrawal — the credential presented against it may still carry an expiry of its own, which is checked separately below.
  • Revocation at the source. ACTIVE → REVOKED is the only transition the registry admits, and a revoked anchor never returns to active. Withdrawal does not depend on chasing credentials already issued.

Who may write an anchor

Every direct write is gated on the caller owning the dataset version, and those are the only writes that execute on any chain today. That rules out the obvious arrangement — a service holding its own key and writing anchors on users' behalf — because no service key is the owner, and giving one that authority would mean giving it the owner's key.

The design answer is to put the authority in the signature rather than the sender: the owner would sign an EIP-712 GrantAuthorization (or GrantRevocation) offline, and any address could submit it, gaining no rights and paying only gas — an EOA or an ERC-1271 contract can sign, so a multisig-held DID works. That code is in the registry's source and on no deployed proxy, and nothing yet produces the signature, so today the owner-called methods are the only writes that execute anywhere. They keep working when the signed path arrives.

What a server must check before releasing a key

Five checks, and the anchor is only one of them. All must pass.

yes

no

Consumer request
DID session + grant credential

Required checks · designed, not deployed

01 · Session controls the subject DID
02 · Owner-signed credential is valid and unexpired
03 · Credential matches the approval digest
04 · Subject and dataset match the anchor
05 · Anchor is active and unexpired

All five pass?

Release the dataset key

Refuse access

Three points are worth naming, because they are what the anchor's minimalism forces:

  • The issuer must be the dataset version's owner on chain, not merely a valid signer. Without that tie, a subject could sign their own credential and grant themselves whatever it says.
  • The credential's own expiry is checked, and the anchor's is not a substitute for it. Both exist and they are different clocks: the anchor commits to no credential, so nothing on chain makes them agree. The approval route does pin them equal when it issues a grant, but an owner can write an anchor directly — that is the only write deployed today — with any expiry it likes, including zero for perpetual, against a credential that says otherwise.
  • The credential must match a digest retained when the owner approved it. Since the anchor stores no digest, the comparison target lives server-side, with the party that approved the grant.

All three are conditions the service must satisfy before it is deployed anywhere. It runs in no environment today, so the checks above describe what a release has to demonstrate, not a gate standing in front of live data.

How the key reaches the consumer

One data encryption key per dataset version, wrapped per grant. The key is held custodially on the platform side — that is the decided architecture, not a temporary stage.

This is worth stating plainly because the earlier design was the opposite, and it was rejected on 2026-09-04 rather than deferred. That design used proxy re-encryption: the owner would produce re-encryption material for one consumer and the service would transform the wrapped key without being able to open it. The engine for it is complete and the full round trip runs, so this is not an unfinished feature. It was dropped because the approval path fixed the scheme at a threshold of one — a single service instance would hold every key fragment — so it paid the whole cost of key distribution, including consumer-side key custody and a Python SDK every buyer would have to run, without buying a materially stronger trust model than custody. Its proxy-re-encryption library has also not shipped a release since 2021, and its own dependency pin holds the rest of the Python workspace back.

The consequence for a reader is direct: confidentiality here rests on custody of the key, not on the platform being unable to read it. A threshold scheme is the thing that would change that, and it is a later decision; the rejected code stays in place against it.

What is recorded

A resolved request is designed to emit an audit event naming the grant, the dataset, the subject and how the key was delivered. That is an access log: it records that a key was handed over, not what was subsequently read, how much, or for how long.

Not in this layer

No usage measurement exists anywhere in the protocol — no usage events, no pricing configuration, no consumer-facing quotas, no policy language, and no licence or payment mode that meters consumption. Metered usage is a v3 concern, under a receipt type that does not exist yet.

The Royalty Engine is paid by whoever pays it. Nothing observes a read and turns it into a charge.

Revocation's reach is limited in one way worth stating: it stops new access. Data a consumer has already decrypted cannot be recalled.

Interfaces

  • In: a DID session, a grant credential issued by the dataset version's owner, and the grant's on-chain anchor.
  • Out (designed): the dataset version's key for the requesting consumer, plus an audit event.
  • Cross-links: datasets come from Data Assembly; the bytes themselves live in Storage & Serving; the identities on both sides are Identity.

Invariants

  • An anchor authorises nothing on its own. It commits to no document and no actions, so every release also rests on off-chain checks.
  • Revocation does not depend on the credential, and does not reach what is already decrypted.
  • Only one status transition exists. ACTIVE → REVOKED, never back.
  • No service key can write an anchor in its own name. The gate is dataset ownership, and the designed way around it is to move authority into the owner's signature so a submitter is only a relay — designed, and on no deployed proxy.
  • A visible reference is not authorisation, and today it may still be enough to read. A hash or manifest URI does not grant you anything. But nothing in the storage layer encrypts and its reads are unauthenticated, so whether the bytes behind a URI are intelligible depends on how their producer uploaded them — see Storage & Serving.
  • Key custody is the trust boundary, and it sits with the platform.

Last updated

On this page