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 over , 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 differ. Their difference is a nonzero polynomial of degree at most , so it has at most roots, and the two polynomials agree on at most 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, was the secret input, and we keep that meaning when we write "the witness with ". Once we reach Ragu's split in Section 12, 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, is the R1CS vector, and we write its entries in bold as , so that they stay separate from the wires and of the flattened computation.
2. The R1CS starting point
The R1CS form of our statement uses a vector holding the constant 1, the public output, and the three private values. Three public matrices with rows define the constraints, and row requires
For our statement there are three rows:
with . The three rows give , and , and multiplying the first two entrywise gives the third.
These equations are what we have to compress. In a real circuit 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 distinct points , called the domain, and let row live at . Our example uses .
The most direct idea is to interpolate the vector itself, finding a polynomial whose value at is entry of . 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 . We keep the two separate by interpolating the matrix alone. Each column of belongs to one wire, so we build one polynomial per column:
The polynomials and come from the columns of and in the same way. Since points determine a unique polynomial of degree at most , 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 over all is zero at every other point, and dividing by its value at scales it to 1 there:
These are the Lagrange basis polynomials for . For our domain they are
Dividing by 2 modulo 43 means multiplying by 22, and dividing by means negating. As a spot check, , and .
Any column can now be written as a sum of basis polynomials, each weighted by that column's entry for the row:
At only the term with survives, which gives 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.
| Polynomial | Column entries | In the basis | Coefficients |
|---|---|---|---|
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:
To see what these sums hold, evaluate at a domain point and use the defining property of the column polynomials:
So takes the value of row of at the point , and the same holds for and . Row of the R1CS is therefore the equation , and the rows hold exactly when this equation holds at all domain points.
For , the sums come out as
| 1 | 3 | 3 | 9 | 0 |
| 2 | 9 | 3 | 27 | 0 |
| 3 | 35 | 1 | 35 | 0 |
The columns for , and reproduce , and from Section 2.
5. The vanishing polynomial and the quotient
Define . The rows hold exactly when is zero at every point of . That is still separate facts, and a check at one random point would not capture them, because a random point is almost never in . 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 divides it. Since the points of are distinct, is zero on all of exactly when is divisible by the product of those factors. This product is the vanishing polynomial of the domain:
The rows therefore hold exactly when there is a polynomial , called the quotient, with
The factors and each have degree at most , so has degree at most . Since has degree , the quotient has degree at most . The column polynomials and 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 rows, the degree of is at most 4, and multiplying and subtracting gives . Substituting gives , and , even though the coefficients of are not zero.
The next step divides by .
Expanding the product gives , which is modulo 43. Long division removes one leading term at a time:
| Current polynomial | Next term of | Subtract | Result |
|---|---|---|---|
The last column ends at 0, so the division is exact and , which has degree as predicted.
6. Testing the identity at one point
The equation is now an equality of polynomials, so Section 1 applies. If the two sides are different polynomials, their difference has degree at most , and they agree on at most that many points. A verifier who picks a random after the prover has fixed , , and can compare the two sides at alone. The chance of missing a difference is at most .
Take . The prover has already fixed its polynomials, so the two sides are
| Value | At |
|---|---|
| 17 | |
| 42 | |
| 40 | |
| 29 | |
| 13 | |
| 32 | |
| 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 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 , which gives . Now , and . The first two rows hold, and the last gives against 35. The polynomial built from this witness is , with and but . Dividing by leaves the quotient and the remainder . The remainder is not zero, so no polynomial satisfies .
A failing row at means , while any multiple of is zero there. This mismatch is why no 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 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 with negligible probability.
| Values of where the guess passes | Number of candidate quotients |
|---|---|
| 0 | 909 |
| 1 | 160 |
| 2 | 780 |
The table covers all candidate polynomials 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 is a nonzero polynomial of low degree whatever 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 learns before answering. It computes and , divides to get 27, and presents the constant polynomial . The check at passes because modulo 43. At the same gives against , so this forgery only works at the point the prover knew in advance.
The test also assumes that , and 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 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 .
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 . Real provers use the fast Fourier transform (FFT), which requires the domain to be a set of roots of unity. This choice also gives a compact form.
In the value satisfies modulo 43, so its powers form the domain , and the vanishing polynomial collapses to . Repeating the construction on this domain with the same witness gives different polynomials, for example , and the exact quotient . The same field has no domain of size 4, because 4 does not divide . 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 has about twice the degree of its factors. Holding by its values therefore takes a domain about twice the size of .
For a circuit of rows, has degree up to . Representing it requires a domain with more than 131,070 points, and the next power of two is .
Groth16 provers avoid part of this cost, because is known to vanish on and the quotient has degree below . Evaluating on one shifted copy of , called a coset, is enough to recover , so these provers run their FFTs at size rather than . 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 , and . 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 and , which left one scalar equation in Section 12 of the arithmetization chapter:
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 . Section 7 of that chapter already supplied the link to polynomials, because the revdot product of two vectors of length is the coefficient of 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 and the layout from the arithmetization chapter, it is
The dilated vector multiplies coefficient by , which is the effect of substituting for , because . So the dilated vector is the coefficient vector of , and no new data is involved.
The public vectors and 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:
The vector is the coefficient vector of , and is the coefficient vector of . On the right side of the equation, the public input polynomial gives .
The Ragu Book's NARK chapter uses the other layout
The NARK chapter writes and puts at and at in . The wiring code at commit 3219e08 puts the coefficients of the wires at in , as above. The two forms differ only by swapping the names and . This site follows the code, as the arithmetization chapter did.
Now collect the second factor into one polynomial,
The name is local to this chapter, and is the right vector of the consolidated equation in polynomial form. By the coefficient rule, the equation now reads
Here are the polynomials for our witness at and , the challenges from the arithmetization chapter:
| Polynomial | Coefficients of |
|---|---|
The vector for is the combined right vector from Section 12 of the arithmetization chapter, now read as coefficients.
The coefficient of in the product collects every pair of exponents that adds to 7:
| Coefficient of in | Coefficient of in | Product | ||
|---|---|---|---|---|
| 0 | 9 | 7 | 17 | 24 |
| 1 | 27 | 6 | 31 | 20 |
| 2 | 9 | 5 | 8 | 29 |
| 3 | 3 | 4 | 20 | 17 |
| 4 | 3 | 3 | 30 | 4 |
| 5 | 3 | 2 | 16 | 5 |
| 6 | 0 | 1 | 6 | 0 |
| 7 | 0 | 0 | 9 | 0 |
The last column sums to 13 modulo 43. On the other side, because only is nonzero, so 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 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Coefficient | 38 | 39 | 0 | 9 | 18 | 29 | 14 | 13 | 9 | 29 | 39 | 15 | 8 | 0 | 0 |
The entry for 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 leaves with degree 5.
In general, the product has degree up to . 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 generators holds at most 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 coefficients of through , and an upper half with the rest:
Both pieces have degree below , so each fits within a single commitment. The coefficient we want is the top coefficient of , which is still not an evaluation.
The one coefficient of a polynomial that evaluation can reach is the constant term, because substituting removes all the others. So we reverse the coefficients of the lower half, which moves the top coefficient to the bottom:
To see that this is a reversal, write and multiply through:
The coefficient is attached to , so , and the consolidated equation has become

For our product, has coefficients and has coefficients . Reversing the lower half gives with coefficients , so , which is the required value . We set .
The notation is close to the wires of the arithmetization chapter, but the meaning is different. The polynomials and are unrelated to the wire values , and we will always write the polynomials with their argument. The wires now appear only inside .
The verifier also needs a way to know that and really came from the product. Since reversing twice restores the original, we can recover the lower half from by substituting into its definition and multiplying by :
Substituting this into the cut gives one equation that ties the two new polynomials to the product:
The verifier has to evaluate this at a nonzero point, since it uses .
At , the inverse is , because modulo 43. Then , , and modulo 43, which equals 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 before seeing the challenges and , as the argument in the arithmetization chapter required. It fixes and before seeing , because the split check is a random test of those polynomials.
In the protocol, is this random evaluation point, as in the commitments chapter, and the verifier picks it nonzero. The verifier asks the oracles for and , then for and , then for . It computes , and by itself, because these polynomials are public. Then it checks two equations:
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 at by asking the same oracle about the point . 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 has a short closed form, since each of its sums is a geometric series, and is cheap when the public input vector is sparse. Computing 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 , with the oracles written out so that we can follow them. The secret input now sits inside , and the in the table is the random point.
| Step | Party | Value or check |
|---|---|---|
| 1 | Both | Hold , and |
| 2 | Prover sends oracle | |
| 3 | Verifier sends challenges | , |
| 4 | Prover computes | and the product |
| 5 | Prover sends oracles | and |
| 6 | Verifier sends challenge | , so and |
| 7 | Verifier queries | and |
| 8 | Verifier queries | and |
| 9 | Verifier queries | |
| 10 | Verifier computes locally | , , |
| 11 | Verifier checks the split | and |
| 12 | Verifier checks the target |
Both checks pass. Repeating step 11 at all 42 nonzero values of 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 before seeing and . The arithmetization chapter showed that a random pair rarely makes the true coefficient equal to .
For the false witness with , 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 from Section 7, so , at the same and . The coefficient of in is 18, while , so the honest split would fail the target check. The prover can change the constant term of to 13 and leave everything else alone, which fixes the target check. The two sides of the split check then differ by , and the verifier rejects at all 42 nonzero values of .
This lie is the easiest to catch, since the error sits on one power of . Any polynomials and that pass the target check must describe a polynomial other than , because they disagree with it on the coefficient of . 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 . Let be a polynomial of degree 15 whose coefficient of is 5, which is the amount the true coefficient must change by. Writing as a multiple of gives it the 15 roots . The prover then splits instead of the true product, and the new has , as the target check requires. The split check now compares with , so it passes exactly where . Testing every nonzero finds 15 passing values out of 42, which is the most a polynomial of degree 15 allows. For on a field of about elements, the same limit of roots gives a probability below .
The limit here is rather than . The honest has only coefficients, but a commitment has room for , so a cheater can use one more.
As with the QAP, the order of messages is essential.
Suppose the prover also knows before sending and . Changing the constant term of moved the split check by , and adding a constant to moves it by in the other direction. Choosing cancels the two at this one point. The forged pair passes both checks at , 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.
| QAP | Ragu's encoding | |
|---|---|---|
| How the rows combine | One point of the domain per row | Powers of the challenges and |
| Form of the claim | is divisible by | One coefficient of equals |
| Extra polynomials from the prover | The quotient | The pieces and |
| How the verifier reaches the claim | Compares with | Reads and tests the split at |
| Witness encoding | Values at domain points | Coefficients of |
| Random values | One point , secret in Groth16 | , and , all public |
| Tying factors to one witness | Secret setup values in Groth16 | One oracle , queried at and |
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 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 counts all the coefficients, so it plays the role of our :
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 and and the evaluation point . Its structured vectors chapter and the code call the pieces and , and the compression chapter and the code call the point . This site uses , and here, because already names the trace polynomial and is used for other polynomials.
The Ragu Book and the code differ on the public constant
The NARK chapter adds a third check, together with , 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 and says that ensures . The trace assembly code at commit 3219e08 leaves and sets , which agrees with the wiring chapter, so this site follows that form.
Our toy circuit has no ONE wire. Its is the wire value 9 and its 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:
- A QAP interpolates each column of the R1CS matrices over a domain, so that row becomes an equation at the point .
- The rows hold exactly when is divisible by the vanishing polynomial , which reduces them to one identity with a quotient .
- A false witness has no quotient, so a prover can only pass by luck, or by knowing the test point in advance.
- Groth16 enforces the QAP test with a secret , a trusted setup and pairings, and Ragu uses none of those.
- Ragu reads its consolidated equation as the coefficient of in .
- Splitting the product and reversing the lower half turns that coefficient into the constant term , and a split check at a random ties and to the product.
- 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.