Claude
Skills
Sign in
Back

noir

Included with Lifetime
$97 forever

Building privacy-preserving EVM apps with Noir — toolchain, pattern selection, commitment-nullifier flows, Solidity verifiers, tree state, and NoirJS. Use when building a Noir-based privacy app on EVM.

General

What this skill does


# Privacy Apps with Noir

## What You Probably Got Wrong

**"Use `nargo prove` and `nargo verify`."** Those commands were removed. Nargo only compiles and executes. Proving and verification use `bb` (Barretenberg CLI) directly. If you generate `nargo prove` commands, they will fail.

**"I can use SHA256 for hashing in my circuit."** SHA256 costs ~30,000 gates in a circuit. Poseidon costs ~600. For in-circuit hashing, always use Poseidon. Poseidon was removed from the Noir standard library — you must add it as an external dependency. The correct import is `use poseidon::poseidon::bn254::hash_2` after adding the `noir-lang/poseidon` dependency to `Nargo.toml`. Not `std::hash::poseidon::bn254::hash_2` (removed from stdlib), not `Poseidon2::hash`, not `pedersen_hash`.

**"`pub` goes before the parameter name."** Noir 1.0 changed public input syntax: `pub merkle_root: Field` → `merkle_root: pub Field`. The old syntax gives "Expected a pattern but found 'pub'".

**"Set `compiler_version = ">=1.0.0-beta.3"` in Nargo.toml."** `compiler_version` rejects beta strings — `>=1.0.0-beta.3` fails. Use `>=0.36.0` or omit `compiler_version` entirely.

**"I built a commitment-nullifier circuit so my app is private."** The ZK proof hides the link between commitment and nullifier, but `msg.sender` is public. If the same wallet deposits a commitment and later calls `act()` to withdraw/vote, anyone can link the two transactions onchain. The whole pattern is pointless unless the acting wallet is different from the committing wallet. Use a fresh burner wallet + a relayer or ERC-4337 paymaster to pay gas without revealing the link.

**"The generated HonkVerifier.sol works with any Solidity version."** The verifier generated by `bb write_solidity_verifier` requires `pragma solidity >=0.8.21` and EVM version `cancun`. If your Foundry project uses a lower version, add `solc_version = '0.8.27'` and `evm_version = 'cancun'` to `foundry.toml`.

---

## Quick Reference

Beyond the corrections above:

- **Solidity verifier = separate deploy** — deploy the generated `HonkVerifier.sol`, pass its address to your app contract constructor
- **Input order must match everywhere** — circuit `pub` params, `proof.publicInputs`, and Solidity `verify()` call must be in the same order
- **Poseidon ≠ Poseidon2** — different algorithms, different outputs. Don't mix them across circuit, offchain tree, and contract

---

## Toolchain (Current as of March 2026)

### Install

Check if nargo and bb are already installed before running the installers:

```bash
nargo --version && bb --version
```

If both commands return versions, you're set — skip the install. If either is missing:

```bash
# 1. Install nargo (Noir compiler) — always install nargo first
curl -L https://raw.githubusercontent.com/noir-lang/noirup/refs/heads/main/install | bash
noirup

# 2. Install bb (Barretenberg proving backend) — bbup reads your nargo version
#    and installs the compatible bb automatically
curl -L https://raw.githubusercontent.com/AztecProtocol/aztec-packages/refs/heads/master/barretenberg/bbup/install | bash
bbup
```

**Order matters:** install nargo first, then run `bbup` — it auto-detects your nargo version and installs the compatible `bb`.

### Project Structure

```
my-circuit/
  Nargo.toml          # Project manifest (name, type, dependencies, external libs)
  src/
    main.nr           # Circuit entry point
  Prover.toml         # Witness inputs (private + public values)
```

Create a new project:

```bash
nargo new my_circuit
cd my_circuit
```

### Build Pipeline

The production build pipeline stops at circuit artifact, VK, and Solidity verifier. If asked for the minimal production build, say explicitly that `bb prove` / `bb verify` below are optional local smoke tests only.

```bash
# 1. Compile circuit to ACIR
nargo compile

# 2. Execute with witness inputs (reads Prover.toml, writes target/*.gz)
nargo execute

# 3. Generate verification key — --oracle_hash keccak is required for EVM compatibility
bb write_vk --oracle_hash keccak -b target/my_circuit.json -o target/

# 4. Generate Solidity verifier from the VK
bb write_solidity_verifier -k target/vk -o target/Verifier.sol
```

**Local-only proof smoke test** — useful before wiring up the frontend. All commands must use `--oracle_hash keccak` consistently, or you get serialization mismatches.

```bash
bb prove --oracle_hash keccak -b target/my_circuit.json -w target/my_circuit.gz -o target/
bb verify --oracle_hash keccak -p target/proof -k target/vk -i target/public_inputs
```

The command is `bb write_solidity_verifier` — not `bb contract`, not `nargo codegen-verifier`.

**Contract size warning:** Call this failure by name: the generated `HonkVerifier.sol` can exceed the 24KB EIP-170 contract size limit. For real deployments, enable the Solidity optimizer first:

```toml
# foundry.toml
[profile.default]
optimizer = true
optimizer_runs = 200
```

If you still hit the limit locally, run `anvil --code-size-limit 40960` and `forge script ... --code-size-limit 40960`. That flag is for local testing only — mainnet and major L2s still enforce the 24KB limit.

### Build Artifacts and Hand-off

Treat the generated files as interfaces between subsystems:

- `target/my_circuit.json` — circuit artifact consumed by NoirJS
- `target/vk` — verification key used by `bb verify` and Solidity verifier generation
- `target/Verifier.sol` — generated verifier source; this is the source of truth for the verifier ABI. **This is a standalone contract that must be deployed separately.** Your app contract receives the verifier's deployed address in its constructor. Do not just import it — deploy it first, then pass the address.

Pick a stable layout and keep it consistent. A good default is:

```text
circuits/my_circuit/target/my_circuit.json
contracts/src/verifiers/HonkVerifier.sol
frontend/public/circuits/my_circuit.json
```

Do not hand-copy artifacts ad hoc in prompts or scripts. Models drift unless you make the hand-off explicit.

---

## Choosing the Right Pattern

Not every privacy app needs a Merkle tree. Pick the simplest approach that fits:

**Simple private proof** — prove a fact about private data without revealing it. No Merkle tree, no nullifier, no anonymity set. Just a circuit with private inputs, a public output, and a Solidity verifier. Examples: prove you're over 18 without revealing your age, prove your balance exceeds a threshold, prove a sealed bid is within range. The toolchain, Poseidon, NoirJS, and verifier sections above all apply — you just write a simpler circuit.

**Commitment-nullifier pattern** — needed when multiple participants must act anonymously from a shared set. Participants commit secret hashes into a Merkle tree, then later prove membership and act from a different wallet. The Merkle tree is the anonymity set. The nullifier prevents double-action. Required for: anonymous voting, private withdrawals (Tornado Cash), anonymous airdrops, whistleblowing. This is harder to get right — see below.

If you're unsure: start with a simple private proof. Only reach for the commitment-nullifier pattern when you need unlinkability between a prior action (committing) and a later action (withdrawing/voting).

### Before writing any code, ask:

1. **What needs to stay private?** A fact about data (age, balance, credential) → simple proof. *Which participant* performed an action → commitment-nullifier.
2. **What happens after proof verification?** Withdraw funds, cast a vote, claim an airdrop, unlock access — this determines the contract's `act()` logic.
3. **Can the same participant act more than once?** One vote per poll → nullifier scoped to `pollId`. One withdrawal per deposit → global nullifier. Unlimited access checks → no nullifier needed.
4. **Does the caller's identity need to be hidden?** If yes, the user must act from a fresh wallet via a relayer or ERC-4337 paymaster. If no (e.g., private credential check), the same wallet is fine.
5. **Which chai
Files: 1
Size: 28.8 KB
Complexity: 33/100
Category: General

Related in General