# A zk-SNARK primer

This page explains what a zero-knowledge proof is and why TONado Cash needs one.

## The problem

You want to withdraw your deposit. The pool needs to confirm two things before paying you:

1. **You actually made a deposit.** Someone could try to withdraw money they never put in.
2. **You haven't already withdrawn it.** Someone could try to withdraw the same deposit twice.

Easy enough if you're willing to tell the pool *which* deposit was yours: just point at it, sign with the deposit's private key, and let everyone watch. But that defeats the entire point: anyone observing the chain can now link your withdrawal to your deposit.

You need to prove *some* deposit in the pool was yours, **without revealing which one**.

That's what a zero-knowledge proof is for.

## What a zero-knowledge proof actually is

A zero-knowledge proof is a cryptographic protocol with three properties:

1. **Completeness.** If a statement is true, there's a proof that convinces the verifier.
2. **Soundness.** If a statement is false, no proof exists, not even a fake one that happens to convince the verifier. Forging a proof is computationally infeasible.
3. **Zero-knowledge.** The proof reveals nothing about *why* the statement is true. The verifier learns that the statement holds, and nothing else.

The classic explanation is the **cave with a magic door**:

> There's a cave shaped like a ring. At the back of the ring is a door that only opens with a secret password. You claim you know the password. Skeptic doesn't believe you.
>
> They wait outside. You walk into the cave, take one branch at random. Skeptic walks in to the fork and shouts which branch they want to see you emerge from. If you knew the password, you can always comply (you just open the door if needed). If you didn't, you have a 50% chance of having guessed the right branch in advance, and a 50% chance of being caught. Repeat 30 times. After 30 successful rounds, the probability you got lucky every time is less than one in a billion. Skeptic is convinced.
>
> Crucially, Skeptic learned **nothing about the password**. They only learned that you know it.

A zk-SNARK ("Succinct Non-interactive ARgument of Knowledge") is the same idea, made non-interactive (no rounds of back-and-forth, just one proof) and succinct (the proof is small, regardless of how complicated the statement is).

## What TONado Cash's proof proves

The statement is:

> "I know two values `nullifier` and `secret` such that:
>
> 1. `Poseidon(nullifier, secret) = commitment`, and that `commitment` is a leaf in the Merkle tree whose root is `R` (which the pool knows is one of the recent on-chain roots).
> 2. `Poseidon(nullifier) = nh`, where `nh` is the nullifier hash being recorded as spent."
>
> The proof additionally binds the recipient, the relayer, the fee, and the refund to itself, so they can't be tampered with after the fact.

It proves these things without revealing `nullifier` or `secret`. It doesn't even reveal *which* commitment in the tree the note corresponds to.

The pool then:

1. Looks up its 30 most recent Merkle roots, confirms `R` is one of them.
2. Looks up `nh` in its nullifiers dict, confirms it hasn't been recorded yet.
3. Calls the on-chain Groth16 verifier with `(proof, [R, nh, recipient, relayer, fee, refund])`.
4. If the verifier says "valid": mark `nh` as spent, send `denomination - fee` to recipient, send `fee` to relayer.

That's the whole flow.

## Why this is hard

Producing a proof requires running a **prover**, which evaluates the statement on your specific witness (the note + path) and outputs a constant-size proof. For TONado Cash, the prover is snarkjs running in WASM on your machine, taking 5–15 seconds and producing a \~200-byte proof.

Verifying a proof requires a **verifier**, which does a series of elliptic-curve pairing checks. For TONado Cash, the verifier is the auto-generated [`verifier.tolk`](https://github.com/tonadocash/monorepo/blob/main/apps/contracts/contracts/verifier.tolk) on-chain, using TVM's native `BLS_PAIRING` opcode.

Both prover and verifier need a **proving/verifying key pair**, generated by a one-time *trusted setup ceremony*. The ceremony is the most subtle piece of the system. See [The trusted setup](/how-it-works/trusted-setup.md) for what we trust about it.

## Why "succinct"

A proof for *any* statement of *any* size is roughly the same size (a few hundred bytes) and takes about the same amount of work to verify. That's what makes SNARKs practical on-chain: verifying a deposit-occurred-and-is-unspent proof costs roughly the same gas regardless of how many deposits the pool has accumulated.

## Why "non-interactive"

The cave example required back-and-forth between prover and verifier. A SNARK collapses all of that into a single proof, computed off-chain, that the verifier evaluates in one shot. This is what makes it possible to verify on-chain: TON contracts can't have a stateful conversation with a user.

## Why "argument of knowledge"

The word "argument" (as opposed to "proof") is a cryptographic term of art: the soundness guarantee is *computational*, not absolute. A computationally unbounded attacker could in principle break it; a normal attacker with current hardware cannot. This is no different from any other cryptographic protocol that depends on a hard problem.

"Of knowledge" means the proof witnesses **knowledge** of the secret, not just that the secret *exists*. The prover can't outsource; they must actually possess `(nullifier, secret)`.

## What we trust

The TONado Cash withdraw proof is sound (forgery is infeasible) as long as:

* **The trusted setup ceremony was honest.** At least one participant must have generated truly random entropy and destroyed it after their contribution. See [The trusted setup](/how-it-works/trusted-setup.md).
* **BLS12-381 pairing remains hard.** This is the same assumption that secures Ethereum's zk rollups, Filecoin, and many other systems.
* **The Poseidon hash function is collision-resistant.** A collision in Poseidon would let someone construct two distinct `(nullifier, secret)` pairs with the same commitment. See [Poseidon vs. MiMC](/how-it-works/poseidon-vs-mimc.md).
* **Random number generation on your machine is good.** Your note's entropy comes from your device. Bad RNG = predictable notes = stealable deposits.

That's the trust stack. There is no piece where you're trusting the relayer, the deployer, or the protocol team to behave well. Those are addressed by other layers (see [Threat model](/protocol-reference/threat-model.md)).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.tonadocash.com/how-it-works/zk-primer.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
