noircashdocs

Trust model

What you have to trust when you use noircash, what you do not, and what each party, Pons included, could and could not do to you.

noircash has no operator: nobody can freeze, move or reveal your notes for you. You still rely on mathematics, on code, on Pons for trading and fees, on your wallet and on your device. This page lists each party, what it can do, and what stops it.

The noircash contracts

The vault (PrivateVault), the router (PrivateRouter), the fee harvester (FeeHarvester), the verifier and the Poseidon2 hasher are immutable:

  • No owner, no admin role, no proxy, no upgrade path, no pause, no freeze, no blocklist.
  • No initializer: every address a contract works with is set in its constructor. The vault's harvester and router are fixed CREATE3 addresses known before any of them is deployed.
  • Every limit is a constant or set once in the constructor: the 20% gas margin, the ±10% price clamp, the 3% bound on harvester trades, the 0.5% harvest tip, the harvester's target deposit.
  • The EntryPoint deposit that pays for gas can be topped up by anyone and withdrawn by nobody. The vault is not staked; stake added with addStake could never be unlocked.

The deployer has no power after the deploy. It deployed the noircash contracts, bought and locked the seed note, and made the first gas deposit. The address that made NOIR's launch on Pons has no special rights over NOIR: it cannot sweep or redirect NOIR's fees, which Pons pays to the harvester. See NOIR on Pons. The other side of immutability: a bug cannot be patched (see Stated limits).

NOIR and Pons

NOIR is a Pons V2 token: OpenZeppelin ERC20 plus ERC20Burnable, with no owner and no transfer restrictions. Nobody, Pons included, can mint it, freeze it or move it from an address, and that includes the vault's balance. A note's NOIR stays in the vault until its owner spends the note.

NOIR trades on Pons contracts: its bonding curve, then the graduated Uniswap v4 pool with the Pons hook. Pons also collects the trade fees and pays the creator share to the harvester. So Pons decides:

Pons canEffect on noircashWhat it cannot do
Take its share of the fees: 30% of the 1% standard fee (protocolFeeShareBps 3000), frozen at launchHolders get the rest: 0.7% of every tradeChange NOIR's fee terms after launch
Redirect NOIR's creator fee recipient with setCreatorFeeRecipient, after a 3-day timelock (visible in pendingCreatorFeeRecipient)The harvester stops receiving fees: holder yield and the ETH that tops up the gas deposit stopTouch the vault, the notes or anyone's NOIR
Use its owner's rescue functions on curves and graduations (rescueCurveFees, forceSweptGraduation, rescueSweptGraduation)Can affect the curve's fees and how and when NOIR moves to the pool, hence trading, the price the vault reads, and harvestsMove NOIR out of the vault
Stop serving the curve or the pool (for example a failed graduation)Private buys and router sales fail; an ERC-4337 sale whose swap fails delivers the NOIR to the ETH recipient insteadStop private sends or unshields, which never touch a Pons contract

The Pons owner is a contract, 0x263ed295dAFaE1d9AAdD6E56c4B6F9f38eE019Dd (read on-chain). This dependency is part of the design: it is what lets NOIR trade on every venue and aggregator that supports Pons.

The graduated pool is the one Pons creates: only the Pons factory can initialize a pool with its hook, and the router, the harvester and the vault use only that pool's id. Anyone can open another ETH/NOIR pool, but it has another id and noircash never trades or prices on it.

The circuit and the verifier

Every spend is a zero-knowledge proof for the transact circuit, written in Noir and proved with UltraHonk. The verifier checks it against public inputs the vault computes itself: the root, two nullifiers, two new commitments, the exiting shares, a hash of the external data and the vault's EIP-712 domain separator.

UltraHonk needs no ceremony for this circuit. It uses a universal reference string (CRS) shared by all circuits; the app serves pinned copies checked against fixed SHA-256 hashes. Soundness rests on:

  • the circuit enforcing membership, ownership through the nullifier key, correct nullifiers, conservation of shares (inputs = outputs + exit), 120-bit range checks and a valid wallet signature (see The circuit);
  • the generated verifier matching the circuit, and no soundness bug in Noir or Barretenberg;
  • Poseidon2 and keccak256 being collision resistant and secp256k1 ECDSA being unforgeable;
  • the universal CRS having been generated honestly.

If one fails, an attacker could create shares from nothing and take the vault's NOIR. This is the largest risk in the system.

Your wallet

Your wallet signs two kinds of messages.

The activation signature. A Sign-In with Ethereum message that names the app's domain and the vault. Its hash is the seed for your viewing key and your nullifier key. Anyone who obtains this signature can see all your notes, past and future. They cannot move them. See Keys.

One signature per spend. Every send, sale or unshield needs an EIP-712 Spend(bytes32 transaction) signature from the same wallet. transaction is the Poseidon2 hash of the proof's public inputs, so the signature covers the root, nullifiers, new notes, exit amount and the hash that binds recipient, fee and sale terms. The circuit checks the signature against the wallet key committed in your registered owner key. The domain separator binds it to this vault on this chain.

Public actions (buying, approving the vault, shielding, registering) are ordinary transactions your wallet sends and shows in full.

You trust your wallet to keep its key secret and to sign deterministically: the app signs the activation message twice on first use and refuses wallets whose signatures differ. Only EOA-key wallets are supported (including EIP-7702 accounts and MPC wallets that produce one ECDSA signature), not contract-based multisigs.

The app (frontend)

The app derives your keys, scans for notes and builds the proof on your device. Keys live only in the page's memory and are not sent to a server. Its Content-Security-Policy allows only the app's own scripts and limits connect-src to the app, the chain RPC, the bundler and the indexer, so injected code cannot fetch your keys to an arbitrary server. The proving CRS is served by the app, so proving contacts no third party.

The policy does not protect you from the app's own code. A compromised frontend (a malicious build on the real domain, or a fake site) could:

  • read your notes and balance once you activate privacy there;
  • ask you to sign a Spend for a transaction that pays someone else;
  • ask you to approve NOIR to an address other than the vault.

What the spend signature protects, and what it does not

The per-spend signature stops anyone who only has your activation signature or your keys. It does not stop an app you are actively using: your wallet shows the Spend request as a 32-byte hash, which you cannot check against the recipient or amount. Use only a frontend you trust, and check the domain in the activation message.

The harvester's callers

Anyone can call harvest(), and the caller earns 0.5% of the ETH it handles. The caller chooses only when a harvest happens. The harvester's buys and reserve sales must land within 3% of the vault's price average after Pons fees, and a buy that does not fit is made smaller or left for the next harvest. See Gas.

The indexer

The indexer is optional. One endpoint serves every vault event from a block onwards, the same for everyone, with no per-user queries, so it does not learn which notes are yours. The app checks the rebuilt tree's root with the vault's isKnownRoot and reads the chain directly on a mismatch or when the indexer is down. The indexer can see your IP address and when you sync. See The Merkle tree.

The bundler

Private transactions are ERC-4337 UserOperations whose sender is the vault. Any bundler can submit them.

  • It cannot change the recipient, gas fee, amounts or sale terms: their hash is a public input of the proof.
  • It cannot starve execution: the proof fixes a minimum callGasLimit that validation enforces.
  • It cannot make the gas deposit pay more than the fee covers: the fee must be worth the operation's maximum gas cost plus 20%, at the price average.
  • It can refuse to submit. Any other bundler works, or a direct call paid by an address you choose, which reveals that address.

See Gas.

The RPC node

The node answers the app's reads and relays transactions, and sees your IP address and calls. A lying node could hide events or give wrong reads, but the vault rejects any proof on a root it does not know: it can make a transaction fail, not succeed wrongly.

Robinhood Chain's sequencer

The sequencer orders transactions and decides which ones enter a block. It filters transactions tied to sanctioned addresses. It could censor transactions to the vault, or delay them. It cannot forge a proof, spend a note or change a transaction's contents. This dependency cannot be removed.

Summary

PartyCanCannot
DeployerNothing after the deployChange a parameter, move notes, pause, upgrade, redirect fees
Pons (its owner)Redirect the creator fees after a 3-day timelock, use its rescue functions, take its 30% shareMove NOIR from the vault or any address, touch notes, change fee terms after launch
Circuit and verifierEverything, if unsoundNothing extra, if sound
Holder of your activation signatureSee all your notes and historySpend them
Whoever controls your wallet keyEverything: re-derive your keys and sign spends—
Compromised frontendRead your notes; get you to sign a harmful spend or approvalSpend without your wallet's signature
Harvest callerChoose when fees are harvested; earn the 0.5% tipBuy or sell more than 3% away from the price average
IndexerWithhold data, see IP and timingLearn which notes are yours; alter the note tree without detection
BundlerCensor, see IP and timingChange recipient, fee or amounts; starve execution
RPC nodeCensor, lie about reads, see IP and callsMake an invalid transaction succeed
SequencerCensor or delayForge, steal or change a transaction

On this page