Skip to content
This repository has been archived by the owner on Dec 27, 2023. It is now read-only.

experimental wnaf type change + try flatten MultiExp input #32

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 25 additions & 22 deletions g1.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
}
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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)
}
Expand Down Expand Up @@ -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")
}
Expand All @@ -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++ {
Expand All @@ -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])
}
}

Expand All @@ -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)
Expand All @@ -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
}
Expand Down
37 changes: 19 additions & 18 deletions g1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
}
Expand Down Expand Up @@ -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[:])
Expand Down Expand Up @@ -419,19 +420,19 @@ 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++ {
scalars[i], err = new(Fr).Rand(rand.Reader)
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()
Expand Down Expand Up @@ -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++ {
Expand Down Expand Up @@ -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++ {
Expand All @@ -670,16 +671,16 @@ 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++ {
scalars[i], err = new(Fr).Rand(rand.Reader)
if err != nil {
t.Fatal(err)
}
bases[i] = g.randAffine()
bases[i].Set(g.randAffine())
}
return bases, scalars
}
Expand Down
6 changes: 3 additions & 3 deletions g2.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down
8 changes: 4 additions & 4 deletions g2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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++ {
Expand Down Expand Up @@ -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++ {
Expand Down
24 changes: 17 additions & 7 deletions wnaf.go
Original file line number Diff line number Diff line change
Expand Up @@ -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++ {
Expand All @@ -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<<w, (1<<(w+1))-1
windowSize, halfSize, mask := int8(1)<<(w+1), int8(1)<<w, (uint8(1)<<(w+1))-1
ee := new(Fr).Set(e)
z := new(Fr)
for !ee.IsZero() {
if !ee.isEven() {
nafSign := int(ee[0]) & mask
nafSign := int8(uint8(ee[0]) & mask)
if nafSign >= halfSize {
nafSign = nafSign - windowSize
}
naf = append(naf, int(nafSign))
naf = append(naf, nafSign)
if nafSign < 0 {
laddAssignFR(ee, z.setUint64(uint64(-nafSign)))
} else {
Expand Down Expand Up @@ -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
}
Expand All @@ -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)
Expand Down
3 changes: 0 additions & 3 deletions wnaf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (
"testing"
)

var maxWindowSize uint = 9

func TestWNAFBig(t *testing.T) {
var w uint
for w = 1; w <= maxWindowSize; w++ {
Expand Down Expand Up @@ -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++ {
Expand Down