Writing a Circuit (Circom / Noir / Cairo)
Circom, Noir, and Cairo for ZK circuits. The "thinking in constraints" mental model. zkVMs like RISC0, SP1, Jolt, and Nexus that let you write Rust instead.
45 min · expert · part of ZK Cryptography & Proof Systems
Thinking in Constraints
The conceptual leap most engineers have to make when first writing ZK circuits is that you are not writing a program in the usual sense. You are writing a set of constraints — algebraic equations — that the prover and verifier both agree must hold over the inputs and intermediate values.
A normal program describes a sequence of operations: load this value, add it to that, branch on the result, store it. A circuit describes a relation between values: this output equals this input plus that input; this boolean equals one if and only if this comparison holds; this hash equals the Poseidon of these field elements. The prover provides values that satisfy all the constraints. The verifier checks that the constraints hold.
**Why constraints, not instructions.** Underneath every SNARK and STARK is a polynomial commitment scheme. To prove a computation, the system encodes the computation as a polynomial identity that holds if and only if the computation was performed correctly. Constraints are how you express that identity in human-readable form. The compiler translates your constraints into the polynomial representation the proof system uses.
**The big mental shifts.**
• **Branches are not free.** In a normal program you write `if (x > 0) y = a else y = b`. In a circuit, both branches must be executed and the result is selected by a multiplexer constraint. There is no skipping. Conditional logic costs constraints proportional to the size of both branches.
• **Loops must be bounded.** A circuit has a fixed number of constraints. Loops must run a known number of times at compile time. Dynamic-length data structures require padding to a maximum size.
• **Non-deterministic hints are powerful.** The prover can compute values out-of-band using any algorithm and supply them to the circuit, which then verifies them with cheap constraints. For example, computing a square root is expensive in constraints, but verifying a claimed square root is one multiplication. So you compute outside the circuit and check inside.
• **Field arithmetic.** All values are elements of a finite field — typically a 254-bit prime field for SNARKs and a 252-bit or smaller field for STARKs. Integer arithmetic, bit operations, and comparisons all have to be carefully expressed in field operations. The constraint counts for these operations are not always intuitive.
• **Hash functions are expensive.** SHA-256 requires tens of thousands of constraints. Poseidon (designed for ZK) costs a few hundred. Choosing the right hash for your circuit can be a 100x difference in proving cost.
These shifts are why writing ZK circuits is a specialized skill. The tooling — Circom, Noir, Cairo, and the zkVMs covered later — exists precisely to make the constraint-writing experience feel more like normal programming while still producing efficient circuits.
Also in this lesson
- Circom: R1CS and Templates
- Noir: A Rust-Like Circuit Language
- Cairo: A STARK-Native Language
- zkVMs: Writing Normal Code That Proves Itself
- Choosing a Tool for Your Use Case
Key terms
- Constraint system
- A set of algebraic equations (typically over a finite field) that defines what a circuit computes; the prover supplies values satisfying all constraints, and the verifier checks them.
- R1CS (Rank-1 Constraint System)
- A constraint representation where each constraint has the form A * B = C with A, B, C linear combinations of signals; the standard target of Circom and many SNARK provers.
- Circom
- An R1CS-targeting circuit DSL developed by iden3, used by Tornado Cash, Semaphore, Worldcoin, and many shielded-asset designs; mature but with ergonomic quirks.
- Noir
- A Rust-inspired ZK circuit language by Aztec Labs, compiling to ACIR and supporting multiple SNARK backends (Barretenberg, UltraHonk); focused on ergonomic privacy and recursive proofs.
- Cairo
- StarkWare's language for STARK-provable programs; Cairo 1 (2023) is a Rust-inspired rewrite of the original Cairo Zero, used for StarkNet smart contracts and other STARK applications.
- zkVM
- A general-purpose virtual machine whose execution can be proved with a ZK proof, letting developers write normal code (typically Rust) instead of writing circuits directly. Examples: RISC0, SP1, Jolt, Nexus, Polygon Miden.
- Poseidon hash
- A ZK-friendly hash function designed for efficient evaluation inside SNARK and STARK constraint systems; typically a few hundred constraints versus tens of thousands for SHA-256.
- Non-deterministic hint
- A value computed outside the circuit and supplied to the prover, then verified inside the circuit with cheap constraints; used heavily to avoid expressing expensive operations (square roots, divisions) as constraints.
- ACIR (Abstract Circuit Intermediate Representation)
- Noir's backend-agnostic intermediate representation, allowing the same Noir program to compile to multiple proving systems.
- Bonsai / SP1 prover network
- Proof-as-a-service infrastructure that lets developers outsource expensive proof generation to specialized provers, paying per proof; Bonsai is RISC0's service and Succinct operates a similar network for SP1.
Continue this lesson — 5 more sections in the CryptoBipto app.
Open lessonEducational only — not financial advice.
