Try   HackMD

Nova and its Implementation:A Deep Dive

This article will analysis Nova's code implementation, and explain how the code works based on the relevant papers.

I will first deduce the formula according to the papers, until it corresponds to the code, and then explain the code, which will be clearer and easier to understand.

As of August 30, 2023, I refer to the code corresponding to the latest commit, and considering that the code comments should be located near the code as much as possible, so I created the Nova-Analysis repo to save the code comments. When there are code comments, I will prompt in this article

Code structure

// private modules mod bellpepper; mod circuit; mod constants; mod nifs; mod r1cs; // public modules pub mod errors; pub mod gadgets; pub mod provider; pub mod spartan; pub mod traits;

According to its lib.rs, we know that Nova has these different mods. we explain these mods below.

r1cs mod

Here is a example on how r1cs works.

R1CS

a example

the relation:

private inputs

{w1,w2,w3,w4} and public output
x1
satisfy the following constraint relation:
(w1+w2)(w3w4)=x1

Let's try to represent this relation in terms of R1CS.

the circuit:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

the R1CS struct:

let

Z=[w1w2w3w4w5x11], According to the definition in Nova
Z=[Wx1]
, where
W
represents witness, including private input and intermediate values, that is
wi
here.
x
represents public inputs and outputs, that is
x1
here. If there are constants in the relation, the 1 can be used to encode them.

Write the

A B C matrix according to the circuit:

for multiplication gate #1, the left input is

(w1+w2)=[1100000][w1w2w3w4w5x11]

for multiplication gate #2, the left input is

w3=[0010000][w1w2w3w4w5x11]

So, we get the left input matrix:

A=[11000000010000]

Matrix

A consists of the left input of the all multiplication gates, and its number of rows is equal to the number of multiplication gates, and its number of columns is equal to the length of vector
Z
.

Using the same approach, we can get the right input matrix:

B=[00001000001000]

Matrix

B consists of the right input of the all multiplication gates. Its shape is the same with
A
.

C=[00000100000100]

Matrix

C consists of the output of the all multiplication gates. Its shape is the same with
A
.

Let's check:

(AZ)(B·Z)=([11000000010000][w1w2w3w4w5x11])([00001000001000][w1w2w3w4w5x11])=[w1+w2w3][w5w4]=[(w1+w2)w5w3w4]=[x1w5]=CZ

R1CS Definition

According to Definition 10 (R1CS) in Nova paper:

Consider a finite field

F. Let the public parameters consist of size bounds
m,n,lN
where
m>l
. The R1CS structure consists of sparse matrices
A,B,CFm×m
with at most
n=Ω(m)
non-zero entries in each matrix. An instance
xFl
consists of public inputs and outputs and is satisfied by a witness
WFml1
if
(AZ)(BZ)=CZ
, where
Z=(W,x,1)
.

R1CS's attempt:

There are different vector

Z1 and
Z2
for different instance witness pairs
(x1,W1)
,
(x2,W2)
and so on, which need to be verified repeatedly
(AZi)(B·Zi)=C·Zi
.

It can be seen that matrix

A,B,C representing constraints will not change. What Folding needs to solve is to reduce the number of verifications
(AZi)(B·Zi)=C·Zi
by merging different instances
Zi

So,

Z=[Wx1], choose a random value
rF
, let

xx1+rx2WW1+rW2

failed because

ZZ1+rZ2

Relaxed R1CS

Relaxed R1CS Definition

According to Definition 11 (Relaxed R1CS) in Nova paper:

Consider a finite field

F. Let the public parameters consist of size bounds
m,n,lN
where
m>l
. The relaxed R1CS structure consists of sparse matrices
A,B,CFm×m
with at most
n=Ω(m)
non-zero entries in each matrix. A relaxed R1CS instance consists of an error vector
EFm
, a scalar
uF
, and public inputs and outputs
xFl
. An instance
(E,u,x)
is satisfied by a witness
WFml1
if
(AZ)(BZ)=u(CZ)+E
, where
Z=(W,x,u)
.

Relaxed R1CS's attempt:

From the definition, we can get:

(AZi)(BZi)=ui(CZi)+EiZ=(W,x,u)

Choose a random value

rF, if we perform a linear combination of two instances in the following way:

xx1+rx2WW1+rW2uu1+ru2EE1+r(AZ1BZ2+AZ2BZ1u1CZ2u2CZ1)+r2E2

We can deduce the following result:

Z=(W,x,u)=[Wxu]=[W1+rW2x1+rx2u1+ru2]=Z1+rZ2.
AZBZ=A(Z1+rZ2)B(Z1+rZ2)=AZ1BZ1+r(AZ1BZ2+AZ2BZ1)+r2AZ2BZ2=u1CZ1+E1+r(AZ1BZ2+AZ2BZ1)+r2(u2CZ2+E2)=u1CZ1+ru2CZ1ru2CZ1+E1+r(AZ1BZ2+AZ2BZ1)+r2(u2CZ2+E2)+ru1CZ2ru1CZ2=(u1+ru2)CZ1+E1ru2CZ1+r(AZ1BZ2+AZ2BZ1)+(u1+ru2)rCZ2+r2E2ru1CZ2=(u1+ru2)C(Z1+rZ2)+r(AZ1BZ2+AZ2BZ1u2CZ1u1CZ2)+E1+r2E2=uCZ+E

Success! we only need to verify whether

Z satisfies the constraints
(AZ)(BZ)=u(CZ)+E
to check whether both
Z1
and
Z2
satisfy the constraints.

Committed Relaxed R1CS

Committed Relaxed R1CS Definition

According to Definition 12 (Committed Relaxed R1CS) in Nova paper:

Consider a finite field

F and a commitment scheme
Com
over
F
. Let the public parameters consist of size bounds
m,n,lN
where
m>l
, and commitment parameters
ppE
and
ppW
for vectors of size
m
and
ml1
respectively. The committed relaxed R1CS structure consists of sparse matrices
A,B,CFm×m
with at most
n=Ω(m)
non-zero entries in each matrix. A committed relaxed R1CS instance is a tuple
(E,u,W,x)
, where
E
and
W
are commitments,
uF
, and
xFl
are public inputs and outputs. An instance
(E,u,W,x)
is satisfied by a witness
(E,rE,W,rW)(Fm,F,Fml1,F)
if
E=Com(ppE,E,rE),W=Com(ppW,W,rW)
, and
(AZ)(BZ)=u(CZ)+E
, where
Z=(W,x,u)
.

For more introduction to the commitment, please refer to the wiki.

A Folding Scheme for Committed Relaxed R1CS

According to Construction 1 (A Folding Scheme for Committed Relaxed R1CS) in Nova paper:

Consider a finite field

F and a succinct, hiding, and homomorphic commitment scheme
Com
over
F
. We define the generator and the encoder as follows.
G(1λ)pp
: output size bounds
m,n,lN
, and commitment parameters
ppE
and
ppW
for vectors of size
m
and
ml1
respectively.
K(pp,(A,B,C))(pk,vk)
: output
pk(pp,(A,B,C))
and
vk
.

The verifier

V takes two committed relaxed R1CS instances
(E1,u1,W1,x1)
and
(E2,u2,W2,x2)
. The prover
P
, in addition to the two instances, takes witnesses to both instances,
(E1,rE1,W1,rW1)
and
(E2,rE2,W2,rW2)
. Let
Z1=(W1,x1,u1)
and
Z2=(W2,x2,u2)
. The prover and the verifier proceed as follows.

  1. P:
    Send
    T:=Com(ppE,T,rT)
    , wherer
    rTRF
    and with cross term
    T=AZ1BZ2+AZ2BZ1u1CZ2u2CZ1.
  2. V:
    Sample and send challenge
    rrF
    .
  3. V,P:
    Output the folded instance
    (E,u,W,x)
    where
    EE1+rT+r2E2uu1+ru2WW1+rW2xx1+rx2
  4. P:
    Output the folded witness
    (E,rE,W,rW)
    , where
    EE1+rT+r2E2rErE1+rrT+r2rE2WW1+rW2rWrW1+rrW2

code

Next, we analyze the code of r1cs mod according to the above theory, located in src/r1cs.rs.

R1CS struct

pub struct R1CS<G: Group> { _p: PhantomData<G>, }

This structure only retains a generic G, which needs to implement the methods in the Group trait, and has no valid data other than that.

There is a method for R1CS:

  • commitment_key, for a given circuit(certain
    A,B,C
    ), it will call Group's CE type's setup method to get a CommitmentKey and return it.

R1CSShape struct

pub struct R1CSShape<G: Group> { pub(crate) num_cons: usize, pub(crate) num_vars: usize, pub(crate) num_io: usize, pub(crate) A: Vec<(usize, usize, G::Scalar)>, pub(crate) B: Vec<(usize, usize, G::Scalar)>, pub(crate) C: Vec<(usize, usize, G::Scalar)>, }

R1CSShape means matrix

A,B,C, that is, circuit constraints.

There are some fields in this structure:

  • num_cons: Length of a column in the matrix, also the number of multiplication gates.
  • num_vars: Length of witness
    W
    , and according to the previous, it equals
    ml1
    .
  • num_io: Length of public input and output
    x
    , and according to the previous, it equals
    l
    .
  • A, B, C: Represent the position and value of the non-zero value in the sparse matrix.

We can get length of a column in the matrix by num_vars + num_io + 1, so the three matrices

A,B,C are completely determined by struct R1CSShape.

There are some methods for R1CSShape:

  • new(): Receive num_cons, num_vars, num_io, A, B, C as parameters, then do some checks,and return R1CSShape. The checks's comments.
  • check_regular_shape(): Checks regularity conditions on the R1CSShape, required in Spartan-class SNARKs. The checks's comments.
  • multiply_vec(): Calculate and return them:
    (AZ,BZ,CZ)
  • is_sat_relaxed(): Check
    AZBZ=uCZ+E
    ,
    W=Com(ppW,W,ck)
    and
    E=Com(ppE,E,ck)
    .
    W
    and
    E
    used the same commitment key.
  • is_sat(): pass CommitmentKey, R1CSInstance and R1CSWitness as parameters, check
    A[Wx1]B[Wx1]=C[Wx1]
    and
    W=Com(ppW,W,ck)
  • commit_T():
    T:=Com(ppW,T,ckT)
    , wherer
    rTRF
    and with cross term
    T=AZ1BZ2+AZ2BZ1u1CZ2u2CZ1
    . first calculate
    Z1
    and
    Z2
    by
    Zi=(Wi,ui,xi)
  • pad(): make witness.len() = M.colume.len() = 2^k, required in Spartan-class SNARKs.

R1CSWitness struct

pub struct R1CSWitness<G: Group> { W: Vec<G::Scalar>, }

R1CSWitness means

W, Witness of R1CS, which is a vector of length
ml1
, the
W
in
Z=[Wx1]

There are some methods for R1CSWitness:

  • new(): Pass in an R1CSShape example S and a vector W. Because creating a Witness needs to know which R1CS's witness it is, and it will check that the length of W is equal to S.num_vars.
  • commit(): Calculate
    W=Com(ppW,W,rW)
    . And the parameter ck, a CommitmentKey, means
    rW
    .

R1CSInstance struct

pub struct R1CSInstance<G: Group> { pub(crate) comm_W: Commitment<G>, pub(crate) X: Vec<G::Scalar>, }

R1CSInstance means

(W,x)

There are a method for R1CSInstance:

  • new():
    (W,x,1)
    and A.num_io should == x.len()

RelaxedR1CSWitness struct

pub struct RelaxedR1CSWitness<G: Group> { pub(crate) W: Vec<G::Scalar>, pub(crate) E: Vec<G::Scalar>, }

RelaxedR1CSWitness means

(W,E).

There are some methods for RelaxedR1CSWitness:

  • default(), use zero value to init the
    W,E
    .
  • from_r1cs_witness(), use zero value to init the
    E
    , and get the
    W
    from parameter.
  • commit(), return
    W/E=Com(ppW/E,W/E,ck)
    , with the same comitment key ck.
  • fold(), Calculate
    W=W1+rW2
    and
    E=E1+rT
    , used the same r. Why is not
    E=E1+rT+r2E2
    here? since
    E2
    of parameter's R1CSWitness is
    0
    ,
    r2E2
    can be omitted.
  • pad(): Pads the provided witness to the correct length.

RelaxedR1CSInstance struct

pub struct RelaxedR1CSInstance<G: Group> { pub(crate) comm_W: Commitment<G>, pub(crate) comm_E: Commitment<G>, pub(crate) X: Vec<G::Scalar>, pub(crate) u: G::Scalar, }

RelaxedR1CSInstance means

(W,E,x,u)

There are some methods for RelaxedR1CSInstance:

  • default(): Produces a default RelaxedR1CSInstance given R1CSGens and R1CSShape
  • from_r1cs_instance(): Initializes a new RelaxedR1CSInstance from an R1CSInstance, the u use one value
  • from_r1cs_instance_unchecked(): Initializes a new RelaxedR1CSInstance from an R1CSInstance, the u use one value
  • fold(): Folds an incoming R1CSInstance into the current one, calculate
    x=x1+rx2
    and
    W=W1+rW2
    and
    E=E1+rT
    and
    u=u1+r
    used the same r. Why is not
    E=E1+rT+r2E2
    here? Since
    E2
    of parameter's R1CSInstance is
    O
    ,
    r2E2
    can be omitted. and why is it
    u=u1+ru2
    ? Since the
    u2
    from R1CSInstance is 1 in default.

nifs mod

A Non-Interactive Folding Scheme

According to Construction 2 (A Non-Interactive Folding Scheme) in Nova paper:

We achieve non-interactivity in the random oracle model using the strong Fiat-Shamir transform. Let

ρ denote a random oracle sampled during parameter generation and provided to all parties. Let
(G,K,P,V)
represent our interactive folding scheme (Construction 1). We construct a non-interactive folding scheme
(G,K,P,V)
as follows:
G(1λ)
: output
ppG(1λ)
.
K(pp,(A,B,C))
:
vkρ(pp,s)
and
pk(pp,(A,B,C),vk)
; output
(vk,pk)
.
P(pk,(u1,w1),(u2,w2))
: runs
P((pk.pp,pk.(A,B,C))
to retrieve its first message
T
, and sends
T
to
V
; computes
rρ(vk,u1,u2,T)
, forwards this to
P
, and outputs the resulting output.
V(vk,u1,u2,T)
: runs
V
with
T
as the message from the prover and with randomness
rρ(vk,u1,u2,T)
, and outputs the resulting output.

Assumption 1 (RO instantiation):

Construction 2 is a non-interactive folding scheme that satisfies completeness, knowledge soundness, and zero-knowledge in the standard model when

ρ is instantiated with a cryptographic hash function.

code

Next, we analyze the code of nifs mod, located in src/nifs.rs.

NIFS struct

pub struct NIFS<G: Group> { pub(crate) comm_T: CompressedCommitment<G>, }

This structure contains

T, where
T=AZ1BZ2+AZ2BZ1u1CZ2u2CZ1,T=Com(ppE,T,rE)
and there are two methods impl for NISF:

  • prove(): Given ck, ro_consts, pp_digest, S
    (A,B,C)
    , U1
    (W1,E1,x1,u1)
    , W1
    (W1,E1)
    , U2
    (W2,x2)
    , W2(
    W2
    ), return NIFS ,
    (W,E)
    and
    (W,E,x,u)
    , and the random r = ρ(ro_consts, pp_digest, U1, U2, comm_T)
  • verify(): Given ro_consts, pp_digest, U1
    (W1,E1,x1,u1)
    , U2
    (W2,x2)
    , get
    T
    from self.comm_T, calculate random r = ρ(ro_consts, pp_digest, U1, U2, comm_T), return the new U = U1.fold(U2).

constants mod

pub(crate) const NUM_CHALLENGE_BITS: usize = 128; pub(crate) const NUM_HASH_BITS: usize = 250; pub(crate) const BN_LIMB_WIDTH: usize = 64; pub(crate) const BN_N_LIMBS: usize = 4; pub(crate) const NUM_FE_WITHOUT_IO_FOR_CRHF: usize = 17; pub(crate) const NUM_FE_FOR_RO: usize = 24;
  • NUM_CHALLENGE_BITS: Valid output bits when a random oracle is used to generate challenge value r.
  • NUM_HASH_BITS: Valid output bits when a random oracle is used to generate hash
  • BN_LIMB_WIDTH and BN_N_LIMBS: Use 4 * 64 bits to represent 256 bits.
  • NUM_FE_WITHOUT_IO_FOR_CRHF
  • NUM_FE_FOR_RO

circuit mod

According to Construction 3 (IVC) in Nova paper:

Let

NIFS=(G,K,P,V) be the non-interactive folding scheme for committed relaxed R1CS (Construction 2). Consider a polynomialtime function F that takes non-deterministic input, and a cryptographic hash function
hash
. We define our augmented function
F
as follows (all arguments to
F
are taken as non-deterministic advice):

F(vk,Ui,ui,(i,z0,zi),wi,T)x:

If

i is
0
, output
hash(vk,1,z0,F(z0,wi),u)
;

otherwise,

(1) check that
ui.x=hash(vk,i,z0,zi,Ui)
, where
ui.x
is the public IO of
ui
,
(2)
check that
(ui.E,ui.u)=(u.E,1)
,
(3)
compute
Ui+1NIFS.V(vk,U,u,T)
, and
(4)
output
hash(vk,i+1,z0,F(zi,wi),Ui+1)
.

Because
F
can be computed in polynomial time, it can be represented as a committed relaxed R1CS structure
sF
. Let
(ui+1,wi+1)trace(F,(vk,Ui,ui,(i,z0,zi),wi,T))

denote the satisfying committed relaxed R1CS instance-witness pair
(ui+1,wi+1)
for the execution of
F
on non-deterministic advice
(vk,Ui,ui,(i,z0,zi),wi,T)
.
We define the IVC scheme
(G,K,P,V)
as follows.

G(1λ)pp: Output
NIFS.G(1λ)
.

K(pp,F)(pk,vk):

Compute

(pkfs,vkfs)NIFS.K(pp,sF) and output
(pk,vk)((F,pkfs),(F,vkfs))
.

P(pk,(i,z0,zi),wi,Πi)Πi+1:

Parse

Πi as
((Ui,Wi),(ui,wi))
and then
(1)
if
i
is
0
, compute
(Ui+1,Wi+1,T)(u,w,u.E)
;
otherwise, compute
(Ui+1,Wi+1,T)NIFS.P(pk,(Ui,Wi),(ui,wi))
,
(2)
compute
(ui+1,wi+1)trace(F,(vk,Ui,ui,(i,z0,zi),wi,T))
, and
(3)
output
Πi+1((Ui+1,Wi+1),(ui+1,wi+1))
.

V(vk,(i,z0,zi),Πi){0,1}:

If

i is
0
, check that
zi=z0
;
otherwise,
(1)
parse
Πi
as
((Ui,Wi),(ui,wi))
,
(2)
check that
ui.x=hash(vk,i,z0,zi,Ui)
,
(3)
check that
(ui.E,u.u)=(u.E,1)
, and
(4)
check that
Wi
and
wi
are satisfying witnesses to
Ui
and
ui
respectively.

code

pub struct NovaAugmentedCircuitParams { limb_width: usize, // word size n_limbs: usize, // how many words is_primary_circuit: bool, // A boolean indicating if this is the primary circuit }
pub struct NovaAugmentedCircuitInputs<G: Group> { params: G::Scalar, // Hash(Shape of u2, Gens for u2). Needed for computing the challenge. i: G::Base, z0: Vec<G::Base>, zi: Option<Vec<G::Base>>, U: Option<RelaxedR1CSInstance<G>>, u: Option<R1CSInstance<G>>, T: Option<Commitment<G>>, }

params:

lib.rs

A zkSNARK of a Valid IVC Proof

Construction 4 (A zkSNARK of a Valid IVC Proof). Let

IVC denote the IVC scheme in Construction 3, let
NIFS
denote the non-interactive folding scheme in Construction 2, and let
hash
denote a randomized cryptographic hash function. Assume a zero-knowledge succinct non-interactive argument of knowledge (Definition 2),
zkSNARK
, for committed relaxed R1CS. That is, given public parameters
pp
, structure
s
, and instance
u
,
zkSNARK.P
can convince
zkSNARK.V
in zero-knowledge and with a succinct proof (e.g.,
Oλ(logN)
-sized proof) that it knows a corresponding witness
w
such that
(pp,s,u,w)
is a satisfying committed relaxed R1CS tuple.

Consider a polynomial-time computable function
F
. Suppose
ppIVC.G(1λ)
and
(pk,vk)IVC.K(pp,F)
. Suppose the prover
P
and verifier
V
are provided an instance
(i,z0,zi)
. We construct a zkSNARK that allows the prover to show that it knows an IVC proof
Πi
such that
IVC.V(vk,i,z0,zi,Πi)=1
.

In a nutshell, we leverage the fact that
Π
is two committed relaxed R1CS instance-witness pairs. So,
P
first folds instance-witness pairs
(u,w)
and
(U,W)
to produce a folded instance-witness pair
(U,W)
, using
NIFS.P
. Next,
P
runs
zkSNARK.P
to prove that it knows a valid witness for
U
. In more detail, for polynomial-time computable function
F
and corresponding function
F
as defined in Construction 3 (and instantiated with
hash
), we define
(G,K,P,V)
as follows.

G(1λ)pp:
(1)
Compute
ppNIFSNIFS.G(1λ)

(2)
Compute
ppzkSNARKzkSNARK.G(1λ)

(3)
Output (
ppNIFS,ppzkSNARK)

K(pp,F)(pk,vk):
(1)
Compute
(pkNIFS,vkNIFS)NIFS.K(pp.ppNIFS,sF)
.
(2)
Compute
(pkzkSNARK,vkzkSNARK)zkSNARK.K(pp.ppzkSNARK,sF)
.
(3)
Output
((pkNIFS,pkzkSNARK),(vkNIFS,vkzkSNARK))
.

P(pk,(i,z0,zi),Π)π:
If
i
is
0
, output
;
otherwise,
(1)
parse
Π
as
((U,W),(u,w))

(2)
compute
(U,W,T)NIFS.P(pkNIFS,(U,W),(u,w))

(3)
compute
πUzkSNARK.P(pkzkSNARK,U,W)

(4)
output
(U,u,T,πU)
.

V(vk,(i,z0,zi),π){0,1}:
If
i
is
0
, check that
z0=zi
;
otherwise,
(1)
parse
π
as
(U,u,T,πU)
,
(2)
check that
u.x=hash(vkNIFS,i,z0,zi,U)
,
(3)
check that
(u.E,u.u)=(u.E,1)
,
(4)
compute
UNIFS.V(vkNIFS,U,u,T)
, and
(5)
check that
zkSNARK.V(vkzkSNARK,U,πU)=1
.

Polynomial Extension(MLE) see Notes for PAZK(MLE)

The Sum-Check Protocol see Notes for PAZK(Sum-Check)

Idealized Relaxed R1CS

Definition 14 (Idealized Relaxed R1CS). Consider a finite field

F. Let the public parameters consist of size bounds
m,n,lN
where
m>l.
The idealized relaxed R1CS structure consists of sparse matrices
A,B,CFm×m
with at most
n=Ω(m)
non-zero entries in each matrix. A idealized relaxed R1CS instance consists of an error vector
EFm
, a scalar
uF
, witness vector
WFm
, and public inputs and outputs
xFl
. An instance
(E,u,W,x)
is satisfying if
(AZ)(BZ)=u(CZ)+E
, where
Z=(W,x,u)
.

Polynomial IOP for Idealized Relaxed R1CS

Construction 5 (Polynomial IOP for Idealized Relaxed R1CS). Consider an idealized relaxed R1CS statement

φ consisting of public parameters
(m,n,l)
, structure
(A,B,C)
, and instance
(E,u,W,x)
, Without loss of generality, we assume that
m
and
n
are powers of
2
and that
m=2(l+1)
.
Let
s=logm
. We interpret the matrices
A,B,C
as functions with signature
{0,1}logm×{0,1}logmF
in a natural manner. In particular, an input in
{0,1}logm×{0,1}logm
is interpreted as the binary representation of an index
(i,j)[m]×[m]
, where
[m]:={1,,m}
and the function outputs
(i,j)
th entry of the matrix. As such, let
A~,B~
, and
C~
denote multilinear extensions of
A,B,
and
C
interpreted as functions, so they are
2logm
-variate sparse multilinear polynomials of size
n
. Similarly, we interpret
E
and
W
as functions with respective signatures
{0,1}logmF
and
{0,1}logm1F
. Furthermore, let
E~
and
W~
denote the multilinear extensions of
E
and
W
interpreted as functions, so they are multilinear polynomials in
logm
and
logm1
variables respectively.
As noted earlier, the verifier has an oracle access to the following polynomials:
A~,B~,C~,E~
, and
W~
. Additionally, the verifier reads
u
and
x
in entirety.
Let
Z=(W,x,u)
. Similar to how we interpret matrices as functions, we interpret
Z
and
(x,u)
as functions with the following respective signatures:
{0,1}sF
and
{0,1}s1F
. Observe that the
MLE
Z~
of
Z
satisfies
Z~(X1,,Xs)=(1X1)W~(X2,,Xs)+X1(x,u)~(X2,,Xs)(1)

Similar to [40, Theorem 4.1], checking if
φ
is satisfiable is equivalent, except for a soundness error of
logm/|F|
over the choice of
τFs
, to checking if the following identity holds:
0=?x{0,1}seq~(τ,x)F(x),(2)
where
F(x)=(y{0,1}sA~(x,y)Z~(y))(y{0,1}sB~(x,y)Z~(y))(uy{0,1}sC~(x,y)Z~(y)+E~(x)),
and
eq~
is the multilinear extension of
eq:{0,1}s×{0,1}sF
where
eq(x,e)=1
if
x=e
and
0
otherwise.
That is, if
φ
is satisfiable, then Equation (2) holds with probability
1
over the choice of
τ
, and if not, then Equation (2) holds with probability at most
O(logm/|F|)
over the random choice of
τ
.
To compute the right-hand side in Equation (2), the prover and the verifier apply the sum-check protocol to the following polynomial:
g(x):=eq~(τ,x)F(x)
From the verifier’s perspective, this reduces the task of computing the right-hand side of Equation (2) to the task of evaluating
g
at a random input
rxFs
. Note that the verifier can locally evaluate
eq~(τ,rx)
in
O(logm)
field operations via
eq~(τ,rx)=i=1s(τirx,i+(1τi)(1rx,i)).
With
eq~(τ,rx)
in hand,
g(rx)
can be computed in
O(1)
time given the four quantities:
y{0,1}sA~(rx,y)Z~(y), y{0,1}sB~(rx,y)Z~(y), y{0,1}sC~(rx,y)Z~(y)
, and
E~(rx)
.
The last quantity can be computed with a single query to polynomial
E~
. Furthermore, the first three quantities can be computed by applying the sum-check protocol three more times in parallel, once to each of the following three polynomials (using the same random vector of field elements,
ryFs
, in each of the three invocations):
A~(rx,y)Z~(y),B~(rx,y)Z~(y)
, and
C~(rx,y)Z~(y)
.
To perform the verifier’s final check in each of these three invocations of the sum-check protocol, it suffices for the verifier to evaluate each of the above three polynomials at the random vector
ry
, which means it suffices for the verifier to evaluate
A~(rx,ry),B~(rx,ry),C~(rx,ry)
, and
Z~(ry)
. The first three evaluations can be obtained via the verifier’s assumed query access to
(A~,B~,C~)
.
Z~(ry)
can be computed (via Equation (1)) from a query to
W~
and from computing
(x,u)~
.
In summary, we have the following polynomial IOP.

  1. VP:τRFs
  2. VP
    : run the sum-check protocol to reduce the check in Equation (2) to checking if the following hold, where
    rx,ry
    are vectors in
    Fs
    chosen at random by the verifier over the course of the sum-check protocol:
    A~(rx,ry)=?vA,B~(rx,ry)=?vB
    , and
    C~(rx,ry)=?vC
    ;
    E~(rx)=?vE;
    and
    Z~(ry)=?vZ
    .
  3. V
    :
    – check if
    A~(rx,ry)=?vA,B~(rx,ry)=?vB
    , and
    C~(rx,ry)=?vC
    , with a query to
    A~,B~,C~
    at
    (rx,ry)
    ;
    – check if
    E~(rx)=?vE
    with an oracle query to
    E~
    ; and
    – check if
    Z~(ry)=?vZ
    by checking if:
    vZ=(1ry[1])vW+ry[1](x,u)~(ry[2..])
    , where
    ry[2..]
    refers to a slice of
    ry
    without the first element of
    ry
    , and
    vWW~(ry[2..])
    via an oracle query (see Equation (1)).)

bellpepper mod

dependencies

bellpepper

see

https://hackmd.io/iR4lHIphQpeyZo1W3-VxQA?view