Open this lesson in your favourite AI. It'll walk you through the why, explain the demo, and quiz you on the try-it list.
In Circom, everything is a signal and every signal lives in a prime field (default: BN254's scalar field, a ~254-bit prime). You cannot use negative numbers, floating points, or strings — only integers mod p. You cannot use != directly; you must express 'not equal' via an inverse existing. You cannot use modular arithmetic other than mod p; 'x mod 2' is a dozen constraints. This is the single largest source of beginner frustration, and internalising 'everything is a field element' early saves weeks of confusion.
Three idioms every Circom programmer needs: IsZero (1 if input is 0, 0 otherwise), IsEqual (1 if a == b, 0 otherwise), and Num2Bits (decompose a field element into its bit representation). These are in circomlib; rewriting them yourself is how you learn the field-arithmetic mindset.
pragma circom 2.1.6;
template IsZero() {
signal input in;
signal output out;
signal inv;
// If in != 0, we must show an inverse exists.
// If in == 0, out = 1 and the constraint degenerates to 1 === 0 + 1 ✓
inv <-- in != 0 ? 1 / in : 0; // witness-only hint
out <== -in * inv + 1; // the actual constraint
in * out === 0; // forces out = 0 when in != 0
}
template IsEqual() {
signal input a, b;
signal output out;
component iz = IsZero();
iz.in <== a - b;
out <== iz.out;
}
component main = IsEqual();
// Witness: a=5, b=5 → out=1. Witness: a=5, b=7 → out=0.<-- line — compile fails, because inv has no witness-gen rule. This is why <-- and <== are separate operators.Use these three in order. Each builds on the one before.
In one paragraph, explain why in Circom everything is a field element over BN254's scalar field, what operations are free versus expensive in constraints, and why comparisons are not natively available.
Walk me through IsZero step by step: why the witness-hint inv uses `<--` not `<==`, what constraint `in * out === 0` enforces, and why this pattern is zero-knowledge.
I'm implementing a circuit that needs to check a SHA-256 hash against a value. Walk me through why SHA-256 is expensive in Circom (bit decompositions, XOR as (a+b-2ab)) and whether I should switch to Poseidon for ~30× cheaper hashing.