Verifier Logic
Verify Hekate zero-knowledge proofs in Rust: pin the program id, read the result, and verify one proof, many with a prepared program, or a parallel batch.
On this page
The verifier decides whether a proof is valid. It replays the prover's transcript and every check in open-source
Rust, from the program you give it, the public instance and the proof bytes, and returns Ok(true) only when all of
them pass.
The example on this page proves and verifies a XOR checksum over four private 32-bit words.
AIR Constraints builds its circuit in src/circuit.rs, and
Execution Trace fills its table in src/trace.rs.
§ What the verifier needs
Four inputs come from your build and one from the prover: the program built from audited source, its pinned program
id, the Config and transcript label, the instance, and the proof.
System Architecture explains why each is pinned.
The verifier runs no prover code and needs no native library, and with default-features = false plus blake3 it builds
as no_std with alloc.
§ The checks, in order
The verifier works through a proof in the order the prover built it; Prover Engine walks through the protocol.
- Shape. Table heights and counts, and the security floor of the configuration.
- Identity. The id computed from your program against the pinned one.
- Binding. The program id, configuration, sizes, public inputs and the commitment over every table enter the transcript.
- Buses. The bus challenges
γandβ, oner_busper lookup bus, then the root of the helper columns. - Each table, chiplets first: the ZeroCheck rounds down to one point and the constraints at that point (recorded for the outer argument with zero knowledge on).
- Close. One evaluation sumcheck over every table and the opened columns against the commitments and the code; then the bus sums cancel or, with zero knowledge on, the outer argument holds over the recorded checks.
§ Reading the result
| Result | Means |
|---|---|
Ok(true) | every check passed |
Ok(false) | the main table's ZeroCheck, any table's evaluation check, or the outer argument, failed |
Err(_) | any other check failed, the proof or input is malformed, the program id differs, or the floor is not met |
Only Ok(true) accepts; a forged proof can produce either of the other two. ProgramIdMismatch points at the verifying build itself: its program drifted from the one you
audited.
§ One proof, many, or a batch
HekateVerifier::verify prepares the program on every call, rebuilding its table shapes and recomputing its id. A
service that verifies many proofs of one program prepares it once.
PreparedProgram::new(&program, &config)computes the tables, shapes and program id once and is read-only after that, which lets one copy serve every thread. ItsConfigis fixed at preparation, andverify_preparedtakes none.VerifierScratchcaches state between proofs and is mutable: one per thread.verify_batchchecks a slice of proofs, one per pool thread with theparallelfeature, each with its own scratch and a transcript opened with the label, and returns the results in input order.
1use crateF;
2use Config;
3use errors;
4use InnerProof;
5use DefaultHasher;
6use Transcript;
7use ;
8use deserialize_proof;
9use HekateVerifier;
10use ;
11
12pub const LABEL: & = b"xor-checksum";
13
14
19
20
1
2
3
4
5use ;
6use Config;
7use InnerProof;
8use ;
9use ;
10use prove;
11use ;
12use ;
13use Error;
14use generate_trace;
15use ;
16
17
54
55
Checker is the long-lived verifier: one prepared program, one scratch, and the pinned id. main checks the trace with
preflight, proves the checksum twice with fresh seeds, and verifies the first proof alone, from its wire bytes, then
both in a batch. It prints the program id, then one proof: true, batch proof 0: true and batch proof 1: true.
program_id(&program) stands in for the pinned id here: a real verifier compiles in the hex that program_id_hex
printed once, at audit time.
§ Speed
parallel, on by default, spreads leaf hashing and proximity checks above a size threshold, the outer argument's
openings and tests, and verify_batch over a Rayon pool. table-math makes basis conversion faster and variable-time: safe in a verifier, which only touches
public values, but Cargo turns it on for every crate in the build: leave it off in a binary that also builds
witnesses. Benchmarks lists verification times for each workload.
§ What a valid proof does not show
A valid proof shows that a trace satisfying your program exists, and nothing beyond the program.
- It is as strong as the circuit. A published cell that no constraint determines can take any value the prover likes; AIR Constraints explains.
- It does not show that the witness stayed private. Zero knowledge depends on how the proof was made: a fresh seed and the prover binary that read the witness.
- Each chiplet proves a stated scope, and Primitives lists what each one leaves outside the proof.
§ Next steps
- System Architecture: where the verifier sits, and what it trusts.
- Prover Engine: the protocol the verifier replays.
- AIR Constraints: the circuit behind the checksum.