From dc2d2a77fc178f27d4f438741f62144a326d64a8 Mon Sep 17 00:00:00 2001 From: protolambda Date: Thu, 20 May 2021 01:03:47 +0200 Subject: [PATCH] experimental wnaf type change + try flatten MultiExp input --- g1.go | 47 +++++++++++++++++++++++++---------------------- g1_test.go | 37 +++++++++++++++++++------------------ g2.go | 6 +++--- g2_test.go | 8 ++++---- wnaf.go | 24 +++++++++++++++++------- wnaf_test.go | 3 --- 6 files changed, 68 insertions(+), 57 deletions(-) diff --git a/g1.go b/g1.go index 20e54ff..f9642c5 100644 --- a/g1.go +++ b/g1.go @@ -356,20 +356,21 @@ func (g *G1) affine(r, p *PointG1) *PointG1 { } // AffineBatch given multiple of points returns affine representations -func (g *G1) AffineBatch(p []*PointG1) { - inverses := make([]fe, len(p)) +func (g *G1) AffineBatch(p []PointG1) { + inverses := make([]fe, len(p), len(p)) for i := 0; i < len(p); i++ { inverses[i].set(&p[i][2]) } inverseBatch(inverses) t := g.t for i := 0; i < len(p); i++ { - if !g.IsAffine(p[i]) && !g.IsZero(p[i]) { + pi := &p[i] + if !g.IsAffine(pi) && !g.IsZero(pi) { square(t[1], &inverses[i]) - mul(&p[i][0], &p[i][0], t[1]) + mul(&pi[0], &pi[0], t[1]) mul(t[0], &inverses[i], t[1]) - mul(&p[i][1], &p[i][1], t[0]) - p[i][2].one() + mul(&pi[1], &pi[1], t[0]) + pi[2].one() } } } @@ -565,7 +566,7 @@ func (g *G1) wnafMulBig(r, p *PointG1, e *big.Int) *PointG1 { func (g *G1) wnafMul(c, p *PointG1, wnaf nafNumber) *PointG1 { - l := (1 << (wnafMulWindowG1 - 1)) + l := int8(1 << (wnafMulWindowG1 - 1)) twoP, acc := g.New(), new(PointG1).Set(p) g.Double(twoP, p) @@ -577,7 +578,7 @@ func (g *G1) wnafMul(c, p *PointG1, wnaf nafNumber) *PointG1 { table[0].Set(p) g.Neg(table[l], table[0]) - for i := 1; i < l; i++ { + for i := int8(1); i < l; i++ { g.AddMixed(acc, acc, twoP) table[i], table[i+l] = g.New(), g.New() table[i].Set(acc) @@ -606,6 +607,11 @@ func (g *G1) glvMulBig(r, p *PointG1, e *big.Int) *PointG1 { return g.glvMul(r, p, new(glvVectorBig).new(e)) } +// TODO: constant size +//const glvMulWindowG1const uint = 4 +//const glvMulWindowG1constL uint = 1 << (glvMulWindowG1const - 1) +//type glvMulTable [glvMulWindowG1constL]PointG1 + func (g *G1) glvMul(r, p0 *PointG1, v glvVector) *PointG1 { w := glvMulWindowG1 @@ -614,20 +620,17 @@ func (g *G1) glvMul(r, p0 *PointG1, v glvVector) *PointG1 { // prepare tables // tableK1 = {P, 3P, 5P, ...} // tableK2 = {λP, 3λP, 5λP, ...} - tableK1, tableK2 := make([]*PointG1, l), make([]*PointG1, l) + var tableK1, tableK2 = make([]PointG1, l), make([]PointG1, l) double := g.New() g.Double(double, p0) g.affine(double, double) - tableK1[0] = new(PointG1) tableK1[0].Set(p0) for i := 1; i < l; i++ { - tableK1[i] = new(PointG1) - g.AddMixed(tableK1[i], tableK1[i-1], double) + g.AddMixed(&tableK1[i], &tableK1[i-1], double) } - g.AffineBatch(tableK1) + g.AffineBatch(tableK1[:]) for i := 0; i < l; i++ { - tableK2[i] = new(PointG1) - g.glvEndomorphism(tableK2[i], tableK1[i]) + g.glvEndomorphism(&tableK2[i], &tableK1[i]) } // recode small scalars @@ -641,13 +644,13 @@ func (g *G1) glvMul(r, p0 *PointG1, v glvVector) *PointG1 { acc, p1 := g.New(), g.New() // function for naf addition - add := func(table []*PointG1, naf int) { + add := func(table []PointG1, naf int8) { if naf != 0 { nafAbs := naf if nafAbs < 0 { nafAbs = -nafAbs } - p1.Set(table[nafAbs>>1]) + p1.Set(&table[nafAbs>>1]) if naf < 0 { g.Neg(p1, p1) } @@ -723,7 +726,7 @@ func (g *G1) MultiExpBig(r *PointG1, points []*PointG1, scalars []*big.Int) (*Po // MultiExp calculates multi exponentiation. Given pairs of G1 point and scalar values `(P_0, e_0), (P_1, e_1), ... (P_n, e_n)`, // calculates `r = e_0 * P_0 + e_1 * P_1 + ... + e_n * P_n`. Length of points and scalars are expected to be equal, // otherwise an error is returned. Result is assigned to point at first argument. -func (g *G1) MultiExp(r *PointG1, points []*PointG1, scalars []*Fr) (*PointG1, error) { +func (g *G1) MultiExp(r *PointG1, points []PointG1, scalars []*Fr) (*PointG1, error) { if len(points) != len(scalars) { return nil, errors.New("point and scalar vectors should be in same length") } @@ -736,7 +739,7 @@ func (g *G1) MultiExp(r *PointG1, points []*PointG1, scalars []*Fr) (*PointG1, e } bucketSize := (1 << c) - 1 - windows := make([]*PointG1, 255/c+1) + windows := make([]PointG1, 255/c+1) bucket := make([]PointG1, bucketSize) for j := 0; j < len(windows); j++ { @@ -748,7 +751,7 @@ func (g *G1) MultiExp(r *PointG1, points []*PointG1, scalars []*Fr) (*PointG1, e for i := 0; i < len(scalars); i++ { index := bucketSize & int(scalars[i].sliceUint64(c*j)) if index != 0 { - g.AddMixed(&bucket[index-1], &bucket[index-1], points[i]) + g.AddMixed(&bucket[index-1], &bucket[index-1], &points[i]) } } @@ -757,7 +760,7 @@ func (g *G1) MultiExp(r *PointG1, points []*PointG1, scalars []*Fr) (*PointG1, e g.Add(sum, sum, &bucket[i]) g.Add(acc, acc, sum) } - windows[j] = g.New().Set(acc) + windows[j].Set(acc) } g.AffineBatch(windows) @@ -767,7 +770,7 @@ func (g *G1) MultiExp(r *PointG1, points []*PointG1, scalars []*Fr) (*PointG1, e for j := 0; j < c; j++ { g.Double(acc, acc) } - g.AddMixed(acc, acc, windows[i]) + g.AddMixed(acc, acc, &windows[i]) } return r.Set(acc), nil } diff --git a/g1_test.go b/g1_test.go index 690de84..6c0c177 100644 --- a/g1_test.go +++ b/g1_test.go @@ -134,18 +134,18 @@ func TestG1IsOnCurve(t *testing.T) { func TestG1BatchAffine(t *testing.T) { n := 20 g := NewG1() - points0 := make([]*PointG1, n) - points1 := make([]*PointG1, n) + points0 := make([]PointG1, n) + points1 := make([]PointG1, n) for i := 0; i < n; i++ { - points0[i] = g.rand() - points1[i] = g.New().Set(points0[i]) - if g.IsAffine(points0[i]) { + points0[i].Set(g.rand()) + points1[i].Set(&points0[i]) + if g.IsAffine(&points0[i]) { t.Fatal("expect non affine point") } } g.AffineBatch(points0) for i := 0; i < n; i++ { - if !g.Equal(points0[i], points1[i]) { + if !g.Equal(&points0[i], &points1[i]) { t.Fatal("batch affine failed") } } @@ -362,10 +362,11 @@ func TestG1MultiExpExpected(t *testing.T) { g := NewG1() one := g.one() var scalars [2]*Fr - var bases [2]*PointG1 + var bases [2]PointG1 scalars[0] = &Fr{2} scalars[1] = &Fr{3} - bases[0], bases[1] = new(PointG1).Set(one), new(PointG1).Set(one) + bases[0].Set(one) + bases[1].Set(one) expected, result := g.New(), g.New() g.mulScalar(expected, one, &Fr{5}) _, _ = g.MultiExp(result, bases[:], scalars[:]) @@ -419,7 +420,7 @@ func TestG1MultiExpBig(t *testing.T) { func TestG1MultiExp(t *testing.T) { g := NewG1() for n := 1; n < 1024+1; n = n * 2 { - bases := make([]*PointG1, n) + bases := make([]PointG1, n) scalars := make([]*Fr, n) var err error for i := 0; i < n; i++ { @@ -427,11 +428,11 @@ func TestG1MultiExp(t *testing.T) { if err != nil { t.Fatal(err) } - bases[i] = g.randAffine() + bases[i].Set(g.randAffine()) } expected, tmp := g.New(), g.New() for i := 0; i < n; i++ { - g.mulScalar(tmp, bases[i], scalars[i]) + g.mulScalar(tmp, &bases[i], scalars[i]) g.Add(expected, expected, tmp) } result := g.New() @@ -621,8 +622,8 @@ func BenchmarkG1MulWNAF(t *testing.B) { g.mulScalar(res, p, s) } }) - for i := 1; i < 8; i++ { - wnafMulWindowG1 = uint(i) + for i := uint(1); i < maxWindowSize; i++ { + wnafMulWindowG1 = i t.Run(fmt.Sprintf("Fr, window: %d", i), func(t *testing.B) { t.ResetTimer() for i := 0; i < t.N; i++ { @@ -651,8 +652,8 @@ func BenchmarkG1MulGLV(t *testing.B) { g.mulScalar(res, p, s) } }) - for i := 1; i < 8; i++ { - glvMulWindowG1 = uint(i) + for i := uint(1); i < maxWindowSize; i++ { + glvMulWindowG1 = i t.Run(fmt.Sprintf("Fr, window: %d", i), func(t *testing.B) { t.ResetTimer() for i := 0; i < t.N; i++ { @@ -670,8 +671,8 @@ func BenchmarkG1MulGLV(t *testing.B) { func BenchmarkG1MultiExp(t *testing.B) { g := NewG1() - v := func(n int) ([]*PointG1, []*Fr) { - bases := make([]*PointG1, n) + v := func(n int) ([]PointG1, []*Fr) { + bases := make([]PointG1, n) scalars := make([]*Fr, n) var err error for i := 0; i < n; i++ { @@ -679,7 +680,7 @@ func BenchmarkG1MultiExp(t *testing.B) { if err != nil { t.Fatal(err) } - bases[i] = g.randAffine() + bases[i].Set(g.randAffine()) } return bases, scalars } diff --git a/g2.go b/g2.go index 7c56ffd..91c3c9a 100644 --- a/g2.go +++ b/g2.go @@ -547,7 +547,7 @@ func (g *G2) wnafMulBig(r, p *PointG2, e *big.Int) *PointG2 { func (g *G2) wnafMul(c, p *PointG2, wnaf nafNumber) *PointG2 { - l := (1 << (wnafMulWindowG2 - 1)) + l := int8(1 << (wnafMulWindowG2 - 1)) twoP, acc := g.New(), new(PointG2).Set(p) g.Double(twoP, p) @@ -559,7 +559,7 @@ func (g *G2) wnafMul(c, p *PointG2, wnaf nafNumber) *PointG2 { table[0].Set(p) g.Neg(table[l], table[0]) - for i := 1; i < l; i++ { + for i := int8(1); i < l; i++ { g.AddMixed(acc, acc, twoP) table[i], table[i+l] = g.New(), g.New() table[i].Set(acc) @@ -623,7 +623,7 @@ func (g *G2) glvMul(r, p0 *PointG2, v glvVector) *PointG2 { acc, p1 := g.New(), g.New() // function for naf addition - add := func(table []*PointG2, naf int) { + add := func(table []*PointG2, naf int8) { if naf != 0 { nafAbs := naf if nafAbs < 0 { diff --git a/g2_test.go b/g2_test.go index 86cbd3f..dd6f6cb 100644 --- a/g2_test.go +++ b/g2_test.go @@ -659,8 +659,8 @@ func BenchmarkG2MulWNAF(t *testing.B) { g.mulScalar(res, p, s) } }) - for i := 1; i < 8; i++ { - wnafMulWindowG2 = uint(i) + for i := uint(1); i < maxWindowSize; i++ { + wnafMulWindowG2 = i t.Run(fmt.Sprintf("Fr, window: %d", i), func(t *testing.B) { t.ResetTimer() for i := 0; i < t.N; i++ { @@ -689,8 +689,8 @@ func BenchmarkG2MulGLV(t *testing.B) { g.mulScalar(res, p, s) } }) - for i := 1; i < 8; i++ { - glvMulWindowG2 = uint(i) + for i := uint(1); i < maxWindowSize; i++ { + glvMulWindowG2 = i t.Run(fmt.Sprintf("Fr, window: %d", i), func(t *testing.B) { t.ResetTimer() for i := 0; i < t.N; i++ { diff --git a/wnaf.go b/wnaf.go index 9ab2d57..204fb92 100644 --- a/wnaf.go +++ b/wnaf.go @@ -4,7 +4,10 @@ import ( "math/big" ) -type nafNumber []int +// in bits +const maxWindowSize = 6 + +type nafNumber []int8 func (n nafNumber) neg() { for i := 0; i < len(n); i++ { @@ -16,20 +19,24 @@ var bigZero = big.NewInt(0) var bigOne = big.NewInt(1) func (e *Fr) toWNAF(w uint) nafNumber { - naf := nafNumber{} + if w > maxWindowSize { + panic("toWNAF: high w") + } + // fits maximum Fr bit length, avoid re-allocating it + naf := make(nafNumber, 0, 128) if w == 0 { return naf } - windowSize, halfSize, mask := 1<<(w+1), 1<= halfSize { nafSign = nafSign - windowSize } - naf = append(naf, int(nafSign)) + naf = append(naf, nafSign) if nafSign < 0 { laddAssignFR(ee, z.setUint64(uint64(-nafSign))) } else { @@ -72,7 +79,10 @@ func (e *Fr) fromWNAF(naf nafNumber, w uint) *Fr { // caution: does not cover negative case func bigToWNAF(e *big.Int, w uint) nafNumber { - naf := nafNumber{} + if w > maxWindowSize { + panic("bigToWNAF: high w") + } + naf := make(nafNumber, 0, e.BitLen()) if w == 0 { return naf } @@ -86,7 +96,7 @@ func bigToWNAF(e *big.Int, w uint) nafNumber { if nafSign.Cmp(halfSize) >= 0 { nafSign.Sub(nafSign, windowSize) } - naf = append(naf, int(nafSign.Int64())) + naf = append(naf, int8(nafSign.Int64())) ee.Sub(ee, nafSign) } else { naf = append(naf, 0) diff --git a/wnaf_test.go b/wnaf_test.go index c8b8955..e3fb963 100644 --- a/wnaf_test.go +++ b/wnaf_test.go @@ -6,8 +6,6 @@ import ( "testing" ) -var maxWindowSize uint = 9 - func TestWNAFBig(t *testing.T) { var w uint for w = 1; w <= maxWindowSize; w++ { @@ -46,7 +44,6 @@ func TestFrWNAF(t *testing.T) { } func TestFrWNAFCrossAgainstBig(t *testing.T) { - var maxWindowSize uint = 20 var w uint for w = 1; w <= maxWindowSize; w++ { for i := 0; i < fuz; i++ {