Documentation/Ghosts and privacy

Ghost Pool

Ghost Pool is a shielded pool for USDG and ETH on Robinhood Chain. You deposit from your wallet or a ghost, then withdraw into any ghost with a zero-knowledge proof made in your tab. The proof shows the withdrawal spends a real deposit that was never spent before, without saying which one, so nothing on chain draws a line from your deposit to the ghost.

4 min read

Depositing

  1. 1
    Open Ghost Pool

    In the app, open Ghost Pool under Private. Your ghosts must be open in this tab: the key that finds your notes comes from them.

  2. 2
    Pick the source and the amount

    Your main wallet or a ghost, USDG or ETH. Round amounts like 100 or 1,000 USDG are shared by more deposits, so they are harder to pair with yours. One deposit is at most 10,000 USDG or 3 ETH.

  3. 3
    Prove and deposit

    Your tab makes the proof for a new private note (a second or two), then the wallet or ghost sends the deposit: an approval first for USDG, then the deposit itself.

The note is a Poseidon commitment to the amount, your pool key and a random blinding. Its contents are also sealed to your key (x25519 and XChaCha20-Poly1305) and posted in the deposit's event, so your tab finds your notes again by reading the pool's events, on any device. A deposit folds up to two of your existing notes into the new one, which keeps later withdrawals to a single note.

Withdrawing into a ghost

  1. 1
    Pick the ghost

    Any of your trade ghosts, or a new one made on the spot. From a ghost's Fund sheet, From Ghost Pool does the same for that ghost.

  2. 2
    Read the check

    Before you withdraw, the sheet reads the pool's public deposits and tells you what could still pair this withdrawal with your deposit: how many people deposited, whether the amount matches yours, how long ago yours was.

  3. 3
    Prove and relay

    Your tab proves the withdrawal. The Ghostdex relayer checks it, sends it and pays its gas. The ghost receives the amount, and with USDG a little ETH (0.0001 ETH today) so it can pay for its first trades.

The relayer is paid a fee out of the note, in the pool's asset: the gas of the withdrawal and the ETH it forwards, plus half again. The proof binds the recipient, the relayer, the fee and the forwarded ETH, so neither the relayer nor anyone who copies the transaction can change them.

Withdrawing straight into a stock

Under Arrives as, pick a stock instead of USDG or ETH: Shielded Buy. The relayer sends the withdrawal to the ghost as usual, then the ghost buys the stock through LI.FI in the same flow, paying the gas with the ETH the relayer forwarded. The ghost signs the approval and the buy in your tab without a sheet for each, after you have seen the price. Prices are asked from a neutral address, so LI.FI never sees your wallet or the ghost before the buy.

Both steps are public: the pool paying the ghost, then the ghost buying the stock a moment later. What stays out of sight is the deposit that paid for it. Amounts and timing still matter, exactly as for a plain withdrawal.

What the proof says

Each transaction is a Groth16 proof over a join-split circuit (two notes in, two out, Tornado Nova design, 12,698 constraints). It shows that the notes spent are in the pool's Merkle tree, that they belong to whoever made the proof, that they were never spent before (each leaves a nullifier the contract records), and that what goes in equals what comes out. It does not reveal which notes, whose they are or how much they hold.

What it shows and hides

WhoWhat they can see
Anyone reading the chainYour wallet or ghost depositing an amount. Later, the pool paying an amount to a ghost, sent by the relayer. Not which deposit paid it.
The relayerThe proof, its fee and the recipient ghost, and your IP address like the Ghostdex relay. Nothing about your wallet.
GhostdexNothing more than the relayer. It cannot move deposits: the contract pays only against a proof.
This browserYour notes, found with your pool key, and the list of what you did under ghostdex:pool:<address>.

A proof hides which deposit paid a ghost; it cannot hide the crowd. If nobody else has deposited, the withdrawal can only be yours. If you take out what you put in, a few minutes later, someone comparing the two can pair them. Wait, let others deposit, and withdraw amounts that differ from your deposits. Trace check reads the pool too and says when a withdrawal can be paired.

Your pool key

The key that owns your notes is a branch of your ghost root, so there is no extra signature and nothing more to back up. Whoever can open your ghosts can spend your notes. Lose the owner wallet without the ghost backup key, and the notes cannot be spent again.

The contracts

ContractAddress
Ghost Pool (USDG)0xa46fF4eBdF062d244Fa3c6c7b78EAa226Eb78DF8
Ghost Pool (ETH)0xe4aaDA1133ff6Cb0e07465468363fB8E4eff9b6f
  • No upgrade path and no proxy. The owner can pause new deposits, and nothing else: withdrawals and moves between notes can never be paused, and no function lets anyone take deposits out without a proof.
  • The trusted setup: phase 1 is the PSE perpetual powers of tau (80 contributions); phase 2 has one contribution, made by Ghostdex, followed by a public beacon. Someone who kept that contribution's secret could forge proofs. An open ceremony with more contributors comes before the deposit limit is raised. The file hashes are in the repository.
  • The contracts and the circuit have not been audited. They are tested with real proofs, but treat what you put in as at risk.