The Prover, The Verifier & The Witness
Three roles. Every ZK system has all of them.

Every ZK proof involves the same cast of characters regardless of whether you are building a ZK rollup, a private voting system, or an identity credential. The names are consistent across the literature, the codebases, and the research papers. Learn them once and they will click everywhere.
The Prover is the party who knows something and wants to convince someone else of it without revealing what they know. In code, the prover runs the proving algorithm, takes in the secret data, and outputs a proof. This is the computationally expensive side. Generating a proof takes real work.
The Verifier is the party checking the claim. The verifier receives the proof, runs the verification algorithm, and outputs a single bit: valid or invalid. Verification is intentionally cheap. In most modern systems it takes milliseconds. This asymmetry is by design and is what makes ZK proofs useful on blockchains where thousands of nodes need to check the same thing.
The Witness is the secret itself. Not the proof of the secret. The actual private data the prover holds. In a password system the witness is the password. In a financial proof the witness is the account balance. In a voting system the witness is the actual vote. The witness never leaves the prover. It goes into the proving algorithm and a proof comes out. The witness stays behind.
How they connect in a real system
Take a concrete example. You want to prove you are over 18 to access a service without revealing your birthdate.
Your birthdate is the witness. You are the prover. The service checking your credential is the verifier.
You run a proving algorithm that takes your birthdate as private input and a public statement as public input: "this person is over 18 as of today." The algorithm produces a proof. You send that proof to the service.
The service runs the verification algorithm. It checks the proof against the public statement. It outputs: valid. You get access. Your birthdate never appeared anywhere in that exchange.
In circuit terms this maps directly to code:
```circom pragma circom 2.0.0;
template AgeCheck() { signal private input birthYear; // the witness signal input currentYear; // public input signal input minimumAge; // public input signal output valid; // what the verifier checks
valid <== (currentYear - birthYear) >= minimumAge; } ```
The private input is the witness. It is marked private because it never leaves the prover's machine. The signal output is what the verifier ultimately checks. Everything else is public context that both parties agree on.
The statement and the relation

There is one more concept worth naming here because you will see it constantly in ZK documentation.
A ZK proof proves that a witness satisfies a relation. The relation is the computation itself, expressed as a circuit or a program. The statement is the public claim being made.
Formally it looks like this:
`` Prove: I know a witness W such that R(public_inputs, W) = true ``
Where R is the relation, the circuit, the program. The verifier knows R. The verifier knows the public inputs. The verifier does not know W. The proof convinces the verifier that W exists and satisfies R without showing what W actually is.
This framing appears in every ZK paper, every SDK, and every protocol specification you will encounter. The prover knows the witness. The verifier knows the relation. The proof is what connects them.
Answer the quiz correctly to continue →
What is the role of the witness in a ZK proof?