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.
Every Circom circuit has two groups of signals: private (inputs the prover knows, verifier never sees) and public (inputs both sides know, plus the outputs). Getting this boundary right IS the zero-knowledge property. Accidentally making a secret public exposes your user's balance; accidentally making a public input private means the verifier can't check against external data. In Circom, public inputs are declared at the component main line. This is easy to get wrong and there's no compiler warning.
A preimage verifier: prove 'I know x such that Poseidon(x) = hash' where hash is PUBLIC and x is PRIVATE. Declaring which is which lives in the component main line: component main { public [hash] } = PreimageCheck();. Anything not listed is implicitly private.
pragma circom 2.1.6;
include "circomlib/circuits/poseidon.circom";
template PreimageCheck() {
signal input x; // private — the preimage
signal input hash; // PUBLIC — the commitment
component poseidon = Poseidon(1);
poseidon.inputs[0] <== x;
poseidon.out === hash; // the ZK statement: x hashes to the known value
}
component main { public [hash] } = PreimageCheck();
// Generate proof:
// input.json = { "x": 42, "hash": <Poseidon(42)> }
// Verifier sees only 'hash' — never 'x'.signal input r) representing a blinding factor. Observe that it doesn't appear in the public-signals list unless you explicitly declare it.Use these three in order. Each builds on the one before.
In one paragraph, explain the public-vs-private signal boundary in Circom — what each means, how you declare them, and why this IS the zero-knowledge property.
Walk me through what the snarkjs verifier actually does: which signals are hashed into the Fiat-Shamir challenge, how does the public-input vector get used, and what would an attacker gain from leaking a 'private' signal?
I'm building an anonymous voting circuit where voters prove 'I'm eligible AND my vote is yes/no AND I haven't voted before.' Walk me through: which signals must be public (for on-chain checks), which private (for anonymity), and which nullifier derivation pattern prevents double-voting.