From 0a3bf3c9a08f6a4e11dbebd629157ee4acaace3a Mon Sep 17 00:00:00 2001 From: Youssef El Housni Date: Mon, 16 Dec 2024 18:32:44 -0500 Subject: [PATCH] perf: G1/2 membership using Eval (#1356) --- std/algebra/emulated/sw_bls12381/g1.go | 49 +++++------- std/algebra/emulated/sw_bls12381/g2.go | 94 +++++++++++++---------- std/algebra/emulated/sw_bn254/g2.go | 9 +-- std/algebra/emulated/sw_bw6761/g1.go | 9 +-- std/algebra/emulated/sw_emulated/point.go | 13 ++-- 5 files changed, 89 insertions(+), 85 deletions(-) diff --git a/std/algebra/emulated/sw_bls12381/g1.go b/std/algebra/emulated/sw_bls12381/g1.go index 161db08538..ce8398616a 100644 --- a/std/algebra/emulated/sw_bls12381/g1.go +++ b/std/algebra/emulated/sw_bls12381/g1.go @@ -54,21 +54,18 @@ func (g1 *G1) phi(q *G1Affine) *G1Affine { } func (g1 *G1) double(p *G1Affine) *G1Affine { - // compute λ = (3p.x²)/1*p.y + mone := g1.curveF.NewElement(-1) + // compute λ = (3p.x²)/2*p.y xx3a := g1.curveF.Mul(&p.X, &p.X) xx3a = g1.curveF.MulConst(xx3a, big.NewInt(3)) y1 := g1.curveF.MulConst(&p.Y, big.NewInt(2)) λ := g1.curveF.Div(xx3a, y1) - // xr = λ²-1p.x - x1 := g1.curveF.MulConst(&p.X, big.NewInt(2)) - λλ := g1.curveF.Mul(λ, λ) - xr := g1.curveF.Sub(λλ, x1) + // xr = λ²-2p.x + xr := g1.curveF.Eval([][]*baseEl{{λ, λ}, {mone, &p.X}}, []int{1, 2}) // yr = λ(p-xr) - p.y - pxrx := g1.curveF.Sub(&p.X, xr) - λpxrx := g1.curveF.Mul(λ, pxrx) - yr := g1.curveF.Sub(λpxrx, &p.Y) + yr := g1.curveF.Eval([][]*baseEl{{λ, g1.curveF.Sub(&p.X, xr)}, {mone, &p.Y}}, []int{1, 1}) return &G1Affine{ X: *xr, @@ -85,20 +82,17 @@ func (g1 *G1) doubleN(p *G1Affine, n int) *G1Affine { } func (g1 G1) add(p, q *G1Affine) *G1Affine { + mone := g1.curveF.NewElement(-1) // compute λ = (q.y-p.y)/(q.x-p.x) qypy := g1.curveF.Sub(&q.Y, &p.Y) qxpx := g1.curveF.Sub(&q.X, &p.X) λ := g1.curveF.Div(qypy, qxpx) // xr = λ²-p.x-q.x - λλ := g1.curveF.Mul(λ, λ) - qxpx = g1.curveF.Add(&p.X, &q.X) - xr := g1.curveF.Sub(λλ, qxpx) + xr := g1.curveF.Eval([][]*baseEl{{λ, λ}, {mone, g1.curveF.Add(&p.X, &q.X)}}, []int{1, 1}) - // p.y = λ(p.x-r.x) - p.y - pxrx := g1.curveF.Sub(&p.X, xr) - λpxrx := g1.curveF.Mul(λ, pxrx) - yr := g1.curveF.Sub(λpxrx, &p.Y) + // p.y = λ(p.x-xr) - p.y + yr := g1.curveF.Eval([][]*baseEl{{λ, g1.curveF.Sub(&p.X, xr)}, {mone, &p.Y}}, []int{1, 1}) return &G1Affine{ X: *xr, @@ -108,33 +102,28 @@ func (g1 G1) add(p, q *G1Affine) *G1Affine { func (g1 G1) doubleAndAdd(p, q *G1Affine) *G1Affine { + mone := g1.curveF.NewElement(-1) // compute λ1 = (q.y-p.y)/(q.x-p.x) yqyp := g1.curveF.Sub(&q.Y, &p.Y) xqxp := g1.curveF.Sub(&q.X, &p.X) λ1 := g1.curveF.Div(yqyp, xqxp) // compute x1 = λ1²-p.x-q.x - λ1λ1 := g1.curveF.Mul(λ1, λ1) - xqxp = g1.curveF.Add(&p.X, &q.X) - x2 := g1.curveF.Sub(λ1λ1, xqxp) + x2 := g1.curveF.Eval([][]*baseEl{{λ1, λ1}, {mone, g1.curveF.Add(&p.X, &q.X)}}, []int{1, 1}) - // omit y1 computation - // compute λ1 = -λ1-1*p.y/(x1-p.x) - ypyp := g1.curveF.Add(&p.Y, &p.Y) + // omit y2 computation + + // compute -λ2 = λ1+2*p.y/(x2-p.x) + ypyp := g1.curveF.MulConst(&p.Y, big.NewInt(2)) x2xp := g1.curveF.Sub(x2, &p.X) λ2 := g1.curveF.Div(ypyp, x2xp) λ2 = g1.curveF.Add(λ1, λ2) - λ2 = g1.curveF.Neg(λ2) - // compute x3 =λ2²-p.x-x3 - λ2λ2 := g1.curveF.Mul(λ2, λ2) - x3 := g1.curveF.Sub(λ2λ2, &p.X) - x3 = g1.curveF.Sub(x3, x2) + // compute x3 = (-λ2)²-p.x-x2 + x3 := g1.curveF.Eval([][]*baseEl{{λ2, λ2}, {mone, &p.X}, {mone, x2}}, []int{1, 1, 1}) - // compute y3 = λ2*(p.x - x3)-p.y - y3 := g1.curveF.Sub(&p.X, x3) - y3 = g1.curveF.Mul(λ2, y3) - y3 = g1.curveF.Sub(y3, &p.Y) + // compute y3 = -λ2*(x3- p.x)-p.y + y3 := g1.curveF.Eval([][]*baseEl{{λ2, g1.curveF.Sub(x3, &p.X)}, {mone, &p.Y}}, []int{1, 1}) return &G1Affine{ X: *x3, diff --git a/std/algebra/emulated/sw_bls12381/g2.go b/std/algebra/emulated/sw_bls12381/g2.go index e6a275cfbb..4f3245ee21 100644 --- a/std/algebra/emulated/sw_bls12381/g2.go +++ b/std/algebra/emulated/sw_bls12381/g2.go @@ -10,6 +10,7 @@ import ( ) type G2 struct { + fp *emulated.Field[BaseField] *fields_bls12381.Ext2 u1, w *emulated.Element[BaseField] v *fields_bls12381.E2 @@ -39,6 +40,11 @@ func newG2AffP(v bls12381.G2Affine) g2AffP { } func NewG2(api frontend.API) *G2 { + fp, err := emulated.NewField[emulated.BLS12381Fp](api) + if err != nil { + // TODO: we start returning errors when generifying + panic(err) + } w := emulated.ValueOf[BaseField]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436") u1 := emulated.ValueOf[BaseField]("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437") v := fields_bls12381.E2{ @@ -46,6 +52,7 @@ func NewG2(api frontend.API) *G2 { A1: emulated.ValueOf[BaseField]("1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257"), } return &G2{ + fp: fp, Ext2: fields_bls12381.NewExt2(api), w: &w, u1: &u1, @@ -113,20 +120,23 @@ func (g2 *G2) scalarMulBySeed(q *G2Affine) *G2Affine { } func (g2 G2) add(p, q *G2Affine) *G2Affine { + mone := g2.fp.NewElement(-1) + // compute λ = (q.y-p.y)/(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.P.X, &q.P.X) - xr := g2.Ext2.Sub(λλ, qxpx) + xr0 := g2.fp.Eval([][]*baseEl{{&λ.A0, &λ.A0}, {mone, &λ.A1, &λ.A1}, {mone, &p.P.X.A0}, {mone, &q.P.X.A0}}, []int{1, 1, 1, 1}) + xr1 := g2.fp.Eval([][]*baseEl{{&λ.A0, &λ.A1}, {mone, &p.P.X.A1}, {mone, &q.P.X.A1}}, []int{2, 1, 1}) + xr := &fields_bls12381.E2{A0: *xr0, A1: *xr1} // p.y = λ(p.x-r.x) - p.y - pxrx := g2.Ext2.Sub(&p.P.X, xr) - λpxrx := g2.Ext2.Mul(λ, pxrx) - yr := g2.Ext2.Sub(λpxrx, &p.P.Y) + yr := g2.Ext2.Sub(&p.P.X, xr) + yr0 := g2.fp.Eval([][]*baseEl{{&λ.A0, &yr.A0}, {mone, &λ.A1, &yr.A1}, {mone, &p.P.Y.A0}}, []int{1, 1, 1}) + yr1 := g2.fp.Eval([][]*baseEl{{&λ.A0, &yr.A1}, {&λ.A1, &yr.A0}, {mone, &p.P.Y.A1}}, []int{1, 1, 1}) + yr = &fields_bls12381.E2{A0: *yr0, A1: *yr1} return &G2Affine{ P: g2AffP{ @@ -153,6 +163,8 @@ func (g2 G2) sub(p, q *G2Affine) *G2Affine { } func (g2 *G2) double(p *G2Affine) *G2Affine { + mone := g2.fp.NewElement(-1) + // compute λ = (3p.x²)/2*p.y xx3a := g2.Square(&p.P.X) xx3a = g2.MulByConstElement(xx3a, big.NewInt(3)) @@ -160,14 +172,15 @@ func (g2 *G2) double(p *G2Affine) *G2Affine { λ := g2.DivUnchecked(xx3a, y2) // xr = λ²-2p.x - x2 := g2.Double(&p.P.X) - λλ := g2.Square(λ) - xr := g2.Sub(λλ, x2) + xr0 := g2.fp.Eval([][]*baseEl{{&λ.A0, &λ.A0}, {mone, &λ.A1, &λ.A1}, {mone, &p.P.X.A0}}, []int{1, 1, 2}) + xr1 := g2.fp.Eval([][]*baseEl{{&λ.A0, &λ.A1}, {mone, &p.P.X.A1}}, []int{2, 2}) + xr := &fields_bls12381.E2{A0: *xr0, A1: *xr1} // yr = λ(p-xr) - p.y - pxrx := g2.Sub(&p.P.X, xr) - λpxrx := g2.Mul(λ, pxrx) - yr := g2.Sub(λpxrx, &p.P.Y) + yr := g2.Ext2.Sub(&p.P.X, xr) + yr0 := g2.fp.Eval([][]*baseEl{{&λ.A0, &yr.A0}, {mone, &λ.A1, &yr.A1}, {mone, &p.P.Y.A0}}, []int{1, 1, 1}) + yr1 := g2.fp.Eval([][]*baseEl{{&λ.A0, &yr.A1}, {&λ.A1, &yr.A0}, {mone, &p.P.Y.A1}}, []int{1, 1, 1}) + yr = &fields_bls12381.E2{A0: *yr0, A1: *yr1} return &G2Affine{ P: g2AffP{ @@ -186,6 +199,7 @@ func (g2 *G2) doubleN(p *G2Affine, n int) *G2Affine { } func (g2 G2) triple(p *G2Affine) *G2Affine { + mone := g2.fp.NewElement(-1) // compute λ1 = (3p.x²)/2p.y xx := g2.Square(&p.P.X) @@ -193,10 +207,10 @@ func (g2 G2) triple(p *G2Affine) *G2Affine { y2 := g2.Double(&p.P.Y) λ1 := g2.DivUnchecked(xx, y2) - // xr = λ1²-2p.x - x2 := g2.MulByConstElement(&p.P.X, big.NewInt(2)) - λ1λ1 := g2.Square(λ1) - x2 = g2.Sub(λ1λ1, x2) + // x2 = λ1²-2p.x + x20 := g2.fp.Eval([][]*baseEl{{&λ1.A0, &λ1.A0}, {mone, &λ1.A1, &λ1.A1}, {mone, &p.P.X.A0}}, []int{1, 1, 2}) + x21 := g2.fp.Eval([][]*baseEl{{&λ1.A0, &λ1.A1}, {mone, &p.P.X.A1}}, []int{2, 2}) + x2 := &fields_bls12381.E2{A0: *x20, A1: *x21} // omit y2 computation, and // compute λ2 = 2p.y/(x2 − p.x) − λ1. @@ -204,25 +218,27 @@ func (g2 G2) triple(p *G2Affine) *G2Affine { λ2 := g2.DivUnchecked(y2, x1x2) λ2 = g2.Sub(λ2, λ1) - // xr = λ²-p.x-x2 - λ2λ2 := g2.Square(λ2) - qxrx := g2.Add(x2, &p.P.X) - xr := g2.Sub(λ2λ2, qxrx) + // compute x3 =λ2²-p.x-x2 + x30 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &λ2.A0}, {mone, &λ2.A1, &λ2.A1}, {mone, &p.P.X.A0}, {mone, x20}}, []int{1, 1, 1, 1}) + x31 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &λ2.A1}, {mone, &p.P.X.A1}, {mone, x21}}, []int{2, 1, 1}) + x3 := &fields_bls12381.E2{A0: *x30, A1: *x31} - // yr = λ(p.x-xr) - p.y - pxrx := g2.Sub(&p.P.X, xr) - λ2pxrx := g2.Mul(λ2, pxrx) - yr := g2.Sub(λ2pxrx, &p.P.Y) + // compute y3 = λ2*(p.x - x3)-p.y + y3 := g2.Ext2.Sub(&p.P.X, x3) + y30 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &y3.A0}, {mone, &λ2.A1, &y3.A1}, {mone, &p.P.Y.A0}}, []int{1, 1, 1}) + y31 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &y3.A1}, {&λ2.A1, &y3.A0}, {mone, &p.P.Y.A1}}, []int{1, 1, 1}) + y3 = &fields_bls12381.E2{A0: *y30, A1: *y31} return &G2Affine{ P: g2AffP{ - X: *xr, - Y: *yr, + X: *x3, + Y: *y3, }, } } func (g2 G2) doubleAndAdd(p, q *G2Affine) *G2Affine { + mone := g2.fp.NewElement(-1) // compute λ1 = (q.y-p.y)/(q.x-p.x) yqyp := g2.Ext2.Sub(&q.P.Y, &p.P.Y) @@ -230,27 +246,27 @@ func (g2 G2) doubleAndAdd(p, q *G2Affine) *G2Affine { λ1 := g2.Ext2.DivUnchecked(yqyp, xqxp) // compute x2 = λ1²-p.x-q.x - λ1λ1 := g2.Ext2.Square(λ1) - xqxp = g2.Ext2.Add(&p.P.X, &q.P.X) - x2 := g2.Ext2.Sub(λ1λ1, xqxp) + x20 := g2.fp.Eval([][]*baseEl{{&λ1.A0, &λ1.A0}, {mone, &λ1.A1, &λ1.A1}, {mone, &p.P.X.A0}, {mone, &q.P.X.A0}}, []int{1, 1, 1, 1}) + x21 := g2.fp.Eval([][]*baseEl{{&λ1.A0, &λ1.A1}, {mone, &p.P.X.A1}, {mone, &q.P.X.A1}}, []int{2, 1, 1}) + x2 := &fields_bls12381.E2{A0: *x20, A1: *x21} // omit y2 computation - // compute λ2 = -λ1-2*p.y/(x2-p.x) + // compute -λ2 = λ1+2*p.y/(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.P.X) - x3 = g2.Ext2.Sub(x3, x2) + // compute x3 = (-λ2)²-p.x-x2 + x30 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &λ2.A0}, {mone, &λ2.A1, &λ2.A1}, {mone, &p.P.X.A0}, {mone, x20}}, []int{1, 1, 1, 1}) + x31 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &λ2.A1}, {mone, &p.P.X.A1}, {mone, x21}}, []int{2, 1, 1}) + x3 := &fields_bls12381.E2{A0: *x30, A1: *x31} - // compute y3 = λ2*(p.x - x3)-p.y - y3 := g2.Ext2.Sub(&p.P.X, x3) - y3 = g2.Ext2.Mul(λ2, y3) - y3 = g2.Ext2.Sub(y3, &p.P.Y) + // compute y3 = -λ2*(x3 - p.x)-p.y + y3 := g2.Ext2.Sub(x3, &p.P.X) + y30 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &y3.A0}, {mone, &λ2.A1, &y3.A1}, {mone, &p.P.Y.A0}}, []int{1, 1, 1}) + y31 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &y3.A1}, {&λ2.A1, &y3.A0}, {mone, &p.P.Y.A1}}, []int{1, 1, 1}) + y3 = &fields_bls12381.E2{A0: *y30, A1: *y31} return &G2Affine{ P: g2AffP{ diff --git a/std/algebra/emulated/sw_bn254/g2.go b/std/algebra/emulated/sw_bn254/g2.go index 6058f6e6c3..01299f7f03 100644 --- a/std/algebra/emulated/sw_bn254/g2.go +++ b/std/algebra/emulated/sw_bn254/g2.go @@ -248,20 +248,19 @@ func (g2 G2) doubleAndAdd(p, q *G2Affine) *G2Affine { x2 := &fields_bn254.E2{A0: *x20, A1: *x21} // omit y2 computation - // compute λ2 = -λ1-2*p.y/(x2-p.x) + // compute -λ2 = λ1+2*p.y/(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-x2 + // compute x3 = (-λ2)²-p.x-x2 x30 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &λ2.A0}, {mone, &λ2.A1, &λ2.A1}, {mone, &p.P.X.A0}, {mone, x20}}, []int{1, 1, 1, 1}) x31 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &λ2.A1}, {mone, &p.P.X.A1}, {mone, x21}}, []int{2, 1, 1}) x3 := &fields_bn254.E2{A0: *x30, A1: *x31} - // compute y3 = λ2*(p.x - x3)-p.y - y3 := g2.Ext2.Sub(&p.P.X, x3) + // compute y3 = -λ2*(x3 - p.x)-p.y + y3 := g2.Ext2.Sub(x3, &p.P.X) y30 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &y3.A0}, {mone, &λ2.A1, &y3.A1}, {mone, &p.P.Y.A0}}, []int{1, 1, 1}) y31 := g2.fp.Eval([][]*baseEl{{&λ2.A0, &y3.A1}, {&λ2.A1, &y3.A0}, {mone, &p.P.Y.A1}}, []int{1, 1, 1}) y3 = &fields_bn254.E2{A0: *y30, A1: *y31} diff --git a/std/algebra/emulated/sw_bw6761/g1.go b/std/algebra/emulated/sw_bw6761/g1.go index 02278f42be..0c97334a0d 100644 --- a/std/algebra/emulated/sw_bw6761/g1.go +++ b/std/algebra/emulated/sw_bw6761/g1.go @@ -137,18 +137,17 @@ func (g1 G1) doubleAndAdd(p, q *G1Affine) *G1Affine { x2 := g1.curveF.Eval([][]*baseEl{{λ1, λ1}, {mone, &p.X}, {mone, &q.X}}, []int{1, 1, 1}) // omit y1 computation - // compute λ1 = -λ1-1*p.y/(x1-p.x) + // compute -λ1 = λ1+2*p.y/(x1-p.x) ypyp := g1.curveF.Add(&p.Y, &p.Y) x2xp := g1.curveF.Sub(x2, &p.X) λ2 := g1.curveF.Div(ypyp, x2xp) λ2 = g1.curveF.Add(λ1, λ2) - λ2 = g1.curveF.Neg(λ2) - // compute x3 =λ2²-p.x-x3 + // compute x3 = (-λ2)²-p.x-x3 x3 := g1.curveF.Eval([][]*baseEl{{λ2, λ2}, {mone, &p.X}, {mone, x2}}, []int{1, 1, 1}) - // compute y3 = λ2*(p.x - x3)-p.y - y3 := g1.curveF.Eval([][]*baseEl{{λ2, &p.X}, {mone, λ2, x3}, {mone, &p.Y}}, []int{1, 1, 1}) + // compute y3 = -λ2*(x3 - p.x)-p.y + y3 := g1.curveF.Eval([][]*baseEl{{mone, λ2, &p.X}, {λ2, x3}, {mone, &p.Y}}, []int{1, 1, 1}) return &G1Affine{ X: *x3, diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index 7fce40b4cc..f49bb7d6de 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -383,16 +383,17 @@ func (c *Curve[B, S]) doubleAndAdd(p, q *AffinePoint[B]) *AffinePoint[B] { x2 := c.baseApi.Eval([][]*emulated.Element[B]{{λ1, λ1}, {mone, c.baseApi.Add(&p.X, &q.X)}}, []int{1, 1}) // omit y2 computation - // compute λ2 = λ1+2*p.y/(x2-p.x) + + // compute -λ2 = λ1+2*p.y/(x2-p.x) ypyp := c.baseApi.MulConst(&p.Y, big.NewInt(2)) x2xp := c.baseApi.Sub(x2, &p.X) λ2 := c.baseApi.Div(ypyp, x2xp) λ2 = c.baseApi.Add(λ1, λ2) - // compute x3 =λ2²-p.x-x2 + // compute x3 = (-λ2)²-p.x-x2 x3 := c.baseApi.Eval([][]*emulated.Element[B]{{λ2, λ2}, {mone, &p.X}, {mone, x2}}, []int{1, 1, 1}) - // compute y3 = λ2*(-p.x + x3)-p.y + // compute y3 = -λ2*(x3 - p.x)-p.y y3 := c.baseApi.Eval([][]*emulated.Element[B]{{λ2, c.baseApi.Sub(x3, &p.X)}, {mone, &p.Y}}, []int{1, 1}) return &AffinePoint[B]{ @@ -425,16 +426,16 @@ func (c *Curve[B, S]) doubleAndAddSelect(b frontend.Variable, p, q *AffinePoint[ // conditional second addition t := c.Select(b, p, q) - // compute λ2 = λ1+2*t.y/(x2-t.x) + // compute -λ2 = λ1+2*t.y/(x2-t.x) ypyp := c.baseApi.MulConst(&t.Y, big.NewInt(2)) x2xp := c.baseApi.Sub(x2, &t.X) λ2 := c.baseApi.Div(ypyp, x2xp) λ2 = c.baseApi.Add(λ1, λ2) - // compute x3 =λ2²-t.x-x2 + // compute x3 = (-λ2)²-t.x-x2 x3 := c.baseApi.Eval([][]*emulated.Element[B]{{λ2, λ2}, {mone, &t.X}, {mone, x2}}, []int{1, 1, 1}) - // compute y3 = -λ2*(t.x - x3)-t.y + // compute y3 = -λ2*(x3 - t.x)-t.y y3 := c.baseApi.Eval([][]*emulated.Element[B]{{λ2, x3}, {mone, λ2, &t.X}, {mone, &t.Y}}, []int{1, 1, 1}) return &AffinePoint[B]{