A Practical Mental Model for Zero Knowledge Proof Systems

A Practical Mental Model for Zero Knowledge Proof Systems
Photo by Daniel Pelaez Duque on Unsplash

It can be challenging for web3 and smart contract developers to learn about Zero Knowledge Proofs because they often involve complex math concepts with steep learning curves. In this discussion, I want to share an easy-to-understand way of learning about Zero Knowledge Proofs with code examples and diagrams but without getting bogged down in mathematical detail.

It's a confusing topic

Let's start with what wikipedia has to say about Zero Knowledge Proofs:

A zero-knowledge protocol is a method by which one party can prove to another party that a given statement is true whilst avoiding conveying any additional information apart from the fact that the statement is indeed true - Wikipedia

You wouldn't be alone if you have never had much exposure to Zero Knowledge cryptography to consider this explanation befuddling.

One of the main challenges here is the idea of proving something without revealing any information about it.

This concept can be counterintuitive, as we usually think of proof as something that involves sharing information to verify a claim. Additionally, the idea of trust in a ZKP system can be difficult to understand, as it requires users to place trust in the integrity of the system without necessarily understanding the technical details of how it works.

Here I will not address systemic integrity but will try to present a better way think about Zero Knowledge Systems which is as a way to create a cryptographic receipt of a function call.

Functions with Receipts

When you begin learning about Zero Knowledge Proofs, you might come across terms like "Arithmetic Circuits" or "Rank 1 Constraint Systems". Trying to understand the construction of these terms without a simple mental model can be confusing. Also people often use the term "statement" as the thing we are proving from the perspective of a programmer this term is very abstract.

We would instead like to suggest that developers think of Zero Knowledge Systems in general as a way to write pure Functions that can create cryptographic Receipts of execution that can then be Verified to guarantee that correct execution was performed.

  1. A Function (commonly called a Circuit)
  2. The system creates a Receipt (Proof) that proves that the Function executed correctly only revealing specific input parameters
  3. The Receipt can then be verified by a separate Verifier component that knows about the Function
  4. The Receipt looks like cryptographic mumbojumbo but can be mathematically verified without revealing the inputs to the function.

Thinking about ZKP systems like this helps a developer understand the basic patterns they can use ZKP systems for within their projects.

Proof of Age Example

So a good way to start understanding how we can use Zero Knowledge Proof Systems is to explore an example for context. Here I would suggest we explore being granted entry to a licenced premises.

When entering a club, it is not uncommon to observe individuals lining up to present their identification cards as proof of being of legal age to consume alcohol. To expedite the age verification process, some clubs have gone a step further by requiring patrons to scan their IDs into a digital system. However, this practice comes with a significant problem - it divulges a plethora of sensitive information about the patrons, including

  • Name
  • Age
  • Address
  • Date of birth
  • Gender
  • License number

This information can be exploited for identity theft purposes and is entirely unnecessary for determining whether the patron is legally permitted to drink alcohol. Legally speaking, the establishment only needs to ensure that the individual being served is of legal drinking age.

Zero Knowledge ID

Let's assume the government creates a signed JSON document with a known key and that the JSON document contains a "birthdate" field.

  "value": {
    "id": "123456789",
    "first_name": "James",
    "middle_name": "Stuart",
    "last_name": "Arent",
    "birthdate": "1984-02-29T00:00:00+00:00",
    "gender": "M",
    "address": {
      "address": "2790 Parkview Drive",
      "city": "Houston",
      "state": "TX",
      "zip": "77074"
  "signature": "iQEzBAABCgAdFiEEGInq7S...EYXwAi2hixPCReWNA===12yS"

Our Function

If we go back to our mental model of "functions with receipts" we can conceive a function that could do the following:

  1. Accept this signed document
  2. Accept todays date
  3. Verify the signature within the document
  4. Check that adding 18 years to the birthdate is less than todays date
  5. Return true if both verifications pass

In Typescript-ish pseudocode this might look like the following:

function canDrink(license, public today) {
  const birthdate = license.value.birthdate;
  return verifyLicense(license) && birthdate < today - years(18);

Creating the Applications

In order to build out a real world system for proving age we would need two mobile apps:

  • A "Proving" mobile app on the Patron's device
  • A "Verifying" mobile app on the Bouncer's device

As we build out the applications we can compile our special function to a bytecode type format and include it with the source of both the prover and verifier.

Describing the Usecase

Prior to heading out to the club the "Prover" has been sent the signed JSON "ID document" above and has imported it to their app and it is stored in app storage.

Then as the Patron approaches the Bouncer the following happens:

  1. The Bouncer requests to see their proof of age QR.
  2. The Patron taps a button that does the following:
  3. Run canDrink passing in the license document alongside todays date and generate the proof of correct execution
  4. Generate a QR code from the proof
  5. The Bouncer then scans the QR which then simply verifies that the proof is valid when run with today's date.


Here we have outlined a mental model and sketched a plausible system for proving age in zero knowledge within the context of being allowed to enter a licensed establishment. By utilizing a "Functions with Receipts" paradigm we can make it easier to conceptualize and reason about the basic properties of a Zero Knowledge cryptosystem when utilized in practice.