Polynomial Commitments
The previous two chapters reduced a computation to claims about polynomials built from the prover's secret data. The verifier must now check those claims without receiving the polynomials. A polynomial with thousands of coefficients is too large to send in every recursive step, and sending it would also expose secret data. A polynomial commitment solves both problems by replacing the polynomial with one short value that the prover cannot later change.
This chapter builds the commitment Ragu uses. We start with a commitment to a vector, read a polynomial as its vector of coefficients, and then rewrite an evaluation as a statement about an inner product. The next chapter proves that statement with a short argument.
1. What a polynomial commitment provides
Suppose a prover holds a polynomial and a verifier holds nothing. The two parties want to run the following exchange:
- The prover sends a short commitment to .
- The verifier later picks a point .
- The prover sends along with a proof that is correct for the polynomial behind .
The verifier gets evidence about from one evaluation because two different low-degree polynomials rarely agree at a random point, as Statements and Challenges showed. This exchange only works if the prover fixes before seeing , so the commitment must be binding: the prover must not be able to open to a second polynomial. When contains secrets, the commitment should also be hiding, which means reveals nothing about .
A hash of the coefficients is binding and short, which makes it a natural first candidate. Hashes have no algebraic structure, however, so the only way to prove something about from its hash is to run the entire hash computation inside a proof. Ragu's accumulation scheme also needs to combine commitments directly, and the hash of a sum has no relation to the hashes of its parts. Elliptic curve points provide the missing structure, because adding two commitments gives a commitment to the sum. Sections 3 to 6 build this commitment and show why it has both properties. Sections 7 to 9 then connect it to polynomial evaluation.
2. The toy curve
The curve groups used in real systems have about elements, which makes their arithmetic unreadable on a page. Every worked example on this site uses a much smaller curve instead:
This curve has 43 points including the identity . The curves appendix lists the parameters.
Two different moduli
The worked examples use two different moduli, and it helps to separate them from the start. Coordinates of points belong to the field the curve is defined over, so we compute with them modulo 31. Here is one point operation carried out on coordinates:
Doubling uses the tangent slope, computed modulo 31: . The new coordinates are and , so .
Scalars count how many times we add a point to itself, and they behave differently. Adding a point to itself repeatedly eventually returns to , and the multiples then repeat:
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 41 | |
| 42 |
One more addition gives , and one after that gives . The multiples repeat with period 43, so only the value of a scalar modulo 43 affects the result.
The group has 43 elements, so scalars are computed modulo 43. Since 43 is prime, every point other than generates the whole group in the same way. From here on, we write for the scalars and treat point addition as a single operation.
Public parameters

We fix six points as public parameters. A real system derives such points by hashing, so that no one knows a relation among them. The next table picks points spaced across the -coordinates instead, which keeps the example readable.
| Name | Point |
|---|---|
The toy curve is deliberately insecure. Anyone can compute its discrete logs by counting, and Section 4 uses this weakness to show what goes wrong when a discrete log is known.
3. Committing to a vector
To commit to one scalar , the prover could send for a public generator . This has both properties we want for a large group. Recovering from the point requires solving discrete log, which hides as long as it is hard to guess. The prover also cannot open the point to a second scalar, because the multiples of are all distinct until they repeat, so each point corresponds to exactly one scalar modulo the group order.
A vector needs more than this, since sending one point per entry would produce a commitment as long as the vector. Adding those points into one point keeps the size constant. If we used the same generator for every entry, the sum would be , which depends only on the sum of the entries and loses their positions.
The vectors and have the same entries in different positions. With in every position, both produce . With a separate generator for each position, they produce and .
A separate generator for each position avoids this collision, because moving a value to a different position changes which generator multiplies it. For and public generators , this gives the Pedersen vector commitment
The result is one curve point regardless of . Here is the computation for a vector of four entries:
Take . Scalars live in , and each point sum follows the curve addition law over .
| Term | Point | Running sum |
|---|---|---|
The commitment is the single point .
4. Why a prover cannot change the vector
Suppose a prover opens the same commitment to two different vectors and . Subtracting the two expressions for gives
where at least one coefficient is nonzero, since the vectors differ. A second opening therefore requires a nontrivial linear relation among the generators.
A relation of this kind is equivalent to knowing a discrete log. To see this for two generators, suppose with . Moving the first term across and dividing by gives
which expresses as a known multiple of . If nobody can find such a multiple, nobody can open a commitment in two ways. Binding rests on this assumption, called the discrete log relation assumption. It also explains how real systems choose generators. If someone produced by multiplying by a chosen scalar, that person would know the relation and could forge openings, so real generators come from a hash whose output has no known relation to the other points.
On the toy curve we can compute such a relation directly, so we can run the argument above in reverse to produce a forgery:
Counting multiples of shows that , so . Adding this relation to the honest vector gives with scalars reduced modulo 43. Computing gives , the same point as , so this commitment now has two valid openings.
The next table compares the two computations term by term. The change to entry 0 and the change to entry 1 cancel exactly, so the later terms and the total stay the same.
| Part of the sum | Honest vector | Forged vector |
|---|---|---|
| Entry 0 term | ||
| Entry 1 term | ||
| Sum of entries 0 and 1 | ||
| Entries 2 and 3 | Unchanged | Unchanged |
| Commitment |
A prover who can do this on a real curve could change the committed polynomial after seeing the challenge. On a curve of 255 bits, no known method finds such a relation in practice.
5. Adding commitments
Point addition is commutative and scalar multiplication distributes over it, so we can regroup the terms of two commitments by generator:
Multiplying a commitment by a scalar regroups in the same way:
Written with the inner product notation, these are two identities that hold for any vectors and any scalar :
Pedersen commitments are therefore linearly homomorphic, meaning anyone can compute a commitment to a linear combination of vectors from the commitments alone, without seeing the vectors. The toy curve confirms both identities:
With , the commitment is . Adding points gives . Committing directly to the sum gives , the same point. Scaling works the same way: , and committing to gives .
Much of the later construction depends on this property. Batched openings and accumulation both replace many committed polynomials with one random linear combination, and the verifier can compute the combined commitment using only group operations.
6. Hiding the vector
The commitment above is deterministic, so anyone who can guess can recompute and test the guess. An observer holding can try one candidate after another:
| Guess | Recomputed commitment | Matches |
|---|---|---|
| No | ||
| No | ||
| Yes |
This matters whenever the vector comes from a small set of likely values. Adding a term with a random blinding factor and one more generator prevents this test:
Hiding now follows from a counting argument. Fix any point and any candidate vector . The difference is some group element, and because generates the group, exactly one satisfies equal to that difference. Every candidate vector therefore explains the point equally well, so alone gives no information about .
Committing to with blinding factors and gives and . Both differ from the unblinded , and without the blinding factor an observer cannot test a guessed vector against either point.
The next example applies the counting argument to one specific point:
Take the blinded commitment made from with . The unrelated vector also explains this point, using : . An observer sees one point, and every candidate vector has exactly one blinding factor that fits it.
The other properties carry over. An opening now consists of the pair , and binding still holds under the same assumption once joins the list of generators, because two openings would again produce a relation among the points. Adding two blinded commitments gives a blinded commitment to the sum of the vectors, whose blinding factor is the sum of the two blinding factors.
The Ragu Book and the code differ here
The Ragu Book's NARK chapter describes hiding commitments with blinding factors. The IPA module at commit 3219e08 states that "Pedersen blinding with generator W is omitted for now because compression currently proves unblinded relations", and its commit function has no blinding term. This site reads the book as the intended design and the code as the current state of the implementation. The authors have not confirmed this reading.
7. Committing to a polynomial
A polynomial of degree less than is determined by its coefficients, which gives a direct route from vectors to polynomials:
A commitment to is the Pedersen commitment to . Adding commitments now corresponds to adding polynomials, because adding polynomials adds their coefficients. The degree bound comes from the number of generators, so a set of generators can commit only to polynomials of degree below . A polynomial of lower degree fits by treating its missing coefficients as zero:
The polynomial has degree 1, so its vector is padded with zeros to . Its commitment is , because the zero entries contribute .
The argument in the next chapter halves the vector in each round, which is why is a power of two.
8. Writing an evaluation as an inner product
Next we need a way to express in terms of the committed vector. Expanding the definition of at a point gives
An evaluation is therefore an inner product between the secret coefficient vector and a public vector, since anyone can compute the powers of . The rewriting matters because the claim is now linear in . Each coefficient appears once, multiplied by a value the verifier already knows, and this is the same kind of expression as the commitment itself.
Let over , whose coefficient vector is the from Section 3, and take .
| 0 | 7 | 1 | 7 |
| 1 | 2 | 9 | 18 |
| 2 | 5 | 38 | 18 |
| 3 | 3 | 41 | 37 |
The last column sums to modulo 43. Direct substitution into gives , the same value.
Evaluations of linear combinations
Evaluation combines with the homomorphic property from Section 5. Evaluation is linear in the coefficients, so for any polynomials and with coefficient vectors and , and any scalar ,
Commitments and evaluations therefore combine with the same coefficients. A verifier holding two commitments and two claimed evaluations can compute the commitment and the evaluation of the combination without seeing either polynomial.
Take with the vectors and from Section 5, each read as a polynomial, at . Their evaluations are and . The combined vector is , and its polynomial evaluates to at , which equals modulo 43. Its commitment is , which equals .
The chapter on batched openings uses this fact to reduce many evaluation claims to one.
9. Combining the commitment and the claim
The prover must now show two facts about one vector at once: opens the commitment , and . Proving these facts separately would not be enough, since a prover could satisfy the first with one vector and the second with another. The two facts must apply to the same vector, so we package them into a single point. Taking the extra generator , the prover and verifier both compute
and the prover claims to know satisfying
This form works because is a Pedersen commitment to the entries under the generators . The binding argument from Section 4 now applies to the longer list. If the last entry is anything other than the true inner product, the prover must know a relation among these generators, including .
To see why the same vector appears in both facts, read the two terms of the equation together. The vector that multiplies is also the vector whose inner product with multiplies , so one vector has to satisfy both parts. The verifier can compute from public values alone, because it holds and .
The statement point is . Treating it as a five-entry commitment to under the generators gives , the same point. A prover claiming instead has the statement point , which does not match the honest computation from the coefficients.
The generator must have no known relation to . If a prover knows those relations, the argument from Section 4 runs in reverse, as it did for the forged opening:
Counting gives the discrete logs of and relative to : , , and . The prover wants to claim the false value , whose statement point is . With every point written as a multiple of , the equation for becomes one linear equation over in the four entries of the vector. Keeping entries 1 to 3 fixed and solving for entry 0 gives . This vector has inner product with the power vector, and , so it satisfies the equation for the false statement point. The vector does not open and does not evaluate to , yet the check passes.
Choosing the point after the commitment
The verifier also has to choose after the prover commits. If the order is reversed, one evaluation says little about the committed polynomial:
Suppose the prover learns before committing. It can then take , a different polynomial that has the same value at this point: . A check at cannot distinguish the two polynomials, even though their commitments and differ.
When the commitment comes first, the prover has to fix the polynomial with no knowledge of , so the random-point test from Statements and Challenges applies. A prover who commits to and hopes it matches a different polynomial at , with both of degree at most , has at most a chance of success.
Take the different polynomial . Evaluating and at all 43 points of finds agreement only at . A uniformly random challenge therefore misses the difference with probability , which is the Schwartz–Zippel bound for degree 3. On a curve the size of Pallas, the same bound is below for any polynomial of the degree Ragu uses.
A complete run with the coefficients revealed
We can now run the whole exchange on the toy curve. In this version the prover finishes by revealing the coefficients, which gives the verifier everything it needs to check the equation directly:
| Step | Party | Value or check |
|---|---|---|
| 1 | Prover commits | |
| 2 | Verifier sends a challenge | |
| 3 | Prover sends the claimed value | |
| 4 | Prover reveals the coefficients | |
| 5 | Verifier computes the statement point | |
| 6 | Verifier computes the power vector | |
| 7 | Verifier computes the inner product | |
| 8 | Verifier checks the equation | , which equals |
This run confirms the claim, but steps 4 and 8 are the problem. Step 4 sends all coefficients, which exposes them and removes the size benefit of the commitment. Step 8 costs the verifier one group operation per generator. The next chapter replaces the reveal with a short argument:
For with 32-byte values, revealing the coefficients costs bytes. An argument with group elements costs bytes, plus a small constant number of extra values.
We can now state exactly what that argument must prove:
10. Comparison with KZG
The most widely known alternative is KZG, which takes a different route to the same interface. KZG requires a setup that publishes the points for a secret scalar , and the commitment to is the point . To open at , the prover sends a commitment to the quotient , which is a polynomial exactly when . The verifier checks this relation at with a pairing, a special bilinear map between curve groups.
KZG proofs are one group element, and their verification cost does not depend on . In exchange, KZG requires pairing-friendly curves and a trusted setup, because anyone who learns can forge openings. Ragu avoids a trusted setup and uses the Pasta curves, which Zcash already deploys in Orchard. The cost of that choice is a verifier whose work grows linearly with , and most of the recursion chapters exist to manage this cost.
11. The commitment in Ragu
The core of Ragu's commitment function matches the definition from Section 3. The function asserts that the coefficient count is exactly and then runs a multi-scalar multiplication over the generators, here from crates/ragu_pcd/src/ipa/mod.rs at commit 3219e08:
pub fn commit<B: SelectableBackend>(&self, poly: &[C::Scalar]) -> C::Projective {
assert_eq!(poly.len(), self.n as usize);
msm::multiexp::<C, B>(poly, &self.g)
}
Reconstructed from code at commit 3219e08, not confirmed by the authors
The Ragu Book writes the opening relation as in Section 9, with a generator in place of . The prover code, adapted from halo2, first adds a random multiple of a masking polynomial's commitment and subtracts the claimed value from the constant coefficient, then proves that the resulting polynomial has a root at . Its generator enters during the rounds of the argument. Both forms establish the same evaluation claim, and we compare them step by step in the next chapter.
12. Where this chapter leaves us
This chapter took the following steps:
- A Pedersen vector commitment compresses a vector into one curve point, with one generator per position.
- Binding holds as long as nobody knows a relation among the generators, and a blinding factor adds hiding.
- Commitments add in the same way as the vectors behind them.
- A polynomial is committed through its coefficient vector, and its evaluation at is an inner product with the powers of .
- The point combines the commitment and the claimed value into one statement about one vector.
- A random chosen after the commitment makes one evaluation meaningful, because distinct low-degree polynomials rarely agree there.
Nothing yet makes the proof of the final statement short. The next chapter supplies that step by halving the vector repeatedly.