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

Batched Openings

The inner product argument proves one evaluation claim about one committed polynomial. A complete proof makes several such claims, about different polynomials at different points, and running the argument once per claim multiplies its cost. This chapter reduces any number of claims to a single claim, so that the argument runs only once.

The reduction has two stages. The first moves every claim to one fresh random point with the help of quotient polynomials, and the second combines the resulting claims at that point using a random linear combination. The Ragu Book calls these stages alpha batching and beta batching after their challenges, and the literature calls the whole technique a batched opening or a multi-opening.

1. Why a proof makes many claims

The next chapter assembles a complete proof, and its final step in the Ragu Book lists the claims that the verifier needs checked. We will meet these polynomials properly in that chapter. For now, the shape of the list is what matters:

two claims about aa(0)=1,a(xz)=⋯​​,b(x)=⋯,s(x,y)=⋯,two claims about kk(0)=1,k(y)=c​​.

That makes six claims about four polynomials at the four points 0, xz, x and y. Later chapters add more, because a recursive step also has to handle the claims it inherits from earlier proofs. Each separate opening carries 2k group elements for a polynomial with n=2k coefficients, and it costs the verifier a linear amount of curve work:

Take n=213 with 32-byte values, and the six claims above. Six separate arguments carry 6×26=156 group elements, or 4,992 bytes. One batched argument carries 26 group elements, plus the extra commitment and the 4 scalars that this chapter introduces, for 992 bytes. Both counts leave out the small constant number of extra values that each argument carries.

We write one claim as a triple (Ci​,xi​,yi​), which says that the polynomial pi​ behind the commitment Ci​ satisfies pi​(xi​)=yi​. Both parties hold the triples, and only the prover holds the polynomials. The goal is a short exchange after which both parties hold a single triple (P,u,v), with the property that a false input claim leads to a false output claim, except with negligible probability.

The name P needs a warning, because it has a different meaning in the commitments chapter. There, P=C+y⋅U was the statement point of an opening. In this chapter P is a plain commitment to a polynomial p, which is the Ragu Book's usage, so the statement point for the output claim would be P+v⋅U.

2. Combining claims at different points

The random linear combinations from chapter 03 already solve the problem when all the claims use one point. If p0​(x)=y0​ and p1​(x)=y1​, the verifier picks r and asks about p0​+rp1​ at x. It can compute the commitment C0​+rC1​ and the expected value y0​+ry1​ alone, because commitments and evaluations combine with the same coefficients.

The method stops working when the points differ, because a combination of polynomials has no single point at which the combined claim makes sense:

Suppose the prover claims p0​(9)=37 and p1​(5)=20, with the polynomials p0​=7+2X+5X2+3X3 and p1​=3+X+8X2+4X3. Take r=6. The combination p0​+6p1​ has the value 36 at 9 and the value 35 at 5, while the combined claim is 37+6⋅20=28. The claimed number matches neither value, even though both claims are true, because the value at 9 needs p1​(9)=7 and nobody has said anything about that.

We therefore need some way to convert a claim at xi​ into a claim at a point shared by all the others. Since the verifier's challenge can supply such a point, we look for a way to restate p(x)=y as a fact that holds everywhere, so that it can be tested anywhere.

3. Writing a claim as a division

The statement p(x)=y says that the polynomial p(X)−y has a root at x. Chapter 03 showed that each root gives a linear factor, so the claim holds exactly when there is a polynomial q with

p(X)−y=(X−x)q(X).

We call q the quotient of the claim. To see how the prover computes it, and why a false claim has no quotient, write out the case n=4. Then p has coefficients a0​,…,a3​, the quotient has degree 2, and we can write q(X)=b0​+b1​X+b2​X2. Multiplying out the right side gives

(X−x)(b0​+b1​X+b2​X2)​=b0​X+b1​X2+b2​X3−xb0​−xb1​X−xb2​X2=−xb0​+(b0​−xb1​)X+(b1​−xb2​)X2+b2​X3.​

Matching each power of X against p(X)−y=(a0​−y)+a1​X+a2​X2+a3​X3 produces four equations:

b2​b1​−xb2​b0​−xb1​−xb0​​=a3​,=a2​,=a1​,=a0​−y.​

The first three equations determine the quotient from the top coefficient down, and y plays no part in them. Solving them gives b2​=a3​, then b1​=a2​+xa3​, then b0​=a1​+xa2​+x2a3​. Only the last equation mentions y, and rearranging it gives

y=a0​+xb0​=a0​+a1​x+a2​x2+a3​x3=p(x).

So the system has a solution exactly when the claim is true. This procedure is called synthetic division, and the same pattern works for any n.

Take p(X)=7+2X+5X2+3X3 and x=9, so a3​,a2​,a1​,a0​=3,5,2,7.

LineFormulaValue modulo 43
b2​a3​3
b1​a2​+xb2​=5+9⋅332
b0​a1​+xb1​=2+9⋅3232
ya0​+xb0​=7+9⋅3237

The quotient is q(X)=32+32X+3X2, and the last line recovers y=37, the value of p(9) from the commitments chapter. Multiplying out (X−9)(32+32X+3X2) returns 13+2X+5X2+3X3, which equals p(X)−37 with coefficients reduced modulo 43.

Here is what the same computation does when the claimed value is wrong:

Suppose the prover claims p(9)=38 instead. The first three lines of the table do not involve y, so they produce the same q(X). The last line still computes 37, which contradicts the claim. Expanding shows the same mismatch, since (X−9)q(X)=p(X)−37 while the claim needs p(X)−38. No polynomial can repair this, because at X=9 the product (X−9)q(X) is zero for every q, whereas p(9)−38=42.

A false claim therefore has no quotient polynomial. The fraction (p(X)−y)/(X−x) still exists as a rational function, with a pole at x that no polynomial can reproduce, and the protocol below relies on that difference.

4. Moving one claim to a new point

The equation p(X)−y=(X−x)q(X) is an identity between polynomials, so it holds at every point. For any u=x, dividing by the nonzero number u−x gives

q(u)=u−xp(u)−y​.

This relation gives us a test at a point unrelated to x. The prover commits to q first, which fixes it. The verifier then picks a random u, the prover sends the value p(u), and the verifier computes what q(u) has to be from the formula. What remains are two claims at the point u. The original commitment must open to the sent value, and the quotient's commitment must open to the computed value. The point x appears only in the verifier's arithmetic and in no remaining opening.

Take a second polynomial p1​(X)=3+X+8X2+4X3, with the commitment C1​=(6,23) and the claim p1​(5)=20. Division gives q1​(X)=12+28X+4X2.

StepPartyValue or check
1Prover commits to the quotientQ1​=(17,24)
2Verifier sends a challengeu=17
3Prover sends the value of p1​ at up1​(17)=11
4Verifier derives the value of q1​ at u(11−20)/(17−5)=10

The commitment C1​ must now open to 11 at 17, and Q1​ must open to 10 at 17. Evaluating the quotient directly confirms that q1​(17)=10.

For one claim this looks like a step backward, because it replaced one opening with two. The gain appears with several claims, since every claim can use the same u, and the same-point method of Section 2 then applies to all of them.

The test also has the behaviour we want for a false claim. If p(x)=y, whatever polynomial q′ the prover commits to differs from the rational function, so the formula gives the wrong value at most values of u. To count the exceptions, multiply through by u−x. The formula matches only where (X−x)q′(X)−(p(X)−y) vanishes, and this polynomial is nonzero because a false claim has no quotient. Its degree is at most n, since the commitment limits q′ to degree n−1, so it has at most n roots and the prover has at most an n/∣F∣ chance of passing.

5. Alpha batching

With m claims, a separate commitment to each quotient would add m curve points to the proof. Commitments add in the same way as polynomials, so the prover can send one commitment to a combination of the quotients. Our running example has three polynomials with one claim each:

Claim iPolynomial pi​(X)Point xi​Value yi​Commitment Ci​Quotient qi​(X)
07+2X+5X2+3X3937(27,30)32+32X+3X2
13+X+8X2+4X3520(6,23)12+28X+4X2
22+9X+4X2+6X3241(17,24)41+16X+6X2

The combination cannot be a plain sum, because errors at a shared point can cancel. Two false claims at the same x have remainders over the same denominator, and a cheater can choose those remainders to be opposite:

The true values at 9 are p0​(9)=37 and p1​(9)=7. A cheater claims 38 and 6, so both claims are false. The errors are opposite, so p0​+p1​−(38+6) still has a root at 9 and division by X−9 leaves no remainder. The result is the genuine polynomial 42+33X+7X2, which the cheater can commit to and open at any point.

Giving each quotient a different random weight prevents this, which is the same reasoning as for powers of one challenge. The verifier sends a challenge α after the claims are fixed, and the prover forms

f(X)=i=0∑m−1​αm−1−iqi​(X).

For three claims this is f(X)=α2q0​(X)+αq1​(X)+q2​(X). The first claim takes the highest power, which is the order Ragu's code uses, and Section 7 compares it with the book's order. The weights rule out the cancellation above:

With the weights α and 1, the two errors from the previous example leave the remainder α⋅42+1 over X−9. Trying all 43 values of α finds that only α=1 removes it, and that value is the plain sum.

The prover now computes f for the running example and commits to it. A quotient has degree n−2, so f fits within the generators, with a zero in the top position.

Take α=11, so α2=35 modulo 43. Each column of the next table combines one power of X.

TermX0X1X2
q0​(X)32323
q1​(X)12284
q2​(X)41166
f(X)=35q0​+11q1​+q2​32526

The prover commits to f and sends the single point F=(27,1).

The commitment F fixes f before the next challenge. The prover has not sent any of the individual quotients, and the verifier does not need them.

6. Moving every claim to u

The verifier now sends a random point u. Section 4 gave a formula for one quotient at u, and because f is a combination of the quotients, the same weights carry over to its value. Substituting term by term gives

f(u)​=i=0∑m−1​αm−1−iqi​(u)=i=0∑m−1​αm−1−iu−xi​pi​(u)−yi​​.​

The right side uses only the values pi​(u) together with numbers the verifier already holds, so the prover sends those values and the verifier computes f(u) for itself. The formula divides by u−xi​, which would fail if u landed on one of the original points. On a real curve this has negligible probability, and the compression verifier rejects if it happens.

Take u=17. The prover sends p0​(17)=14, p1​(17)=11 and p2​(17)=1, and the verifier computes each term from those values and the original claims.

ipi​(u)u−xi​(pi​(u)−yi​)/(u−xi​)WeightWeighted term
0148243523
11112101124
211526126

The last column sums to f(17)=30 modulo 43. The prover, who holds f, gets the same number by direct substitution into 3+25X+26X2. The verifier has obtained this value without seeing f.

The verifier now holds m+1 claims that all use the point u. The commitment F must open to the computed f(u), and each Ci​ must open to the sent pi​(u). The obstacle from Section 2 has gone, because no remaining opening refers to the points xi​. The original claims have not disappeared, however, since each yi​ and xi​ now sits inside the formula for f(u), and a false yi​ makes that number wrong.

7. Beta batching

Since all the claims now use one point, a random linear combination finishes the job. The verifier sends a challenge β after the prover has sent its values, and the prover forms

p(X)=βmf(X)+i=0∑m−1​βm−1−ipi​(X).

For three claims this is p(X)=β3f(X)+β2p0​(X)+βp1​(X)+p2​(X). The verifier cannot compute p, but linearity gives it everything else. The commitment comes from the homomorphic property, and the value comes from substituting u into the definition of p:

Pv​=βm⋅F+i=0∑m−1​βm−1−i⋅Ci​,=βmf(u)+i=0∑m−1​βm−1−ipi​(u).​

The output is the triple (P,u,v), a claim of exactly the form the inner product argument proves.

Take β=23, whose powers modulo 43 are β2=13 and β3=41.

InputWeightCommitmentValue at uCoefficients
f41(27,1)30(3,25,26,0)
p0​13(27,30)14(7,2,5,3)
p1​23(6,23)11(3,1,8,4)
p2​1(17,24)1(2,9,4,6)
Combined pP=(14,9)v=32(27,8,29,8)

The verifier derives P and v from the first four rows, using only group operations and field arithmetic. The prover derives the coefficients of p. Committing to those coefficients gives (14,9), and substituting u=17 into p gives 32, so both agree with what the verifier computed.

The polynomial f needs a weight of its own, distinct from the weight of every pi​. If two inputs share a weight, an error in one can cancel an error in the other for every β. The book's formulas leave this point open, because they do not state where the index starts:

The Ragu Book and the code differ here

The book writes f=∑i​αiqi​ and p=f+∑i​βipi​ and does not state the range of i. The compression verifier at commit 3219e08 gives the first claim the highest power of α, gives f the highest power of β, and gives the last polynomial weight 1. This site follows the code. A different order of distinct weights only relabels the inputs, so the book's formula read with βi starting at i=1 is equally good, and that is the form the Halo 2 book uses for its final polynomial.

Reading the book's sum from i=0 would not be safe, since f and p0​ would then both have weight 1. We do not suggest the authors intend this reading, and the code's distinct weights do not have this collision. The collision comes from the β sum alone, so the range of the α sum makes no difference to it. The toy curve shows why the index matters:

Keep the false claim p1​(5)=21, and use the sum from i=0 in both places, so that f and p0​ both have weight 1 in p. The cheater commits to the honest f=∑i​αiqi​, which at α=11 is 8+40X+42X2. At u=17 the derived value misses f(17) by 26. The cheater then sends 18 for p0​(17), a shift of 4. The shift changes the derived value of f(u) and the p0​ term of v, and the two changes add up to exactly that miss. No power of β appears in this equation, so we checked that the forged message passes for all 43 values of β. The attack works at 39 of the 40 allowed values of u, for a total of 1677 of the 1720 pairs (u,β). This forgery fails only at u=8, where 1+1/(u−x0​)=0 modulo 43.

8. The complete protocol

The following diagram shows what the two stages do to the claims, and the sequence after it lists the messages.

Three grids of polynomials against points. Three claims at three different points become four claims at the point u, including one about f, and then one claim about p at u.

The soundness of the protocol depends on the order of these messages, as Section 9 explains. Under Fiat–Shamir, each challenge becomes a hash of a transcript that has absorbed everything before it, including the claims themselves. The worked examples here use chosen challenges so that the numbers stay readable.

Here is the whole run, gathered from the previous sections. For the last step, the prover reveals p, and the verifier checks it directly:

StepPartyValue or check
0Both hold the claims((27,30),9,37), ((6,23),5,20), ((17,24),2,41)
1Verifier sends a challengeα=11
2Prover commits to fF=(27,1)
3Verifier sends a challengeu=17
4Prover sends the values at u14, 11, 1
5Verifier sends a challengeβ=23
6Verifier derives f(u)30
7Verifier derives the output claimP=(14,9), v=32
8Prover reveals p(27,8,29,8)
9Verifier checks the commitment⟨p,G⟩=(14,9), which equals P
10Verifier checks the valuep(17)=32, which equals v

Steps 8 to 10 are the expensive ones. The Ragu Book's NARK really does finish this way, with the prover sending p in full, and the next chapter returns to that choice. A succinct proof replaces those three steps with one inner product argument for (P,u,v), as compression does in the code.

9. Why cheating fails

The argument below relies on three assumptions. Commitments are binding under the discrete log relation assumption, the final opening is sound, and Fiat–Shamir challenges behave like uniform random values that nobody can predict before the preceding messages are fixed, which is the random oracle assumption.

Take one false claim in the running example. We follow what a cheater can try at each stage, and we count its success on the toy field by trying every challenge.

The cheater commits to the quotients and reports true values

A cheater who runs the honest division gets a perfectly good polynomial f, because division ignores y. The false value only shows up later, inside the verifier's formula.

The cheater claims p1​(5)=21, whereas the true value is 20. It computes the quotients by the division table, which ignores y, and commits to the same f, then reports true values at u. The false y1​ enters the verifier's formula, and at u=17 the derived value is 4 while f(17)=30, a gap of 26. We tried every pair of challenges, with 40 allowed values of u and 43 of β. The gap is nonzero at all 40 values of u, and the only passing runs are the 40 that have β=0.

The gap is never zero here, because it equals a nonzero weight times a nonzero remainder, divided by u−xi​. The check at β=0 passes only because βm then removes f from p altogether, and a random β avoids that value except with probability 1/∣F∣.

The cheater lies about a value at u

To close the gap, the cheater can change a value that it sends at u. This moves the error from the formula for f(u) into the term for pi​(u), where β catches it instead:

At u=17 the cheater sends 12 for p1​(17) in place of the true 11, a shift of 1 chosen so that the derived value equals f(17)=30. In effect it reports values of p1​+1, a polynomial that does satisfy the false claim, while its commitment still holds p1​. The output claim now carries that shift. With β=23, the value v and the true p(17) differ by β⋅1=23, so the check fails. Of the 43 values of β, only β=0 passes.

The cheater can also spread its lies across all the values. Let ef​ be the error in the derived f(u), and let ei​ be the error in the sent pi​(u). The difference between v and the true value of p at u is

βmef​+i=0∑m−1​βm−1−iei​,

which is a polynomial in β of degree at most m. All of its coefficients are fixed before β is chosen. If any of them is nonzero, at most m values of β make it vanish.

Fix f and u=17 as above. The cheater can send any of 433=79507 triples of values. Trying all of them against all 43 values of β shows that no triple passes for more than 3 values of β, which agrees with the fact that the error is a nonzero polynomial of degree at most 3 in β.

The cheater commits to a different polynomial

The remaining option is to commit to something other than the quotients, chosen so that the formula holds with true values at as many points as possible. Suppose the claims use d distinct points. Clearing denominators by multiplying through by the product of the u−xi​ for those points turns the requirement into a polynomial equation in u of degree at most n−1+d. It is not identically zero as long as the combined fraction has a pole. The cheater therefore matches at most n−1+d values of u. In our example only one claim is false, which leaves one pole, and the count is n:

The cheater can make the committed polynomial match the verifier's formula at a few values of u by interpolation. Through the four points u∈{3,11,17,30} it gets f′(X)=20+20X+32X2+26X3, with commitment (7,6). If the challenge lands on one of these four values, the cheater reports true values and passes for every β. If it lands anywhere else among the 40 allowed values, this polynomial does not match. We tried all 434=3,418,801 polynomials of degree at most 3. None matches the formula at more than 4 points, and exactly 91,390 reach 4, one for each choice of four points.

The numbers on the toy field are large only because the field has 43 elements:

Combining the counts bounds the best cheater on the toy curve. It wins on at most 4 of the 40 values of u outright and on at most 3 of the 43 values of β at each of the other 36, which is at most 280 of the 1720 pairs of challenges.

The cheater hopes for a cancelling alpha

Section 5 showed that false claims at a shared point can cancel for one particular α. If they do, the combined fraction has no pole, and the cheater holds a genuine f that passes everything afterwards. With m claims, the leftover remainder at a point is a nonzero polynomial in α of degree at most m−1, so at most m−1 values of α remove it.

Adding the three stages gives a bound of ((m−1)+(n−1+d)+ℓ)/∣F∣, where ℓ is the number of polynomials. The running example has ℓ=m, and Section 10 covers claims that share a polynomial, for which ℓ is smaller.

For n=213, with the six claims, four points and four polynomials from Section 1, the three bounds add up to (5+8195+4)/∣F∣=8204/∣F∣. For a field of about 2254 elements, as with the Pasta curves, this is below 2−240. The fuse step draws β from a 143-bit endoscalar, as Section 13 notes, and with that range the β term alone is about 4/2143=2−141 and dominates the sum.

Fiat–Shamir lets a cheater retry privately, so as chapter 03 explains, the chance grows with the number of attempts. We make no claim about Ragu's overall security level here.

Each challenge has to come after the message it tests

All of these counts assume the cheater does not know a challenge when it sends the message that the challenge tests. The protocol fails if any challenge arrives early:

Suppose the cheater learns α=11 before it makes its two claims at the point 9. It claims p0​(9)=38 and p1​(9)=39, whose errors 42 and 11 satisfy 11⋅42+11=0 modulo 43. Both claims are false, yet α(p0​−38)+(p1​−39) is divisible by X−9, which gives the genuine polynomial f=18+9X+37X2. This cheater passes for all 42 values of u and all 43 values of β, a total of 1806 of 1806 runs.

Suppose the cheater learns u=17 before it commits. The interpolated polynomial f′ from earlier in this section matches the formula at that point, so the cheater commits to it, reports true values, and passes for all 43 values of β.

Suppose the cheater learns β=23 before sending the values at u=17. It sends 38 for p1​(17), with the shift 27 solved from the one linear equation that makes the total error vanish at this β. The check passes. Moving to β=24 makes the same message fail.

Binding at the end

The check on (P,u,v) means something only because P can be opened in one way. Every polynomial above was fixed by its commitment, and a prover who knows a relation among the generators loses that restriction:

Using the known discrete logs of the toy generators, a prover can adjust entries 0 and 1 of p to get p′=(26,41,29,8). This vector commits to the same P=(14,9) and evaluates to 33 at u=17, not 32. A prover with this ability could satisfy the final check for a wrong v, which is why the discrete log relation assumption is necessary.

10. Claims that share a polynomial or a point

The running example gave each claim its own polynomial, while Section 1 listed two claims each about a and k. The protocol needs only a small change for this. The prover's values at u depend on the polynomial and not on the original point, so it sends one value per polynomial, and each claim about that polynomial reuses the value. As a result the formula for f(u) still has one term per claim, whereas p has one term per polynomial. Writing ℓ for the number of polynomials and ji​ for the polynomial that claim i refers to, the formulas become

f(u)p(X)​=i=0∑m−1​αm−1−iu−xi​pji​​(u)−yi​​,=βℓf(X)+j=0∑ℓ−1​βℓ−1−jpj​(X).​

This explains the proof-size count in Section 1, since six claims need only four values.

Add a fourth claim, p0​(2)=12. This claim reuses p0​ and also shares the point 2 with claim 2. The quotient polynomial gains one term, f(X)=α3q0​+α2q1​+αq2​+q3​ with q3​=24+11X+3X2, and becomes f(X)=14+28X+31X2 with commitment F=(16,10) at α=11. The prover still sends only the three values 14,11,1, because both claims about p0​ use the same number 14 when the verifier derives f(17)=32. The output at β=23 is P=(8,22) and v=28, and opening p=5+2X+19X2+8X3 confirms both.

Two claims may also share a point, as claims 2 and 3 do here. The verifier then needs only one inverse of u−xi​, and the α weights keep the claims apart as Section 5 showed. Two claims about the same polynomial at the same point with different values cannot both be true, and the code rejects such a list before batching.

The Ragu Book and the code differ here

The book notes that only one evaluation per polynomial is needed, but its formulas for p and v still index βipi​ by claim. The prover at commit 3219e08 loops over polynomials, so each polynomial appears once in p. This site follows the code.

11. Blinding factors

The book's protocol uses hiding commitments, written Cˉi​ and Fˉ with blinding factors γi​ and γf​. Blinding factors combine with the same weights as the polynomials, as chapter 06 showed, so the prover sets γ=βmγf​+∑i​βm−1−iγi​, and the verifier's formula for the commitment does not change in form.

Take blinding factors γ0​,γ1​,γ2​=17,29,11 and γf​=5. The blinded commitments are Cˉ0​=(5,29), Cˉ1​=(8,9), Cˉ2​=(9,9) and Fˉ=(26,23). The verifier combines them into Pˉ=(24,1). The prover computes γ=41⋅5+13⋅17+23⋅29+11=29 modulo 43, and ⟨p,G⟩+29⋅H=(24,1), the same point.

The warning in chapter 06 applies here as well. At commit 3219e08 the IPA code omits this term, and the fuse step commits to f with no blinding factor.

12. Relation to SHPLONK and Halo 2

The Ragu Book credits this technique to SHPLONK, by Boneh, Drake, Fisch and Gabizon. That paper works with KZG commitments and treats polynomials opened at sets of points. In its second scheme, the prover commits to

h(X)=i∑​γi−1ZSi​​(X)fi​(X)−ri​(X)​,

where ZSi​​ vanishes on the point set of fi​, and ri​ interpolates the claimed values on that set. When each set holds one point, ri​ is the constant yi​ and ZSi​​ is X−xi​, so h is our f with the weights in a different order.

The two protocols then part ways. SHPLONK's verifier sends a random z, and instead of receiving values there it builds a commitment to a polynomial L that must vanish at z. In the one-point case with distinct points, with T the set of all points and ZT​ its vanishing polynomial, that polynomial is

L(X)=i∑​γi−1z−xi​ZT​(z)​(fi​(X)−yi​)−ZT​(z)h(X).

Every coefficient here is a number the verifier can compute, so it can derive the commitment to L from the input commitments and the commitment to h. Dividing the formula by ZT​(z) and setting X=z gives the same relation as Section 6, which shows that L(z)=0 for honest polynomials. The paper finishes with one KZG opening of L at z. We can run this form on our example, taking a Pedersen commitment to a constant y as y⋅G0​ and using z=u with our α weights:

In our run ZT​(u)=21, and the construction gives L(X)=11+26X+16X2+31X3. Substituting u=17 gives 0, and the combination of Ci​, yi​ and F gives the commitment (25,2), which matches L directly. The prover sent no values at u for this check.

Ragu instead has the prover send the values at u and combines them under β. This matches the multipoint opening in Halo 2, which also forms a combination of quotients, evaluates it at a fresh challenge using the opened polynomials' values, and adds the result to those polynomials under one more challenge. Halo 2 first groups polynomials by their set of query points and interpolates over each set, whereas Ragu gives every claim its own term and needs no interpolation.

This comparison is our own reading of these sources, except that we could not retrieve the SHPLONK paper's text when checking this chapter, so the formulas for h and L above are unverified against it. Neither the Ragu Book nor the code explains why Ragu sends the values instead of using SHPLONK's L.

13. Batching in Ragu

The clearest place to see this protocol in the code is the compression path, whose module comment describes the same steps. The prover divides by X−xi​ without using the claimed value, as Section 3 predicted, then writes F, squeezes u, writes the values, and squeezes β. The verifier computes f(u) and v by Horner's rule, which is how the weights from Section 7 arise. This excerpt comes from compress/batch/verifier.rs at commit 3219e08:

let mut f_at_u = C::Scalar::ZERO;
for claim in claims {
    let denominator = (u - claim.point)
        .invert()
        .ok_or_else(|| Error::InvalidWitness("u lands on a query point".into()))?;
    f_at_u = f_at_u * alpha + (batch.evaluations[claim.poly] - claim.value) * denominator;
}

let mut value = f_at_u;
for &evaluation in &batch.evaluations {
    value = value * beta + evaluation;
}

Each pass through the first loop multiplies everything so far by α, so the first claim ends up with the highest power. The second loop starts from f(u), which therefore gets the highest power of β. The index claim.poly is the ji​ of Section 10.

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

The fuse step runs the same reduction with the same weights, spread across _08_f.rs, _09_eval.rs and _10_p.rs, with the verifier's arithmetic in the compute_v circuit. It differs from the description above in two ways that later chapters cover. The values at u go into a committed stage rather than being sent directly, which is the subject of staging. The challenge β is also derived from a 143-bit endoscalar rather than taken as a full field element, which is the subject of endoscalars.

The chapter on split accumulation wraps this protocol so that the output triple becomes a running accumulator, and the chapter on curve cycles divides its arithmetic between two circuits. We stop before both, since each depends on recursion, which we have not reached.

14. Where this chapter leaves us

This chapter took the following steps:

  1. A claim p(x)=y holds exactly when p(X)−y is divisible by X−x, so a true claim has a quotient polynomial and a false one does not.
  2. The relation q(u)=(p(u)−y)/(u−x) moves a claim from x to a new point u, because the verifier can compute the quotient's value from the value of p.
  3. Alpha batching commits to one combination f of all the quotients, with random weights that stop errors at a shared point from cancelling.
  4. The prover sends one value per polynomial at a random u, and the verifier derives f(u) from those values and the original claims.
  5. Beta batching combines f and the polynomials at u into one triple (P,u,v), and every input needs a distinct weight.
  6. A false claim survives only if a challenge lands on one of a small number of bad values, provided that each challenge comes after the message it tests.

Together with the inner product argument, this gives a single short opening for all of a proof's evaluation claims. The next chapter assembles the arithmetization, the polynomial encoding, the commitments and this batching into one complete proof.

Last Updated: 11/4/26, 12:56 PM
Contributors: Hanh
Prev
The Inner Product Argument
Next
The Complete Proof