Skip to content
Docs / Circuit

Inside Ordeo

One circuit proves every spend

Every private send, unshield and sale uses the same Noir circuit: up to two notes in, exactly two notes out. This page lists its inputs, what it proves and what the contract checks around it.


On this page

Inputs

Ten public inputs, in the order the pool passes them to the verifier:

#InputMeaning
0rootA tree root the pool knows
1asset0 for ETH, 1 for the token; all four notes share it
2-3nullifier0, nullifier1Nullifier for each input
4-5commitment0, commitment1Commitment for each output
6exitValueNote units leaving the pool
7transferFeeNote units paid as the private transfer fee
8feeBpsThe pool's transfer fee rate, supplied by the contract
9extDataHashExternal data hash (see below)

Private inputs: the spending key sk; for each input its value, blinding, leaf index and 24-node Merkle path; for each output its value, owner key and blinding.

What the proof shows

  1. Each input with a non-zero value is a leaf of the tree under root. The leaf index is range-checked to 24 bits.
  2. The prover knows sk, and Poseidon(sk) is the owner key inside both inputs.
  3. Both nullifiers are computed correctly from commitment, leaf index and sk, and they differ.
  4. Both output commitments match their value, owner key and blinding.
  5. Value is conserved: in0 + in1 = out0 + out1 + exitValue + transferFee.
  6. Every value fits in 120 bits, so no sum can wrap around the field. feeBps fits in 14 bits.
  7. transferFee × 10000 ≥ feeBps × sent, where sent is the value of outputs going to a key other than the prover’s. Change back to yourself pays no transfer fee.

Checks the pool does outside the circuit

  • The root appears among the 100 most recent roots (UnknownRoot otherwise).
  • Neither nullifier is spent yet, and the two differ (NullifierSpent, SameNullifier).
  • Nullifiers and commitments are below the field order; exit value and fee are at most 2^120 - 1; asset is 0 or 1.
  • Each encrypted output is at most 512 bytes.
  • feeBps is the pool’s own immutable, and extDataHash is computed by the pool from the call data. The prover cannot choose either.
  • Relayer rules: a spend that pays a relayer must be sent by that relayer (NotRelayer); a private send must have an empty recipient; the exit must cover the fees (ExitTooSmall).

Binding the external data

extDataHash = keccak256(abi.encode(chainId, poolAddress,
                (recipient, relayer, relayerFee, encryptedOutput0, encryptedOutput1))) mod p

Because the proof takes this hash as a public input, it attests to everything the hash covers. Alter the recipient, the bundler, its fee, either ciphertext, the chain or the pool, and the pool computes a different hash and the proof fails. That is why a bundler can only submit a proof as built, and why sale terms placed in the second ciphertext cannot be edited.

Sizes

ItemValue
Tree depth24 (16,777,216 leaves)
Inputs / outputs per proof2 / 2
Circuit size2^16 gates (65,536)
Public input words the verifier reads18: the 10 inputs above plus 8 words of pairing points
Note value bound120 bits
Ciphertext per output114 bytes (the pool allows up to 512)
Measured gasPrivate send about 4.4M, unshield about 4.5M, router sale about 3.7M

Proof system and toolchain

  • Circuit language: Noir 1.0.0-beta.22, with the Noir Poseidon library (BN254, circomlib constants).
  • Prover and verifier generator: Barretenberg bb 5.0.0-nightly.20260522, UltraHonk using a keccak transcript, with zero-knowledge enabled.
  • No setup ceremony specific to Ordeo. UltraHonk uses the public Aztec Ignition SRS. The site serves the first 2^17 points itself, because the prover loads points in blocks of that size; the circuit needs 2^16.
  • circuits/build.sh --check rebuilds the circuit and confirms that the committed OrdeoAttestor.sol and the browser circuit file equal a fresh build.

Where proving happens

In your browser, in a dedicated web worker. The worker solves the witness with noir_js and proves with Barretenberg compiled to WebAssembly. The circuit, the WebAssembly files and the SRS points all come from this site. Nothing about your notes leaves the worker except the finished proof. On a laptop, a proof needs a few seconds.