07

V0.5 Testnet · Noid → Open

Unmask (withdraw)

Unmasking is the door back out: notes are spent and real coins go to a public address. Structurally it is a transfer with one output sent to the public world instead of into a note.

Sent by

The relayer

Proof

withdraw (19 signals)

Pays to

Any address

Notes

up to 4 in → 2 out

Menoid wallet

gathers notes

proves the withdraw

Withdraw Calls

Relayer

validates

submits

withdraw(…, to)

NoidPool

verifies · nullifies

pays once, at the end

coins

Receiving address

gets the coins

publicly

Send (transfer)Unmask (withdraw)
Outputs3 notes: receiver, change, relayer2 notes: change, relayer — plus a public payout
Public signals1919, including receiver and withdrawAmount
Balance ruleΣ in = Σ outΣ in = Σ out + withdrawAmount
Coins move?NoYes — out of the pool
ReceiverPrivatePublic address and amount

In the wallet

  1. 1You choose the amount and the receiving address — a flat relayer fee applies.
  2. 2Gathers and batches notes (at most 4 per proof); each batch’s outputs are your change and the relayer’s fee.
  3. 3Proves every batch for that one destination.

At the relayer

  1. 4Validates the calls and submits withdraw(calls, to).

Inside NoidPool

  1. 5For each call: checks the inputs, rejects duplicate commitments, builds the 19 public signals with publicSignals[0] = the to address, and verifies the proof.
  2. 6Marks the nullifiers spent, inserts the change and fee commitments, and emits NoteCreated.
  3. 7Sends the total to the address once, at the end — one transfer for the whole batch. Any failure reverts everything: no partial withdrawals.

The destination is bound into the proof

On-chain
publicSignals[0] = uint256(uint160(to))   // the contract feeds the destination into the proof

The proof was made for one destination. A relayer that redirects the payout changes publicSignals[0], and verification fails. The relayer is a courier, not a custodian: it can deliver the withdrawal or drop it, never re-address it.

Go deeperThe 19 public signals
IndexSignalCount
0receiver (the destination address)1
1relayerCommitment1
2–5enabled[]4
6–9roots[]4
10–13nullifiers[]4
14withdrawAmount1
15–16out_enabled[]2
17–18c_outs[]2

On-chain, anyone can see

  • The amount, the destination and the time

Stays private

  • Which notes paid for it — and so which deposit it came from

The pool is the crowd

Privacy is strongest when many people hold many notes. Deposit 7.31 and withdraw 7.31 a few minutes later, and the timing and amount speak for themselves — split amounts and let time pass.