From 5b04c2bc423afb580df1a011dd5a0d45d8058c86 Mon Sep 17 00:00:00 2001 From: Sun Yimin Date: Tue, 14 Jun 2022 14:53:51 +0800 Subject: [PATCH 1/5] fix arm64 issue #27 --- mul_arm64.h | 1 + 1 file changed, 1 insertion(+) diff --git a/mul_arm64.h b/mul_arm64.h index d405eb8..b43404b 100644 --- a/mul_arm64.h +++ b/mul_arm64.h @@ -126,6 +126,7 @@ SBCS R6, R22, R11 \ SBCS R7, R23, R12 \ SBCS R8, R24, R13 \ + SBCS $0, R0, R0 \ \ CSEL CS, R10, R21, R1 \ CSEL CS, R11, R22, R2 \ From a5b7210d53b38c59595f3196efe768a445fc1c16 Mon Sep 17 00:00:00 2001 From: Sun Yimin Date: Wed, 12 Jul 2023 06:39:53 +0800 Subject: [PATCH 2/5] fix // go:noescape --- gfp_decl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfp_decl.go b/gfp_decl.go index be1b809..36710ff 100644 --- a/gfp_decl.go +++ b/gfp_decl.go @@ -11,7 +11,7 @@ import ( var hasBMI2 = cpu.X86.HasBMI2 -// go:noescape +//go:noescape func gfpNeg(c, a *gfP) //go:noescape From b532ebb0ff76a27de8ec9c5a05956c5823bb36ba Mon Sep 17 00:00:00 2001 From: Sun Yimin Date: Thu, 13 Jul 2023 11:26:51 +0800 Subject: [PATCH 3/5] Special squaring loop for use on elements in T_6(gfP2) --- gfp12.go | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++ gfp12_test.go | 84 +++++++++++++++++++++++++++++++++++++ optate.go | 12 +++--- 3 files changed, 203 insertions(+), 6 deletions(-) create mode 100644 gfp12_test.go diff --git a/gfp12.go b/gfp12.go index 250e65e..9d9d227 100644 --- a/gfp12.go +++ b/gfp12.go @@ -158,6 +158,45 @@ func (c *gfP12) Exp(a *gfP12, power *big.Int) *gfP12 { return c } +func (e *gfP12) SpecialPowV(a *gfP12) *gfP12 { + t0, t1, t2 := &gfP12{}, &gfP12{}, &gfP12{} + + t0.SpecialSquare(a) + t0.SpecialSquare(t0) + t0.SpecialSquare(t0) // t0 = a ^ 8 + t1.SpecialSquare(t0) + t1.SpecialSquare(t1) + t1.SpecialSquare(t1) // t1 = a ^ 64 + t2.Conjugate(t0) // t2 = a ^ -8 + t2.Mul(t2, a) // t2 = a ^ -7 + t2.Mul(t2, t1) // t2 = a ^ 57 + t2.SpecialSquare(t2) + t2.SpecialSquare(t2) + t2.SpecialSquare(t2) + t2.SpecialSquare(t2) + t2.SpecialSquare(t2) + t2.SpecialSquare(t2) + t2.SpecialSquare(t2) // t2 = a ^ (2^7 * 57) = a ^ 7296 + t2.Mul(t2, a) // t2 = a ^ 7297 + t2.SpecialSquare(t2) + t2.SpecialSquare(t2) + t2.SpecialSquare(t2) + t2.SpecialSquare(t2) + t2.SpecialSquare(t2) + t2.SpecialSquare(t2) + t2.SpecialSquare(t2) + t2.SpecialSquare(t2) // t2 = a ^ (7297 * 256) = a ^ 1868032 + e.Mul(t2, a) + return e +} + +func (e *gfP12) SpecialPowU(a *gfP12) *gfP12 { + e.SpecialPowV(a) + e.SpecialPowV(e) + e.SpecialPowV(e) + return e +} + func (e *gfP12) Square(a *gfP12) *gfP12 { // Complex squaring algorithm v0 := (&gfP6{}).Mul(&a.x, &a.y) @@ -174,6 +213,80 @@ func (e *gfP12) Square(a *gfP12) *gfP12 { return e } +// Special squaring loop for use on elements in T_6(gfP2) (after the +// easy part of the final exponentiation. Used in the hard part +// of the final exponentiation. Function uses formulas in +// Granger/Scott (PKC2010). +func (e *gfP12) SpecialSquare(a *gfP12) *gfP12 { + tmp := &gfP12{} + + f02 := &tmp.y.x + f01 := &tmp.y.y + f00 := &tmp.y.z + f12 := &tmp.x.x + f11 := &tmp.x.y + f10 := &tmp.x.z + + t00, t01, t02, t10, t11, t12 := &gfP2{}, &gfP2{}, &gfP2{}, &gfP2{}, &gfP2{}, &gfP2{} + + gfP4Square(t11, t00, &a.x.y, &a.y.z) + gfP4Square(t12, t01, &a.y.x, &a.x.z) + gfP4Square(t02, t10, &a.x.x, &a.y.y) + + f00.MulXi(t02) + t02.Set(t10) + t10.Set(f00) + + f00.Add(t00, t00) + t00.Add(f00, t00) + f00.Add(t01, t01) + t01.Add(f00, t01) + f00.Add(t02, t02) + t02.Add(f00, t02) + f00.Add(t10, t10) + t10.Add(f00, t10) + f00.Add(t11, t11) + t11.Add(f00, t11) + f00.Add(t12, t12) + t12.Add(f00, t12) + + f00.Add(&a.y.z, &a.y.z) + f00.Neg(f00) + f01.Add(&a.y.y, &a.y.y) + f01.Neg(f01) + f02.Add(&a.y.x, &a.y.x) + f02.Neg(f02) + f10.Add(&a.x.z, &a.x.z) + f11.Add(&a.x.y, &a.x.y) + f12.Add(&a.x.x, &a.x.x) + + f00.Add(f00, t00) + f01.Add(f01, t01) + f02.Add(f02, t02) + f10.Add(f10, t10) + f11.Add(f11, t11) + f12.Add(f12, t12) + + return e.Set(tmp) +} + +// Implicit gfP4 squaring for Granger/Scott special squaring in final expo +// gfP4Square takes two gfP2 x, y representing the gfP4 element. +func gfP4Square(retX, retY, x, y *gfP2) { + t1, t2 := &gfP2{}, &gfP2{} + + t1.Square(x) + t2.Square(y) + + retX.Add(x, y) + retX.Square(retX) + retX.Sub(retX, t1) + retX.Sub(retX, t2) // retX = 2xy + + retY.MulXi(t1) + retY.Add(retY, t2) // retY = x^2*xi + y^2 +} + func (e *gfP12) Invert(a *gfP12) *gfP12 { // See "Implementing cryptographic pairings", M. Scott, section 3.2. // ftp://136.206.11.249/pub/crypto/pairings.pdf diff --git a/gfp12_test.go b/gfp12_test.go new file mode 100644 index 0000000..a1f60be --- /dev/null +++ b/gfp12_test.go @@ -0,0 +1,84 @@ +package bn256 + +import ( + "math/big" + "testing" +) + +func TestGfP12SpecialSquare(t *testing.T) { + in := gfP12Gen + + got := &gfP12{} + expected := &gfP12{} + + got.SpecialSquare(in) + expected.Square(in) + + if *got != *expected { + t.Errorf("not same got=%v, expected=%v", got, expected) + } +} + +func TestGfp12SpecialPowV(t *testing.T) { + in := gfP12Gen + + got := &gfP12{} + expected := &gfP12{} + + got.SpecialPowV(in) + expected.Exp(in, big.NewInt(1868033)) + + if *got != *expected { + t.Errorf("not same got=%v, expected=%v", got, expected) + } +} + +func TestGfp12SpecialPowU(t *testing.T) { + in := gfP12Gen + + got := &gfP12{} + expected := &gfP12{} + + got.SpecialPowU(in) + expected.Exp(in, u) + + if *got != *expected { + t.Errorf("not same got=%v, expected=%v", got, expected) + } +} + +func BenchmarkGfp12Square(b *testing.B) { + got := &gfP12{} + b.ResetTimer() + + for i := 0; i < b.N; i++ { + got.Square(gfP12Gen) + } +} + +func BenchmarkGfp12SpecialSquare(b *testing.B) { + got := &gfP12{} + b.ResetTimer() + + for i := 0; i < b.N; i++ { + got.SpecialSquare(gfP12Gen) + } +} + +func BenchmarkGfp12ExpU(b *testing.B) { + got := &gfP12{} + b.ResetTimer() + + for i := 0; i < b.N; i++ { + got.Exp(gfP12Gen, u) + } +} + +func BenchmarkGfp12SpecialPowU(b *testing.B) { + got := &gfP12{} + b.ResetTimer() + + for i := 0; i < b.N; i++ { + got.SpecialPowU(gfP12Gen) + } +} diff --git a/optate.go b/optate.go index 126c64c..7307679 100644 --- a/optate.go +++ b/optate.go @@ -224,9 +224,9 @@ func finalExponentiation(in *gfP12) *gfP12 { fp2 := (&gfP12{}).FrobeniusP2(t1) fp3 := (&gfP12{}).Frobenius(fp2) - fu := (&gfP12{}).Exp(t1, u) - fu2 := (&gfP12{}).Exp(fu, u) - fu3 := (&gfP12{}).Exp(fu2, u) + fu := (&gfP12{}).SpecialPowU(t1) + fu2 := (&gfP12{}).SpecialPowU(fu) + fu3 := (&gfP12{}).SpecialPowU(fu2) y3 := (&gfP12{}).Frobenius(fu) fu2p := (&gfP12{}).Frobenius(fu2) @@ -245,14 +245,14 @@ func finalExponentiation(in *gfP12) *gfP12 { y6 := (&gfP12{}).Mul(fu3, fu3p) y6.Conjugate(y6) - t0 := (&gfP12{}).Square(y6) + t0 := (&gfP12{}).SpecialSquare(y6) t0.Mul(t0, y4).Mul(t0, y5) t1.Mul(y3, y5).Mul(t1, t0) t0.Mul(t0, y2) - t1.Square(t1).Mul(t1, t0).Square(t1) + t1.SpecialSquare(t1).Mul(t1, t0).SpecialSquare(t1) t0.Mul(t1, y1) t1.Mul(t1, y0) - t0.Square(t0).Mul(t0, t1) + t0.SpecialSquare(t0).Mul(t0, t1) return t0 } From 384aadc371c4061758a67b1b632ee15238ad9136 Mon Sep 17 00:00:00 2001 From: Sun Yimin Date: Mon, 17 Jul 2023 09:47:22 +0800 Subject: [PATCH 4/5] update according review --- gfp12.go | 61 +++++++++++++++++++++++++-------------------------- gfp12_test.go | 23 ++++++++++--------- optate.go | 17 +++++++------- 3 files changed, 51 insertions(+), 50 deletions(-) diff --git a/gfp12.go b/gfp12.go index 9d9d227..496b40b 100644 --- a/gfp12.go +++ b/gfp12.go @@ -158,42 +158,42 @@ func (c *gfP12) Exp(a *gfP12, power *big.Int) *gfP12 { return c } -func (e *gfP12) SpecialPowV(a *gfP12) *gfP12 { +func (e *gfP12) powToVCyclo6(a *gfP12) *gfP12 { t0, t1, t2 := &gfP12{}, &gfP12{}, &gfP12{} - t0.SpecialSquare(a) - t0.SpecialSquare(t0) - t0.SpecialSquare(t0) // t0 = a ^ 8 - t1.SpecialSquare(t0) - t1.SpecialSquare(t1) - t1.SpecialSquare(t1) // t1 = a ^ 64 + t0.SquareCyclo6(a) + t0.SquareCyclo6(t0) + t0.SquareCyclo6(t0) // t0 = a ^ 8 + t1.SquareCyclo6(t0) + t1.SquareCyclo6(t1) + t1.SquareCyclo6(t1) // t1 = a ^ 64 t2.Conjugate(t0) // t2 = a ^ -8 t2.Mul(t2, a) // t2 = a ^ -7 t2.Mul(t2, t1) // t2 = a ^ 57 - t2.SpecialSquare(t2) - t2.SpecialSquare(t2) - t2.SpecialSquare(t2) - t2.SpecialSquare(t2) - t2.SpecialSquare(t2) - t2.SpecialSquare(t2) - t2.SpecialSquare(t2) // t2 = a ^ (2^7 * 57) = a ^ 7296 + t2.SquareCyclo6(t2) + t2.SquareCyclo6(t2) + t2.SquareCyclo6(t2) + t2.SquareCyclo6(t2) + t2.SquareCyclo6(t2) + t2.SquareCyclo6(t2) + t2.SquareCyclo6(t2) // t2 = a ^ (2^7 * 57) = a ^ 7296 t2.Mul(t2, a) // t2 = a ^ 7297 - t2.SpecialSquare(t2) - t2.SpecialSquare(t2) - t2.SpecialSquare(t2) - t2.SpecialSquare(t2) - t2.SpecialSquare(t2) - t2.SpecialSquare(t2) - t2.SpecialSquare(t2) - t2.SpecialSquare(t2) // t2 = a ^ (7297 * 256) = a ^ 1868032 + t2.SquareCyclo6(t2) + t2.SquareCyclo6(t2) + t2.SquareCyclo6(t2) + t2.SquareCyclo6(t2) + t2.SquareCyclo6(t2) + t2.SquareCyclo6(t2) + t2.SquareCyclo6(t2) + t2.SquareCyclo6(t2) // t2 = a ^ (7297 * 256) = a ^ 1868032 e.Mul(t2, a) return e } -func (e *gfP12) SpecialPowU(a *gfP12) *gfP12 { - e.SpecialPowV(a) - e.SpecialPowV(e) - e.SpecialPowV(e) +func (e *gfP12) PowToUCyclo6(a *gfP12) *gfP12 { + e.powToVCyclo6(a) + e.powToVCyclo6(e) + e.powToVCyclo6(e) return e } @@ -213,11 +213,9 @@ func (e *gfP12) Square(a *gfP12) *gfP12 { return e } -// Special squaring loop for use on elements in T_6(gfP2) (after the -// easy part of the final exponentiation. Used in the hard part -// of the final exponentiation. Function uses formulas in // Granger/Scott (PKC2010). -func (e *gfP12) SpecialSquare(a *gfP12) *gfP12 { +// https://link.springer.com/chapter/10.1007/978-3-642-13013-7_13 +func (e *gfP12) SquareCyclo6(a *gfP12) *gfP12 { tmp := &gfP12{} f02 := &tmp.y.x @@ -271,7 +269,8 @@ func (e *gfP12) SpecialSquare(a *gfP12) *gfP12 { } // Implicit gfP4 squaring for Granger/Scott special squaring in final expo -// gfP4Square takes two gfP2 x, y representing the gfP4 element. +// gfP4Square takes two gfP2 x, y representing the gfP4 element xu+y, where +// u²=ξ. func gfP4Square(retX, retY, x, y *gfP2) { t1, t2 := &gfP2{}, &gfP2{} diff --git a/gfp12_test.go b/gfp12_test.go index a1f60be..58670c4 100644 --- a/gfp12_test.go +++ b/gfp12_test.go @@ -5,13 +5,14 @@ import ( "testing" ) -func TestGfP12SpecialSquare(t *testing.T) { +func TestGfP12SquareCyclo6(t *testing.T) { + // in MUST be an element of the 6-th cyclotomic group. in := gfP12Gen got := &gfP12{} expected := &gfP12{} - got.SpecialSquare(in) + got.SquareCyclo6(in) expected.Square(in) if *got != *expected { @@ -19,13 +20,14 @@ func TestGfP12SpecialSquare(t *testing.T) { } } -func TestGfp12SpecialPowV(t *testing.T) { +func TestGfp12PowToVCyclo6(t *testing.T) { + // in MUST be an element of the 6-th cyclotomic group. in := gfP12Gen got := &gfP12{} expected := &gfP12{} - got.SpecialPowV(in) + got.powToVCyclo6(in) expected.Exp(in, big.NewInt(1868033)) if *got != *expected { @@ -33,13 +35,14 @@ func TestGfp12SpecialPowV(t *testing.T) { } } -func TestGfp12SpecialPowU(t *testing.T) { +func TestGfp12PowToUCyclo6(t *testing.T) { + // in MUST be an element of the 6-th cyclotomic group. in := gfP12Gen got := &gfP12{} expected := &gfP12{} - got.SpecialPowU(in) + got.PowToUCyclo6(in) expected.Exp(in, u) if *got != *expected { @@ -56,12 +59,12 @@ func BenchmarkGfp12Square(b *testing.B) { } } -func BenchmarkGfp12SpecialSquare(b *testing.B) { +func BenchmarkGfp12SquareCyclo6(b *testing.B) { got := &gfP12{} b.ResetTimer() for i := 0; i < b.N; i++ { - got.SpecialSquare(gfP12Gen) + got.SquareCyclo6(gfP12Gen) } } @@ -74,11 +77,11 @@ func BenchmarkGfp12ExpU(b *testing.B) { } } -func BenchmarkGfp12SpecialPowU(b *testing.B) { +func BenchmarkGfp12PowToUCyclo6(b *testing.B) { got := &gfP12{} b.ResetTimer() for i := 0; i < b.N; i++ { - got.SpecialPowU(gfP12Gen) + got.PowToUCyclo6(gfP12Gen) } } diff --git a/optate.go b/optate.go index 7307679..362e1f0 100644 --- a/optate.go +++ b/optate.go @@ -196,9 +196,8 @@ func miller(q *twistPoint, p *curvePoint) *gfP12 { r = newR r2.Square(&minusQ2.y) - a, b, c, newR = lineFunctionAdd(r, minusQ2, bAffine, r2) + a, b, c, _ = lineFunctionAdd(r, minusQ2, bAffine, r2) mulLine(ret, a, b, c) - r = newR return ret } @@ -218,15 +217,15 @@ func finalExponentiation(in *gfP12) *gfP12 { t1.Mul(t1, inv) t2 := (&gfP12{}).FrobeniusP2(t1) - t1.Mul(t1, t2) + t1.Mul(t1, t2) // t1 = in^(p^6-1)(p^2+1), where t1 becomes an element of the 6-th cyclotomic group. fp := (&gfP12{}).Frobenius(t1) fp2 := (&gfP12{}).FrobeniusP2(t1) fp3 := (&gfP12{}).Frobenius(fp2) - fu := (&gfP12{}).SpecialPowU(t1) - fu2 := (&gfP12{}).SpecialPowU(fu) - fu3 := (&gfP12{}).SpecialPowU(fu2) + fu := (&gfP12{}).PowToUCyclo6(t1) + fu2 := (&gfP12{}).PowToUCyclo6(fu) + fu3 := (&gfP12{}).PowToUCyclo6(fu2) y3 := (&gfP12{}).Frobenius(fu) fu2p := (&gfP12{}).Frobenius(fu2) @@ -245,14 +244,14 @@ func finalExponentiation(in *gfP12) *gfP12 { y6 := (&gfP12{}).Mul(fu3, fu3p) y6.Conjugate(y6) - t0 := (&gfP12{}).SpecialSquare(y6) + t0 := (&gfP12{}).SquareCyclo6(y6) t0.Mul(t0, y4).Mul(t0, y5) t1.Mul(y3, y5).Mul(t1, t0) t0.Mul(t0, y2) - t1.SpecialSquare(t1).Mul(t1, t0).SpecialSquare(t1) + t1.SquareCyclo6(t1).Mul(t1, t0).SquareCyclo6(t1) t0.Mul(t1, y1) t1.Mul(t1, y0) - t0.SpecialSquare(t0).Mul(t0, t1) + t0.SquareCyclo6(t0).Mul(t0, t1) return t0 } From 71fb82f233b49554618ca2968c8a2248bda553e9 Mon Sep 17 00:00:00 2001 From: Sun Yimin Date: Tue, 18 Jul 2023 11:03:11 +0800 Subject: [PATCH 5/5] add more comments --- gfp12.go | 53 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/gfp12.go b/gfp12.go index 496b40b..c2332cb 100644 --- a/gfp12.go +++ b/gfp12.go @@ -158,18 +158,23 @@ func (c *gfP12) Exp(a *gfP12, power *big.Int) *gfP12 { return c } +// "New software speed records for cryptographic pairings" +// Section 3.3, Final exponentiation - +// Algorithm 2 Exponentiation by v = 1868033. +// https://cryptojedi.org/papers/dclxvi-20100714.pdf func (e *gfP12) powToVCyclo6(a *gfP12) *gfP12 { + // The sequence of 21 special squarings and 4 multiplications t0, t1, t2 := &gfP12{}, &gfP12{}, &gfP12{} - + t0.SquareCyclo6(a) t0.SquareCyclo6(t0) t0.SquareCyclo6(t0) // t0 = a ^ 8 t1.SquareCyclo6(t0) t1.SquareCyclo6(t1) t1.SquareCyclo6(t1) // t1 = a ^ 64 - t2.Conjugate(t0) // t2 = a ^ -8 - t2.Mul(t2, a) // t2 = a ^ -7 - t2.Mul(t2, t1) // t2 = a ^ 57 + t2.Conjugate(t0) // t2 = a ^ -8 + t2.Mul(t2, a) // t2 = a ^ -7 + t2.Mul(t2, t1) // t2 = a ^ 57 t2.SquareCyclo6(t2) t2.SquareCyclo6(t2) t2.SquareCyclo6(t2) @@ -177,7 +182,7 @@ func (e *gfP12) powToVCyclo6(a *gfP12) *gfP12 { t2.SquareCyclo6(t2) t2.SquareCyclo6(t2) t2.SquareCyclo6(t2) // t2 = a ^ (2^7 * 57) = a ^ 7296 - t2.Mul(t2, a) // t2 = a ^ 7297 + t2.Mul(t2, a) // t2 = a ^ 7297 t2.SquareCyclo6(t2) t2.SquareCyclo6(t2) t2.SquareCyclo6(t2) @@ -190,6 +195,8 @@ func (e *gfP12) powToVCyclo6(a *gfP12) *gfP12 { return e } +// PowToUCyclo6 is used in final exponentiation after easy part(a ^ ((p^2 + 1)(p^6-1))). +// Due to u = v^3, so a^u can be implemented as three [powToVCyclo6]. func (e *gfP12) PowToUCyclo6(a *gfP12) *gfP12 { e.powToVCyclo6(a) e.powToVCyclo6(e) @@ -213,9 +220,24 @@ func (e *gfP12) Square(a *gfP12) *gfP12 { return e } -// Granger/Scott (PKC2010). -// https://link.springer.com/chapter/10.1007/978-3-642-13013-7_13 +// SquareCyclo6 is used in final exponentiation after easy part(a ^ ((p^2 + 1)(p^6-1))). +// Note that after the easy part of the final exponentiation, +// the resulting element lies in cyclotomic subgroup. +// "New software speed records for cryptographic pairings" +// Section 3.3, Final exponentiation +// https://cryptojedi.org/papers/dclxvi-20100714.pdf +// The fomula reference: +// Granger/Scott (PKC2010). +// Section 3.2 +// https://eprint.iacr.org/2009/565.pdf func (e *gfP12) SquareCyclo6(a *gfP12) *gfP12 { + // f = xω + y = (h2τ² + h1τ + h0)ω + (g2τ² + g1τ + g0) = h2ω^5 + g2ω^4 + h1 ω^3 + g1ω² + h0ω + g0 + // we can also represets f as a cubic over a quadartic extension: + // Fp4[s]=Fp2[s]/(s^2-ξ), Fp12[t]=Fp4[t]/(t^3-s), s^2=ξ, t^3=s then + // f = ct² + bt + a = (c0 + c1s)t² + (b0 + b1s)t + (a0 + a1s) = c1t^5 + b1t^4 + a1t^3 + c0t^2 + b0t + a0 + // both extensions are based on Fp2, so we got t^6 = ω^6 = ξ, and + // a0 = g0, a1 = h1, b0 = h0, b1 = g2, c0 = g1, c1 = h2 + // g0 = a.y.z, h1 = a.x.y, h0 = a.x.z, g2 = a.y.x, g1 = a.y.y, h2 = a.x.x tmp := &gfP12{} f02 := &tmp.y.x @@ -227,14 +249,19 @@ func (e *gfP12) SquareCyclo6(a *gfP12) *gfP12 { t00, t01, t02, t10, t11, t12 := &gfP2{}, &gfP2{}, &gfP2{}, &gfP2{}, &gfP2{}, &gfP2{} - gfP4Square(t11, t00, &a.x.y, &a.y.z) - gfP4Square(t12, t01, &a.y.x, &a.x.z) - gfP4Square(t02, t10, &a.x.x, &a.y.y) + gfP4Square(t11, t00, &a.x.y, &a.y.z) // (t00 + t11s) = (a0 + a1s)^2 = a² + gfP4Square(t12, t01, &a.y.x, &a.x.z) // (t01 + t12s) = (b0 + b1s)^2 = b² + gfP4Square(t02, t10, &a.x.x, &a.y.y) // (t10 + t02s) = (c0 + c1s)^2 = c² + // t02 + t10s = (t10 + t02s)s f00.MulXi(t02) t02.Set(t10) t10.Set(f00) + // triples + // (t00 + t11s) = 3a² + // (t01 + t12s) = 3b² + // (t02 + t10s) = 3c²s f00.Add(t00, t00) t00.Add(f00, t00) f00.Add(t01, t01) @@ -248,6 +275,9 @@ func (e *gfP12) SquareCyclo6(a *gfP12) *gfP12 { f00.Add(t12, t12) t12.Add(f00, t12) + // (f00 + f11s) = -2Conjugate(a0 + a1s) = -2Conjugate(a) + // (f01 + f12s) = -2Conjugate(c0 + c1s) = -2Conjugate(c) + // (f02 + f10s) = 2Conjugate(b0 + b1s) = 2Conjugate(b) f00.Add(&a.y.z, &a.y.z) f00.Neg(f00) f01.Add(&a.y.y, &a.y.y) @@ -258,6 +288,9 @@ func (e *gfP12) SquareCyclo6(a *gfP12) *gfP12 { f11.Add(&a.x.y, &a.x.y) f12.Add(&a.x.x, &a.x.x) + // A = (f00 + f11s) = 3a² - 2Conjugate(a) + // C = (f01 + f12s) = 3b² - 2Conjugate(c) + // B = (f02 + f10s) = 3c² + 2Conjugate(b) f00.Add(f00, t00) f01.Add(f01, t01) f02.Add(f02, t02)