PrivacyArchitecture

ASP Compliance

Association Set Provider architecture

Architecture Exploration

The ASP compliance architecture is in active exploration. We are designing a system where compliance flows through the entire note lifecycle - ensuring the bona fide rule that a compliant note today was always handled by compliant parties. This includes exploring note-centric ASP models where notes carry their own compliance requirements. The current implementation is one of several approaches we are evaluating.

What is an ASP?

An Association Set Provider maintains a list of addresses meeting specific compliance criteria. When withdrawing, users prove their funds' origin is on an ASP's allowlist.

How It Works

  1. Monitor deposits: ASP watches Shield events, checks if depositor meets criteria
  2. Build Merkle tree: Approved addresses organized in a tree
  3. Publish root: Updated root posted on-chain
  4. User withdrawal: Proves origin is in the ASP tree
// ASP backend monitors deposits
pool.on('Shield', (commitment, origin) => {
  if (meetsCriteria(origin)) {
    allowlist.add(origin)
    updateMerkleRoot()
  }
})

Origin Semantics

Origin is the address that originally deposited funds.

  • Preserved through transfers
  • Only changes via merge (merger becomes new origin)
  • Used for compliance checking
Alice shields → origin = Alice
Alice → Bob transfer → origin still = Alice
Bob merges → origin = Bob (Bob vouches for funds)

Withdrawal Paths

Ragequit

Original depositors can always withdraw their own funds, regardless of ASP status.

If origin is later sanctioned, they can still ragequit. But notes they sent to others become restricted - recipients must merge to become new origin or ragequit to the original origin.

Multiple ASPs

Different ASPs serve different use cases:

ASP TypeCriteriaUse Case
OFAC ScreenNot sanctionedGeneral compliance
InstitutionalVerified institutionsB2B
Exchange KYCPassed KYCExchange integration

Recipients can require specific ASPs:

// Exchange only accepts its own ASP
function receiveFromPool(bytes proof) external {
    require(verifyASPRoot(proof, EXCHANGE_ASP_ID));
}

Privacy Properties

ASPs know:

  • List of all depositors (public Shield events)
  • Which addresses meet their criteria

ASPs don't know:

  • Who is withdrawing (ZK proof hides identity)
  • Which origin is being used
  • Transaction patterns

ASPs cannot censor specific withdrawals.

On this page