A guide to Zero Knowledge Proofs (Part 2)

Luca Franceschini
21 min readDec 4, 2023

--

Introduction

We have introduced what ZKPs are, why they are cool, and why now in a previous article called “A Guide to Zero Knowledge Proofs (Part 1)”. If you are new to SNARKS, make sure to have a look at that article first.

Here, we will learn more about the IOP, PCS, and how we can combine them to build a SNARK. We will get into the details on why this stuff is so complicated.

What is a SNARK?

A SNARK is a succinct proof that a certain statement is true. The proof should be short and fast to verify. To better understand what this means, let’s see an example.

Let’s assume we want to prove that we know a message M such that the SHA256(M) is equal to 0.

We could prove the above statement by sending the message M directly. It would work, but there would be some issues:

  • What if the message M is a lot of data to send? We want to have a shorter proof, and make sure it’s fast to verify. The proof should be smaller than the message itself.
  • We don’t want the Verifer to run the function that the Prover wants to prove. In this case, we don’t want to have the Verifer running the hash function.
  • We want to prove that SHA256(M) = 0 without revealing the message M.

If we just sent the message M to the verifier, the proof won’t be neither short or fast to verify (meaning that it won’t be succinct). We want to have a SNARK instead.

Also, if we sent the full message M, the Verifier would know the content of it. We want to prevent the Verifier from learning anything about M, by using Zero Knowledge proprieties.

To get a perspective, the proprieties of a SNARK are:

  • Completeness: An honest Prover always will convince the Verifier.
  • Soundness: if the Prover lies, the Verifier will reject the answer with a high probability.
  • Succinctness: proof is short, and verifying time is fast.
  • In a ZK-SNARK, the Verifier does not learn anything about the message itself.

Why is everything so damn complicated?

The reason why everything is so complicated is that when we talk about SNARKS we are talking about Computer Science, Information Theory, and Cryptography at the same time.

That’s because to build a modern SNARK, we need to combine a cryptographic object with an information-theoretic one. By combining cryptography with interactive proofs, we obtain a succinct non-interactive arguments of knowledge (SNARK).

To be more precise, the cryptographic object we need is a Polynomial Commitment Scheme, and the information-theoretic object we need is an Interactive Oracle Proof.

Therefore, the current paradigm on how to build an efficient snark for general circuits is to have:

  • A functional Polynomial Commitment Scheme (PCS). The PCS is a cryptographic object, and its security depends on its cryptographic assumptions.
  • An Interactive Oracle Proof (IOP), compatible with the PCS. Because the IOP is an information-theoretic object, we can prove its security without underlying assumptions.

The reason why we call these “modern” SNARKS, is that we figured out how to separate the IOP construction from the PCS construction. This flexibility gave us room for important innovations.

That’s why it feels that when talking SNARKs there are a lot of moving pieces. Depending on which PCS and IOP you choose to construct your SNARK, you would have different tradeoffs, cryptographic assumptions, and so on…

Mathematicians and cryptographers are currently investigating these tradeoffs, as this is an open field of research.

Once we combine the PCS with the IOP, we obtain an interactive SNARK. This is cool, but we would like to have a non-interactive SNARK instead. The main reason is that interactive SNARKs depend on synchronous communication, meaning that both the Prover and Verifier need to be online during the proof generation. As the proof generation could take some time, this can be a problem.

How can we transform an interactive SNARK into a non-interactive one? Well, we would need to apply the Fiat-Shamir transformation. The Fiat-Shamir heuristic is the important piece that allows us to get a non-interactive proof from an interactive one.

Keep in mind that at this point we didn’t add any cryptographic gadget to make the SNARK a ZK-SNARK.

To recap, if we want to construct a SNARK we need to:

  • Choose an Interactive Oracle Proof (IOP) that expects a certain type of Polynomial Commitment Scheme.
  • Construct the Polynomial Commitment Scheme (PCS).
  • Pair the IOP and PCS together
  • Transform the interactive SNARK into a non-interactive one via the Fiat-Shamir transformation

Fundamental concepts

Let’s recap some concepts, as we will need them later on.

Statement

A statement is a claim that the Prover wants to prove to the Verifier. A statement is publicly known information, that the prover wants to prove.

In our SHA256 example, the statement would be SHA256(M) = 0

Witness

A witness is a secret that the Prover possesses that is used to prove the statement. The witness is the necessary element for the Prover to generate a valid proof. In a ZK setup, the Prover wants to prove to the Verifier that he knows the witness, without showing it. In our example, the witness would be the message M.

Arithmetic Circuit

Once we have the code of the computation we want to prove, we can use an arithmetic circuit to represent that computation through algebraic relations.

An arithmetic circuit is a mathematical model that allows us to represent our program as relations between polynomials. Using this math, we can leverage the propriety of polynomials to prove statements and do cool stuff. The arithmetic circuit itself tells you how to evaluate the polynomials so that you can use polynomials instead of computing in the “classical” way.

So, if we want to construct a SNARK, we need to make sure that whatever code we have is translated into an arithmetic circuit. This allows us to perform arithmetic operations like additions and multiplications over the finite field. A finite field is a set of numbers from 0 to a very large prime number, on which we can perform a special type of additions and multiplications (modulo p). Therefore, to define an arithmetic circuit, we need first to choose a finite field for some prime number.

You can also think of an arithmetic circuit to be a Directed Acyclic Graph (DAG), where Internal nodes are gates that represent an arithmetic operation (x,+,-,:), and inputs are the variables.

There are 2 types of arithmetic circuits:

  • Structured: the circuit is built in layers where you have one fixed arithmetic circuit that is repeated over and over again. You can think of it as a step of a microprocessor operation.
  • Unstructured: a circuit with arbitrary wires

Some SNARKS use structured circuits, and others use unstructured ones.

In other words, an arithmetic circuit is a function that takes as inputs some elements in the finite field and produces an element of the field as output. The bigger the computation you want to prove, the bigger the number of gates you need to have in your circuit. The circuit is constrained to have a maximum number of gates equal to the degree of the polynomial.

To get a sense, If we wanted to transform the SHA256 algorithm into an arithmetic circuit, we would have around 20 thousand gates! This would be considered to be a “small” circuit.

A bigger arithmetic circuit could be one that verifies digital signatures. For example, it could take as inputs a public key, a message, and a signature, and it would output “0” if the signature is valid with respect to the public key.

Polynomial Commitment Schemes (PCS)

Before understanding what a PCS is, let’s first recap what a commitment scheme is.

A commitment scheme is a protocol that needs to satisfy the following propriety(ies):

  • Binding propriety: it cannot produce two opening values for the commitment string. In other words, one commitment can only be “tied” to just one message.
  • Hiding propriety (in the case of ZK proofs). The committed string cannot reveal anything about the committed data.

To have a commitment scheme, we need a commitment algorithm and a verifier algorithm.

  • Commit algorithm. It allows you to commit a message to a random value. The output commitment string is very short (e.g. 32bytes), and its inputs are the message and the random value.
  • Verifier algorithm. It runs by having as input the message, the commitment string, and the random number.

Until now we have been talking about committing to some data. But what if we wanted to commit to a polynomial instead?

As most commitment schemes use hash functions, the trivial commitment scheme would be to use a hash function and commit to the coefficients of the polynomial.

Anyways, this would mean that the prover would need to send a proof that includes all the coefficients of the polynomial. As the polynomial can be extremely big though, our proof would not be succinct though. To construct a SNARK, we need succintness. That’s why we need to use a Polynomial Commitment Scheme (PCS).

A Polynomial Commitment Scheme (PCS) is a cryptographic protocol that allows us to transform a polynomial IOP into a succinct argument of knowledge. The PCS allows the Prover to simulate the polynomial IOP without explicitly sending a description of a large polynomial to the Verifier.

This is possible because with the PCS we send to the verifier just a commitment to the polynomial (e.g. a hash value of an element of a cryptographic group). The PCS supports the functionality that allows the verifier to choose a random point and demand that the Prover evaluates the polynomial at that point (e.g. doing the hash of M, like SHA256(M) ). Because the Verifier can choose random points to let the Prover evaluate the polynomial on, the Verifier is convinced after enough evaluation proofs.

By using a PCS, we are not requiring the Verifier to use a complete description of the polynomial, but instead the Verifier:

  • Receives a single hash value (or cryptographic group element) that commits to the polynomial.
  • Receives the requested evaluation of the polynomial and a proof that the requested evaluation of the polynomial is correct.

The PCS allows us to run a polynomial IOP succinctly: the Prover doesn’t need to send the whole polynomial to the Verifier, just a commitment to it!

The PCS reduces the claim over the correctness of the circuit to the evaluation of polynomials (which can be error-correcting schemes, hash-based schemes, additive groups schemes..).

The reason why it is enough to send a commitment to the polynomial to the Verifier (instead of the whole description of the polynomial), is that the Verifier doesn’t care specifically about the polynomial. The Verifier only cares about doing evaluations on the polynomial.

For this reason, the Verifier only needs evaluation points and queries their evaluations. When it queries the evaluations, the Verifier treats the polynomial commitment as if it was an “oracle”. The Verifier needs the concept of an “oracle” so that he can query the evaluations from it. The way we are going to provide an oracle to the Verifier is by instantiating the Oracle into a Polynomial Commitment Scheme. The reason why we talk about “instantiating” oracles, is because an oracle is just an information-theoretic concept: it doesn’t actually exist. The oracle is a model that can respond to the Verifer with the evaluations of the polynomial. To be able to use it, we need to encode the polynomial into an oracle.

When it comes to committing to a polynomial, there are three important families of functions we may want to commit to:

  • Polynomial commitments (univariate polynomials of degree at most d)
  • Multilinear commitments (multilinear polynomials in at most k variables, and degree 1 in each variable).
  • Vector commitments (where we commit to a vector). Merkle threes is a way of implementing a vector commitment scheme.
  • Inner Product Commitments. We commit to a vector and later we prove that the inner product of the committed vector and a vector chosen by a Verifier satisfies some proprieties.

Different SNARKS systems use different commitment schemes. In general, these commitment schemes are equivalent to one another, in the sense that they can be constructed from each other. In terms of generalization, a linear commitment is more general than a multilinear commitment, which is more general than a polynomial commitment. This means that if you have a multilinear commitment, it is “easy” to get a polynomial commitment out of it.

Which types of PCS are there?

  • Based on pairings + trusted setup (not transparent nor post-quantum), for example KZG. In this case, we have constant evaluation proofs, because there is only a constant number of field elements (taken from a pairing-friendly cryptographic group). These types of commitments are also homomorphic, which allows for efficient batching and amortization of proofs. This is because the homomorphic propriety allows you to commit to two separate polynomials without even knowing them. This is because the homomorphic propriety allows you to still obtain the commitment to the addition of the two polynomials (regardless if you know the polynomials or not). These commitments use bilinear groups.
  • Based on elliptic curves, where the discrete logarithm is hard (transparent, but not post-quantum). For example IPAs, Bulletproofs.. These PCS are also homomorphic, so you have efficient batching and amortization of proofs. This is cool because it helps a Prover who needs to prove different witnesses without having so much of a bigger cost. This is similar to how Schnorr signatures work.
  • Based on IOP + hashing (FRI, Ligero, Orion..). The proofs are usually bigger, as they are not homomorphic (and therefore not batchable. Because they only use hashing, they are quantum-proof. As an example, FRI can be used as a building block for the STARK system, or used to construct a PCS.
  • Groups of unknown order (DARK20). No trusted setup. This PCS is usually not used a lot, as it is still not so feasible.

Cryptographic assumptions come from the PCS used, and therefore if a SNARK is transparent (or quantum secure) depends entirely on the PCS. Once you choose a PCS, you would need to choose an IOP compatible with that specific PCS.

Interactive Oracle Proof (IOP)

An Interactive Oracle Proof is a theoretical object that provides interactive proofs. Interactive proofs are the result of having both interactions and randomness. These IOPs are considered to be “oracles”, in the sense that they are expected to give the correct value when they are queried. In this theoretical framework, the Verifier’s parameters consist of oracles that can be queried. As they are theoretic objects, they don’t actually exist until they are instantiated (for example through a PCS). In practice, these oracles are replaced by PCS, allowing the verifier to evaluate them at any chosen point with the assistance of the Prover. Anyways, their information-theoretic nature allows us not to add any assumptions on their underlying security.

The IOP provides us with the interaction between the Prover and Verifier, as the Prover sends Oracles to the Verifier, and the Verifier can query those oracles and send challenges in the form of random field elements to the Prover.

When we are constructing the SNARK, the oracles are transformed into commitments to the functions using the PCS. An oracle cannot be used without being instantiated, and that’s why we need to instantiate it by using the PCS. So, even if in theory the verifier parameters are a bunch of oracles that the Verifier can query, in practice these oracles are replaced by commitments that the verifier can evaluate at any point of his choice using the Prover’s help.

We need the IOP because the proving process requires interactions between the Prover and Verifier. The Prover sends oracles to the Verifier, and the Verifier responds with random bits. This allows the Verifier to evaluate the oracles of his choice. This exchange continues for several rounds until the prover sends the last oracle.

An IOP is a proof system designed to demonstrate that a given circuit C equals to zero for a given public statement x and private witness w. In other words, the IOP is a proof system that proves C(x,w)= 0.

An IOP allows us to have an interactive protocol that works the following way:

  • The Verifier sends random bits to the Prover
  • Prover Sends the oracle to a function
  • The Verifier sends other randomness to the Prover
  • Prover sends an oracle to another function to the Verifier
  • The above steps happen for several rounds until the Prover sends the last oracle for the last function.
  • The Verifier uses the verification procedure to either accept or reject the proof. The Verifier uses the verification procedure provided by the IOP by verifying the statement x that needs to be proven, the randomness given by the Verifier from all rounds and the received oracles from the Prover. The Verifier evaluates any of these functions at any point of his choice in order to know if accepting or rejecting the proof.

The IOP guarantees that the final proof is sound. This means that a malicious prover cannot fool the Verifier.

The IOP gives us the interaction between the Prover and Verifier through oracles. But as we said, oracles do not actually “exist”, they are just a model. When we actually build the SNARK, we need to replace the oracle to the function with the commitment. Using the PCS allows us to instantiate the oracles through polynomial commitments.

Which types of polynomial IOPs exist?

  • Based on Interactive proofs (IPs)
  • Based on multi-prover interactive proofs (MIPs)
  • Based on constant-round polynomial IOPs (Marlin and Plonk..)

The point is that an IOP can be combined with a PCS, and the combination of those will give you a SNARK.

Constructing a SNARK

Combining the IOP with the PCS allows us to obtain a SNARK for general circuits. As we said, the reason why we need both PCS and IOP is because we need to send oracles in the form of polynomial commitments.

When it comes to parameters, the Prover takes as inputs the Prover parameters, the statement, and the witness. Instead, the Verifier takes as inputs the Verifier parameter and the statement.

But how can we get the public parameters for both the Prover and the Verifier?

We’ll need to talk a bit about the pre-processing.

Pre-processing (setup)

By using a setup procedure, we obtain the public parameters for both Prover and Verifier.

We have said that if a circuit has a number of gates d, the polynomial would have at most a degree d. An imporant thing to note is that the Verifier will need to have enough time to read the circuit if he wants to be able to verify the proofs. Allowing the Verifier to read the circuit would mean that the Verifier algorithm would need to run in linear time to the size of the circuit. This is a problem though. Because the polynomial we are dealing with can be huge(e.g. a degree of 1 billion) if we had the Verfier running in linear time to the size of the circuit, we won’t have a succint proof (meaning that we won’t have a SNARK!).

To have a SNARK, we need to have the Verifier algorithm to operate in a logarithmic time in the size of the circuit C. This way, we would have enough succinctness. But Operating in logarithmic time implies that the verifier doesn’t even know exactly what the circuit looks like! How is this possible?

We have few open questions then.

  • Given that the Verifier needs to ask for evaluations, shouldn’t he know the full description of the polynomial?
  • If the Verifier doesn’t know how the polynomial look like, how is he supposed to query it?

Because the polynomial can have a degree that corresponds to the size of the circuit (number of gates), we cannot have the Verifier just read the coefficients of the polynomial to understand it. We need to give him a summary of it, by allowing the Verifier to evaluate the polynomial only at one single point. The point is randomly chosen by the Verifier himself.

This is necessary, because if we want to have a succinct proof, the evaluation proof size and verifier time need to be logarithmic in the degree of the polynomial. More specifically, we would need to have some parameters that can function as a summary of the circuit. To do this, we would need to use the PCS to have the Prover commit to the polynomial by using a very short string.

The pre-processing step is important, because it’s the algorithm that generates parameters for both the Prover and the Verifier, and allows the verifier to operate in a logarithmic time in the size of the circuit C. Thanks to the pre-processing, we don’t need to deal with monstrous polynomials!

More precisely, with the pre-processing step, the Verifier can work on a summary of the circuit and verify evaluations at arbitrary points without needing to know the full description of the circuit. The pre-processing steps involve an algorithm that takes as an input the circuit C and some randomness (random bits) . With this initial setup, we can create a very short summary of the circuit (a string!), and let the Verifier be able to know a summary of the circuit through that string. This way, the pre-processing allows the Verifier to read the circuit in a logarithmic time to the size of the circuit.

The pre-processing argument system takes in 3 algorithms: the setup, the verifier, and the prover algorithms. When it comes to inputs, the Prover takes the Prover’s public parameters, the witness, and the statement. The Verifier takes the Verifier’s public parameters, the proof, and the statement.

So, how does the pre-processing work?

To create the setup, we can either:

  1. Use a transparent setup. No secret data is required, and everyone can run the setup procedure and verify that the setup has been run correctly. No possibility of dangerous leaks. Proofs are usually bigger though.
  2. Create a trusted setup for the specific circuit. In this case, when the setup procedure is running and dealing with those random bits, we need to keep those bits secret from the Prover. Otherwise, the Prover can exploit the protocol and prove false statements. For every circuit, we would need to re-run the setup procedure, and every time keep secret those random bits (and destroy them after the pre-process setup is done). Proofs are shorter, but it’s a hassle.
  3. Create a trusted universal setup. In this case, the setup is updatable and the random bits are not circuit-specific. We only deal with that randomness only once. This is more secure than the previous case, because the risk of leaking that dangerous information is reduced. What makes this setup possible is breaking down the algorithm into two parts:

3.1 The initialization procedure. This step takes the random bits to create some global parameters. It is a one-time process, and after the initialization process is done, we throw away the random bits. This part is only run once because doesn’t take the circuit as an input. We use these global parameters just to derive the Prover and Verifier parameters. This separation of tasks allows this “dangerous” procedure of initialization to be run just once.

3.2 The indexing procedure. This part is a determinist algorithm that takes the global parameters and the circuit and generates the public parameters for both Prover and Verifier. Everyone can create public parameters for the Verifiers and Provers based on the public parameters in a deterministic way.

Constructing a SNARK

So, how the hell can we build a SNARK? Let’s go step by step:

  1. First, we choose a finite field for some prime number. Basically, we are fixing a set of functions.
  2. Then we write an arithmetic circuit (using the choosen finite field). We can use a Domain Specific Language (DSL) such as Circom, Leo, Cairo, Noir..). Our circuit would take as inouts a public statement and a private witness. The circuit would output some elements in the finite field. The arithmetic circuit has additions and multiplications gates (mod p), and the Circuit takes as inputs a statement x and a witness w. This way, we can compile our code into a SNARK-friendly format (R1CS, Plonk, AIR..). We now have an argument system.
  3. We need to pre-process the circuit with a setup algorithm. The setup algorithm takes a description of the circuit as input and outputs the public parameters for the Prover and Verifier. This allows us to pre-process the circuit. To be specific, the parameter for the verifier is a commitment to a bunch of polynomials. This is where the Fiat-Shamir transformation comes into play: it is the step that allows us to deal with non-interactive proof systems instead of interactive ones. The setup algorithm outputs some global parameters that are used by the Verifier and Prover. For non-interactive systems the pre-processing step is necessary, as this allows the Prover to just send the proof without any additional interactions.
  4. Once we choose the Prover and Verifier algorithms, we feed the public parameters into the snark backend prover system (e.g. a prover would be running something like Groth16, Plonk, Bulletproofs..).
  5. The Prover wants to prove that he can calculate f(x) = y. The Prover also wants to prove that the function f is included in the specific domain (the set of functions we chose before). In other words, the Prover wants to prove that for a circuit C and a statement s, he knows a witness w such as that the circuit is equal to 0, which in short means C(s,w) = 0. The witness in this case is the description of the function f along with the randomness r. Hopefully, the proof is short enough (e.g. few KBs). The first message in the protocol is the commitment to a polynomial sent from the Prover to the Verifier. To send the first message, the Prover chooses a function in the set and commits to it by running the commit algorithm. The commit algorithm outputs a commitment string, which is then used as a commitment to the global parameters, the selected function, and the randomness. This first message is important because it specifies the polynomial that the Prover committed to. After this first message, the interactive procedure starts. The interactive procedure corresponds to the evaluation protocol, which allows interactions between the Prover and the Verifier. In this interactive procedure, the messages from the Prover are short and read by the Verifier in full. This procedure involves a series of rounds where:

​ ​ ​​​ ​ ​​​ ​ ​​​ 6.1)The Verifier chooses a random point in the finite field and asks the Prover to evaluate the polynomial on that random point. In other words, the Verifier asks the Prover to “open” the selected polynomial at a specific point.

​ ​ ​​​ ​ ​​​ ​ ​​​6.2) The Prover needs to evaluate the polynomial on the point chosen by the Verifier so that he can prove that he knows how to evaluate the function he committed to. The Prover sends back the evaluation, along with the proof that the evaluation is correct.

​ ​ ​​​ ​ ​​​ ​ ​​​6.3) Prover commits to another polynomial and sends the commitment to the Verifier.

​ ​ ​​​ ​ ​​​ ​ ​​​6.4) The Verifier chooses another random value and sends it to the prover.

​ ​ ​​​ ​ ​​​ ​ ​​​6.5) The Prover evaluates the polynomial at the new point and provides the Verifier with both the new evaluations and the new proof that the evaluation is correct.

7) The steps of point 6 are repeated for several rounds. This is a continuous interaction between the Prover and Verifier. Anyways, because we used the Fiat-Shamir transformation by doing a pre-processing, we can simulate this interaction. The verifier can ask the prover to open any of these polynomials at any point of the Verifier’s choice.

8) The Prover commits to the last polynomial and sends the commit. This means that the Prover commits to a function so that later on he can produce a succinct proof that the committed function satisfies f(x)=y. The Prover is proving that knows a witness (meaning a function description and a randomness)such that f(x)=y.

9) After a certain number of interactions, the Verifier then chooses whether to accept or reject the proof. The Verifier does this verification by taking as inputs the statement, the random values, and the evaluations of the polynomials at all the points that he chooses.

Final Snark

In summary, to build a SNARK, we parametrize the polynomial IOP by two parameters:

  • The number of polynomial commitments.
  • The number of evaluation queries from the verify algorithm. This is the number of points at which the prover needs to open the evaluated polynomial).

The final SNARK consists in:

  • Prover sending the polynomial commitments to the Verifier.
  • The verifier running the evaluation queries several times.

The final SNARK ends up being several polynomial commitments + several evaluation proofs.

Considerations

  • The Verifier time is the number of evaluation proofs multiplied by their time. Because the number of polynomial commitments and the number of evaluation proofs are usually constant, the Verifier time is usually independent of the size of the circuit.
  • The Prover time is the time to compute the number of polynomial commitments plus the time to compute the evaluation proofs.
  • If the polynomial we are dealing with has a degree of 1 billion or more, the Prover needs to be able to manipulate polynomials of a degree of one billion to be able to commit to it. This computation is heavy, and that’s why we are interested in optimizing the Prover algorithm. The Prover time cannot go sub-linear in the size of the circuit, as it needs to read it in order to create the proof. Our objective is that the time to generate the proof should be slightly above linear, and this is crucial to scale the prover for bigger circuits. The Prover algorithm is a bottleneck for creating SNARKS, and a lot of work is being done on decreasing the prover time and memory requirements.
  • The prover wants to convince the Verifier that f(x)=y.The proof that the Prover needs to give to the Verifier, is the single commitment to the quotient polynomial. To do this, the prover needs to compute the quotient polynomial and commit to it, and this is a quite heavy computation. Note that it is enough for the Prover to compute the single group element that corresponds to the commitment to the quotient polynomial, and the proof is just one group element of the commitment to the quotient polynomial. The reason is that if two polynomials evaluate to 0 at a random point, then most probably they are the same polynomial. Similarly, if polynomials agree on a random point, then they are with high probability the same polynomial.
  • Because we have now several ways of proving the proprieties of polynomials, we now have a new generation of Provers, which are way faster than before, making it feasible to write general circuits. Because Provers are faster (proof generation time is nearly linear in computation size), we can now prove complex statements.
  • A SNARK provides a succinct argument of knowledge, in the sense that the proof’s size is sublinear in the size of the witness w and at most logarithmic in the size of the circuit C. Verification time should be at most logarithmic in the size of the circuit, and linear in the size of the statement. In some SNARKS the size of the proof and the time to verify the proof is constant, which means that it is independent of the size of the circuit.
  • To achieve zero knowledge, preventing leakage of information unknown to the verifier, the IOP exploits the property that every element in the witness set is a root of the polynomial f. The Prover computes the univariate polynomial f, along with the quotient polynomial q. Oracles for f and q are sent (as commitments in SNARK instantiation), and the Verifier, having a public value r, queries the function f at chosen points. The prover computes the value, sends the evaluation, and proves its correctness. The verifier then makes an acceptance or rejection decision based on this information.

--

--