How to prove y=F(n)(x)? The naïve approach would be unrolling this into a single circuit and proving with some SNARK. But this would require a lot of memory and the proof is not incrementally updatable. Also, the verifier's time may depend on n. To tackle this problem more efficiently, a new approach called incrementally-verifiable computation was introduced in , . In IVC, an augmented circuit is introduced which ensures correct execution of F as well as some verifier circuit which can now be used to inductively prove the correct execution of F(n)(x).
Folding R1CS
Standard R1CS
Given three m×m matrices A,B,C and public input x, does there exist witness W such that: AZ∘BZ=CZ where Z=(W,x,1). Here, we use x instead of vector x for public input since in Nova, it is typically a hash value.
An attempt to fold R1CS
Suppose prover P holds W1 and W2 and verifier V holds U1=(W1,x1) and U2=(W2,x2).
Verifier picks random r and send it to the prover.
Verifier computes x←x1+r⋅x2 so the folded instance becomes (A,B,C,x).
Prover computes the folded witness W←W1+r⋅W2.
Unfortunately there exists many r such that AZ∘BZ=CZ for Z=(W,x,1).
Need to account the cross-term: r⋅(AZ2∘BZ1+AZ1∘BZ2)
Mismatch in coefficient of CZ2:r2⋅CZ2=r⋅CZ2
Even Z=Z1+r⋅Z2 since Z1+r⋅Z2=(W,x,1+r⋅1)
To address first issue, we add error vector E∈Fm which absorbs the cross-terms. To handle the second and third issues, we introduce a scalar u, which absorbs an extra factor of r in CZ2 and in Z=(W,x,1+r⋅1). We refer to the R1CS with these additional terms as relaxed R1CS.
Relaxed R1CS
Definition 11 from the paper. Consider a finite field F. Let the public parameters consist of size bounds m,n,l∈N where m>l. The relaxed R1CS structure consists of sparse matrices A,B,C∈Fm×m with at most n=Ω(m) non-zero values in each matrix. A relaxed R1CS instance consists of an error vectorE∈Fm, a scalaru∈F, and public inputs and outputs x∈Fl. An instance ((A,B,C),(E,u,x)) is satisfied by a witness W∈Fm−l−1 if
AZ∘BZ=u⋅CZ+E
where Z=(W,x,u). In this setup, notice that if u=1 and E=0 then it is same as standard R1CS.
Folding relaxed R1CS
To fold relaxed R1CS, the prover and verifier additionally compute:
Now, you will be able get AZ∘BZ=u⋅CZ+E where Z=Z1+r⋅Z2. But there is still a few issues remaining:
The verifier has to compute E which has multiple large matrix multiplications so it is non-trivial.
Verifier cannot check if W is indeed the outcome of W1+r⋅W2 so it cannot be zero-knowledge because verifier needs to know W1 and W2 to fully verify.
To circumvent these issues, we use succinct and hiding additive homomorphic commitments to W and E in the instance, and treat both W and E as the witness. We refer to this variant as committed relaxed R1CS.
Committed Relaxed R1CS
Definition 12 from the paper. Consider a finite field F and a commitment scheme Com over F. Let the public parameters consist of size bounds m,n,l∈N where m>l, and commitment parameters ppW and ppE for vectors of size m and m−l−1 respectively. The committed relaxed R1CS structure consists of sparse matrices A,B,C∈Fm×m with at most n=Ω(m) non-zero entries in each matrix. A committed relaxed R1CS instance is a tuple (A,B,C,Wˉ,Eˉ,u,x), where Wˉ and Eˉ are commitments, u∈F, and x∈Fl are public inputs and outputs. An instance is satisfied by a witness (W,E,rW,rE)∈(Fm−l−1,Fm,F,F) if :
Eˉ=Com(ppE,E,rE)
Wˉ=Com(ppW,W,rW)
AZ∘BZ=u⋅CZ+E, where Z=(W,x,u).
A Folding Scheme for Committed Relaxed R1CS
Suppose prover holds (W1,E1,rW1,rE1) and (W2,E2,rW2,rE2). The verifier takes two committed instances (W1ˉ,E1ˉ,u1,x1) and (W2ˉ,E2ˉ,u2,x2). Let Z1=(W1,x1,u1) and Z2=(W2,x2,u2).
Prover sends Tˉ=Com(ppE,T,rT) where rT←F and
T=AZ1∘BZ2+AZ2∘BZ1−u1⋅CZ2−u2⋅CZ1
Verifier sends challenge r←F.
Prover and verifier computes folded instance (Wˉ,Eˉ,u,x) where
Proof of completeness. To prove completeness, we must show that for any valid witness pairs, the folding verifier will accept the folded instance. For the folded witness to satisfy the constraint, we must have:
Since W1 and W2 are satisfying witnesses, we have:
E1+r⋅T+r2⋅E2=E
which holds by construction.
Proof of soundness. To prove soundness, we must show that for any wrongly constructed folded instance will be rejected by the folding verifier. The intuition is we can extract a satisfying witness from the proof if the verification passes. TODO: elaborate how we can extract it.
Theorem 3 from the paper. The above construction is a public-coin folding scheme for committed relaxed R1CS with perfect completeness, knowledge soundness, and zero-knowledge.
From Folding to IVC
We constructed a way to fold two R1CS instances into one but now what? How do we incrementally prove and verify with this? To prove that zn=Fn(z0), for some count n, initial input z0, and output zn, we use an augmented constraint system which in addition to invoking F, performs additional bookkeeping to fold proofs of prior invocations of itself. A simple version of this augmented constraint system would take two committed relaxed R1CS instances Uacc,i and Ui as an input where Uacc,i represents the correct execution of previous invocations and Ui represents correct execution of i-th invocation. Mainly, it performs two tasks:
(State transition) Execute a step of the incremental computation: instance Uicontains zi which the augmented constraint system uses to output zi+1=F(zi).
(Folding) Fold Uacc,i and Ui into a single R1CS instance Uacc,i+1.
IVC over a single curve
First, let's understand how we can construct it over a single curve. What we need to constrain within this R1CS is:
Check previous state transitions are correct
IsStrict(Ui)=True (checks if error term is 0 and scalar is 1)
Check if Ui.x=H(i,z0,zi,Uacc,i). It might be confusing since we don't use hash here normally. To prove Fn(z0)=zn we would typically have x=(z0,zn,n). But for IVC, we need to keep track of the accumulated claim as well so we use hash here to keep the input size constant.
Apply the state transition and accumulate instances.
Check if zi+1=F(zi)
Accumulate into Uacc,i+1=FoldV(Ui,Uacc,i)
Generate the instance for next state transitions.
Set Ui+1.x=H(i+1,z0,zi+1,Uacc,i+1)
Generate Ui+1=(0ˉ,Wˉi+1,x,1) instance which resembles correct execution of this step. Notice that the error term should be 0 and scalar should be 1 since it is not a folded instance.
IVC Verification
Given a proof π=((Ui,Wi),(Uacc,i,Wacc,i)), the IVC verification will do the following:
Verify((i,z0,zi),π):
IsStrict(Ui)=True
((Ui,Wi),(Uacc,i,Wacc,i)) satisfy R1CS.
Ui.x=H(i,z0,zi,Uacc,i)
Conclusion
References
In proof-of-concept benchmarks, Nova was shown to be 4x faster at proving 10000 recursive SHA256 hashes than Halo2 (KZG) and memory usage is constant with respect to number of iterations in Nova while in Halo2 (KZG), the memory usage increases almost linearly with respect to number of iterations. This result is taken from: