Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
Circom circuits scale by composition. A template defines a parameterised circuit (e.g., 'a Merkle-path verifier for depth d'). Instantiating a template creates a component. Components can include other components. This is how circomlib gives you a Poseidon hash over any 2-element input, or a Merkle proof over any depth — by exposing templates parameterised on the relevant dimensions. Understanding the difference between templates and components, and how template parameters differ from signals, is the foundation of writing clean Circom.
A Multiplier template that's parameterised on N — the number of inputs. Instantiate with N=3 to multiply three numbers. N is a compile-time parameter (known when circom generates R1CS); signals are witness-time values.
pragma circom 2.1.6;
template NMultiplier(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];
}
component main = NMultiplier(3);
// Witness: in = [2, 3, 5] → out = 30.NMultiplier(n) where n is a signal. Compile fails: template parameters MUST be compile-time. This constraint is the most surprising to programmers from dynamic languages.for (var i = 0; i < in[0]; i++)): compile fails. Circom's unrolling requires compile-time bounds.