Skip to main content

Debug a failing witness

When a proof won't generate, the culprit is almost always the witness — a value out of range, a broken relation, a wrong commitment. zerostyl-debug runs the MockProver and surfaces exactly which constraint failed and where, far more readably than bare halo2. This tutorial walks a real failure end to end.

You'll use: zerostyl-debug, zerostyl-prove. Time: ~10 minutes.

1. See what the circuit expects

zerostyl-prove info state_mask
Circuit: state_mask v1.0.0
Privacy-preserving state proof: Poseidon commitment + bounded range + balance comparison.
Default k: 10
Public inputs: 2
Private witnesses: 5

Witness fields:
- [private] state_value : u64 Secret value committed via Poseidon hash.
- [private] nonce : fp Commitment randomness (Poseidon input)
- [private] collateral_ratio : u64 Must lie in [150, 300].
- [private] hidden_balance : u64 Must be strictly greater than `threshold`.
- [public ] threshold : u64 Public minimum balance.

Witness template (copy, fill, save as <circuit>.json):
{
"collateral_ratio": "0",
"hidden_balance": "0",
"nonce": "0",
"state_value": "0",
"threshold": "0"
}

The constraints are stated inline: collateral_ratio ∈ [150, 300] and hidden_balance > threshold.

2. Inspect the circuit structure (optional)

zerostyl-debug inspect --circuit state_mask
Circuit: state_mask
k: 10 (2^k = 1024 rows)
Columns: 20 total
advice: 11
instance: 1
fixed: 8
Selectors: 16
Max degree: 6

3. Run a valid witness

good.json
{ "state_value": "42", "nonce": "7", "collateral_ratio": "200", "hidden_balance": "5000", "threshold": "1000" }
zerostyl-debug debug --circuit state_mask --witnesses good.json
=== Debug Report: state_mask ===

Circuit: state_mask k=10

Result: ALL CONSTRAINTS SATISFIED

4. Break it and read the diagnostics

Now set collateral_ratio to 999 — outside the required [150, 300]:

bad.json
{ "state_value": "42", "nonce": "7", "collateral_ratio": "999", "hidden_balance": "5000", "threshold": "1000" }
zerostyl-debug debug --circuit state_mask --witnesses bad.json
=== Debug Report: state_mask ===

Circuit: state_mask k=10

Result: 2 FAILURE(S)

--- Failure 1 [permutation] ---
Region: in Region 17 ('range check 16 bits') at offset 16
Column: Column('Advice', 4)
Details: Equality constraint not satisfied by cell (..., in Region 17 ('range check 16 bits') at offset 16)

--- Failure 2 [permutation] ---
Region: in Region 17 ('range check 16 bits') at offset 16
Column: Column('Advice', 5)
Details: Equality constraint not satisfied by cell (..., in Region 17 ('range check 16 bits') at offset 16)

The failing region — range check 16 bits — names the problem: the bounded range proof on collateral_ratio cannot decompose 999 into the expected range, so its recomposition equality fails. The fix is to bring the value back into [150, 300].

5. Fix and confirm

Set collateral_ratio back to 200 and re-run:

zerostyl-debug debug --circuit state_mask --witnesses good.json
# → Result: ALL CONSTRAINTS SATISFIED

Now zerostyl-prove generate will succeed — see Prove & verify with the Rust SDK.

Mock-prove is instant

zerostyl-debug debug (and the SDK's mock_prove) run the constraint system without generating a real proof or any keygen, so they return in milliseconds. Always debug the witness here before paying for a full proof.

  • zerostyl-debug schema --circuit <name> — the witness schema plus a copy-pastable template.
  • zerostyl-debug witness --circuit <name> --witnesses w.json — pretty-print a witness against the schema.