Skip to main content
Try out the RareSkills ZK AI Tutor!
The RareSkills Book of Zero Knowledge

Range Proof

Last updated on Nov 20, 2024

A range proof in the context of inner product arguments is a proof that the scalar v has been committed to V and v is less than 2n for some non-negative integer n.

This article shows how the Bulletproofs paper constructs such a proof. The high level idea is that if we can prove that a vector 𝐚L consists only of ones and zeros and that 𝐚L is the binary representation of v, then v must be less than 2n. This is analogous to saying that a number that fits in an 8 bit unsigned integer must be less than 256.

The advantage of using Bulletproofs for range proofs is that the range proof can be directly constructed without the need of an arithmetic circuit.

Monero uses Bulletproof Range Proofs (the algorithm presented here) to ensure that the sum of transactions is not negative (in a finite field, the negative numbers are the elements greater than p/2 as they are additive inverses of the elements less than or equal p/2 where p is the field order).

This article is part of a series on ZK Bulletproofs.

Notation

𝟎n is an n dimensional vector of all zeros.

𝟏n is an n dimensional vector of all ones.

𝟐n is an n dimensional vector [1,2,4,8,...,2n−1]

𝐲n is an n dimensional vector [1,y,y2,y3,...,yn−1]

𝐲−n is an n dimensional vector [1,y−1,y−2,...,y−(n−1)]

Note that 𝐲n∘𝐲−n=𝟏n.

Range proof overview

Proving that V is a commitment to a scalar with a value less than 2n requires proving the following:

  1. 𝐚L is binary (only holds values 0 and 1).
  2. The inner product ⟨𝐚L,𝟐n⟩=v.

The second point is easy to prove, we do a normal inner product proof then reveal 𝟐n is one of the vectors in the commitment – or have the verifier construct the commitment of 𝟐n themselves. However, proving that 𝐚L is binary without an arithmetic circuit requires a couple algebraic tricks.

Four useful tricks

The bulletproofs paper implicitly uses four algebraic tricks that are best taught explicitly before looking at the range proof algorithm directly.

1. Proving 𝐚L is binary

The statement 𝐚L is binary is equivalent to the following two assertions:

  • 𝐚R=𝐚L−𝟏n
  • 𝐚L∘𝐚R=𝟎n

For example, if 𝐚L=[1,0,0,1] then 𝐚R=[0,−1,−1,0].

In this case, 𝐚L∘𝐚R=𝟎n because

[1,0,0,1]∘[0,−1,−1,0]=[0,0,0,0]=𝟎n

Now consider a case where 𝐚L is not binary, for example [2,1,0,0]. 𝐚R will be [1,0,−1,−1] The Hadamard product of 𝐚L and 𝐚R will be [2,0,0,0]≠𝟎n.

More generally, if 𝐚L has a non-binary entry, that entry will be subtracted by 1, and the resulting entry in 𝐚R will be non-zero. When the Hadamard product is computed, then at that particular index, 𝐚L and 𝐚R will both be non-zero and the product will be non-zero, meaning 𝐚L∘𝐚R≠𝟎n.

However, if a particular entry in 𝐚L is 1, then 𝐚R will be 0 at that index so that the Hadamard product at that index will be zero, too.

Finally, if a particular entry in 𝐚L is 0, then 𝐚R will be −1 at that index and their element-wise product will still be zero at that index.

Therefore, if 𝐚L is binary and 𝐚R is computed as 𝐚R=𝐚L−𝟏, then 𝐚L∘𝐚R=𝟎n.

2. Proving a vector is all zero

Suppose we wish to prove that the Pedersen commitment A holds a zero vector. We create the Pedersen commitment A=⟨𝐚,𝐆⟩+αB and wish to prove to a verifier that 𝐚=𝟎n.

It might seem sufficient to simply send the blinding term α, but to make our solution more composable, we do not want to reveal the blinding term because that might affect other commitments we have created.

Instead, the prover sends A to the verifier, and the verifier responds a vector full of random values 𝐫. The prover must now prove that

⟨𝐚,𝐫⟩=0

Note that this is a probabilistic test. It is possible, with negligible probability, that ⟨𝐚,𝐫⟩=0 for 𝐚≠𝟎n, but it is not possible for the prover to forge such an 𝐚 because they do not know in advance what 𝐫 will be.

However, transmitting 𝐫 requires 𝒪(n) communication overhead, so the verifier instead only sends a single random element y and the prover computes 𝐲n and uses 𝐲n as a the random vector.

Then, the prover proves that ⟨𝐚,𝐲n⟩=0.

3. Proving an inner product is of the form ⟨𝐚L,𝐚R∘𝐲n⟩ where y is chosen by the verifier and the prover computes 𝐲n

We don’t yet have a mechanism to prove that 𝐚L∘𝐚R=𝟎n, as that is a Hadamard product, not an inner product. However, stating the vector 𝐚L∘𝐚R is identically 𝟎n is the same as stating that ⟨𝐚L∘𝐚R,𝐲n⟩=0. By the inner product rules, we can move 𝐚R to the other side of the inner product and we now have ⟨𝐚L,𝐚R∘𝐲n⟩=0.

The verifier will receive commitments to 𝐚L and 𝐚R, not 𝐚R∘𝐲n. It will be up to the verifier to construct a commitment to 𝐚R∘𝐲n so they are convinced the prover used 𝐚R∘𝐲n as the second vector in the inner product.

The key trick we rely on is that the prover uses the basis vectors 𝐆 and 𝐇 to commit their vectors, but the verifier uses 𝐆 and 𝐇∘𝐲−n.

When the prover sends the evaluation 𝐫u, the prover must ensure that 𝐲n terms will cancel with the 𝐲−n in the verifier’s basis vector 𝐲−n∘𝐇.

Specifically, the prover constructs the commitments

A=⟨𝐚L,𝐆⟩+⟨𝐚R,𝐇⟩+αBS=⟨𝐬L,𝐆⟩+⟨𝐬R,𝐇⟩+βB

And sends (A,S) to the verifier. There is no need to commit and send V because it is zero in this case.

The prover’s polynomials will be

𝐥(x)=𝐚L+𝐬Lx𝐫(x)=𝐚R∘𝐲n+𝐬R∘𝐲nx

Crucially, the prover has Hadamard multiplied 𝐬R by 𝐲n. Previously, 𝐫(x) was computed as 𝐫(x)=𝐚R∘𝐲n+𝐬Rx (without the 𝐲n∘𝐬R. This will later allow all of the 𝐲n terms to be canceled when the verifier computes the commitment ⟨𝐫u,𝐲−n∘𝐇⟩. Under the hood, 𝐫u is (𝐚R+𝐬Ru)∘𝐲n so the 𝐲n will cancel when the verifier computes ⟨(𝐚R+𝐬Ru)∘𝐲n,𝐲−n∘𝐇⟩, i.e.

⟨(𝐚R+𝐬Ru)∘𝐲n,𝐲−n∘𝐇⟩=⟨(𝐚R+𝐬Ru),𝐲n∘𝐲−n∘𝐇⟩=⟨(𝐚R+𝐬Ru),𝟏n∘𝐇⟩=⟨(𝐚R+𝐬Ru),𝐇⟩

However, the prover cannot compute 𝐥(x) or 𝐫(x) yet because the verifier hasn’t sent y yet. Therefore, after receiving (A,S) the verifier sends y and the prover computes 𝐲n and computes the polynomial t(x):

t(x)=⟨𝐥(x),𝐫(x)⟩=⟨𝐚L,𝐚R∘𝐲n⟩+t1x+t2x2

where

t1=⟨𝐚L,𝐬R∘𝐲n⟩+⟨𝐬L,𝐚R∘𝐲n⟩t2=⟨𝐬L,𝐬R∘𝐲n⟩

The prover commits to the coefficients t1 and t2 as

T1=t1G+τ1BT2=t2G+τ2B

and sends (T1,T2) to the verifier. The verifier responds with u and the prover evaluates the vector polynomials 𝐥(x) and 𝐫(x):

𝐥u=𝐚L+𝐬Lu𝐫u=𝐚R∘𝐲n+(𝐬R∘𝐲n)utu=⟨𝐥u,𝐫u⟩πlr=α+βuπt=τ1u+τ2u2

Note that πt only includes the blinding terms for t1 and t2. In the previous implementation, πt was computed as γ+τ1u+τ2u2, where γ is the blinding term for V, which is also the constant coefficient of the polynomial t(x).

There is no blinding term γ because there is no commitment to V, i.e. v is not secret – it is 0. The prover sends (𝐥u,𝐫u,tu,πlr,πt) and the verifier checks that:

tu=?⟨𝐥u,𝐫u⟩A+Su=?⟨𝐥u,𝐆⟩+⟨𝐫u,𝐲−n∘𝐇⟩+πlrBtuG=?T1u+T2u2−πtB

The first crucial difference is that the commitment to 𝐫u is done with respect to the basis vector 𝐲−n∘𝐇 instead of 𝐇 for the reasons discussed earlier.

Second, tuG=?T1u+T2u2−πtB has no constant commitment. Normally, the equation is tuG=?V+T1u+T2u2−πtB, but V is a commitment to 0 in this case.

In general, if V contains values known to the verifier, the verifier can construct the commitment to V as we show in the next section.

4. Proving an inner product when an additive public constant is involved

As alluded in the section above, the verifier can reconstruct commitments if the verifier knows the underlying vector.

For example, suppose we are proving that

⟨𝐚L+𝐣,𝐚R∘𝐲n+𝐤⟩=vz

where 𝐣 and 𝐤 are a vectors known to the verifier and z is a scalar known to the verifier in advance. Unlike 𝐲n, these vectors and scalar are known before the proof begins. Note that 𝐤 is not Hadamard multiplied by 𝐲n in this example.

The prover still only commits to the secret values 𝐚L, 𝐚R and v as usual:

A=⟨𝐚L,𝐆⟩+⟨𝐚R,𝐇⟩+αBS=⟨𝐬L,𝐆⟩+⟨𝐬R,𝐇⟩+βBV=vG+γB

As usual, the polynomials 𝐥(x) and 𝐫(x) are such that the constant term is the vector from the original inner product and the linear terms are 𝐬L and 𝐬R. Upon receiving y from the verifier, the prover computes 𝐲n and crafts but does not evaluate 𝐥(x) and 𝐫(x):

𝐥(x)=𝐚L+𝐣⏟left vector+𝐬Lx𝐫(x)=𝐚R∘𝐲n+𝐤⏟right vector+𝐬R∘𝐲nx

Note that 𝐤 is not Hadamard multiplied with 𝐲n, but the linear term 𝐬R still is. We will show how the verifier handles this later.

For now, we compute t(x) as

t(x)=vz+t1x+t2x2

where

t1=⟨𝐚L+𝐣,𝐬R∘𝐲n⟩+⟨𝐬L,𝐚R∘𝐲n+𝐤⟩t2=⟨𝐬L,𝐬R∘𝐲n⟩

Note that the constant term in t(x) is vz and not v. The commitments are computed as

T1=t1G+τ1BT2=t2G+τ2B

and sent to the verifier who then sends the random value u.

The prover computes:

𝐥u=𝐚L∘𝐲n+𝐣+(𝐬L∘𝐲n)u𝐫u=𝐚R∘𝐲n+𝐤+𝐬Rutu=⟨𝐥u,𝐫u⟩πlr=α+βuπt=vz+τ1u+τ2u2

Note that the constant term in πt is γz. The prover sends (𝐥u,𝐫u,tu,πlr,πt). Finally, the verifier computes:

tu=?⟨𝐥u,𝐫u⟩A+Su+⟨𝐣,𝐆⟩⏟commitment to 𝐣 in 𝐥(x)+⟨𝐤,𝐲−n∘𝐇⟩⏟commitment to 𝐤 in 𝐫(x)=?⟨𝐥u,𝐆⟩+⟨𝐫u,𝐲−n∘𝐇⟩+πlrBtuG=?Vz+T1u+T2u2−πtB

𝐥u and 𝐫u contain 𝐣 and 𝐤 respectively, but A and S do not. Hence, the verifier computes commitments to those vectors and adds them to the commitments A and S. In the case of 𝐤, the basis vector 𝐲−n∘𝐇 will cause 𝐤 to become 𝐤∘𝐲−n, so the commitment must be computed with respect to 𝐲−n∘𝐇. Finally, the blinding term πt contains vz but V does not contain z. Therefore, the prover must multiply V by z.

By computing ⟨𝐣,𝐆⟩, ⟨𝐤,𝐲n∘𝐇⟩ and Vz, the verifier can be sure the inner product computation actually included those terms.

Range proof

To prove that V is a value less than 2n we have three things to prove:

  • the inner product ⟨𝐚L,𝟐n⟩=V, i.e. 𝐚L is the binary representation of v
  • 𝐚R=𝐚L−𝟏
  • 𝐚L∘𝐚R=𝟎

The last two claims are not directly in the form of an inner product. However, we can modify them slightly to accomplish this. What we are really saying is that the vectors

  • 𝐚R−𝐚L+𝟏
  • 𝐚L∘𝐚R

are both 𝟎n. We can use the trick from a previous section to prove that they are zero. That is, the the prover needs to establish that

⟨𝐚L∘𝐚R,𝐲n⟩=𝟎

and

⟨𝐚R−𝐚L+𝟏,𝐲n⟩=𝟎

where 𝐲n is the random vector derived from the y value sent from the verifier.

The original bulletproofs paper slightly modifies the first claim as follows so that we can use the third trick in the previous section:

⟨𝐚L,𝐚R∘𝐲n⟩=𝟎

Therefore, the prover has three inner products to establish:

  1. ⟨𝐚L,𝟐n⟩=v
  2. ⟨𝐚L,𝐚R∘𝐲n⟩=𝟎n
  3. ⟨𝐚L−𝟏n−𝐚R,𝐲n⟩=𝟎n

Combining three inner products into one

The three inner products can be combined into a single one using a random linear combination with randomness z provided from the verifier.

z2⋅⟨𝐚𝐋,2n⟩+z1⋅⟨𝐚𝐋−𝟏n−𝐚𝐑,𝐲n⟩+z0⟨𝐚𝐋,𝐚𝐑∘𝐲n⟩=z2⋅v+z1⋅𝟎n+z0⋅𝟎n
z2⋅⟨𝐚𝐋,2n⟩+z⋅⟨𝐚𝐋−𝟏n−𝐚𝐑,𝐲n⟩+⟨𝐚𝐋,𝐚𝐑∘𝐲n⟩=z2⋅v

With some very hefty inner product algebra, we can combine all the inner products as follows. We show the derivation in the appendix.

⟨𝐚𝐋−z⋅𝟏n,𝐲n∘𝐚𝐑+𝐲n⋅z+z2⋅2n⟩=z2⋅v+(z−z2)⋅⟨𝟏n,yn⟩−z3⟨𝟏n,2n⟩

The terms in boxes below contain values known to the verifier, so we will construct our verification algorithm to explicitly check for those values. That is, the verifier will compute commitments to the values in the boxed terms, not the prover:

⟨𝐚𝐋−z⋅𝟏n,𝐲n∘𝐚𝐑+𝐲n⋅z+z2⋅2n⟩=z2⋅v+(z−z2)⋅⟨𝟏n,yn⟩−z3⟨𝟏n,2n⟩

To save space, the Bulletproofs paper refers to the term (z−z2)⋅⟨𝟏n,yn⟩−z3⟨𝟏n,2n⟩ as δ(y,z), so the inner product can be written as

⟨𝐚𝐋−z⋅𝟏n,𝐲n∘𝐚𝐑+𝐲n⋅z+z2⋅2n⟩=z2⋅v+δ(y,z)

Note that δ(y,z) is a value the verifier can compute.

Range Proof Algorithm

The prover chooses v and it’s binary representation 𝐚L and computes 𝐚R=𝐚L−𝟏.

The prover then randomly chooses the blinding term α and computes the combined commitment of 𝐚L and 𝐚R using basis vectors 𝐆 and 𝐇 as

A=⟨𝐚L,𝐆⟩+⟨𝐚R,𝐇⟩+αB

The prover then chooses the linear terms of the soon-to-be-created vector polynomials 𝐥(x) and 𝐫(x) as 𝐬L and 𝐬R and commits to them

S=⟨𝐬L,𝐆⟩+⟨𝐬R,𝐇⟩+βB

The prover commits the inner product to V as with respect to G of an unknown discrete log (unrelated to 𝐆):

V=vG+γB

The prover sends (A,S,V) to the verifier.

The verifier responds with random values (y,z) which the prover will use to combine the three inner products into a single one.

⟨𝐚𝐋−z⋅𝟏n,𝐲n∘𝐚𝐑+𝐲n⋅z+z2⋅2n⟩=z2⋅v+δ(y,z)

The left part of the inner product 𝐚L−z⋅𝟏 will be the constant term of 𝐥(x) and 𝐲n∘𝐚𝐑+𝐲n⋅z+z2⋅2n will be the constant term of 𝐫(x).

Thus, we construct 𝐥(x) as

𝐥(x)=𝐚L−z⋅𝟏⏟constant term+𝐬Lx

and we construct 𝐫(x) as

𝐫(x)=𝐲n∘(𝐚R+z⋅𝟏)+z2𝟐n⏟constant term+𝐲n∘𝐬Rx

Note that we element-wise multiplied 𝐬Rx with 𝐲n for the reasons we discussed in part 3 of the prerequisites section above.

The prover can now construct t(x)=⟨𝐥(x),𝐫(x)⟩ with constant coefficient t0, linear coefficient t1 and quadratic coefficient t2 as:

t0=⟨𝐚𝐋−z⋅𝟏n,𝐲n∘𝐚𝐑+𝐲n⋅z+z2⋅2n⟩t1=⟨(𝐚L−z⋅𝟏),𝐲n∘𝐬R⟩+⟨𝐲n∘(𝐚R+z⋅𝟏)+z2𝟐n,𝐬𝐋⟩t2=⟨𝐬L,𝐲n∘𝐬R⟩

where t(x)=t0+t1x+t2x2

The prover sends commitments to t1 and t2 as

T1=t1G+τ1BT2=t2G+τ2B

There is no need to commit to t0 – observe that it is exactly the inner product we are trying to prove, so the verifier already has the commitment as V.

The verifier sends randomness u and the prover computes

𝐥u=𝐥(u)𝐫u=𝐫(u)tu=𝐭(u)πlr=α+βuπt=z2γ+τ1u+τ2u2

Note that the constant term of πt is multiplied by z2 to reflect the z2⋅v term of the original inner product.

The verifier then computes a new basis vector 𝐇𝐲−1=𝐲−n∘𝐇 and runs the following checks:

tu=?⟨𝐥u,𝐫u⟩

A+Su+⟨−z⋅𝟏n,𝐆⟩+⟨z⋅𝐲n+z2⋅𝟐n,𝐇𝐲−1⟩=?⟨𝐥u,𝐆⟩+⟨𝐫u,𝐇y−1⟩+πlrB

tuG+πtB=Vz2+δ(y,z)⋅G+T1u+T2u2

Recall that the prover did not commit the entire vectors they used for the left and right side of the inner product, but only 𝐚L and 𝐛L. The rest of the vectors were additive public vectors known to the verifier, so the verifier reconstructed the commitments to the vectors by constructing commitments to the constant terms and adding them to the commitment of the secret vectors supplied by the prover.

By way of reminder, here is the original inner product with the values known to the verifier boxed:

⟨𝐚𝐋+−z⋅𝟏n,𝐲n∘𝐚𝐑+𝐲n⋅z+z2⋅2n⟩=z2⋅v+δ(y,z)

The reader is encouraged to verify that the boxed terms (values known to the verifier) in the original product were reconstructed by the verifier in the boxed terms in the set of equality checks above.

By replicating a portion of the prover’s computation, the verifier asserts that the prover actually carried out the computation as claimed.

Correctness of the verification algorithm

We now show that the final verification checks are identically correct if the prover was honest.

Below we show the exact algebra, but intuitively the verifier is “reconstructing” the left vector in the inner product 𝐚𝐋−z⋅𝟏n, the right vector in the inner product 𝐲n∘𝐚𝐑+𝐲n⋅z+z2⋅2n and the output z2v+δ(y,z).

The verifier is not given commitments to 𝐚𝐋−z⋅𝟏n and 𝐲n∘𝐚𝐑+𝐲n⋅z+z2⋅2n but to 𝐚L and 𝐚R. Similarly, the verifier is not given a commitment to the output z2v+δ(y,z) but only to v.

The additive terms and the terms element-wise multiplied by 𝐲n must be reconstructed by the verifier.

Correctness of tu=𝐭(u)

For the tu=?⟨𝐥u,𝐫u⟩ check, this is true by definition, as that is how the prover computed tu.

Correctness of the committed 𝐥(x) and 𝐫(x) with respect to A and S

For
A+Su+⟨−z⋅𝟏n,𝐆⟩+⟨z⋅𝐲n+z2⋅𝟐n,𝐇𝐲−1⟩=?⟨𝐥u,𝐆⟩+⟨𝐫u,𝐇y−1⟩+πlrB

we make the following substitution:

⟨𝐚L,𝐆⟩+⟨𝐚R,𝐇⟩+αB⏟A+(⟨𝐬L,𝐆⟩+⟨𝐬R,𝐇⟩+βB)⏟Su+⟨−z⋅𝟏n,𝐆⟩+⟨z⋅𝐲n+z2⋅𝟐n,𝐇𝐲−1⟩=?⟨𝐚L−z⋅𝟏+𝐬Lu⏟𝐥u,𝐆⟩+⟨𝐲n∘(𝐚R+z⋅𝟏)+z2𝟐n+𝐲n∘𝐬Rx⏟𝐫u,𝐇y−1⟩+(α+βu)⏟πlrB

All the 𝐆 terms cancel as follows:

⟨𝐚L,𝐆⟩+⟨𝐚R,𝐇⟩+αB+(⟨𝐬L,𝐆⟩+⟨𝐬R,𝐇⟩+βB)u+⟨−z⋅𝟏n,𝐆⟩+⟨z⋅𝐲n+z2⋅𝟐n,𝐇𝐲−1⟩=?⟨𝐚L−z⋅𝟏+𝐬Lu,𝐆⟩+⟨𝐲n∘(𝐚R+z⋅𝟏)+z2𝟐n+𝐲n∘𝐬Rx,𝐇y−1⟩+(α+βu)B

⟨𝐚R,𝐇⟩+αB+(⟨𝐬R,𝐇⟩+βB)u+⟨z⋅𝐲n+z2⋅𝟐n,𝐇𝐲−1⟩=?⟨𝐲n∘(𝐚R+z⋅𝟏)+z2𝟐n+𝐲n∘𝐬Rx,𝐇y−1⟩+(α+βu)B

The blinding terms related to B cancel as follows:

⟨𝐚R,𝐇⟩+αB+(⟨𝐬R,𝐇⟩+βB)u+⟨z⋅𝐲n+z2⋅𝟐n,𝐇𝐲−1⟩=?⟨𝐲n∘(𝐚R+z⋅𝟏)+z2𝟐n+𝐲n∘𝐬Rx,𝐇y−1⟩+(α+βu)B

⟨𝐚R,𝐇⟩+(⟨𝐬R,𝐇⟩u)+⟨z⋅𝐲n+z2⋅𝟐n,𝐇𝐲−1⟩=?⟨𝐲n∘(𝐚R+z⋅𝟏)+z2𝟐n+𝐲n∘𝐬Ru,𝐇y−1⟩

The 𝐇y−1 cancels with the 𝐲n terms:

⟨𝐚R,𝐇⟩+(⟨𝐬R,𝐇⟩u)+⟨z⋅𝐲n+z2⋅𝟐n,𝐇𝐲−1⟩=?⟨𝐚R+z⋅𝟏,𝐇⟩+⟨z2𝟐n,𝐇𝐲−1⟩+⟨𝐬Ru,𝐇⟩

Split the inner products:

⟨𝐚R,𝐇⟩+(⟨𝐬R,𝐇⟩u)+⟨z⋅𝐲n,𝐇𝐲−1⟩+⟨z2⋅𝟐n,𝐇𝐲−1⟩=?⟨𝐚R,𝐇⟩+⟨z⋅𝟏,𝐇⟩+⟨z2𝟐n,𝐇𝐲−1⟩+⟨𝐬Ru,𝐇⟩

Cancel terms that appear on both sides of the equation:

⟨𝐚R,𝐇⟩+(⟨𝐬R,𝐇⟩u)+⟨z⋅𝐲n,𝐇𝐲−1⟩+⟨z2⋅𝟐n,𝐇𝐲−1⟩=?⟨𝐚R,𝐇⟩+⟨z⋅𝟏,𝐇⟩+⟨z2𝟐n,𝐇𝐲−1⟩+⟨𝐬Ru,𝐇⟩
(⟨𝐬R,𝐇⟩u)+⟨z⋅𝐲n,𝐇𝐲−1⟩+⟨z2⋅𝟐n,𝐇𝐲−1⟩=?⟨z⋅𝟏,𝐇⟩+⟨z2𝟐n,𝐇𝐲−1⟩+⟨𝐬Ru,𝐇⟩
⟨z⋅𝐲n,𝐇𝐲−1⟩+⟨z2⋅𝟐n,𝐇𝐲−1⟩=?⟨z⋅𝟏,𝐇⟩+⟨z2⋅𝟐n,𝐇𝐲−1⟩
⟨z⋅𝐲n,𝐇𝐲−1⟩=?⟨z⋅𝟏,𝐇⟩

Move 𝐲n to the other side:

⟨z⋅𝟏,𝐇⟩=?⟨z⋅𝟏,𝐇⟩
⟨z⋅𝟏,𝐇⟩=?⟨z⋅𝟏,𝐇⟩

Correctness of the evaluation of t(u)

To see that

tuG+πtB=Vz2+δ(y,z)G+T1u+T2u2

is correct, we could substitute the terms as follows:

⟨𝐥u,𝐫u⟩⏟tuG+(z2γ+τ1u+τ2u2)⏟πtB=(vG+γB)⏟Vz2+δ(y,z)G+(t1G+τ1B⏟T1)u+(t2G+τ2B)⏟T2u2

with 𝐥u, 𝐫u, t1, t2:

𝐥u=𝐚𝐋−z⋅𝟏n𝐫u=𝐲n∘𝐚𝐑+𝐲n⋅z+z2⋅2nt1=⟨(𝐚L−z⋅𝟏),𝐲n∘𝐬R⟩+⟨𝐲n∘(𝐚R+z⋅𝟏)+z2𝟐n,𝐬𝐋⟩t2=⟨𝐬L,𝐲n∘𝐬R⟩

However, such algebra would be extremely messy. Instead, we observe that z2v+δ(y,z)G is the constant term of the vector polynomial inner product of of ⟨𝐥(x),𝐫(x)⟩. To cancel out the blinding term in γB in V, observe that πt contains z2γ, so this will cancel with the gamma term in Vz2=(vG+γB)z2.

Since Pedersen commitments are additively homomorphic, the verifier can simply compute and add δ(y,z)G to Vz2 to compute the commitment to the constant term of the polynomial t(x).

Logarithmic-sized range proof

We can reduce the size of the data transmission by sending a commitment C to 𝐥u and 𝐫u and proving that the committed vectors have inner product tu using the logarithmic-sized proof, and then verifying that

A+Su+⟨−z⋅𝟏n,𝐆⟩+⟨z⋅𝐲n+z2⋅𝟐n,𝐇𝐲−1⟩−πlrB=?C

and

tu=?⟨𝐥u,𝐫u⟩

with respect to the basis vectors 𝐆 and 𝐇𝐲−1.

Using the range proof algorithm for the subset sum

The subset sum problem asks, "given a set of numbers, does a subset (possibly including the entire set) sum up to k? For example if k=16 and the set is {3,5,7,11} the answer is yes because 5+11=16. However if k=13, then the answer is no.

The subset sum problem is NP-Complete, meaning that, similar to a Boolean circuit or arithmetic circuit, it can represent any problem in NP. That is, any problem in NP can be rewritten (the technical word is “reduced”) to a subset sum instance.

By replacing 𝟐n with [3,5,7,11], we can prove we know a solution to a subset sum without revealing the answer. Specifically, the prover would know that 𝐚L=[0,1,0,1] if k=16. In general, a one entry in 𝐚L means we include that element in the subset and a zero means it is not included in the subset.

Therefore, Bulletproofs are capable of proving knowledge of any witness for any problem in NP.

Appendix: Derivation of combining three inner products into one

Starting with the three inner products

z2⋅⟨𝐚𝐋,𝟐n⟩+z⋅⟨𝐚𝐋−𝟏n−𝐚𝐑,𝐲n⟩+⟨𝐚𝐋,𝐚𝐑∘𝐲n⟩=z2⋅v

we show how to derive the final result

⟨𝐚𝐋−z⋅𝟏n,𝐚R∘𝐲n+z⋅𝐲n+z2⋅𝟐n⟩=z2⋅v+(z−z2)⋅⟨𝟏n,𝐲n⟩−z3⟨⋅𝟏n,𝟐n⟩

using the inner product algebra we learned previously.

  1. The middle term can be split into separate inner products:
z2⋅⟨𝐚𝐋,𝟐n⟩+z⋅⟨𝐚𝐋−𝟏n−𝐚𝐑,𝐲n⟩+⟨𝐚𝐋,𝐚𝐑∘𝐲n⟩=z2⋅v
z2⋅⟨𝐚𝐋,𝟐n⟩+z⋅⟨𝐚L,𝐲n⟩+z⋅⟨−𝟏n,𝐲n⟩+z⋅⟨−𝐚R,𝐲n⟩+⟨𝐚𝐋,𝐚𝐑∘𝐲n⟩=z2⋅v
  1. We can move the constant z terms inside the inner products:

    ⟨𝐚𝐋,z2⋅𝟐n⟩+⟨𝐚L,z⋅𝐲n⟩+⟨−z⋅𝟏n,𝐲n⟩+⟨−𝐚R,z⋅𝐲n⟩+⟨𝐚𝐋,𝐚𝐑∘𝐲n⟩=z2⋅v

  2. Move the values known to the verifier to the right:

    ⟨𝐚𝐋,z2⋅𝟐n⟩+⟨𝐚L,z⋅𝐲n⟩+⟨−z⋅𝟏n,𝐲n⟩+⟨−𝐚R,z⋅𝐲n⟩+⟨𝐚𝐋,𝐚𝐑∘𝐲n⟩=z2⋅v

⟨𝐚𝐋,z2⋅𝟐n⟩+⟨𝐚L,z⋅𝐲n⟩+⟨−𝐚R,z⋅𝐲n⟩+⟨𝐚𝐋,𝐚𝐑∘𝐲n⟩=z2⋅v−⟨−z⋅𝟏n,𝐲n⟩
  1. Convert the 𝐚R terms to both be 𝐚R∘𝐲n:
⟨𝐚𝐋,z2⋅𝟐n⟩+⟨𝐚L,z⋅𝐲n⟩+⟨−𝐚R∘𝐲n,z⋅𝟏n⟩+⟨𝐚𝐋,𝐚𝐑∘𝐲n⟩=z2⋅v−⟨−z⋅𝟏n,𝐲n⟩
⟨𝐚𝐋,z2⋅𝟐n⟩+⟨𝐚L,z⋅𝐲n⟩+⟨𝐚R∘𝐲n,−z⋅𝟏n⟩+⟨𝐚𝐋,𝐚𝐑∘𝐲n⟩=z2⋅v−⟨−z⋅𝟏n,𝐲n⟩
⟨𝐚𝐋,z2⋅𝟐n⟩+⟨𝐚L,z⋅𝐲n⟩+⟨𝐚R∘𝐲n,−z⋅𝟏n⟩+⟨𝐚𝐋,𝐚𝐑∘𝐲n⟩=z2⋅v−⟨−z⋅𝟏n,𝐲n⟩
⟨𝐚𝐋,z2⋅𝟐n⟩+⟨𝐚L,z⋅𝐲n⟩+⟨𝐚R∘𝐲n,−z⋅𝟏n⟩+⟨𝐚𝐑∘𝐲n,𝐚𝐋⟩=z2⋅v−⟨−z⋅𝟏n,𝐲n⟩
  1. Combine the 𝐚R∘𝐲n terms into one:
⟨𝐚𝐋,z2⋅𝟐n⟩+⟨𝐚L,z⋅𝐲n⟩+⟨𝐚R∘𝐲n,−z⋅𝟏n⟩+⟨𝐚𝐑∘𝐲n,𝐚𝐋⟩⏟=z2⋅v−⟨−z⋅𝟏n,𝐲n⟩
⟨𝐚𝐋,z2⋅𝟐n⟩+⟨𝐚L,z⋅𝐲n⟩+⟨𝐚R∘𝐲n,𝐚L−z⋅𝟏n⟩=z2⋅v−⟨−z⋅𝟏n,𝐲n⟩
  1. Combine the two 𝐚L terms on the left:
⟨𝐚𝐋,z2⋅𝟐n⟩+⟨𝐚L,z⋅𝐲n⟩+⟨𝐚R∘𝐲n,𝐚L−z⋅𝟏n⟩=z2⋅v−⟨−z⋅𝟏n,𝐲n⟩
⟨𝐚𝐋,z⋅𝐲n+z2⋅𝟐n⟩+⟨𝐚R∘𝐲n,𝐚L−z⋅𝟏n⟩=z2⋅v−⟨−z⋅𝟏n,𝐲n⟩
  1. Split the last left-hand side term into two inner products:
    ⟨𝐚𝐋,z⋅𝐲n+z2⋅𝟐n⟩+⟨𝐚R∘𝐲n,𝐚L−z⋅𝟏n⟩=z2⋅v−⟨−z⋅𝟏n,𝐲n⟩
⟨𝐚𝐋,z⋅𝐲n+z2⋅𝟐n⟩+⟨𝐚R∘𝐲n,𝐚L⟩+⟨𝐚R∘𝐲n,−z⋅𝟏n⟩=z2⋅v−⟨−z⋅𝟏n,𝐲n⟩
  1. Combine the 𝐚L terms:
    ⟨𝐚𝐋,z⋅𝐲n+z2⋅𝟐n⟩+⟨𝐚R∘𝐲n,𝐚L⟩+⟨𝐚R∘𝐲n,−z⋅𝟏n⟩=z2⋅v−⟨−z⋅𝟏n,𝐲n⟩
⟨𝐚𝐋,𝐚R∘𝐲n+z⋅𝐲n+z2⋅𝟐n⟩+⟨𝐚R∘𝐲n,−z⋅𝟏n⟩=z2⋅v−⟨−z⋅𝟏n,𝐲n⟩
  1. We can use the rule ⟨𝐱,𝐛+𝐜⟩+⟨𝐛,𝐲⟩=v→⟨𝐱+𝐲,𝐛+𝐜⟩=v+⟨𝐲,𝐜⟩ to combine the terms that contain 𝐚R∘𝐲n. Here 𝐛 is 𝐚R∘𝐲n, 𝐜 is z⋅𝐲n+z2⋅𝟐n, and 𝐲 is −z⋅𝟏n.
⟨𝐚𝐋⏟𝐱,𝐚R∘𝐲n⏟𝐛+z⋅𝐲n+z2⋅𝟐n⏟𝐜⟩+⟨𝐚R∘𝐲n⏟𝐛,−z⋅𝟏n⏟𝐲⟩=z2⋅v−⟨−z⋅𝟏n,𝐲n⟩⏟v
⟨𝐚𝐋⏟𝐱−z⋅𝟏n⏟𝐲,𝐚R∘𝐲n⏟𝐛+z⋅𝐲n+z2⋅𝟐n⏟𝐜⟩=z2⋅v−⟨−z⋅𝟏n,𝐲n⟩⏟v+⟨−z⋅𝟏n⏟𝐲,z⋅𝐲n+z2⋅𝟐n⏟𝐜⟩
⟨𝐚𝐋−z⋅𝟏n,𝐚R∘𝐲n+z⋅𝐲n+z2⋅𝟐n⟩=z2⋅v−⟨−z⋅𝟏n,𝐲n⟩+⟨−z⋅𝟏n,z⋅𝐲n+z2⋅𝟐n⟩
  1. We now break up the terms on the right-hand side:
⟨𝐚𝐋−z⋅𝟏n,𝐚R∘𝐲n+z⋅𝐲n+z2⋅𝟐n⟩=z2⋅v−⟨−z⋅𝟏n,𝐲n⟩+⟨−z⋅𝟏n,z⋅𝐲n⟩+⟨−z⋅𝟏n,z2⋅𝟐n⟩
  1. Take the scalars out of the inner products on the right:
⟨𝐚𝐋−z⋅𝟏n,𝐚R∘𝐲n+z⋅𝐲n+z2⋅𝟐n⟩=z2⋅v+z⋅⟨𝟏n,𝐲n⟩−z2⋅⟨𝟏n,𝐲n⟩−z3⟨⋅𝟏n,𝟐n⟩
  1. Factor out ⟨𝟏n,𝐲n⟩:
⟨𝐚𝐋−z⋅𝟏n,𝐚R∘𝐲n+z⋅𝐲n+z2⋅𝟐n⟩=z2⋅v+(z−z2)⋅⟨𝟏n,𝐲n⟩−z3⟨⋅𝟏n,𝟐n⟩

Since δ(y,z)=(z−z2)⋅⟨𝟏n,𝐲n⟩−z3⟨⋅𝟏n,𝟐n⟩, we have:

⟨𝐚𝐋−z⋅𝟏n,𝐚R∘𝐲n+z⋅𝐲n+z2⋅𝟐n⟩=z2⋅v+δ(y,z)

This completes the derivation. ■