How it works
The details behind the highlights — including where it stops.
How it works
-
1
Connect and sign once. Your private-transfer keys come from one signature in the wallet you already use. Registering publishes the key others pay you with — once, and best before anyone needs it.
-
2
Add funds in a fixed amount. 0.1, 0.5, 1, 5 or 10 ETH, so your deposit looks like everyone else's. "Fund a transfer" adds the small fee note alongside it in the same step.
-
3
Send. Choose private, public or stealth; the page shows where the money ends up before you confirm. Proofs are built on your device — about half a minute — and a relayer submits the transaction.
-
4
Prove it later, only if you need to. Give one person a receipt or a disclosure key. They check it on the verify page, without a wallet.
What it solves
Three ways money can arrive
Nothing is public: no amount, no recipient. They must have registered once.
Source: the recipient cannot show where it came from on their own — only you can prove your side.
The address and amount are public. Who sent it is not — a relayer submits it.
Source: you can prove it came from your own deposit — the depositing address and amount.
The amount is public; nothing ties the address to its owner or to other payments.
Source: you can prove it came from your own deposit, as with a public withdrawal.
No single mode fits every case. If you may need to show where money came from, send from funds you deposited yourself by public withdrawal or stealth payout. If you need nobody to see the payment at all, use a private transfer — and accept that its source cannot be traced back for an audit.
Where disclosure records live: Ethereum calldata, via Facet
A receipt needs nothing stored anywhere — it is a proof you make when asked. A disclosure key is different: it opens a record you chose to write when you sent. That record is not kept on our server or in a contract we control. It is written into Ethereum's own transaction data, in Facet's format, where anyone can read it back and no one can change it.
-
1
Sealed on your device. When you tick "Attach a disclosure record", the page encrypts what the transfer was — which note was spent, the amount, the recipient, your memo — to your own key, with the same post-quantum scheme as the payment itself (ML-KEM-768 + AES-GCM).
-
2
Published by the relayer, separately. Right after the transfer, the relayer sends the sealed bytes to Facet's inbox address as a transaction of its own. It handles ciphertext only and cannot read it. It is sent by the relayer, not by you, so that writing a record does not reveal you as the sender. It costs you nothing extra.
-
3
Permanent. Facet's state is derived from Ethereum calldata, so the record can be rebuilt by anyone replaying the chain. No operator — us included — can edit, withhold or delete it. That is also why writing one is your choice, per transfer: once written, it cannot be taken back.
-
4
Opened by one key. The disclosure key is the record's id, the transaction that published it, and a key for that record only. The verify page reads the transaction from a public node, decrypts it, then checks the claim against the pool: the spend must exist, and for a public withdrawal the amount and recipient must match the chain. A private transfer has no public amount to compare, and the page says so. A match shows what was paid, not who paid it: anyone who saw a public payment could write a record that matches. To show a payment was yours, give a receipt.
to 0x…face7 Facet inbox from relayer not you value 0 data 0x46 ‖ rlp( chain_id, to=0, value=0, gas_limit=0, data, mine_boost=0 ) data = "SIGILLO-DISCLOSE-v1" ‖ recordId 32 bytes ‖ sealed body ML-KEM+AES
- Size
- about 1.7 KB
- L1 gas
- about 84,000, measured on Sepolia
- Executes
- nothing — it is data, not a call
Points
Deposits earn points. They are worked out in your browser, from the pool's public deposit events and the rule below — no server keeps a list of anyone's points, and anyone can recount them from the chain. Points are not a token, cannot be transferred, and nothing has been decided about what they will become.
Time points
The longer ETH stays in the pool, the larger the crowd every payment hides in — so time kept there earns points too. They are counted per note, not per address, and claimed after each season with a zero-knowledge proof that reveals only the total: never which deposit was yours, nor when or where it was spent.
What it does not do — yet
- Testnet only. It runs on Sepolia. There is no mainnet deployment.
- Few people use it so far. The cryptography holds at any size, but with a small crowd, timing and amounts can narrow down who is who. Privacy grows with users.
- Not independently audited. Do not use it for money you cannot lose.
- Deposits and public withdrawals show their amount. That is why amounts come in fixed sizes — 0.1, 0.5, 1, 5, 10 ETH — so yours looks like everyone else's.
- One relayer, run by us. It sees the recipient, amount and time of public withdrawals. More independent relayers are the plan.
- The node this page reads from sees your IP address. By default it is a public node we do not run; you can use your own instead. It can tie your IP address to your wallet address — what it sees.
- This page cannot hold a transfer back for you. Sending right after depositing links the two by timing. The browser extension holds a transfer back for you — for hours on mainnet; on this test network, a couple of minutes, since there is no one else's traffic to hide in. A web page cannot hold anything once its tab is closed.
Works with
Questions
Why only fixed amounts?
A deposit's amount is public, and so is a public withdrawal's. If you deposit 0.017 ETH and later 0.017 ETH leaves the pool, anyone can pair the two — however many people use it. When everyone moves 0.1 or 0.5, amounts stop pointing at anyone.
Why does funding a 0.1 transfer take 0.12 ETH?
The relay fee is paid from a second, small note so the recipient receives exactly 0.1 rather than 0.1 minus a fee — otherwise the amount they receive would be unique again. The 0.02 note is reused for later transfers until it runs down, and what is left stays yours.
What does the relayer see?
For every transfer: the network address the request came from, and when. For a public withdrawal, also the recipient and the amount. For a private transfer it forwards encrypted data and sees neither the amount nor the recipient. It can refuse to send; it cannot take or redirect money — the contract pays the recipient directly. Today there is one relayer, and we run it.
What does the node this page reads from see?
This page and the extension read the chain through a public Ethereum node — by default Tenderly’s Sepolia gateway, which we do not run. It sees your IP address and every request. You can point both at your own node instead: in the app, under Advanced; in the extension, under Settings → Your own node. The wallet checks the node can do everything it needs before it switches.
Most requests tell it nothing about you: to find your notes, the page downloads the pool’s whole history and decides locally which are yours, so the node never learns which ones they are. Your keys and your notes never leave your device.
How a transfer you sent is going is asked of the relayer, not the node. The relayer already knows the transfer is yours — you just handed it over — so asking it reveals nothing new, while a node asked the same question from your IP address, seconds after the transfer went out, would learn whose transfer it was.
A few requests to the node are still yours alone. The balance of your wallet address. In the extension, a one-time address when you pay from it, or check how much you can — the payment itself goes out through the node from your IP address anyway. Checking for payments does not ask about any one address: the extension reads the balances of every announced address at once, the same request any wallet reading those blocks sends. And on the verify page, which transaction you are checking.
Finding your disclosure keys again, in a new browser, reads the few blocks after every transfer in the pool, not only yours — the same blocks for every wallet — and recognises yours on your device.
A VPN or Tor hides your IP address from the node; it does not hide that one session asked about these things together. Your own node is the fix that covers all of them.
Who can see my private balance?
Only someone holding the signature your keys derive from — which is you, in your wallet. This page stores nothing on a server. Closing the tab clears what it held in the browser.
What if I lose this browser, or this site goes away?
Your funds sit in a contract that nobody — including us — can change or pause, and your keys come from your wallet's signature, so they are never lost with a browser: signing again from the same wallet finds the same notes. But be clear about today: finding and moving them needs software like this page or our wallet extension, and sending needs a relayer, of which there is currently one. A site that disappears does not take your money, but it does take the easy way to reach it.
Is this compliant with the rules where I live?
We cannot answer that for you. What exists is technical: our relayer screens public recipients against the OFAC sanctions list (see below), and you can prove any single transfer to a party you choose. Whether that meets your obligations is a question for your own adviser.
What does a receipt show the person I give it to?
That the spend was yours, plus everything the public chain already ties to that note once the link is shown: the address your identity is registered to, the transaction that created the note — and, if the note came straight from a deposit, the depositing address and the amount deposited — the transaction that spent it, and anything it paid out publicly.
None of this can be left out of a receipt, because the person checking it reads it from the chain, not from us. So the app lists every line before it makes one, and you decide whether to hand it over.
What is screened, and by whom?
Two different checks, often confused:
Our relayer screens who gets paid. Before it submits a public withdrawal or a stealth payout, it checks the recipient address in that transaction against the OFAC SDN list and refuses a listed one. If its copy of the list is more than a day old, it refuses to submit anything until it refreshes. A private transfer has no public recipient, so there is nothing to check. This is a setting of the relayer, not of the pool or of your payment: ours has it on and publishes that in its details; anyone running their own relayer decides for themselves.
A screened pool checks who deposits. A separate pool — deployed on Sepolia, but not the one this app uses yet — accepts a deposit only with a recent attestation that the depositing address is not on the same list. The pool's contract enforces that, so no relayer setting changes it, and the attestation can be recomputed by anyone from the public list.
Can I prove where my money came from?
Yes, if you deposited it yourself and send it out publicly. A receipt for a public withdrawal or stealth payout shows the depositing address, the amount and where it was paid — an auditor or an exchange then applies its own checks to that address.
No, not past a private transfer. Money received by private transfer carries no record of its origin; the receipt says "received inside the pool" and the trail stops there. Only the person who sent it can prove their side. The same applies if you later withdraw money you received privately: its source cannot be shown.
This is a deliberate boundary, not a missing feature. Choose the mode that fits what you may need to prove later.
Do I need to install anything?
No — a wallet such as MetaMask is enough. There is also a browser extension wallet, which holds a transfer back after you deposit so the two are not linked by timing — for hours on mainnet, a couple of minutes on this test network, where there is no other traffic to hide in. A web page cannot do that once its tab is closed.