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.
Circom has arrays of signals and loops, but with a sharp twist: loops are unrolled at compile time. This means for (var i = 0; i < 100; i++) produces 100 copies of the body in R1CS, one per iteration. There is no 'runtime loop.' This is why the circuit size is determined entirely at compile time and why 'check this one of N items' is expensive unless you use specific techniques (selectors, Merkle proofs).
A circuit that sums an array of N signals. Straightforward with a compile-time loop — produces N constraints. Beginners often reach for 'sum all items in a list of unknown length'; Circom forces you to fix the length at compile time, or use a maximum-N + padding pattern.
pragma circom 2.1.6;
template Sum(N) {
signal input in[N];
signal output out;
signal acc[N];
acc[0] <== in[0];
for (var i = 1; i < N; i++) {
acc[i] <== acc[i-1] + in[i];
}
out <== acc[N-1];
}
template SelectorOneOfN(N) {
// Prove: 'this index selects this value from the array'
signal input arr[N];
signal input idx;
signal output out;
// Build a one-hot vector [0,0,1,0,...] whose '1' is at position idx.
signal selector[N];
var sum = 0;
for (var i = 0; i < N; i++) {
// selector[i] = 1 if i == idx else 0.
// Force via: selector[i] * (i - idx) = 0 AND sum of selectors = 1.
selector[i] <-- (i == idx) ? 1 : 0;
selector[i] * (i - idx) === 0;
sum += selector[i];
}
sum === 1;
var acc = 0;
for (var i = 0; i < N; i++) { acc += selector[i] * arr[i]; }
out <== acc;
}
component main = Sum(10);out <== arr[idx]). Compile fails: arrays can't be indexed by a signal (idx must be a compile-time var OR you need the selector pattern).Use these three in order. Each builds on the one before.
In one paragraph, explain why Circom loops are unrolled at compile time, what consequences this has for circuit size, and how selectors let you 'pick one of N' with N constraints.
Walk me through the selector pattern step by step: why does `selector[i] * (i - idx) === 0` plus `sum(selectors) = 1` force exactly one selector to 1 at position idx, and why is this N constraints?
I'm building a circuit that operates on arbitrary-length user input (e.g., arbitrary-length emails for an identity proof). Walk me through the 'maximum length + padding + length check' pattern, and what assumptions it leaks to the verifier.