Skip to content

Commit 8455981

Browse files
authored
Merge branch 'master' into chore/gkr-gateregistry
2 parents 71b3101 + b51a3d4 commit 8455981

20 files changed

+1544
-145
lines changed

std/algebra/emulated/sw_bls12381/pairing.go

+114
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,120 @@ func (pr Pairing) AssertIsEqual(x, y *GTEl) {
185185
pr.Ext12.AssertIsEqual(x, y)
186186
}
187187

188+
func (pr Pairing) MuxG2(sel frontend.Variable, inputs ...*G2Affine) *G2Affine {
189+
if len(inputs) == 0 {
190+
return nil
191+
}
192+
if len(inputs) == 1 {
193+
pr.api.AssertIsEqual(sel, 0)
194+
return inputs[0]
195+
}
196+
for i := 1; i < len(inputs); i++ {
197+
if (inputs[0].Lines == nil) != (inputs[i].Lines == nil) {
198+
panic("muxing points with and without precomputed lines")
199+
}
200+
}
201+
var ret G2Affine
202+
XA0 := make([]*emulated.Element[BaseField], len(inputs))
203+
XA1 := make([]*emulated.Element[BaseField], len(inputs))
204+
YA0 := make([]*emulated.Element[BaseField], len(inputs))
205+
YA1 := make([]*emulated.Element[BaseField], len(inputs))
206+
for i := range inputs {
207+
XA0[i] = &inputs[i].P.X.A0
208+
XA1[i] = &inputs[i].P.X.A1
209+
YA0[i] = &inputs[i].P.Y.A0
210+
YA1[i] = &inputs[i].P.Y.A1
211+
}
212+
ret.P.X.A0 = *pr.curveF.Mux(sel, XA0...)
213+
ret.P.X.A1 = *pr.curveF.Mux(sel, XA1...)
214+
ret.P.Y.A0 = *pr.curveF.Mux(sel, YA0...)
215+
ret.P.Y.A1 = *pr.curveF.Mux(sel, YA1...)
216+
217+
if inputs[0].Lines == nil {
218+
return &ret
219+
}
220+
221+
// switch precomputed lines
222+
ret.Lines = new(lineEvaluations)
223+
for j := range inputs[0].Lines[0] {
224+
lineR0A0 := make([]*emulated.Element[BaseField], len(inputs))
225+
lineR0A1 := make([]*emulated.Element[BaseField], len(inputs))
226+
lineR1A0 := make([]*emulated.Element[BaseField], len(inputs))
227+
lineR1A1 := make([]*emulated.Element[BaseField], len(inputs))
228+
for k := 0; k < 2; k++ {
229+
for i := range inputs {
230+
lineR0A0[i] = &inputs[i].Lines[k][j].R0.A0
231+
lineR0A1[i] = &inputs[i].Lines[k][j].R0.A1
232+
lineR1A0[i] = &inputs[i].Lines[k][j].R1.A0
233+
lineR1A1[i] = &inputs[i].Lines[k][j].R1.A1
234+
}
235+
le := &lineEvaluation{
236+
R0: fields_bls12381.E2{
237+
A0: *pr.curveF.Mux(sel, lineR0A0...),
238+
A1: *pr.curveF.Mux(sel, lineR0A1...),
239+
},
240+
R1: fields_bls12381.E2{
241+
A0: *pr.curveF.Mux(sel, lineR1A0...),
242+
A1: *pr.curveF.Mux(sel, lineR1A1...),
243+
},
244+
}
245+
ret.Lines[k][j] = le
246+
}
247+
}
248+
249+
return &ret
250+
}
251+
252+
func (pr Pairing) MuxGt(sel frontend.Variable, inputs ...*GTEl) *GTEl {
253+
if len(inputs) == 0 {
254+
return nil
255+
}
256+
if len(inputs) == 1 {
257+
pr.api.AssertIsEqual(sel, 0)
258+
return inputs[0]
259+
}
260+
var ret GTEl
261+
A0s := make([]*emulated.Element[BaseField], len(inputs))
262+
A1s := make([]*emulated.Element[BaseField], len(inputs))
263+
A2s := make([]*emulated.Element[BaseField], len(inputs))
264+
A3s := make([]*emulated.Element[BaseField], len(inputs))
265+
A4s := make([]*emulated.Element[BaseField], len(inputs))
266+
A5s := make([]*emulated.Element[BaseField], len(inputs))
267+
A6s := make([]*emulated.Element[BaseField], len(inputs))
268+
A7s := make([]*emulated.Element[BaseField], len(inputs))
269+
A8s := make([]*emulated.Element[BaseField], len(inputs))
270+
A9s := make([]*emulated.Element[BaseField], len(inputs))
271+
A10s := make([]*emulated.Element[BaseField], len(inputs))
272+
A11s := make([]*emulated.Element[BaseField], len(inputs))
273+
for i := range inputs {
274+
A0s[i] = &inputs[i].A0
275+
A1s[i] = &inputs[i].A1
276+
A2s[i] = &inputs[i].A2
277+
A3s[i] = &inputs[i].A3
278+
A4s[i] = &inputs[i].A4
279+
A5s[i] = &inputs[i].A5
280+
A6s[i] = &inputs[i].A6
281+
A7s[i] = &inputs[i].A7
282+
A8s[i] = &inputs[i].A8
283+
A9s[i] = &inputs[i].A9
284+
A10s[i] = &inputs[i].A10
285+
A11s[i] = &inputs[i].A11
286+
}
287+
ret.A0 = *pr.curveF.Mux(sel, A0s...)
288+
ret.A1 = *pr.curveF.Mux(sel, A1s...)
289+
ret.A2 = *pr.curveF.Mux(sel, A2s...)
290+
ret.A3 = *pr.curveF.Mux(sel, A3s...)
291+
ret.A4 = *pr.curveF.Mux(sel, A4s...)
292+
ret.A5 = *pr.curveF.Mux(sel, A5s...)
293+
ret.A6 = *pr.curveF.Mux(sel, A6s...)
294+
ret.A7 = *pr.curveF.Mux(sel, A7s...)
295+
ret.A8 = *pr.curveF.Mux(sel, A8s...)
296+
ret.A9 = *pr.curveF.Mux(sel, A9s...)
297+
ret.A10 = *pr.curveF.Mux(sel, A10s...)
298+
ret.A11 = *pr.curveF.Mux(sel, A11s...)
299+
return &ret
300+
}
301+
188302
func (pr Pairing) AssertIsOnCurve(P *G1Affine) {
189303
pr.curve.AssertIsOnCurve(P)
190304
}

std/algebra/emulated/sw_bls12381/pairing_test.go

+91
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"crypto/rand"
66
"fmt"
7+
"math/big"
78
"testing"
89

910
"github.com/consensys/gnark-crypto/ecc"
@@ -302,6 +303,96 @@ func TestGroupMembershipSolve(t *testing.T) {
302303
assert.NoError(err)
303304
}
304305

306+
type MuxesCircuits struct {
307+
InG2 []G2Affine
308+
InGt []GTEl
309+
SelG2 frontend.Variable
310+
SelGt frontend.Variable
311+
ExpectedG2 G2Affine
312+
ExpectedGt GTEl
313+
}
314+
315+
func (c *MuxesCircuits) Define(api frontend.API) error {
316+
g2api := NewG2(api)
317+
pairing, err := NewPairing(api)
318+
if err != nil {
319+
return fmt.Errorf("new pairing: %w", err)
320+
}
321+
var inG2 []*G2Affine
322+
for i := range c.InG2 {
323+
inG2 = append(inG2, &c.InG2[i])
324+
}
325+
var inGt []*GTEl
326+
for i := range c.InGt {
327+
inGt = append(inGt, &c.InGt[i])
328+
}
329+
g2 := pairing.MuxG2(c.SelG2, inG2...)
330+
gt := pairing.MuxGt(c.SelGt, inGt...)
331+
if len(c.InG2) == 0 {
332+
if g2 != nil {
333+
return fmt.Errorf("mux G2: expected nil, got %v", g2)
334+
}
335+
} else {
336+
g2api.AssertIsEqual(g2, &c.ExpectedG2)
337+
}
338+
if len(c.InGt) == 0 {
339+
if gt != nil {
340+
return fmt.Errorf("mux Gt: expected nil, got %v", gt)
341+
}
342+
} else {
343+
pairing.AssertIsEqual(gt, &c.ExpectedGt)
344+
}
345+
return nil
346+
}
347+
348+
func TestPairingMuxes(t *testing.T) {
349+
assert := test.NewAssert(t)
350+
var err error
351+
for _, nbPairs := range []int{0, 1, 2, 3, 4, 5} {
352+
assert.Run(func(assert *test.Assert) {
353+
g2s := make([]bls12381.G2Affine, nbPairs)
354+
gts := make([]bls12381.GT, nbPairs)
355+
var p bls12381.G1Affine
356+
witG2s := make([]G2Affine, nbPairs)
357+
witGts := make([]GTEl, nbPairs)
358+
for i := range nbPairs {
359+
p, g2s[i] = randomG1G2Affines()
360+
gts[i], err = bls12381.Pair([]bls12381.G1Affine{p}, []bls12381.G2Affine{g2s[i]})
361+
assert.NoError(err)
362+
witG2s[i] = NewG2Affine(g2s[i])
363+
witGts[i] = NewGTEl(gts[i])
364+
}
365+
circuit := MuxesCircuits{InG2: make([]G2Affine, nbPairs), InGt: make([]GTEl, nbPairs)}
366+
var witness MuxesCircuits
367+
if nbPairs > 0 {
368+
selG2, err := rand.Int(rand.Reader, big.NewInt(int64(nbPairs)))
369+
assert.NoError(err)
370+
selGt, err := rand.Int(rand.Reader, big.NewInt(int64(nbPairs)))
371+
assert.NoError(err)
372+
expectedG2 := witG2s[selG2.Int64()]
373+
expectedGt := witGts[selGt.Int64()]
374+
witness = MuxesCircuits{
375+
InG2: witG2s,
376+
InGt: witGts,
377+
SelG2: selG2,
378+
SelGt: selGt,
379+
ExpectedG2: expectedG2,
380+
ExpectedGt: expectedGt,
381+
}
382+
} else {
383+
witness = MuxesCircuits{
384+
InG2: witG2s,
385+
InGt: witGts,
386+
SelG2: big.NewInt(0),
387+
SelGt: big.NewInt(0),
388+
}
389+
}
390+
err = test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField())
391+
assert.NoError(err)
392+
}, fmt.Sprintf("nbPairs=%d", nbPairs))
393+
}
394+
}
395+
305396
// bench
306397
func BenchmarkPairing(b *testing.B) {
307398
// e(a,2b) * e(-2a,b) == 1

std/algebra/emulated/sw_bn254/pairing.go

+114
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,120 @@ func (pr Pairing) AssertIsOnCurve(P *G1Affine) {
313313
pr.curve.AssertIsOnCurve(P)
314314
}
315315

316+
func (pr Pairing) MuxG2(sel frontend.Variable, inputs ...*G2Affine) *G2Affine {
317+
if len(inputs) == 0 {
318+
return nil
319+
}
320+
if len(inputs) == 1 {
321+
pr.api.AssertIsEqual(sel, 0)
322+
return inputs[0]
323+
}
324+
for i := 1; i < len(inputs); i++ {
325+
if (inputs[0].Lines == nil) != (inputs[i].Lines == nil) {
326+
panic("muxing points with and without precomputed lines")
327+
}
328+
}
329+
var ret G2Affine
330+
XA0 := make([]*emulated.Element[BaseField], len(inputs))
331+
XA1 := make([]*emulated.Element[BaseField], len(inputs))
332+
YA0 := make([]*emulated.Element[BaseField], len(inputs))
333+
YA1 := make([]*emulated.Element[BaseField], len(inputs))
334+
for i := range inputs {
335+
XA0[i] = &inputs[i].P.X.A0
336+
XA1[i] = &inputs[i].P.X.A1
337+
YA0[i] = &inputs[i].P.Y.A0
338+
YA1[i] = &inputs[i].P.Y.A1
339+
}
340+
ret.P.X.A0 = *pr.curveF.Mux(sel, XA0...)
341+
ret.P.X.A1 = *pr.curveF.Mux(sel, XA1...)
342+
ret.P.Y.A0 = *pr.curveF.Mux(sel, YA0...)
343+
ret.P.Y.A1 = *pr.curveF.Mux(sel, YA1...)
344+
345+
if inputs[0].Lines == nil {
346+
return &ret
347+
}
348+
349+
// switch precomputed lines
350+
ret.Lines = new(lineEvaluations)
351+
for j := range inputs[0].Lines[0] {
352+
lineR0A0 := make([]*emulated.Element[BaseField], len(inputs))
353+
lineR0A1 := make([]*emulated.Element[BaseField], len(inputs))
354+
lineR1A0 := make([]*emulated.Element[BaseField], len(inputs))
355+
lineR1A1 := make([]*emulated.Element[BaseField], len(inputs))
356+
for k := 0; k < 2; k++ {
357+
for i := range inputs {
358+
lineR0A0[i] = &inputs[i].Lines[k][j].R0.A0
359+
lineR0A1[i] = &inputs[i].Lines[k][j].R0.A1
360+
lineR1A0[i] = &inputs[i].Lines[k][j].R1.A0
361+
lineR1A1[i] = &inputs[i].Lines[k][j].R1.A1
362+
}
363+
le := &lineEvaluation{
364+
R0: fields_bn254.E2{
365+
A0: *pr.curveF.Mux(sel, lineR0A0...),
366+
A1: *pr.curveF.Mux(sel, lineR0A1...),
367+
},
368+
R1: fields_bn254.E2{
369+
A0: *pr.curveF.Mux(sel, lineR1A0...),
370+
A1: *pr.curveF.Mux(sel, lineR1A1...),
371+
},
372+
}
373+
ret.Lines[k][j] = le
374+
}
375+
}
376+
377+
return &ret
378+
}
379+
380+
func (pr Pairing) MuxGt(sel frontend.Variable, inputs ...*GTEl) *GTEl {
381+
if len(inputs) == 0 {
382+
return nil
383+
}
384+
if len(inputs) == 1 {
385+
pr.api.AssertIsEqual(sel, 0)
386+
return inputs[0]
387+
}
388+
var ret GTEl
389+
A0s := make([]*emulated.Element[BaseField], len(inputs))
390+
A1s := make([]*emulated.Element[BaseField], len(inputs))
391+
A2s := make([]*emulated.Element[BaseField], len(inputs))
392+
A3s := make([]*emulated.Element[BaseField], len(inputs))
393+
A4s := make([]*emulated.Element[BaseField], len(inputs))
394+
A5s := make([]*emulated.Element[BaseField], len(inputs))
395+
A6s := make([]*emulated.Element[BaseField], len(inputs))
396+
A7s := make([]*emulated.Element[BaseField], len(inputs))
397+
A8s := make([]*emulated.Element[BaseField], len(inputs))
398+
A9s := make([]*emulated.Element[BaseField], len(inputs))
399+
A10s := make([]*emulated.Element[BaseField], len(inputs))
400+
A11s := make([]*emulated.Element[BaseField], len(inputs))
401+
for i := range inputs {
402+
A0s[i] = &inputs[i].A0
403+
A1s[i] = &inputs[i].A1
404+
A2s[i] = &inputs[i].A2
405+
A3s[i] = &inputs[i].A3
406+
A4s[i] = &inputs[i].A4
407+
A5s[i] = &inputs[i].A5
408+
A6s[i] = &inputs[i].A6
409+
A7s[i] = &inputs[i].A7
410+
A8s[i] = &inputs[i].A8
411+
A9s[i] = &inputs[i].A9
412+
A10s[i] = &inputs[i].A10
413+
A11s[i] = &inputs[i].A11
414+
}
415+
ret.A0 = *pr.curveF.Mux(sel, A0s...)
416+
ret.A1 = *pr.curveF.Mux(sel, A1s...)
417+
ret.A2 = *pr.curveF.Mux(sel, A2s...)
418+
ret.A3 = *pr.curveF.Mux(sel, A3s...)
419+
ret.A4 = *pr.curveF.Mux(sel, A4s...)
420+
ret.A5 = *pr.curveF.Mux(sel, A5s...)
421+
ret.A6 = *pr.curveF.Mux(sel, A6s...)
422+
ret.A7 = *pr.curveF.Mux(sel, A7s...)
423+
ret.A8 = *pr.curveF.Mux(sel, A8s...)
424+
ret.A9 = *pr.curveF.Mux(sel, A9s...)
425+
ret.A10 = *pr.curveF.Mux(sel, A10s...)
426+
ret.A11 = *pr.curveF.Mux(sel, A11s...)
427+
return &ret
428+
}
429+
316430
func (pr Pairing) computeTwistEquation(Q *G2Affine) (left, right *fields_bn254.E2) {
317431
// Twist: Y² == X³ + aX + b, where a=0 and b=3/(9+u)
318432
// (X,Y) ∈ {Y² == X³ + aX + b} U (0,0)

0 commit comments

Comments
 (0)