Skip to content

Commit 3af3ead

Browse files
authored
perf(bulletproof): optimize IPA prover with batched MSMs (#1719)
Signed-off-by: Ankit Basu <ankitbasu14@gmail.com>
1 parent 5ae5b75 commit 3af3ead

1 file changed

Lines changed: 50 additions & 35 deletions

File tree

  • token/core/zkatdlog/nogh/v1/crypto/rp/bulletproof

token/core/zkatdlog/nogh/v1/crypto/rp/bulletproof/ipa.go

Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -184,25 +184,63 @@ func (p *ipaProver) Prove() (*IPA, error) {
184184
// of the left vector and right is a function of right vector.
185185
// Both vectors are committed in com which is passed as a parameter to reduce
186186
func (p *ipaProver) reduce(X, com *mathlib.G1) (*mathlib.Zr, *mathlib.Zr, []*mathlib.G1, []*mathlib.G1, error) {
187-
leftGen, rightGen := CloneGenerators(p.LeftGenerators, p.RightGenerators)
188-
189187
left := p.leftVector
190188
right := p.rightVector
191189

192190
LArray := make([]*mathlib.G1, p.NumberOfRounds)
193191
RArray := make([]*mathlib.G1, p.NumberOfRounds)
192+
xList := make([]*mathlib.Zr, 0, p.NumberOfRounds)
193+
194194
for i := range p.NumberOfRounds {
195195
// in each round the size of the vector is reduced by 2
196-
n := len(leftGen) / 2
197-
leftIP := math.InnerProduct(left[:n], right[n:], p.Curve)
198-
rightIP := math.InnerProduct(left[n:], right[:n], p.Curve)
199-
// LArray[i] is a commitment to left[:n], right[n:] and their inner product
200-
LArray[i] = CommitVectorPlusOne(left[:n], right[n:], leftGen[n:], rightGen[:n], leftIP, X, p.Curve)
201-
// LArray[i].Add(X.Mul(leftIP))
196+
n_current := len(left) / 2
197+
leftIP := math.InnerProduct(left[:n_current], right[n_current:], p.Curve)
198+
rightIP := math.InnerProduct(left[n_current:], right[:n_current], p.Curve)
199+
200+
var s, sInv []*mathlib.Zr
201+
if i == 0 {
202+
s = []*mathlib.Zr{math.One(p.Curve)}
203+
sInv = []*mathlib.Zr{math.One(p.Curve)}
204+
} else {
205+
s, sInv = ComputeSVector(1<<i, xList, p.Curve)
206+
}
207+
208+
pointsL := make([]*mathlib.G1, 0, len(p.LeftGenerators)+1)
209+
scalarsL := make([]*mathlib.Zr, 0, len(p.LeftGenerators)+1)
210+
211+
pointsR := make([]*mathlib.G1, 0, len(p.LeftGenerators)+1)
212+
scalarsR := make([]*mathlib.Zr, 0, len(p.LeftGenerators)+1)
213+
214+
for m := range 1 << i {
215+
for j := range n_current {
216+
idxG_R := j + (2*m+1)*n_current
217+
idxH_L := j + 2*m*n_current
218+
219+
pointsL = append(pointsL, p.LeftGenerators[idxG_R], p.RightGenerators[idxH_L])
220+
scalarsL = append(scalarsL,
221+
p.Curve.ModMul(left[j], s[m], p.Curve.GroupOrder),
222+
p.Curve.ModMul(right[n_current+j], sInv[m], p.Curve.GroupOrder),
223+
)
224+
225+
idxG_L := j + 2*m*n_current
226+
idxH_R := j + (2*m+1)*n_current
227+
228+
pointsR = append(pointsR, p.LeftGenerators[idxG_L], p.RightGenerators[idxH_R])
229+
scalarsR = append(scalarsR,
230+
p.Curve.ModMul(left[n_current+j], s[m], p.Curve.GroupOrder),
231+
p.Curve.ModMul(right[j], sInv[m], p.Curve.GroupOrder),
232+
)
233+
}
234+
}
235+
236+
pointsL = append(pointsL, X)
237+
scalarsL = append(scalarsL, leftIP)
238+
239+
pointsR = append(pointsR, X)
240+
scalarsR = append(scalarsR, rightIP)
202241

203-
// RArray[i] is a commitment to left[n:], right[:n] and their inner product
204-
RArray[i] = CommitVectorPlusOne(left[n:], right[:n], leftGen[:n], rightGen[n:], rightIP, X, p.Curve)
205-
// RArray[i].Add(X.Mul(rightIP))
242+
LArray[i] = p.Curve.MultiScalarMul(pointsL, scalarsL)
243+
RArray[i] = p.Curve.MultiScalarMul(pointsR, scalarsR)
206244

207245
// compute this round's challenge x
208246
array := common.GetG1Array([]*mathlib.G1{LArray[i], RArray[i]})
@@ -211,14 +249,12 @@ func (p *ipaProver) reduce(X, com *mathlib.G1) (*mathlib.Zr, *mathlib.Zr, []*mat
211249
return nil, nil, nil, nil, err
212250
}
213251
x := p.Curve.HashToZr(bytesToHash)
252+
xList = append(xList, x)
214253

215254
// compute 1/x
216255
xInv := x.Copy()
217256
xInv.InvModOrder()
218257

219-
// reduce the generators by 1/2, as a function of the old generators and x and 1/x
220-
leftGen, rightGen = reduceGenerators(leftGen, rightGen, x, xInv, p.Provider)
221-
222258
// reduce the vectors by 1/2, a function of the old vectors and x and 1/x
223259
left, right = reduceVectors(left, right, x, xInv, p.Curve)
224260

@@ -404,27 +440,6 @@ func reduceVectors(left, right []*mathlib.Zr, x, xInv *mathlib.Zr, c *mathlib.Cu
404440
return leftPrime, rightPrime
405441
}
406442

407-
// reduceGenerators reduces the number of generators passed in the parameters by 1/2,
408-
// as a function of the old generators, x and 1/x
409-
func reduceGenerators(leftGen, rightGen []*mathlib.G1, x, xInv *mathlib.Zr, provider executor.ExecutorProvider) ([]*mathlib.G1, []*mathlib.G1) {
410-
l := len(leftGen) / 2
411-
// Use the Executor abstraction so that the execution strategy can be
412-
// swapped without changing this function. SerialExecutor runs each task
413-
// immediately with no locks or goroutine overhead.
414-
exec := provider.New()
415-
for i := range l {
416-
exec.Submit(func() {
417-
// G_i = G_i^{x_inv} * G_{i+l}^x
418-
leftGen[i].Mul2InPlace(xInv, leftGen[i+l], x)
419-
// H_i = H_i^x * H_{i+l}^{x_inv}
420-
rightGen[i].Mul2InPlace(x, rightGen[i+l], xInv)
421-
})
422-
}
423-
exec.Wait()
424-
425-
return leftGen[:l], rightGen[:l]
426-
}
427-
428443
func CommitVector(
429444
left []*mathlib.Zr,
430445
right []*mathlib.Zr,

0 commit comments

Comments
 (0)