Introduction

From the 1st of June to the 12th of June (10 working days), two consultants from zkSecurity reviewed the generalized-bulletproofs crate inside the monero-oxide project, commit f3660043e042b5608fc9c8ce1383cee238da9d0a for MAGIC Grants. This code is slated for use in the upcoming Monero ‘fullchain membership proofs’ (FCMP++) and a soundness/privacy critical component of the whole system. We reviewed the codebase as a general library, meaning, we did not discount findings simply because the current application does not trigger the issue.

The code was found to be well-written and easy to understand. The code was reviewed along with its associated paper, for context and because of some concerns about the formal writeup of the extractor (proof of knowledge soundness), we include here a writeup / motivation for the ‘generalized bulletproofs’ protocol as well as a formal proof of (computational) knowledge soundness.

Notation

Let 𝔽 denote the scalar field and 𝔾 a prime-order group (in practice a subgroup of an elliptic curve), written additively. Generators are denoted G,H𝔾 and G,H𝔾n; commitments are capitalized (V(k),AC(i)) and blinding factors written as Greek letters (γ). We write aS to denote sampling an element from the set S uniformly. An (honest) vector Pedersen commitment to v with randomness γ is v,G+γ·H, and a scalar commitment to v is v·G+γ·H.

Bold font denotes vectors, a=(a1,,an)𝔽n, with 1 and 0 the all-ones and all-zeros vectors, respectively; the witness wires aL,aR,aO (left, right, output) lie in 𝔽n, where n and q are the number of multiplication gates and linear constraints. We denote by a,b=iaibi the inner product, and by ab=(a1b1,,anbn) the Hadamard (entry-wise) product; (a)1 is the entry-wise inverse, so a(a)1=1. For y𝔽* we write y=(1,y,,yn1) for the vector of powers and abbreviate (y)1=(y)1; likewise z=(1,z,,zq1).

Generalized Bulletproofs

Bulletproofs provide a Non-Interactive (perfectly) Zero-Knowledge Argument-of-Knowledge (NIZKAoK) for knowledge of aL,aR,aO,v such that the following relation holds:

BP={(aL,aR,aO,v,{γk}k=1m) :0=WL·aL+WR·aR+WO·aO+WV·v+c0=aLaRaOk. V(k)=vk·G+γk·H}

Where aL,aR,aO𝔽n and v are the witnesses, with v being the opening of a number of (scalar) Pedersen commitments V(1),,V(m)𝔾. Compared to the standard bulletproofs description, to follow the implementation, we have moved WV·v and c over, so the relation is a single linear combination equal to 0. Generalized bulletproofs extends this with c “pre-committed” vectors aC(1),,aC(c), each the opening of a Pedersen commitment of some higher dimension:

GBP={(aL,aR,aO,v,{aC(i),aux(i),γ(i)}i=1c,{γk}k=1m) :0=WL·aL+WR·aR+WO·aO+i=1cWC(i)·aC(i)+WV·v+c0=aLaRaOi. AC(i)=aC(i),G+aux(i),H+γ(i)·Hk. V(k)=vk·G+γk·H}

For vector commitments AC(1),,AC(c)𝔾 and scalar commitments V(1),,V(m)𝔾. Each committed vector aC(i) comes with its own public weight matrix WC(i) and public commitment AC(i). The “aux(i),H” term is an artifact of the proof system: it lets a prover who only knows an opening which also depends on the H generators complete a proof, however these “wires” cannot be “accessed” from within the circuit. To build context for the following code-level review, let’s walk through the Bulletproof arithmetization, which turns this R1CS-equivalent system into an inner product relation, between uniformly random vectors.

GBP Arith 1: R1CS Σ IP

To simplify the claim:

0=aLaRaO0=WL·aL+WR·aR+WO·aO+i=1cWC(i)·aC(i)+WV·v+c

The verifier samples y𝔽* and z𝔽, and defines y=(1,,yn1) and z=(1,,zq1). We use this to compute linear combinations of every row of each expression:

0=y,aLaRaO0=z,WL·aL+WR·aR+WO·aO+i=1cWC(i)·aC(i)+WV·v+c

In case either of the old relations did not hold, this new relation only holds with probability max(n,q)/|𝔽|. Finally, we can compute a linear combination of each of these equations to end up with a single equation which must equal zero, here, we “reuse” the challenge z to “shift” the second equation:

0=y,aLaRaO+z·z,WL·aL+WR·aR+WO·aO+i=1cWC(i)·aC(i)+WV·v+c

In summary, we went from an equation over vectors to single field elements using the challenges y and z. Moving z· in and splitting the inner products, we can rewrite the second part of the expression as:

0=zz·WL,aL+zz·WR,aR+zz·WO,aO+i=1czz·WC(i),aC(i)+zz·WV,v+zz,c

Let us define:

wL=z·z·WL𝔽nwR=z·z·WR𝔽nwV=z·z·WV𝔽nwC(i)=z·z·WC(i)𝔽n(i=1,,c)wO=z·z·WO𝔽nwc=z·z,c𝔽

Note that the verifier can compute all the vectors itself, since the matrices are public.

We are now left to “deal” with:

0=y,aLaRaO+wL,aL+wR,aR+wO,aO+i=1cwC(i),aC(i)+wV,v+wc𝔽

Splitting the first inner product, we get the expression that we want to look at going forward:

0=y,aLaRy,aO+wL,aL+wR,aR+wO,aO+i=1cwC(i),aC(i)+wV,v+wc𝔽

The next issue at hand is that the expression above has many inner products. Since we need to do an expensive folding argument for every inner product we would like to avoid this: we want to combine all these inner products into a single one. The trick is going to be to interpret these as committed vector polynomials, enabling us to evaluate many parallel polynomials of low degree. More on that now…

GBP Arith 2: Vector Polynomials

An “n” dimensional “vector polynomial” consists of n polynomials “in parallel”:

𝐟(X)=(f1(X),,fn(X))=i=0dci·Xi𝔽[X]n

In other words, a polynomial with coefficients in ci𝔽n and evaluation points from 𝔽, such that plugging an x into 𝐟(X) evaluates to 𝐟(x)𝔽n. This notion is useful, because (vector) Pedersen commitments allow us to commit to a vector polynomial efficiently (independently of the dimension n):

ComG,H : (𝔽n)[X]d×𝔽d+1𝔾d+1ComG,H(𝐟(X); r)(c0,G+r0·H,,cd,G+rd·H)𝔾d+1

As well as homomorphically evaluate every coordinate of the vector polynomial at some public point x:

i=0dxi·(ci,G+ri·H)=𝐟(x),G+r·H𝔾

Pedersen vector commitments support one further homomorphic operation we will rely on: multiplying the committed vector by a public vector, i.e. a Hadamard product with a public factor, simply by a change of basis. Writing the commitment to v in basis G explicitly as v,G+r·H, a public Hadamard factor s is applied to the opening by re-committing in the basis (s)1G:

Com(s)1G, H(vs; r)=ComG, H(v; r)vs,(s)1G+r·H=v,G+r·H

In other words, a commitment to v in basis G is also a commitment to vs in the basis (s)1G with the same blinding r: to apply a public Hadamard factor s to the opening, one re-commits in the basis (s)1G. This holds because s(s)1=1 leaves each generator’s contribution unchanged and the blinding term r·H is untouched.

The “inner product” between two vector polynomials is defined in the intuitive way (for any module over any ring): taking the coordinate-wise product of polynomials and summing:

𝐟(X),𝐠(X)=ifi(X)·gi(X)𝔽[X]

Note that x.𝐟,𝐠(x)=𝐟(x),𝐠(x) and deg(𝐟,𝐠)=deg(𝐟)+deg(𝐠).

GBP Arith 3: Σ IP Single IP

Viewing the vectors as vector polynomials is useful because it allows us to batch check independent inner products. Suppose we have two inner products:

Δ=𝐚,𝐛+𝐜,𝐝

We define the vector polynomials (“left/right”):

fL(X)=a·X+c·X2fR(X)=b·X+d

And consider the inner product, then the desired inner product Δ lands in the square term:

fL,fR(X)=δ0+δ1·X+Δ·X2+δ3·X3𝔽[X]

Where δ0,δ1,δ3 are some cross-term garbage we don’t care about. More generally: we define a “left polynomial” where powers increase for every left term in the series of inner products and a “right polynomial” where the powers decrease for every right term, then the terms will “align” at the “middle power”. i.e. in general, suppose we have:

Δ=i=1tLi,Ri

Then we define:

fL(X)=i=1tLi·XifR(X)=i=1tRi·Xti

In which case, the t‘th coefficient of fL,fR(X) is Δ. This observation suggests the following approach to reduce a sum of multiple inner products, given commitments to every vector, to a single inner product as follows:

  1. Prover sends commitments to the coefficients {δi}i0,,2·t1, where we are interested in δt=Δ, which is usually implicit (e.g. fixed to 0). Then both parties locally define:
fL(X)=i=1tLi·Xi𝔽[X]nfR(X)=i=1tRi·Xti𝔽[X]ng(X)=i=02·t1δi·Xi𝔽[X]
  1. Verifier samples x𝔽
  2. Both sides compute commitments to the vectors:
fL(x),fR(x)𝔽n

And a commitment to the field element g(x)𝔽, using the homomorphic property of the Pedersen commitments. We now have just a single inner product claim about Pedersen commitments:

fL(x),fR(x)=g(x)

GBP Arith 4: Combining

Recall the expression we were trying to verify, before our digression about batching inner products and vector polynomials:

0=y,aLaRy,aO+wL,aL+wR,aR+wO,aO+i=1cwC(i),aC(i)+wV,v+wc𝔽

To apply the techniques above, we want to:

  • Eliminate Pairwise Products. We haven’t yet described a technique for proving Hadamard (pairwise) products of secret (committed) vectors, so we get to get rid of aLaR; we want each secret to appear on a different side of an inner product.

  • Collect Common Terms. Reduce the number of inner products, for efficiency, by collecting common terms. This reduces the degree of the vector polynomials, meaning: less committed coefficients and less cross-terms.

Eliminate Secret-Secret Hadamard Product

Note that the left side of the inner product y,aLaR is public, so let us move one secret to each side, using y,aLaR=aL,yaR to get rid of the Hadamard product between secret values:

0=y,aLaRy,aO+wL,aL+wR,aR+wO,aO+i=1cwC(i),aC(i)+wV,v+wc𝔽

Becomes

0=aL,yaRy,aO+wL,aL+wR,aR+wO,aO+i=1cwC(i),aC(i)+wV,v+wc𝔽

Note that we know how to deal with a Hadamard product between a secret and a public value.

Combine the aO terms

0=aL,yaRy,aO+wL,aL+wR,aR+wO,aO+i=1cwC(i),aC(i)+wV,v+wc𝔽

Becomes

0=aL,yaR+wL,aL+wR,aR+wOy,aO+i=1cwC(i),aC(i)+wV,v+wc𝔽

Rewrite aR Inner Product

Using aR,wR=wR(y)1,yaR rewrite:

0=aL,yaR+wL,aL+wR,aR+wOy,aO+i=1cwC(i),aC(i)+wV,v+wc𝔽

Becomes

0=aL,yaR+wL,aL+wR(y)1,yaR+wOy,aO+i=1cwC(i),aC(i)+wV,v+wc𝔽

Collect yaR Terms

This was our motivation for the previous step:

0=aL,yaR+wL,aL+wR(y)1,yaR+wOy,aO+i=1cwC(i),aC(i)+wV,v+wc𝔽

Becomes

0=aL+wR(y)1,yaR+wL,aL+wOy,aO+i=1cwC(i),aC(i)+wV,v+wc𝔽

Add δ(y,z) to Both Sides

Add the public scalar δ(y,z)=(y)1wR,wL to both sides (note that 0 on the left becomes δ(y,z)):

0=aL+wR(y)1,yaR+wL,aL+wOy,aO+i=1cwC(i),aC(i)+wV,v+wc𝔽

Becomes

δ(y,z)=aL+wR(y)1,yaR+wL,aL+(y)1wR,wL+wOy,aO+i=1cwC(i),aC(i)+wV,v+wc𝔽

Note that δ(y,z) does not depend on the witness! (the verifier can compute it)

Combine wL Terms

δ(y,z)=aL+wR(y)1,yaR+wL,aL+(y)1wR,wL+wOy,aO+i=1cwC(i),aC(i)+wV,v+wc𝔽

Becomes

δ(y,z)=aL+wR(y)1,yaR+(y)1wR+aL,wL+wOy,aO+i=1cwC(i),aC(i)+wV,v+wc𝔽

Combine aL+wR(y)1 Terms

δ(y,z)=aL+wR(y)1,yaR+(y)1wR+aL,wL+wOy,aO+i=1cwC(i),aC(i)+wV,v+wc𝔽

Becomes

δ(y,z)=aL+wR(y)1,yaR+wL+wOy,aO+i=1cwC(i),aC(i)+wV,v+wc𝔽

So we are left with 2+c inner products: two coming from the aL,aR,aO terms and one for each of the c committed vectors aC(i). All these are combined into a single inner product using the previous technique based on vector polynomials.

Note that during verification everything except the 2+c inner products is known to the verifier: δ(y,z) (on the left) and wc are public, and wV,v is a commitment to a single field element, formed homomorphically from the V(k). Those inner products are folded into a single one next.

Arithmetization

Public inputs: generators G,H𝔾n and G,H𝔾; weight matrices WL, WR, WO, {WC(k)}k=1c, WV with constant c; vector commitments {AC(k)}k=1c and scalar commitments {V(j)}j=1m. Write n=2c+2 for the target monomial.

  • Prover Verifier.
    • Sample α,β,ρ𝔽 and sL,sR𝔽n.
    • AL|R=aL,G+aR,H+αH
    • AO=aO,G+βH
    • S=sL,G+sR,H+ρH
    • Send (AL|R,AO,S).
  • Verifier Prover.
    • Sample y,z𝔽*.
    • Send (y,z).
    • Both parties compute:
      • The challenge vectors y,(y)1,z
      • The weights wL,wR,wO,{wC(k)},wV,wc
      • δ(y,z)=(y)1wR,wL
  • Prover Verifier.
    • Recall that the inner products to batch are: tn=aL+wR(y)1,yaR+wL+aO,wOy+k=1caC(k),wC(k)=δ(y,z)wcwV,v.
    • Build fL(X),fR(X)𝔽[X]n (powers as in GBP Arith 3) with nonzero coefficients:
      • fL(X):
        • aL+wR(y)1 at Xn/2
        • aC(k) at Xnk for k=1,,c
        • aO at Xn
        • sL at Xn+1
      • fR(X):
        • wOy at X0
        • wC(k) at Xk for k=1,,c
        • yaR+wL at Xn/2
        • yaux(k) at Xnk for k=1,,c
        • ysR at Xn+1
      • Corresponding to generators in G and H respectively.
    • t(X)=fL(X),fR(X)=i=n/22(n+1)tiXi; the target coefficient is tn.
    • Sample τi𝔽 for every in and set Ti=tiG+τiH.
    • Send {Ti}in.
  • Verifier Prover.
    • Sample x𝔽*.
    • Send x.
  • Prover Verifier.
    • Opening of t(x) (value t^, blinding τx): t^=fL(x),fR(x)=t(x)τx=inτixixnwV,γV
    • Opening of P (vectors fL(x),fR(x), blinding μ): μ=α·xn/2+β·xn+ρ·xn+1+k=1cγ(k)·xnk With γV the blinding factors of the V(j) and γ(k) the blinding factor of AC(k).
    • Send (τx,μ,t^,fL(x)𝔽n,fR(x)𝔽n).
  • Verifier.
    • Set H(y)1=(y)1H.
    • Define: W~L=wL,H(y)1𝔾W~R=(y)1wR,G𝔾W~O=wOy,H(y)1𝔾W~k=wC(k),H(y)1𝔾
    • Compute: P=W~O+k=1cxkW~k+xn/2(AL|R+W~L+W~R)+k=1cxnkAC(k)+xnAO+xn+1S
    • Check: t^G+τxH=xn((δ(y,z)wc)Gj=1m(wV)jV(j))+inxiTi
    • Check: ((G,H(y)1,H,P,μ,t^), (fL(x),fR(x)))IP

Computational Special Soundness

We prove that the arithmetization (‘Generalized Bulletproofs’) is an argument of knowledge for GBP. The theorem below establishes (n,q+1,2n+3)-computational special soundness. By Attema, Fehr and Klooß (TCC 2022) the Fiat-Shamir compiled argument then has tight security: under the hardness of discrete log over 𝔾 it is knowledge sound with knowledge error at most (Qro+1)·(n+q+4c+5)/(|𝔽|1), where Qro is the number of random-oracle queries made by the adversary.

Theorem. Assume WV has full column rank m, i.e. a left inverse. The full arithmetization is (n,q+1,2n+3)-computationally special sound for GBP: from any (n,q+1,2n+3)-tree of accepting transcripts a deterministic extractor returns either a witness for GBP, or a non-trivial discrete-log relation among the generators Γ=GHGH𝔾2n+2, i.e. a non-zero v with v,Γ=0.

The Tree of Transcripts. A (n,q+1,2n+3)-tree fixes the first message (AL|R,AO,S) at the root and branches on the three challenges, recording each verifier message at its node: n distinct children on y; under each, q+1 distinct children on z, each with its {Ti}; under each, 2n+3 distinct leaves on x, each with its opening (τx,μ,fL(x),fR(x)). Every root-to-leaf path is an accepting transcript. Index a (y,z)-node by (iy,iz) and its x-leaves by ix, so (iy,iz,ix) indexes a full transcript. The three arities are forced by the three interpolations below: 2n+3=degt+1 for x; q+1 for the q constraint rows together with the constant Hadamard term; n for the Hadamard coordinates.

AL|R,AO,S
y1
y2
yiy
yn
z1
ziz
zq+1
x1
x2
xix
x2n+3
Each Leaf Accepts(τx,μ,fL(x),fR(x))
transcript root
n branches
q+1 branches
2n+3 leaves
The (n,q+1,2n+3) tree of accepting transcripts: each edge is a verifier challenge (y, then z, then x), and every root-to-leaf path is an accepting transcript (one highlighted).

Step 1: x-Vandermonde Read-off. Fix a node (iy,iz). The verifier’s P is the value at the leaf’s challenge of a polynomial p=02(n+1)xpPp whose coefficients Pp𝔾 are:

P0=W~O,Pk=W~k (1kc),Pn/2=AL|R+W~L+W~R,Pnk=AC(k),Pn=AO,Pn+1=S,

With Pp=0 for p>n+1.

The 2n+3 leaves of the node share (y,z) and use distinct x, so the P-opening check at leaf ix:

pxixpPp=fL(xix),G+fR(xix),H(y)1+μixH,

Is a Vandermonde system in x; inverting it writes each Pp as a representation in the (G,H(y)1,H) basis. When the node’s collision candidates (Step 5) all vanish, the G-block of Pp at every degree equals the honest fL coefficient and the H(y)1-block at every degree n equals the honest fR coefficient: the public degrees 0 and k open purely on H(y)1 to wOy and wC(k); degree n/2 gives aL+wR(y)1 on G and yaR+wL on H(y)1; degrees nk, n, n+1 give the wires aC(k),aO,sL on G and yaux(k),ysR on H(y)1. The lone degree-n H(y)1-block — the H-part of AO — is unconstrained; the relation tolerates this slack, and since its convolution partner is the degree-0 coefficient of fL, which is 0, it never contributes downstream.

Step 2: The Per-Node Identity (). With the leaf openings pinned to the honest fL,fR, the n-coefficient of fL(X),fR(X) — the committed target tn, recovered from the leaves by inverting the same x-Vandermonde at degree n — expands without invoking any constraint into δ(y,z), the z-aggregated linear R1CS rows, and the y-weighted Hadamard term y,aLaRaO. The first verifier check independently pins the same coefficient to tn=δ(y,z)wcwV,v; here the check couples wV,v to the aggregate j(wV)jV(j) through its degree-n coefficient, the two agreeing once the corresponding (G,H)-collision candidate of Step 5 vanishes. Equating the two expansions and cancelling δ(y,z) gives, at every node (iy,iz):

()y,aLaRaO+=1qz(WLaL+WRaR+WOaO+kWC(k)aC(k)+WVv+c)=0

Step 3: Deaggregation over z then y. It suffices to know () on one reference row and one reference column. Fix a reference y-child: as z ranges over the q+1 children of that node, () is a degree-q polynomial in z — constant term y,aLaRaO, row at z — vanishing at q+1 distinct points, so a Vandermonde in z forces every R1CS row to zero. With the rows gone, () on the reference column (z fixed to a reference child, y ranging over its n children) collapses to y,aLaRaO=0 at n distinct y; a Vandermonde in y forces each coordinate. This yields the first two relation clauses:

WLaL+WRaR+WOaO+kWC(k)aC(k)+WVv+c=0aLaRaO=0

(The q+1 arity is the constant term plus q rows; the L-shape avoids needing () on the full n·(q+1) grid.)

Step 4: Commitment Openings. Two clauses remain, read straight off Step 1. The degree-(nk) coefficient is AC(k), whose G-, H- and H-blocks give the vector-commitment clause:

AC(k)=aC(k),G+aux(k),H+γ(k)H

with the aux(k),H slack retained — precisely the term the improved protocol removes. For the scalar commitments, the first check’s degree-n coefficient opens the aggregate j(wV)jV(j) as a (G,H)-combination at each of the q+1 z-children; inverting the Vandermonde in z and applying the left inverse of WV recovers each V(k)=vkG+γkH.

Step 5: Witness or Relation. The extractor reads a candidate witness W off the Step-1 representations at a fixed reference (y,z) (the first y- and z-children): aL from the G-block at degree n/2 minus the public wR(y)1; aO at degree n; aC(k) and γ(k) from the G- and H-blocks at degree nk; aR from the H(y)1-block at degree n/2, minus the public wL and rescaled by (y)1; aux(k) from the H(y)1-block at degree nk, rescaled by (y)1; and v,{γk} from the degree-n first-check coefficients via the left inverse of WV. It is computed by Lagrange-form Vandermonde inversion and Gaussian elimination — no discrete-log search. It also forms a list of candidate discrete-log relations: differences of two recovered representations of the same group element — the public coefficients W~O,W~k; the challenge-independent commitments AL|R,AO,AC(k),S across distinct nodes; the degree-n (G,H)-candidate of Step 2; and the high-degree coefficients, which open 0 directly. Each candidate c satisfies c,Γ=0 by construction, being a difference of two openings of the same commitment; it is non-trivial exactly when c0.

The extractor outputs W if WGBP, and otherwise the first non-zero candidate relation; we argue the contrapositive. If every candidate vanishes, the Step-1 read-offs hold and the degree-n identity of Step 2 holds at every node, so () holds on the reference row and column; Step 3 deaggregates it into the first two clauses, and Step 4 supplies the vector- and scalar-commitment clauses. All four clauses hold, so WGBP, contradicting the assumption. Hence a failing W yields a non-zero candidate, which the extractor returns as the discrete-log relation.

Reduce IPIPA,n

The t^ check above ties t^ to the committed polynomial t(X); the remaining verifier check is membership in a single inner-product relation IP, with statement (G,H(y)1,H,P,μ,t^) and witness (a,b):

IP={ ((G,H(y)1,H,P,μ,t^), (a,b)) : P=a,G+b,H(y)1+μH    t^=a,b }

Here a,b𝔽n and H(y)1=(y)1H. The generators G,H(y)1,H are public; the verifier derives the remaining statement components P,μ,t^ from the protocol transcript, and the prover holds the witness (a,b)=(fL(x),fR(x)). We abbreviate H~=H(y)1.

To recursively fold this relation, we first want to reduce it to:

IPA,N={ ((G,H~,U,P), (a,b)) : a,b𝔽N    P=a,G+b,H~+a,b·U }

The verifier samples a challenge ξ0𝔽*; both parties set U=ξ0·G (a generator independent of G,H~) and update the commitment:

P  PμH+t^·U

Subtracting μH removes the blinding term from the IP commitment, and adding t^·U encodes the claimed inner product in the U component. Since t^=a,b, the updated statement is an instance of IPA,n.

Inner-Product Argument

The argument proves membership in IPA,N on length-N vectors, initially N=n. In each round, the prover and verifier combine the left and right halves of each vector into vectors of half the length. After log2n rounds, the prover has sent 2log2n group elements and sends two final scalars.

Folding

Split each vector in half:

a=(a1a2)b=(b1b2)G=(G1G2)H~=(H~1H~2)

The prover sends the two cross terms:

L=a1,G2+b2,H~1+a1,b2·UR=a2,G1+b1,H~2+a2,b1·U

The verifier replies with a challenge ξ𝔽*, and both sides fold the generators and statement to half length:

G=ξ1·G1+ξ·G2H~=ξ·H~1+ξ1·H~2P=ξ2·L+P+ξ2·R

While the prover folds the witness the same way:

a=ξ·a1+ξ1·a2b=ξ1·b1+ξ·b2

A simple calculation shows the relation is preserved, P=a,G+ b,H~+ a,b·U. The folded statement and witness then form a smaller instance of the same relation, ((G,H~,U,P),(a,b))IPA,N/2.

Base Case

After log2n rounds the vectors have length one, leaving the base relation IPA,1. The prover sends the two scalars a,b𝔽, and the verifier accepts iff:

P=a·G+b·H~+(a·b)·U

The verifier never folds the generators one round at a time: the round challenges ξ1,,ξlog2n assign each original generator a fixed coefficient (a product of the ξj±1), so the whole check collapses into a single multi-exponentiation, batched with the rest of verification.

Improvements

We describe two improvements to the protocol above: a cheaper arithmetization, and an inversion-free inner-product argument with a tighter and simpler proof of computational special soundness.

Arithmetization

Recall that the full arithmetization spreads t(X) across degree 2(n+1)=4c+6, so the prover commits to all 3c+5 of its coefficients. Most of that degree is wasted: it exists only to park the two halves of AL|R (and of S) on a shared monomial, so that they can be jointly committed; this is a bad ‘optimization’, that ends up hurting efficiency in the GBP setting. If we give every vector its own monomial and t(X) collapses to degree 2(c+2), the prover commits to 2c+4 coefficients, a saving of c+1. We pay for this by splitting AL|R into (AL,AR) and S into (SL,SR): two extra commitments, leaving a net saving of c1 group elements. For 4 vector commitments the saving is 96 bytes: 3 fewer group elements.

The split buys something else: it tightens the relation. A vector commitment opens as:

AC(k)=aC(k),G+aux(k),H+γ(k)H

The aux(k),H term is slack the circuit cannot reach; the full arithmetization tolerates it, carrying it along in the yaux(k) terms of fR(X). However, the improved protocol below can ensure that all those terms are zero. The verifier evaluates the G- and H-sides separately and recombines them with a binding challenge r, drawn after the evaluation point x and before the opening. The improved protocol then proves the tighter relation GBP, identical to the generalized Bulletproofs relation except that the vector commitments carry no H component:

GBP={(aL,aR,aO,v,{aC(i),γ(i)}i=1c,{γk}k=1m) :0=WL·aL+WR·aR+WO·aO+i=1cWC(i)·aC(i)+WV·v+c0=aLaRaOi. AC(i)=aC(i),G+γ(i)·Hk. V(k)=vk·G+γk·H}

Public inputs are as in the arithmetization above; the target monomial is now Xc+1.

  • Prover Verifier.
    • Sample αL,αR,β,ρL,ρR𝔽 and sL,sR𝔽n.
    • Commit: SL=sL,G+ρLHSR=sR,H+ρRHAL=aL,G+αLHAR=aR,H+αRHAO=aO,G+βH
    • Send (AL,AR,AO,SL,SR).
  • Verifier Prover.
    • Sample y𝔽* and z𝔽.
    • Send (y,z).
    • Both parties compute:
      • The challenge vectors y,(y)1,z
      • The weights wL,wR,wO,{wC(k)},wV,wc
      • δ(y,z)=(y)1wR,wL
  • Prover Verifier.
    • Recall that the inner products to batch are: tc+1=aL+wR(y)1,yaR+wL+aO,wOy+k=1caC(k),wC(k)=δ(y,z)wcwV,v.
    • Build fL(X),fR(X)𝔽[X]n with nonzero coefficients:
      • fL(X):
        • aL+wR(y)1 at X0
        • aO at X1
        • aC(k) at Xk+1 for k=1,,c
        • sL+zq+1·1 at Xc+2
      • fR(X):
        • wC(k) at Xck for k=1,,c
        • wOy at Xc
        • yaR+wL at Xc+1
        • ysR at Xc+2
      • Corresponding to generators in G and H respectively.
    • t(X)=fL(X),fR(X)=i=02(c+2)tiXi; the target coefficient is tc+1.
    • Sample τi𝔽 for every ic+1 and set Ti=tiG+τiH.
    • Send {Ti}ic+1.
  • Verifier Prover.
    • Sample x𝔽, then r𝔽*.
    • Send (x,r).
  • Prover Verifier.
    • Opening of t(x) (value t^, blinding τx): t^=fL(x),fR(x)=t(x)τx=ic+1τixixc+1wV,γV
    • Opening of P (vectors fL(x),fR(x), blinding μ=μL+rμR): μL=αL+βx+k=1cγ(k)xk+1+ρLxc+2μR=αRxc+1+ρRxc+2 with γV the blinding factors of the V(j) and γ(k) the blinding factor of AC(k).
    • Send (τx,t^,μ,fL(x)𝔽n,fR(x)𝔽n).
  • Verifier.
    • Set H(y)1=(y)1H.
    • Define: W~L=wL,H(y)1𝔾W~R=(y)1wR,G𝔾W~O=wOy,H(y)1𝔾W~k=wC(k),H(y)1𝔾
    • Compute: P=x0(AL+W~R)+x1AO+k=1cxk+1AC(k)+xc+2(SL+zq+1·1,G)fL(x),G+μLH+r(k=1cxckW~k+xcW~O+xc+1(AR+W~L)+xc+2SR)fR(x),H(y)1+μRH
    • Check: t^G+τxH=xc+1((δ(y,z)wc)Gj=1m(wV)jV(j))+ic+1xiTi
    • Check: ((G, r·H(y)1, H, P, μ, t^), (fL(x),fR(x)))IP

Computational Special Soundness

We prove that the protocol is an argument of knowledge for GBP. The theorem below establishes (n,q+2,2c+5,3)-computational special soundness; by Attema, Fehr and Klooß (TCC 2022) the Fiat-Shamir compiled argument then has tight security: under the hardness of discrete log over 𝔾 it is knowledge sound with knowledge error at most (Qro+1)·(n+q+2c+6)/(|𝔽|1), where Qro is the number of random-oracle queries.

Theorem. Assume WV has full column rank m, i.e. a left inverse. The improved arithmetization is (n,q+2,2c+5,3)-computationally special sound for GBP: from any (n,q+2,2c+5,3)-tree of accepting transcripts a deterministic extractor returns either a witness for GBP, or a non-trivial discrete-log relation among the generators Γ=GHGH𝔾2n+2, i.e. a non-zero v with v,Γ=0.

The Tree of Accepting Transcripts. A (n,q+2,2c+5,3)-tree fixes the first message (AL,AR,AO,SL,SR) at the root and branches on the four challenges, recording each verifier message at its node: n distinct children on y; under each, q+2 distinct children on z, each with its {Ti}; under each, 2c+5 distinct children on x; under each, 3 distinct leaves on r. The opening (τx,μ,a,b)=(τx,μL+rμR,fL(x),fR(x)) is the never-sent final message decorating the leaves; drawn after r, it may differ across the r-children. Every root-to-leaf path is an accepting transcript. Index a (y,z,x)-node by (iy,iz,ix) and its r-leaves by e{0,1,2}, with challenges re and leaf openings (τx,e,μe,ae,be). Write PL,PR for the two bracketed sums of the verifier’s P (so P=PL+rPR) and H(y)1=(y)1H. The four arities are forced by the four interpolations below: 2c+5=degt+1 for x; q+2 for the constraints together with the fresh offset degree; n for the Hadamard rows; 3 for the quadratic in r.

Step 1: Interpolation in r. Fix a node (iy,iz,ix). The second verifier check at leaf e reads:

PL+rePR=ae,G+rebe,H(y)1+μeH

with μe the single blinding supplied at the leaf. The leaves e=0,1 (with r0r1) form a 2×2 system whose unique solution pins both sides to four quadrant vectors and recovers the two blinders:

PL=a,G+β,H(y)1+μLHPR=α,G+b,H(y)1+μRH

Where the quadrants are the interpolants:

a=r1a0r0a1r1r0β=r0r1(b0b1)r1r0α=a1a0r1r0b=r1b1r0b0r1r0

And the blinding factors by the same interpolation, μL=r1μ0r0μ1r1r0 and μR=μ1μ0r1r0. Here β is a H(y)1-mass sitting on the G-side PL, and α a G-mass on the H-side PR. The opening is sent after r, so nothing yet forces β=α=0; this is the slack the offset must remove.

Step 2: The t^-Quadratic Forces the Cross Terms to Vanish. On this family the e-th leaf satisfies ae=a+reα and be=re1β+b (leaves 0,1 by construction; leaf 2 either lies on the family — vectors and blinding alike — since its candidate below vanishes, or yields a relation). Hence:

ae,be=a,βre1+(a,b+α,β)+α,bre

The first check at leaf e reads ae,beG+τx,eH=R, with right-hand side R=ic+1xiTi+xc+1((δ(y,z)wc)Gj(wV)jV(j)) determined before r is drawn. Subtracting the leaf-0 instance, (ae,bea0,b0)G+(τx,eτx,0)H=0 is a discrete-log relation on (G,H); unless it is trivial — both ae,be and τx,e constant across the r-children — the extractor returns it. With ae,be pinned to a single value, a map rAr1+C+Br constant at the three distinct non-zero r0,r1,r2 has A=B=0; hence at every node:

a,β=0,α,b=0,ae,be=a,b+α,β

Forcing both the r1- and r-terms to vanish requires three points, which fixes the r-arity at 3.

Step 3: x-Vandermonde Extraction. Fix y and z. Across the 2c+5 accepting transcripts that share them and use distinct x, each quadrant is the evaluation at xix of a vector polynomial of degree 2c+4 whose coefficients are the per-degree representations of PL(X) and PR(X). Inverting the Vandermonde in x recovers, for each degree p, a representation in three blocks:

[coeffpPL]=gp,G+hp,H(y)1+ηpH

And likewise for PR. Matching the layout of fL, the G-blocks at degrees 0,1,k+1,c+2 are aL+wR(y)1, aO, aC(k), and sL+zq+1·1 (the mask with offset); the H(y)1-blocks are the residual components β at each degree.

Step 4: The Offset Eliminates the Residual Components. The residual H(y)1-block of each PL-coefficient is the same fixed vector wp for every (y,z) (up to the y-rescaling), a property of the fixed commitments AL,AO,AC(k),SL. We show every wp=0 by descending induction on p, from c+2 down.

Step 2 gives a(x),β(x)=0 at every x-child; interpolating across the 2c+5 points, every convolution coefficient of the two degree-(c+2) quadrant polynomials vanishes. Take the coefficient at convolution degree p0+c+2. With the higher-degree residual components already zero by the induction hypothesis, the only nonzero term pairs the G-block of the mask slot c+2 with wp0; that block is u+zq+1·1, with u the fixed representation of SL, so the coefficient is:

u,ywp0+zq+1tyt(wp0)t=0

Fix y. The summand D=u,ywp0 and the coefficient B=tyt(wp0)t are independent of z: the weights live at z1,,zq, and u is fixed before z. The term zq+1B carries the fresh power, so D+zq+1B is a polynomial vanishing at the q+2 distinct z, and full-degree Vandermonde forces B=0. (Pairwise differences would not suffice: distinct z can share a (q+1)-th power, which is why the z-arity is q+2, not q+1.) Finally tyt(wp0)t=0 across the n distinct y is a Vandermonde in y, so wp0=0 coordinate-wise.

Since every wp=0, the residual quadrant β vanishes at every node, and each leaf’s inner product equals the honest convolution a,b.

Step 5: Witness or Relation. The extractor reads a candidate witness W off the Step-3 representations at a fixed reference (y,z) (the first y- and z-children): aL from the G-block of PL at degree 0, minus the public wR(y)1; aO at degree 1; aC(k) and its blinder γ(k) from the G- and H-blocks of PL at degree k+1; aR from the H(y)1-block of PR at degree c+1, minus the public wL and rescaled by (y)1; and v,{γk} from the first check’s degree-(c+1) coefficient across the first q+1 z-children, via the precomputed left inverse of WV. It also forms a list of candidate discrete-log relations: differences of two recovered representations of the same group element, e.g. the representation of AL at (yiy,ziz) minus the one at the reference (y0,z0), the high-degree coefficients, and the per-node consistency checks — the third r-child’s opening and blinding against the family interpolated from the first two (Step 1), and the agreement of (ae,be,τx,e) across the r-children (Step 2). Each candidate c satisfies c,Γ=0 by construction, being the difference of two representations of the same commitment; it is therefore a discrete-log relation, non-trivial exactly when c0.

The extractor outputs W if WGBP, and otherwise the first non-zero candidate relation; we argue the contrapositive. If every candidate vanishes, the Step-3 representations and the per-node identities of Step 2 hold, and the residual components are pinned to the single family wp, so Step 4 forces every wp to zero. With the leaf openings now honest, cancelling δ in the first-check identity tc+1=δ(y,z)wcwV,v gives, for each (y,z):

y,aLaRaO+=1qz(WLaL+WRaR+WOaO+kWC(k)aC(k)+WVv+c)=0

Deaggregating over the n distinct y and the q+1 distinct z (two Vandermondes) splits this into the first two relation clauses:

WLaL+WRaR+WOaO+kWC(k)aC(k)+WVv+c=0,aLaRaO=0

The vector-commitment clause is tight: since the residual components vanish, the degree-(k+1) G-block representation gives AC(k)=aC(k),G+γ(k)H, with no H-component. The scalar clause V(k)=vkG+γkH follows from the degree-(c+1) recovery and the WV left inverse. All four clauses hold, so WGBP, contradicting the assumption. Hence a failing W yields a non-zero candidate, which the extractor returns as the discrete-log relation.

Inner-Product Argument

The improved arithmetization reduces to the same inner-product relation IP, so it can reuse the inner-product argument above. Folding in the value yields the same relation IPA,N, and the base case is unchanged; we change only the folding round, replacing the Laurent fold with a polynomial fold. This removes every field inversion.

Folding

Split each vector in half:

a=(a1a2)b=(b1b2)G=(G1G2)H~=(H~1H~2)

The prover sends the two cross terms:

L=a1,G2+b2,H~1+a1,b2·UR=a2,G1+b1,H~2+a2,b1·U

The verifier replies with a challenge ξ𝔽, and both sides fold the generators and statement to half length:

G=G1+ξ·G2H~=ξ·H~1+H~2P=ξ2·L+ξ·P+R

While the prover folds the witness the same way:

a=ξ·a1+a2b=b1+ξ·b2

A simple calculation shows the relation is preserved, P=a,G+ b,H~+ a,b·U. The folded statement and witness then form a smaller instance of the same relation, ((G,H~,U,P),(a,b))IPA,N/2. Observe that, unlike the original version, the field element ξ may take any value in 𝔽.

Base Case

After log2n rounds the vectors have length one, leaving the base relation IPA,1. The prover sends the two scalars a,b𝔽, and the verifier accepts iff:

P=a·G+b·H~+(a·b)·U