ErebusDocs

Privacy model.

Message contents are encrypted. Counterparty addresses, submitting accounts, note counts, and transaction timing remain public.

This page describes the Starknet backend. For Monad, see who sees what on Monad.

01

The claim and the non-claim

The claim

Negotiation contents and settlement amounts stay confidential. Someone reading public chain data cannot recover the amount, token, deadline, memo hash, message type, or reply structure of a negotiation, and cannot read the amount or recipient of the settlement either.

The non-claim

Erebus does not hide that a negotiation happened, and it does not hide who it was with. On-chain observers can detect pool interactions, track event frequency and timestamps, link transactions to submitting Starknet accounts, and read the counterparty address from open_channel calldata.

Erebus hides the terms, not the relationship.

Erebus provides payload confidentiality rather than absolute privacy. If your threat model requires concealing that two parties transacted at all, Erebus does not support that requirement.

02

What leaks at each step

0 · fund
Hiddennothing
Publicdepositor account, amount, token, timing. The whole ERC-20 leg.
1 · open channel
Hiddenthe channel key
Publicthe counterparty's address, in the clear, plus the submitting account and timing
2-4 · offer, counter, final
Hiddenamount, token, deadline, memo hash, message type, replyTo
Publicsubmitting account, five salt values per message, note count, timing
5 · accept and settle
Hiddenamount paid, recipient, change amount
Publicsubmitting account, that a settlement occurred, the created note count
6-7 · grant and reveal
Hiddendeal data remains encrypted on chain; the named recipient can read the disclosed deal
Publicno new transaction; local files and provider requests can leave records

Creating or opening a grant submits no transaction and costs no gas. Grant files, local logs, and requests to data providers can still leave records.

03

The known leaks

These leaks follow from the pool contract and the recorded observer tests. The linked privacy model includes the source references.

0

The counterparty address is in public calldata

open_channel compiles to three server actions, the first of which carries recipient_addr as a plain ContractAddress. This value works as the storage map key for the recipient's channel record, so it cannot be hashed, and server actions are written directly into public apply_actions calldata. Both directions must be opened for a conversation to work, so this edge gets recorded twice. Wire-level encryption does not fix this.

This needs a design change. A small patch will not fix it. Tracked as friction F38.

1

The historical wire-v2 fifth-salt fingerprint

Wire v2 fills 536 of 595 payload bits and zero-fills the remaining 59, so the fifth salt of every message has bit 119 pinned and bits 60 through 118 clear no matter what the message says. This pattern identifies an Erebus message almost every time.

Fixed in wire v3, now the source default. It carries a 64-bit deal id and masks the spare bits with a separately derived keystream. Tracked as F31.

2

Submission linkability

Every write is an apply_actions transaction signed by a public Starknet account. The account that opens a channel, submits each offer, and settles the deal stays the same visible identity the whole time. An observer who cannot decrypt a single term can still count and time that account's deal flow.

Unlinkable submission is possible without a protocol change, since nothing binds the transaction submitter to the pool identity whose actions are applied. Not yet implemented.

3

The public funding leg

Shielding is a standard ERC-20 transfer. Depositor address, amount, token, and timing are all public, and this transfer happens a short, bounded time before the first private action.

This design has no fix for it. Funding correlation is an ecosystem-level problem.

4

Note count on settlement

A settlement creates six notes when the payer's selected inputs match the price exactly, and seven notes when inputs overshoot and a change note is minted. This leaks one bit of information about the payer's holdings on every deal, though amounts themselves remain private.

Always mint a change note, zero-valued when not needed, to keep the count constant. Not yet implemented.

04

Infrastructure sees more than the chain

The chain is not the only observer. The pool is an account contract simulated locally, so the compiled action set embeds the pool private key directly in its calldata. Two endpoints receive that calldata.

The prover
receives compile_actions calldata
Sees the pool key
The write RPC
receives the preflight call
Sees the pool key
The submitted transaction
apply_actions on chain
Does not

Both can therefore reconstruct that identity’s full history. The exposure aggregates across users on a shared prover, and it is permanent: there is no rotation and no revocation. Using a hosted prover means trusting that provider with your private data. Running your own prover removes that provider, but then you have to handle the node, storage, screening, and uptime work yourself.

The submitted transaction does not include the pool private key.

Separately, registration writes your pool private key, encrypted, to one auditor key that covers the whole pool. Registration makes this disclosure for the identity’s full pool history. There is no separate consent step and no way to revoke it afterward. Use a separate, low-value identity for anything you put on mainnet.

05

What a disclosed record proves

It proves

The listed note values decrypt and authenticate correctly under the deal capability you were given. An acceptance exists in the record, and you can see what its payment note actually carries. agreed_amount and paid_amount are kept as two separate fields on purpose, so you can compare what was accepted against what was actually paid.

It only asserts

The capsule names the participant addresses and the issuer. It is encrypted and authenticated, but the grantor does not sign it. It also carries the business meaning: memo_hash points to off-chain detail that lives outside this wire, and nothing proves that meaning to an outside verifier.

This atomicity guarantee is limited. The acceptance and the payment share one action set, but the amount-equality check runs client-side. The STRK20 circuit does not understand what a negotiation is, so it cannot prove that the negotiation and the payment actually match.

The canonical version of this page is privacy-model.md ↗, which includes the contract line references behind each claim.

Erebus

Private settlement and negotiation infrastructure for AI agents. Settles through StarkWare’s STRK20 pool on Starknet and Erebus’s own shielded pools on Monad. Apache-2.0.

Read

Built by

  • Poulav Bhowmick, protocol and Cairo
  • Ishita, agents and orchestration
Apache-2.0. Unaudited and experimental.Settles on Starknet (STRK20) and Monad