Skip to content

Commit

Permalink
Merge branch 'perf/kzg' into perf/plonk-verifier
Browse files Browse the repository at this point in the history
  • Loading branch information
yelhousni committed Dec 6, 2023
2 parents df19d9b + f8a3f82 commit b4f4738
Show file tree
Hide file tree
Showing 32 changed files with 1,699 additions and 3,486 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import (
{{ template "import_fr" . }}
{{ template "import_kzg" . }}
"github.com/consensys/gnark-crypto/ecc/{{toLower .Curve}}/fr/iop"
"io"
"io"
"errors"
)

Expand Down Expand Up @@ -385,4 +385,4 @@ func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) {
}

return dec.BytesRead(), nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import (
{{ template "import_curve" . }}
{{ template "import_fr" . }}
{{ template "import_fft" . }}
"testing"
"testing"
"math/big"
"math/rand"
"github.com/consensys/gnark/io"
Expand Down
Binary file modified internal/stats/latest.stats
Binary file not shown.
24 changes: 12 additions & 12 deletions internal/stats/snippet.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,10 @@ func initSnippets() {
var dummyG2 sw_bls12377.G2Affine
dummyG1.X = newVariable()
dummyG1.Y = newVariable()
dummyG2.X.A0 = newVariable()
dummyG2.X.A1 = newVariable()
dummyG2.Y.A0 = newVariable()
dummyG2.Y.A1 = newVariable()
dummyG2.P.X.A0 = newVariable()
dummyG2.P.X.A1 = newVariable()
dummyG2.P.Y.A0 = newVariable()
dummyG2.P.Y.A1 = newVariable()

// e(psi0, -gamma)*e(-πC, -δ)*e(πA, πB)
_, _ = sw_bls12377.Pair(api, []sw_bls12377.G1Affine{dummyG1}, []sw_bls12377.G2Affine{dummyG2})
Expand All @@ -126,14 +126,14 @@ func initSnippets() {
var dummyG2 sw_bls24315.G2Affine
dummyG1.X = newVariable()
dummyG1.Y = newVariable()
dummyG2.X.B0.A0 = newVariable()
dummyG2.X.B0.A1 = newVariable()
dummyG2.X.B1.A0 = newVariable()
dummyG2.X.B1.A1 = newVariable()
dummyG2.Y.B0.A0 = newVariable()
dummyG2.Y.B0.A1 = newVariable()
dummyG2.Y.B1.A0 = newVariable()
dummyG2.Y.B1.A1 = newVariable()
dummyG2.P.X.B0.A0 = newVariable()
dummyG2.P.X.B0.A1 = newVariable()
dummyG2.P.X.B1.A0 = newVariable()
dummyG2.P.X.B1.A1 = newVariable()
dummyG2.P.Y.B0.A0 = newVariable()
dummyG2.P.Y.B0.A1 = newVariable()
dummyG2.P.Y.B1.A0 = newVariable()
dummyG2.P.Y.B1.A1 = newVariable()

// e(psi0, -gamma)*e(-πC, -δ)*e(πA, πB)
_, _ = sw_bls24315.Pair(api, []sw_bls24315.G1Affine{dummyG1}, []sw_bls24315.G2Affine{dummyG2})
Expand Down
152 changes: 100 additions & 52 deletions std/algebra/emulated/sw_bls12381/g2.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,29 @@ type G2 struct {
v *fields_bls12381.E2
}

type G2Affine struct {
type g2AffP struct {
X, Y fields_bls12381.E2
}

// G2Affine represents G2 element with optional embedded line precomputations.
type G2Affine struct {
P g2AffP
Lines *lineEvaluations
}

func newG2AffP(v bls12381.G2Affine) g2AffP {
return g2AffP{
X: fields_bls12381.E2{
A0: emulated.ValueOf[BaseField](v.X.A0),
A1: emulated.ValueOf[BaseField](v.X.A1),
},
Y: fields_bls12381.E2{
A0: emulated.ValueOf[BaseField](v.Y.A0),
A1: emulated.ValueOf[BaseField](v.Y.A1),
},
}
}

func NewG2(api frontend.API) *G2 {
w := emulated.ValueOf[BaseField]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436")
u1 := emulated.ValueOf[BaseField]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437")
Expand All @@ -36,25 +55,44 @@ func NewG2(api frontend.API) *G2 {

func NewG2Affine(v bls12381.G2Affine) G2Affine {
return G2Affine{
X: fields_bls12381.E2{
A0: emulated.ValueOf[BaseField](v.X.A0),
A1: emulated.ValueOf[BaseField](v.X.A1),
},
Y: fields_bls12381.E2{
A0: emulated.ValueOf[BaseField](v.Y.A0),
A1: emulated.ValueOf[BaseField](v.Y.A1),
},
P: newG2AffP(v),
}
}

// NewG2AffineFixed returns witness of v with precomputations for efficient
// pairing computation.
func NewG2AffineFixed(v bls12381.G2Affine) G2Affine {
lines := precomputeLines(v)
return G2Affine{
P: newG2AffP(v),
Lines: &lines,
}
}

// NewG2AffineFixedPlaceholder returns a placeholder for the circuit compilation
// when witness will be given with line precomputations using
// [NewG2AffineFixed].
func NewG2AffineFixedPlaceholder() G2Affine {
var lines lineEvaluations
for i := 0; i < len(bls12381.LoopCounter)-1; i++ {
lines[0][i] = &lineEvaluation{}
lines[1][i] = &lineEvaluation{}
}
return G2Affine{
Lines: &lines,
}
}

func (g2 *G2) psi(q *G2Affine) *G2Affine {
x := g2.Ext2.MulByElement(&q.X, g2.u1)
y := g2.Ext2.Conjugate(&q.Y)
x := g2.Ext2.MulByElement(&q.P.X, g2.u1)
y := g2.Ext2.Conjugate(&q.P.Y)
y = g2.Ext2.Mul(y, g2.v)

return &G2Affine{
X: fields_bls12381.E2{A0: x.A1, A1: x.A0},
Y: *y,
P: g2AffP{
X: fields_bls12381.E2{A0: x.A1, A1: x.A0},
Y: *y,
},
}
}

Expand All @@ -76,32 +114,36 @@ func (g2 *G2) scalarMulBySeed(q *G2Affine) *G2Affine {

func (g2 G2) add(p, q *G2Affine) *G2Affine {
// compute λ = (q.y-p.y)/(q.x-p.x)
qypy := g2.Ext2.Sub(&q.Y, &p.Y)
qxpx := g2.Ext2.Sub(&q.X, &p.X)
qypy := g2.Ext2.Sub(&q.P.Y, &p.P.Y)
qxpx := g2.Ext2.Sub(&q.P.X, &p.P.X)
λ := g2.Ext2.DivUnchecked(qypy, qxpx)

// xr = λ²-p.x-q.x
λλ := g2.Ext2.Square(λ)
qxpx = g2.Ext2.Add(&p.X, &q.X)
qxpx = g2.Ext2.Add(&p.P.X, &q.P.X)
xr := g2.Ext2.Sub(λλ, qxpx)

// p.y = λ(p.x-r.x) - p.y
pxrx := g2.Ext2.Sub(&p.X, xr)
pxrx := g2.Ext2.Sub(&p.P.X, xr)
λpxrx := g2.Ext2.Mul(λ, pxrx)
yr := g2.Ext2.Sub(λpxrx, &p.Y)
yr := g2.Ext2.Sub(λpxrx, &p.P.Y)

return &G2Affine{
X: *xr,
Y: *yr,
P: g2AffP{
X: *xr,
Y: *yr,
},
}
}

func (g2 G2) neg(p *G2Affine) *G2Affine {
xr := &p.X
yr := g2.Ext2.Neg(&p.Y)
xr := &p.P.X
yr := g2.Ext2.Neg(&p.P.Y)
return &G2Affine{
X: *xr,
Y: *yr,
P: g2AffP{
X: *xr,
Y: *yr,
},
}
}

Expand All @@ -112,24 +154,26 @@ func (g2 G2) sub(p, q *G2Affine) *G2Affine {

func (g2 *G2) double(p *G2Affine) *G2Affine {
// compute λ = (3p.x²)/2*p.y
xx3a := g2.Square(&p.X)
xx3a := g2.Square(&p.P.X)
xx3a = g2.MulByConstElement(xx3a, big.NewInt(3))
y2 := g2.Double(&p.Y)
y2 := g2.Double(&p.P.Y)
λ := g2.DivUnchecked(xx3a, y2)

// xr = λ²-2p.x
x2 := g2.Double(&p.X)
x2 := g2.Double(&p.P.X)
λλ := g2.Square(λ)
xr := g2.Sub(λλ, x2)

// yr = λ(p-xr) - p.y
pxrx := g2.Sub(&p.X, xr)
pxrx := g2.Sub(&p.P.X, xr)
λpxrx := g2.Mul(λ, pxrx)
yr := g2.Sub(λpxrx, &p.Y)
yr := g2.Sub(λpxrx, &p.P.Y)

return &G2Affine{
X: *xr,
Y: *yr,
P: g2AffP{
X: *xr,
Y: *yr,
},
}
}

Expand All @@ -144,76 +188,80 @@ func (g2 *G2) doubleN(p *G2Affine, n int) *G2Affine {
func (g2 G2) triple(p *G2Affine) *G2Affine {

// compute λ1 = (3p.x²)/2p.y
xx := g2.Square(&p.X)
xx := g2.Square(&p.P.X)
xx = g2.MulByConstElement(xx, big.NewInt(3))
y2 := g2.Double(&p.Y)
y2 := g2.Double(&p.P.Y)
λ1 := g2.DivUnchecked(xx, y2)

// xr = λ1²-2p.x
x2 := g2.MulByConstElement(&p.X, big.NewInt(2))
x2 := g2.MulByConstElement(&p.P.X, big.NewInt(2))
λ1λ1 := g2.Square(λ1)
x2 = g2.Sub(λ1λ1, x2)

// ommit y2 computation, and
// compute λ2 = 2p.y/(x2 − p.x) − λ1.
x1x2 := g2.Sub(&p.X, x2)
x1x2 := g2.Sub(&p.P.X, x2)
λ2 := g2.DivUnchecked(y2, x1x2)
λ2 = g2.Sub(λ2, λ1)

// xr = λ²-p.x-x2
λ2λ2 := g2.Square(λ2)
qxrx := g2.Add(x2, &p.X)
qxrx := g2.Add(x2, &p.P.X)
xr := g2.Sub(λ2λ2, qxrx)

// yr = λ(p.x-xr) - p.y
pxrx := g2.Sub(&p.X, xr)
pxrx := g2.Sub(&p.P.X, xr)
λ2pxrx := g2.Mul(λ2, pxrx)
yr := g2.Sub(λ2pxrx, &p.Y)
yr := g2.Sub(λ2pxrx, &p.P.Y)

return &G2Affine{
X: *xr,
Y: *yr,
P: g2AffP{
X: *xr,
Y: *yr,
},
}
}

func (g2 G2) doubleAndAdd(p, q *G2Affine) *G2Affine {

// compute λ1 = (q.y-p.y)/(q.x-p.x)
yqyp := g2.Ext2.Sub(&q.Y, &p.Y)
xqxp := g2.Ext2.Sub(&q.X, &p.X)
yqyp := g2.Ext2.Sub(&q.P.Y, &p.P.Y)
xqxp := g2.Ext2.Sub(&q.P.X, &p.P.X)
λ1 := g2.Ext2.DivUnchecked(yqyp, xqxp)

// compute x2 = λ1²-p.x-q.x
λ1λ1 := g2.Ext2.Square(λ1)
xqxp = g2.Ext2.Add(&p.X, &q.X)
xqxp = g2.Ext2.Add(&p.P.X, &q.P.X)
x2 := g2.Ext2.Sub(λ1λ1, xqxp)

// ommit y2 computation
// compute λ2 = -λ1-2*p.y/(x2-p.x)
ypyp := g2.Ext2.Add(&p.Y, &p.Y)
x2xp := g2.Ext2.Sub(x2, &p.X)
ypyp := g2.Ext2.Add(&p.P.Y, &p.P.Y)
x2xp := g2.Ext2.Sub(x2, &p.P.X)
λ2 := g2.Ext2.DivUnchecked(ypyp, x2xp)
λ2 = g2.Ext2.Add(λ1, λ2)
λ2 = g2.Ext2.Neg(λ2)

// compute x3 =λ2²-p.x-x3
λ2λ2 := g2.Ext2.Square(λ2)
x3 := g2.Ext2.Sub(λ2λ2, &p.X)
x3 := g2.Ext2.Sub(λ2λ2, &p.P.X)
x3 = g2.Ext2.Sub(x3, x2)

// compute y3 = λ2*(p.x - x3)-p.y
y3 := g2.Ext2.Sub(&p.X, x3)
y3 := g2.Ext2.Sub(&p.P.X, x3)
y3 = g2.Ext2.Mul(λ2, y3)
y3 = g2.Ext2.Sub(y3, &p.Y)
y3 = g2.Ext2.Sub(y3, &p.P.Y)

return &G2Affine{
X: *x3,
Y: *y3,
P: g2AffP{
X: *x3,
Y: *y3,
},
}
}

// AssertIsEqual asserts that p and q are the same point.
func (g2 *G2) AssertIsEqual(p, q *G2Affine) {
g2.Ext2.AssertIsEqual(&p.X, &q.X)
g2.Ext2.AssertIsEqual(&p.Y, &q.Y)
g2.Ext2.AssertIsEqual(&p.P.X, &q.P.X)
g2.Ext2.AssertIsEqual(&p.P.Y, &q.P.Y)
}
Loading

0 comments on commit b4f4738

Please sign in to comment.