Explainer 02

What is a zero-knowledge proof?

The everyday version

A zero-knowledge proof (ZK proof) is a way to convince someone that a statement is true without revealing why.

Some real-world analogies:

A ZK proof is the cryptographic version of that envelope: a small piece of math, typically a few hundred bytes, that a verifier can check in milliseconds and that reveals only the truth of the claim, nothing else.

What Jomhoor uses ZK proofs for

We use ZK proofs to let a user prove three claims at once, on-chain, without revealing identity:

  1. "I hold a genuine Iranian travel document or national ID." Proven against the document's cryptographic signature and the official ICAO certificate tree.
  2. "I have not registered or voted before for this event." Proven via a unique, deterministic value called a nullifier — derived from the document and the event, but unlinkable to identity.
  3. "My document has not expired and I meet age / citizenship criteria." Proven against birth-date and expiry fields inside the document, without disclosing the actual values.

The on-chain record is just: some valid Iranian citizen, eligible for this vote, has voted "yes" on proposal #42. Nothing more.

The three properties every ZK proof must have

When cryptographers talk about ZK proofs, they always mean a system with three properties. The user-facing meaning of each is what matters:

PropertyPlain EnglishWhy it matters to Jomhoor
CompletenessIf the statement is true, an honest user can always produce a valid proof.A real Iranian passport holder is never falsely rejected by the smart contract.
SoundnessIf the statement is false, a cheater cannot produce a valid proof — except with vanishingly small probability (typically 1 in 2¹²⁸).An attacker cannot register a fake identity by guessing or by computing a "lucky" proof.
Zero-knowledgeThe proof reveals nothing beyond the truth of the statement — not the inputs, not the intermediate values, not any side information.The chain never learns passport number, name, date of birth, or which person any given vote belongs to.

These three together are what makes ZK proofs different from a signature, a hash, or an attestation. A signature proves "I have the key"; a ZK proof proves "I know inputs that satisfy a specific computation" — and only that.

How "soundness" actually works

The 1-in-2¹²⁸ number is not a guess. It comes from how the proof is built:

  1. The computation we want to verify (e.g. "passport signature is valid AND nullifier was derived correctly AND document is not expired") is compiled into a giant arithmetic circuit — millions of additions and multiplications over a prime field.
  2. The prover commits to every intermediate value of that computation using elliptic-curve points.
  3. The verifier issues a random challenge derived deterministically from those commitments.
  4. The prover must respond with values that satisfy a single algebraic identity tying the commitments and the challenge together.

A cheater would have to forge values that satisfy that identity by chance. The identity lives over a field with ~2²⁵⁴ elements, so the cheating probability collapses to roughly 1 in 2¹²⁸ even for the strongest known attacks. For context: 2¹²⁸ is more than the number of atoms in a billion human bodies. It is treated as "impossible" by every banking and government cryptography standard.

What "zero-knowledge" actually means

Zero-knowledge does not mean "the data is encrypted somewhere on the chain." It means the data was never put into the proof to begin with.

Compare:

For Jomhoor, this means:

The only way an attacker learns your passport number is by getting it from your physical device — same threat surface as your photos or your WhatsApp messages, and unrelated to anything we publish on-chain.

"The shape of the circuit" — what that phrase means

Throughout these explainers we say things like "the circuit's shape determines what can and cannot be proved." Concretely, the circuit is a fixed program that says:

Given private inputs (passport bytes, signature, secrets) and
public inputs (event ID, current date, ICAO root):
  1. Hash the data groups (DG1, DG2, ...) and verify SOD signature.
  2. Verify the Document Signer certificate against the ICAO Merkle root.
  3. Derive the nullifier = poseidon(secret, event_id).
  4. Check that birth_date + 18 years ≤ current_date.
  5. Output: nullifier, citizenship, current_date, ICAO root.

Every Jomhoor user's phone runs the same circuit for a given document class. Only the inputs differ. This is what lets one smart contract verify millions of users' proofs with one verification key.

Different document classes (Iranian passport RSA-2048-SHA256, Iranian passport RSA-3072-SHA1, INID RSA-2048, future ECDSA passports) use different circuits, because the signature math differs. That is why our SSO service keeps a circuit registry rather than a single hardcoded verifier.

What ZK proofs do not do

It is just as important to be honest about what this technology cannot solve.

ZK provesZK does NOT prove
"I hold a document that the Iranian Civil Registry signed.""The Iranian Civil Registry only signs real people."
"Some valid input satisfies this circuit.""The input came from a live, consenting human."
"I have not voted on event X before.""I am the same human across two events." (Different nullifier per event by design.)
"My birth date is before 2008.""I am not lying about my opinions."

The biggest honest limit: a ZK proof inherits the trust of whoever signed the document. If the issuer's signing key is compromised — by a state actor or otherwise — fake-but-valid documents can be minted and will pass the proof system perfectly. This is true of every passport-ZK system in the world, including ours. See the passport trust chain for the full attack surface and our mitigations.

Why this is still worth doing

Even with that honest limit, ZK identity beats every alternative on the deployable spectrum:

ApproachReveals identity?Resists sybil?Censorship resistant?Cost per check
Government login (e.g. Sana / Shahkar)Yes — everythingYesNo — server can block any userServer cost
Username + passwordNo, but no identity guaranteesNoDepends on hostServer cost
Plain digital signature with passportYes — full documentYesDepends on hostServer cost
ZK proof from passport / INIDNoYes (via nullifier)Yes (on-chain)~$0.001

The combination of no identity disclosure, one-person-one-vote enforcement, and no central server able to delete users is what makes ZK proofs the right primitive for civic-scale democratic infrastructure under hostile conditions.

Glossary

TermMeaning
CircuitThe fixed arithmetic program that defines what is being proved.
WitnessThe full set of intermediate values the prover computes while running the circuit on their inputs. Stays on-device.
ProofThe 256-byte (Groth16) cryptographic object that gets uploaded.
Public signalsThe small set of circuit outputs (nullifier, root, date, etc.) that the verifier sees. Never includes raw document data.
NullifierA deterministic, identity-blinding value used to prevent double-voting. Same person + same event = same nullifier; same person + different event = different nullifier.
Verification keyA small file the smart contract holds, used to check proofs from a specific circuit. One per circuit.
Soundness errorThe mathematical probability a cheater succeeds (~2⁻¹²⁸ in our setup — treated as zero in practice).

Next

Up next: the passport trust chain — how we get to the assumption that "the document a user scans is real," and exactly where that assumption stops being true.