Ragu & Tachyon
Home
  • Scaling Zcash
  • An Introduction to Proof-Carrying Data
  • Statements and Challenges
  • Arithmetization
  • QAP and Polynomial Encoding
  • Polynomial Commitments
  • The Inner Product Argument
  • Batched Openings
  • The Complete Proof
  • Recursive Proofs
  • Accumulation
  • Split Accumulation
  • Curve Cycles
  • Revdot Folding
  • Wiring and the Registry
  • Endoscalars
  • Staging
  • Recursion in Ragu
  • Notes, Nullifiers, and Tachygrams
  • Pool State and Anchors
  • Oblivious Sync
  • The Proof Tree
  • Aggregation and Bundles
Final Recap
  • Notation
  • Glossary
  • Curves
Home
  • Scaling Zcash
  • An Introduction to Proof-Carrying Data
  • Statements and Challenges
  • Arithmetization
  • QAP and Polynomial Encoding
  • Polynomial Commitments
  • The Inner Product Argument
  • Batched Openings
  • The Complete Proof
  • Recursive Proofs
  • Accumulation
  • Split Accumulation
  • Curve Cycles
  • Revdot Folding
  • Wiring and the Registry
  • Endoscalars
  • Staging
  • Recursion in Ragu
  • Notes, Nullifiers, and Tachygrams
  • Pool State and Anchors
  • Oblivious Sync
  • The Proof Tree
  • Aggregation and Bundles
Final Recap
  • Notation
  • Glossary
  • Curves
  • Scaling Zcash
  • An Introduction to Proof-Carrying Data
  • Statements and Challenges
  • Arithmetization
  • QAP and Polynomial Encoding
  • Polynomial Commitments
  • The Inner Product Argument
  • Batched Openings
  • The Complete Proof
  • Recursive Proofs
  • Accumulation
  • Split Accumulation
  • Curve Cycles
  • Revdot Folding
  • Wiring and the Registry
  • Endoscalars
  • Staging
  • Recursion in Ragu
  • Notes, Nullifiers, and Tachygrams
  • Pool State and Anchors
  • Oblivious Sync
  • The Proof Tree
  • Aggregation and Bundles
  • Final Recap
  • Appendix

    • Notation
    • Glossary
    • Curves

QAP and Polynomial Encoding

The arithmetization chapter ended with two ways to write the same statement, a list of R1CS rows and Ragu's single consolidated equation. Neither form helps the verifier yet, because checking either one means looking at the whole witness. This chapter turns those equations into statements about polynomials, which a verifier can test at a single random point.

There are two routes, and we take them in order. The first is the quadratic arithmetic program (QAP), the standard reduction behind systems such as Groth16, which ends in a divisibility test with a quotient polynomial. The second is the route Ragu takes, which reads the claim from one coefficient of a product and needs no division. We run both on the statement x3+x+5=35 over F43​, the scalar field of the toy curve. No curve points appear in this chapter, because commitments come in the next one.

1. What polynomials provide

Suppose two polynomials of degree at most d differ. Their difference is a nonzero polynomial of degree at most d, so it has at most d roots, and the two polynomials agree on at most d points. This is the one-variable case of the Schwartz–Zippel lemma from Statements and Challenges. So a check at one random point says something about every coefficient at once, and a verifier can learn whether two large polynomials are equal without reading either of them.

To use this fact, we have to express "all the constraints hold" as an equality of polynomials. Each route does this differently. A QAP assigns each constraint row to its own point of the field, so a true statement makes a polynomial vanish at all of those points. Ragu has already merged its constraints into one scalar equation, so it only has to place that scalar where a verifier can reach it.

Three symbols need care in this chapter. In the arithmetization chapter, x was the secret input, and we keep that meaning when we write "the witness with x=3". Once we reach Ragu's split in Section 12, x also names a random evaluation point, as it does in the commitments chapter, and the context will always say which is meant. The random point of the QAP test is called τ. Finally, w is the R1CS vector, and we write its entries in bold as wℓ​, so that they stay separate from the wires w1​ and w2​ of the flattened computation.

2. The R1CS starting point

The R1CS form of our statement uses a vector w holding the constant 1, the public output, and the three private values. Three public matrices with m rows define the constraints, and row i requires

(ℓ∑​Aiℓ​wℓ​)(ℓ∑​Biℓ​wℓ​)=ℓ∑​Ciℓ​wℓ​.

For our statement there are three rows:

A=​005​000​101​010​001​​,B=​001​000​110​000​000​​,C=​000​001​000​100​010​​,

with w=(1,35,3,9,27). The three rows give Aw=(3,9,35), Bw=(3,3,1) and Cw=(9,27,35), and multiplying the first two entrywise gives the third.

These m equations are what we have to compress. In a real circuit m can be many thousands, so the verifier should not have to examine them one by one.

3. Interpolating the rows

We want one polynomial that carries all the rows. A polynomial can store one value at each point of the field, so we can give each row its own point. Fix a set of m distinct points D={ρ0​,…,ρm−1​}, called the domain, and let row i live at ρi​. Our example uses D={1,2,3}.

The most direct idea is to interpolate the vector Aw itself, finding a polynomial whose value at ρi​ is entry i of Aw. That polynomial would hold the right values, but it would mix the circuit with the witness in a way the verifier cannot pull apart, and nothing would show that it came from the matrix A. We keep the two separate by interpolating the matrix alone. Each column of A belongs to one wire, so we build one polynomial per column:

Aℓ​(ρi​)=Aiℓ​for every row i.

The polynomials Bℓ​ and Cℓ​ come from the columns of B and C in the same way. Since m points determine a unique polynomial of degree at most m−1, these polynomials exist and depend only on the circuit.

To construct them, we first build a polynomial for each domain point that equals 1 at that point and 0 at the others. A product of factors (X−ρj​) over all j=i is zero at every other point, and dividing by its value at ρi​ scales it to 1 there:

Li​(X)=j=i∏​ρi​−ρj​X−ρj​​.

These are the Lagrange basis polynomials for D. For our domain they are

L0​(X)L1​(X)L2​(X)​=(1−2)(1−3)(X−2)(X−3)​=2X2−5X+6​=3+19X+22X2,=(2−1)(2−3)(X−1)(X−3)​=−1X2−4X+3​=40+4X+42X2,=(3−1)(3−2)(X−1)(X−2)​=2X2−3X+2​=1+20X+22X2.​

Dividing by 2 modulo 43 means multiplying by 22, and dividing by −1 means negating. As a spot check, L0​(1)=1, L0​(2)=0 and L0​(3)=0.

Any column can now be written as a sum of basis polynomials, each weighted by that column's entry for the row:

Aℓ​(X)=i=0∑m−1​Aiℓ​Li​(X).

At X=ρi​ only the term with Li​ survives, which gives Aiℓ​ as required. The nonzero columns of our three matrices produce the following polynomials, and every column not listed is all zeros and gives the zero polynomial.

PolynomialColumn entriesIn the basisCoefficients
A0​(0,0,5)5L2​5+14X+24X2
A2​(1,0,1)L0​+L2​4+39X+X2
A3​(0,1,0)L1​40+4X+42X2
A4​(0,0,1)L2​1+20X+22X2
B0​(0,0,1)L2​1+20X+22X2
B2​(1,1,0)L0​+L1​23X+21X2
C1​(0,0,1)L2​1+20X+22X2
C3​(1,0,0)L0​3+19X+22X2
C4​(0,1,0)L1​40+4X+42X2

4. Adding the witness

The column polynomials describe the circuit, so we now bring in the witness. Multiply each column polynomial by its wire value and add:

A(X)=ℓ∑​wℓ​Aℓ​(X),B(X)=ℓ∑​wℓ​Bℓ​(X),C(X)=ℓ∑​wℓ​Cℓ​(X).

To see what these sums hold, evaluate A(X) at a domain point and use the defining property of the column polynomials:

A(ρi​)=ℓ∑​wℓ​Aℓ​(ρi​)=ℓ∑​wℓ​Aiℓ​=(Aw)i​.

So A(X) takes the value of row i of Aw at the point ρi​, and the same holds for B and C. Row i of the R1CS is therefore the equation A(ρi​)B(ρi​)=C(ρi​), and the m rows hold exactly when this equation holds at all m domain points.

For w=(1,35,3,9,27), the sums come out as

A(X)B(X)C(X)​=17+19X+10X2,=1+3X+42X2,=24+33X+38X2.​

ρi​A(ρi​)B(ρi​)C(ρi​)A(ρi​)B(ρi​)−C(ρi​)
13390
293270
3351350

The columns for A, B and C reproduce Aw, Bw and Cw from Section 2.

5. The vanishing polynomial and the quotient

Define P(X)=A(X)B(X)−C(X). The rows hold exactly when P is zero at every point of D. That is still m separate facts, and a check at one random point would not capture them, because a random point is almost never in D. We need an equivalent statement that holds as an identity across the whole field.

The factor theorem provides it. If a polynomial is zero at ρ, then X−ρ divides it. Since the points of D are distinct, P is zero on all of D exactly when P is divisible by the product of those factors. This product is the vanishing polynomial of the domain:

V(X)=i=0∏m−1​(X−ρi​).

The rows therefore hold exactly when there is a polynomial h(X), called the quotient, with

A(X)B(X)−C(X)=h(X)V(X).

The factors A and B each have degree at most m−1, so P has degree at most 2(m−1). Since V has degree m, the quotient has degree at most m−2. The column polynomials and V together make up the QAP. A witness satisfies the QAP when the quotient exists, and this equation is the polynomial form of the R1CS.

With m=3 rows, the degree of P is at most 4, and multiplying and subtracting gives P(X)=36+37X+12X2+11X3+33X4. Substituting gives P(1)=0, P(2)=0 and P(3)=0, even though the coefficients of P are not zero.

The next step divides P by V.

Expanding the product gives V(X)=(X−1)(X−2)(X−3)=X3−6X2+11X−6, which is 37+11X+37X2+X3 modulo 43. Long division removes one leading term at a time:

Current polynomialNext term of hSubtractResult
36+37X+12X2+11X3+33X433X17X+19X2+17X3+33X436+20X+36X2+37X3
36+20X+36X2+37X33736+20X+36X2+37X30

The last column ends at 0, so the division is exact and h(X)=37+33X, which has degree m−2=1 as predicted.

6. Testing the identity at one point

The equation P(X)=h(X)V(X) is now an equality of polynomials, so Section 1 applies. If the two sides are different polynomials, their difference has degree at most 2(m−1), and they agree on at most that many points. A verifier who picks a random τ after the prover has fixed A, B, C and h can compare the two sides at τ alone. The chance of missing a difference is at most 2(m−1)/∣Fq​∣.

Take τ=11. The prover has already fixed its polynomials, so the two sides are

ValueAt τ
A(τ)17
B(τ)42
C(τ)40
A(τ)B(τ)−C(τ)29
h(τ)13
V(τ)32
h(τ)V(τ)29

The fourth and last rows agree. Checking every one of the 43 values of τ confirms that the honest polynomials pass at all of them, as an identity should.

This test replaces all m rows with one comparison of field elements, because the domain and the vanishing polynomial packed the rows into a single identity.

7. Why a cheater's quotient does not exist

Take a statement the witness does not satisfy, and follow what happens to the quotient.

Keep the public value 35 and try x=4, which gives w=(1,35,4,16,21). Now Aw=(4,16,30), Bw=(4,4,1) and Cw=(16,21,35). The first two rows hold, and the last gives 30⋅1=30 against 35. The polynomial built from this witness is P′(X)=17+12X+3X2+34X3+20X4, with P′(1)=0 and P′(2)=0 but P′(3)=38. Dividing by V(X) leaves the quotient 25+20X and the remainder 38+29X+19X2. The remainder is not zero, so no polynomial h satisfies P′(X)=h(X)V(X).

A failing row at ρi​ means P′(ρi​)=0, while any multiple of V is zero there. This mismatch is why no h can work, whatever the prover tries. The prover can still present some polynomial as its quotient and hope that the test at τ misses the difference. On the toy field we can count every such attempt. We leave the domain points out of the count, because V is zero there and a test at such a point says nothing about the quotient. A real field has so many elements that a random τ lands in D with negligible probability.

Values of τ where the guess passesNumber of candidate quotients
0909
1160
2780

The table covers all 432=1849 candidate polynomials h of degree at most 1, each tried at the 40 values of τ outside the domain. No candidate passes at more than 2 of them, which is 2/40. Averaged over all candidates, a random guess passes at a rate of 1 in 43.

The count stays low because P′−hV is a nonzero polynomial of low degree whatever h the prover chooses. This argument only works if the prover commits to its polynomials before learning τ, and the next example shows what happens otherwise.

Suppose the prover with x=4 learns τ=11 before answering. It computes P′(11)=4 and V(11)=32, divides to get 27, and presents the constant polynomial h(X)=27. The check at τ=11 passes because 27⋅32=4 modulo 43. At τ=12 the same h gives 27 against P′(12)=33, so this forgery only works at the point the prover knew in advance.

The test also assumes that A, B and C really are combinations of the column polynomials with one shared witness. If the prover could present any three polynomials, it could set all of them to zero, and the identity would hold with h=0 for any statement. A complete QAP-based system therefore has to enforce three things: the prover fixes its polynomials before τ is known, each polynomial has the required form, and all three use the same w.

8. Enforcing the test in Groth16

Groth16 enforces these requirements by keeping τ secret from everyone. A setup ceremony publishes elliptic curve points that encode powers of τ, in the style of the KZG setup from Section 10 of the polynomial commitments chapter, together with points derived from the column polynomials and further secret values. The prover can only form linear combinations of these points, so it can evaluate its polynomials at τ inside the group without knowing τ. The further secret values are what force a single shared witness into all three polynomials.

The verifier checks the identity using pairings, the bilinear maps mentioned in that same section. The resulting proof is three group elements, and verification uses three pairings. We do not need the details of the construction here, only the list of things it relies on, which the next section examines.

9. The cost of QAP

Each ingredient of the QAP route has a cost, and several of those costs conflict with what Ragu needs.

The prover works over a special domain. Interpolating and multiplying term by term, as we did above, takes time quadratic in m. Real provers use the fast Fourier transform (FFT), which requires the domain to be a set of roots of unity. This choice also gives V a compact form.

In F43​ the value ω=6 satisfies 63=216=1 modulo 43, so its powers form the domain {1,6,36}, and the vanishing polynomial collapses to V(X)=X3−1. Repeating the construction on this domain with the same witness gives different polynomials, for example A(X)=30+7X+9X2, and the exact quotient h(X)=11+42X. The same field has no domain of size 4, because 4 does not divide 43−1=42. Real proof systems pick fields whose multiplicative group has a large power of two in its order for this reason.

The product is also larger than the circuit, because A(X)B(X) has about twice the degree of its factors. Holding P by its values therefore takes a domain about twice the size of D.

For a circuit of m=216=65,536 rows, P(X) has degree up to 2(m−1)=131,070. Representing it requires a domain with more than 131,070 points, and the next power of two is 217=131,072.

Groth16 provers avoid part of this cost, because P is known to vanish on D and the quotient h has degree below m. Evaluating on one shifted copy of D, called a coset, is enough to recover h, so these provers run their FFTs at size m rather than 2m. They still have to run several of them, over a field with the required roots of unity.

The setup requires trust. Anyone who learns τ or the other secret values can forge proofs, as Section 7 showed on a small scale. Groth16 also ties its setup to one circuit, so a new circuit needs a new setup. Ragu's overview sets out to avoid a trusted setup, and its non-uniform model lets a prover switch among many circuits without verification keys.

The verifier needs pairings. The pairing check is what makes the secret τ usable. Ragu works over the Pasta curves, which are not pairing-friendly, so this check is not available to it.

The circuit description has to exist as polynomials. Before any proof, someone has to compute the column polynomials Aℓ​, Bℓ​ and Cℓ​. The same overview lists this among the things its construction avoids, since Ragu never builds sparse R1CS matrices or a QAP reduction, while its cost model stays close to that of QAP-based SNARKs.

Ragu therefore has to reach a polynomial test some other way, using only the commitments from the next chapter.

10. The consolidated equation as a coefficient

Ragu starts from a different place. A QAP keeps the rows separate until the very end and uses the domain to pack them together. Ragu has already combined its gates and constraints using the challenges z and y, which left one scalar equation in Section 12 of the arithmetization chapter:

⟨⟨r,r∘z4n+t+s⟩⟩=⟨k,y4n⟩.

No domain and no vanishing polynomial are needed, since there are no separate rows left to pack. The remaining job is to let the verifier check this one equation without seeing r. Section 7 of that chapter already supplied the link to polynomials, because the revdot product of two vectors of length 4n is the coefficient of X4n−1 in the product of the polynomials with those coefficient vectors. So we read every vector in the equation as a list of coefficients.

The witness vector becomes the trace polynomial. With d=0 and the layout from the arithmetization chapter, it is

r(X)=i=0∑n−1​(ci​Xi+ai​X2n−1−i+bi​X2n+i).

The dilated vector r∘z4n multiplies coefficient k by zk, which is the effect of substituting zX for X, because rk​(zX)k=(rk​zk)Xk. So the dilated vector is the coefficient vector of r(zX), and no new data is involved.

The public vectors s and t depend on the challenges, and the circuit is fixed before the challenges exist. We therefore describe them with polynomials in two variables, and substitute a challenge for the second variable once it is known. Placing each coefficient at the partner position worked out in that chapter gives the wiring polynomial and the gate polynomial:

s(X,Y)=j=0∑4n−1​Yji=0∑n−1​(uj,i​X2n+i+vj,i​X2n−1−i+wj,i​X4n−1−i),

t(X,Z)=−i=0∑n−1​(Z2n−1−i+Z2n+i)X4n−1−i.

The vector s is the coefficient vector of s(X,y), and t is the coefficient vector of t(X,z). On the right side of the equation, the public input polynomial k(Y)=∑j​kj​Yj gives ⟨k,y4n⟩=k(y).

The Ragu Book's NARK chapter uses the other layout

The NARK chapter writes r(X)=∑i​(ci​Xi+bi​X2n−1−i+ai​X2n+i) and puts uj,i​ at X2n−1−i and vj,i​ at X2n+i in s(X,Y). The wiring code at commit 3219e08 puts the coefficients of the a wires at X2n+i in s(X,Y), as above. The two forms differ only by swapping the names a and b. This site follows the code, as the arithmetization chapter did.

Now collect the second factor into one polynomial,

f(X)=r(zX)+s(X,y)+t(X,z).

The name f is local to this chapter, and f(X) is the right vector of the consolidated equation in polynomial form. By the coefficient rule, the equation now reads

the coefficient of X4n−1 in r(X)f(X) equals k(y).

Here are the polynomials for our witness at z=5 and y=7, the challenges from the arithmetization chapter:

PolynomialCoefficients of X0,…,X7
r(X)(9,27,9,3,3,3,0,0)
r(5X)(9,6,10,31,26,1,0,0)
s(X,7)(0,0,6,42,37,7,42,36)
t(X,5)(0,0,0,0,0,0,32,24)
f(X)(9,6,16,30,20,8,31,17)

The vector for f(X) is the combined right vector from Section 12 of the arithmetization chapter, now read as coefficients.

The coefficient of X7 in the product collects every pair of exponents that adds to 7:

iCoefficient of Xi in r7−iCoefficient of X7−i in fProduct
0971724
12763120
295829
3342017
433304
532165
60160
70090

The last column sums to 13 modulo 43. On the other side, k(Y)=30Y3 because only k3​ is nonzero, so k(7)=30⋅73=13 modulo 43.

11. Why the coefficient is out of reach

We can expand the whole product to see where this coefficient sits.

The full product has 15 coefficients:

Power of X01234567891011121314
Coefficient383909182914139293915800

The entry for X7 is 13, the value the consolidated equation requires. Every other entry is a by-product of the multiplication that the check does not constrain. The two highest coefficients are zero in this example because d=0 leaves r with degree 5.

In general, the product has degree up to 8n−2. Two obstacles keep the verifier from checking the coefficient directly. The first is that the commitments in the next chapter let a verifier learn evaluations of a committed polynomial, and one coefficient in the middle of a polynomial is not an evaluation at any point. The second is size. A commitment with 4n generators holds at most 4n coefficients, as Section 7 of the commitments chapter explained, and the product needs almost twice as many. Doubling the number of generators would fix the second obstacle, but it would make every commitment in the system about twice as expensive, and all of that would serve to expose one coefficient.

12. Splitting the product

A single reshaping of the product removes both obstacles. For the size problem, cut the product into a lower half with the 4n coefficients of X0 through X4n−1, and an upper half with the rest:

r(X)f(X)=clo​(X)+X4nchi​(X).

Both pieces have degree below 4n, so each fits within a single commitment. The coefficient we want is the top coefficient of clo​, which is still not an evaluation.

The one coefficient of a polynomial that evaluation can reach is the constant term, because substituting X=0 removes all the others. So we reverse the coefficients of the lower half, which moves the top coefficient to the bottom:

c1​(X)=X4n−1clo​(X−1),c2​(X)=chi​(X).

To see that this is a reversal, write clo​(X)=∑k=04n−1​λk​Xk and multiply through:

c1​(X)=X4n−1k=0∑4n−1​λk​X−k=k=0∑4n−1​λk​X4n−1−k.

The coefficient λ4n−1​ is attached to X0, so c1​(0)=λ4n−1​, and the consolidated equation has become

c1​(0)=k(y).

Fifteen cells for the powers X^0 to X^14 of the product. The lower eight cells appear in reverse order as c_1, with X^7 in position 0, and the upper seven appear in the same order as c_2.

For our product, clo​ has coefficients (38,39,0,9,18,29,14,13) and chi​ has coefficients (9,29,39,15,8,0,0). Reversing the lower half gives c1​(X) with coefficients (13,14,29,18,9,0,39,38), so c1​(0)=13, which is the required value k(7). We set c2​=chi​.

The notation is close to the wires of the arithmetization chapter, but the meaning is different. The polynomials c1​(X) and c2​(X) are unrelated to the wire values c0​,c1​,…, and we will always write the polynomials with their argument. The wires now appear only inside r(X).

The verifier also needs a way to know that c1​ and c2​ really came from the product. Since reversing twice restores the original, we can recover the lower half from c1​ by substituting X−1 into its definition and multiplying by X4n−1:

X4n−1c1​(X−1)=X4n−1⋅X−(4n−1)clo​(X)=clo​(X).

Substituting this into the cut gives one equation that ties the two new polynomials to the product:

r(X)f(X)=X4n−1c1​(X−1)+X4nc2​(X).

The verifier has to evaluate this at a nonzero point, since it uses X−1.

At x=9, the inverse is x−1=24, because 9⋅24=216=1 modulo 43. Then c1​(24)=6, x7=36, and 36⋅6=1 modulo 43, which equals clo​(9) computed directly.

13. Polynomial oracles

So far we have written the checks in terms of polynomials the verifier does not hold. The usual way to separate this reasoning from the cryptography is to pretend for the moment that the verifier has an oracle for each polynomial the prover sends. An oracle is a black box that fixes a polynomial when the prover creates it, and that afterward answers any question of the form "what is the value at this point?" The verifier never sees the coefficients. A protocol built this way is called a polynomial interactive oracle proof, or polynomial IOP.

This separation lets us check the logic of the protocol now. The next chapter replaces each oracle with a commitment, and later chapters provide the evaluation proofs.

The order of messages carries much of the protocol's soundness. The prover fixes r(X) before seeing the challenges z and y, as the argument in the arithmetization chapter required. It fixes c1​(X) and c2​(X) before seeing x, because the split check is a random test of those polynomials.

In the protocol, x is this random evaluation point, as in the commitments chapter, and the verifier picks it nonzero. The verifier asks the oracles for r(x) and r(xz), then for c1​(x−1) and c1​(0), then for c2​(x). It computes s(x,y), t(x,z) and k(y) by itself, because these polynomials are public. Then it checks two equations:

r(x)(r(xz)+s(x,y)+t(x,z))=x4n−1c1​(x−1)+x4nc2​(x),

c1​(0)=k(y).

The first is the split check, and the second is the target check. The dilation helps in the first check, because the verifier gets the value of r(zX) at x by asking the same oracle about the point xz. No separate polynomial is involved, so the prover cannot substitute a different trace in the second factor.

The verifier's local work differs among the three public polynomials. The value t(x,z) has a short closed form, since each of its sums is a geometric series, and k(y) is cheap when the public input vector is sparse. Computing s(x,y) directly costs time linear in the circuit size, and the chapter on wiring and the registry studies how to avoid this.

14. A complete run

Here is the whole protocol on the witness with x=3, with the oracles written out so that we can follow them. The secret input now sits inside r(X), and the x in the table is the random point.

StepPartyValue or check
1BothHold s(X,Y), t(X,Z) and k(Y)=30Y3
2Prover sends oracler(X)=9+27X+9X2+3X3+3X4+3X5
3Verifier sends challengesz=5, y=7
4Prover computesf(X)=r(5X)+s(X,7)+t(X,5) and the product r(X)f(X)
5Prover sends oraclesc1​(X)=13+14X+29X2+18X3+9X4+39X6+38X7 and c2​(X)=9+29X+39X2+15X3+8X4
6Verifier sends challengex=9, so xz=2 and x−1=24
7Verifier queries rr(9)=5 and r(2)=9
8Verifier queries c1​c1​(24)=6 and c1​(0)=13
9Verifier queries c2​c2​(9)=30
10Verifier computes locallys(9,7)=23, t(9,5)=3, k(7)=13
11Verifier checks the split5⋅(9+23+3)=3 and 36⋅6+23⋅30=3
12Verifier checks the targetc1​(0)=13=k(7)

Both checks pass. Repeating step 11 at all 42 nonzero values of x shows that the honest polynomials pass at every one.

15. Why cheating fails

The argument assumes that oracles are fixed when sent, and that the challenges are uniform and arrive after the messages they test. The commitments of the next chapter provide the first assumption, under the discrete log relation assumption. Fiat–Shamir provides the second in a non-interactive proof, treating its hash as a random oracle. Inside this model, the argument only counts roots of polynomials.

A prover with a false witness has to send some r′(X) before seeing z and y. The arithmetization chapter showed that a random pair (z,y) rarely makes the true coefficient equal to k(y).

For the false witness with x=4, counting all pairs finds 43 of the 1849 that do so.

Outside those lucky pairs, the honest split fails the target check, so the prover has to lie about the split. The most direct lie changes only the coefficient the target check reads.

Take the false witness with x=4 from Section 7, so r′(X)=16+21X+16X2+4X3+4X4+4X5, at the same z=5 and y=7. The coefficient of X7 in r′(X)f′(X) is 18, while k(7)=13, so the honest split would fail the target check. The prover can change the constant term of c1​ to 13 and leave everything else alone, which fixes the target check. The two sides of the split check then differ by 5X7, and the verifier rejects at all 42 nonzero values of x.

This lie is the easiest to catch, since the error sits on one power of X. Any polynomials c1​ and c2​ that pass the target check must describe a polynomial other than r′(X)f′(X), because they disagree with it on the coefficient of X4n−1. Whatever they are, the two sides of the split check form a nonzero polynomial difference, so the prover's best option is to give that difference as many roots as possible.

The prover can do better by spreading the difference over many powers of X. Let Δ(X) be a polynomial of degree 15 whose coefficient of X7 is 5, which is the amount the true coefficient must change by. Writing Δ as a multiple of (X−1)(X−2)⋯(X−15) gives it the 15 roots 1,…,15. The prover then splits r′(X)f′(X)−Δ(X) instead of the true product, and the new c1​ has c1​(0)=13, as the target check requires. The split check now compares r′(x)f′(x) with r′(x)f′(x)−Δ(x), so it passes exactly where Δ(x)=0. Testing every nonzero x finds 15 passing values out of 42, which is the most a polynomial of degree 15 allows. For n=211 on a field of about 2255 elements, the same limit of 8n−1 roots gives a probability below 2−240.

The limit here is 8n−1 rather than 8n−2. The honest c2​ has only 4n−1 coefficients, but a commitment has room for 4n, so a cheater can use one more.

As with the QAP, the order of messages is essential.

Suppose the prover also knows x=9 before sending c1​ and c2​. Changing the constant term of c1​ moved the split check by 5x7, and adding a constant e to c2​ moves it by ex8 in the other direction. Choosing e=5/9=34 cancels the two at this one point. The forged pair passes both checks at x=9, and testing the other nonzero values confirms that it passes at no other point.

16. Comparing the two routes

Both routes turn many constraints into one polynomial test at a random point, and they differ in how they reach that test.

QAPRagu's encoding
How the rows combineOne point of the domain per rowPowers of the challenges z and y
Form of the claimP(X) is divisible by V(X)One coefficient of r(X)f(X) equals k(y)
Extra polynomials from the proverThe quotient h(X)The pieces c1​(X) and c2​(X)
How the verifier reaches the claimCompares P(τ) with h(τ)V(τ)Reads c1​(0) and tests the split at x
Witness encodingValues at domain pointsCoefficients of r(X)
Random valuesOne point τ, secret in Groth16z, y and x, all public
Tying factors to one witnessSecret setup values in Groth16One oracle r, queried at x and xz

The central difference is division against extraction. The QAP has to show that a whole polynomial vanishes across a domain, and a quotient is the evidence for that. Ragu's claim concerns one number, so the prover has no quotient to compute and only has to move that number to a place evaluation can reach.

This does not make the multiplication free. Splitting the product still requires the prover to compute it, and for large polynomials that takes FFTs on a domain of about 8n points. The Ragu Book's structured vectors chapter notes that Ragu only needs this at the places in the PCD tree where succinctness is required, so a prover can skip it elsewhere. The Book's overview also credits this design with largely avoiding the encoding of witnesses at domain points, without using the sum-check protocol.

17. The encoding in Ragu

The split appears in the compression step of the code as a short function, here from crates/ragu_pcd/src/compress/revdot/prover.rs at commit 3219e08. Its n counts all the coefficients, so it plays the role of our 4n:

let q = c.split_off(n);
c.reverse();
(c, q)

The verifier recomputes the right side of the split check from the claimed evaluations and rejects on a mismatch.

Naming differs across the Ragu Book and the code

The Book's NARK chapter calls the two pieces c1​ and c2​ and the evaluation point x. Its structured vectors chapter and the code call the pieces p and q, and the compression chapter and the code call the point r. This site uses c1​, c2​ and x here, because r already names the trace polynomial and p is used for other polynomials.

The Ragu Book and the code differ on the public constant

The NARK chapter adds a third check, r(0)=1 together with k(0)=1, and says that the first element of the witness is the public constant ONE. The Book's local wiring chapter instead places ONE in the wire d0​ and says that c0​=0 ensures r(0)=0. The trace assembly code at commit 3219e08 leaves c0​=0 and sets d0​=1, which agrees with the wiring chapter, so this site follows that form.

Our toy circuit has no ONE wire. Its r(0)=c0​ is the wire value 9 and its k(0) is 0, so the run in Section 14 leaves this check out.

Reconstructed from code at commit 3219e08, not confirmed by the authors

The split in this chapter is not the only way Ragu checks a revdot claim. The Book's NARK chapter presents the oracle protocol above and then builds its concrete NARK differently. In that NARK, the verifier receives the two vectors and recomputes their revdot product directly, which avoids the prover's FFTs at the cost of a larger proof. The uncompressed verifier follows this form. The split appears in compression, where the prover applies it to a random combination of folded claims instead of a single product. We return to the direct form in the complete proof and to folded claims in revdot folding.

18. Where this chapter leaves us

This chapter took the following steps:

  1. A QAP interpolates each column of the R1CS matrices over a domain, so that row i becomes an equation at the point ρi​.
  2. The rows hold exactly when A(X)B(X)−C(X) is divisible by the vanishing polynomial V(X), which reduces them to one identity with a quotient h(X).
  3. A false witness has no quotient, so a prover can only pass by luck, or by knowing the test point in advance.
  4. Groth16 enforces the QAP test with a secret τ, a trusted setup and pairings, and Ragu uses none of those.
  5. Ragu reads its consolidated equation as the coefficient of X4n−1 in r(X)(r(zX)+s(X,y)+t(X,z)).
  6. Splitting the product and reversing the lower half turns that coefficient into the constant term c1​(0), and a split check at a random x ties c1​ and c2​ to the product.
  7. Written with oracles, the protocol is a polynomial IOP whose soundness depends on the order of its messages.

Every oracle in this protocol is still an assumption. The next chapter builds the commitment that replaces each oracle with one curve point.

Last Updated: 11/4/26, 10:49 AM
Contributors: Hanh
Prev
Arithmetization
Next
Polynomial Commitments