From b532ebb0ff76a27de8ec9c5a05956c5823bb36ba Mon Sep 17 00:00:00 2001 From: Sun Yimin Date: Thu, 13 Jul 2023 11:26:51 +0800 Subject: [PATCH] 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 }