From f7d16aaed17d9bfbd2577e5c54bce1703ab6bc57 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 25 Jun 2025 09:10:00 +0000 Subject: [PATCH 1/6] tests: benchmark GLV and windowed mul for different scalar sizes --- .../ecc/template/tests/point.go.tmpl | 51 +++++++++---------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/internal/generator/ecc/template/tests/point.go.tmpl b/internal/generator/ecc/template/tests/point.go.tmpl index 032a452cf2..5a6778f3a1 100644 --- a/internal/generator/ecc/template/tests/point.go.tmpl +++ b/internal/generator/ecc/template/tests/point.go.tmpl @@ -20,10 +20,7 @@ import ( "math/big" "testing" "math/rand/v2" - - {{if eq .Name "secp256k1"}} - crand "crypto/rand" - {{end}} + crand "crypto/rand" {{if or (eq .CoordType "fptower.E2") (eq .CoordType "fptower.E4")}} "github.com/consensys/gnark-crypto/ecc/{{.Name}}/internal/fptower" @@ -795,34 +792,32 @@ func Benchmark{{ $TAffine }}BatchScalarMultiplication(b *testing.B) { } func Benchmark{{ $TJacobian }}ScalarMultiplication(b *testing.B) { - - var scalar big.Int - r := fr.Modulus() - scalar.SetString("5243587517512619047944770508185965837690552500527637822603658699938581184513", 10) - scalar.Add(&scalar, r) - - var doubleAndAdd {{ $TJacobian }} - - b.Run("double and add", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&{{.PointName}}Gen, &scalar) + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) } - }) - - {{if .GLV}} - var glv {{ $TJacobian }} - b.Run("GLV", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - glv.mulGLV(&{{.PointName}}Gen, &scalar) - } - }) - {{end}} + var doubleAndAdd G1Jac + b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + doubleAndAdd.mulWindowed(&g1Gen, scalar) + } + }) + {{ if .GLV }} + var glv G1Jac + b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + glv.mulGLV(&g1Gen, scalar) + } + }) + {{ end }} + } } - {{if .CofactorCleaning}} func Benchmark{{ $TAffine }}CofactorClearing(b *testing.B) { var a {{ $TJacobian }} From 27e99f3c894cb42de4fad81cb76a4490b68b989d Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 25 Jun 2025 09:10:43 +0000 Subject: [PATCH 2/6] chore: generate --- ecc/bls12-377/g1_test.go | 42 ++++++++++++++++++++------------------ ecc/bls12-377/g2_test.go | 42 ++++++++++++++++++++------------------ ecc/bls12-381/g1_test.go | 42 ++++++++++++++++++++------------------ ecc/bls12-381/g2_test.go | 42 ++++++++++++++++++++------------------ ecc/bls24-315/g1_test.go | 42 ++++++++++++++++++++------------------ ecc/bls24-315/g2_test.go | 42 ++++++++++++++++++++------------------ ecc/bls24-317/g1_test.go | 42 ++++++++++++++++++++------------------ ecc/bls24-317/g2_test.go | 42 ++++++++++++++++++++------------------ ecc/bn254/g1_test.go | 42 ++++++++++++++++++++------------------ ecc/bn254/g2_test.go | 42 ++++++++++++++++++++------------------ ecc/bw6-633/g1_test.go | 42 ++++++++++++++++++++------------------ ecc/bw6-633/g2_test.go | 42 ++++++++++++++++++++------------------ ecc/bw6-761/g1_test.go | 42 ++++++++++++++++++++------------------ ecc/bw6-761/g2_test.go | 42 ++++++++++++++++++++------------------ ecc/grumpkin/g1_test.go | 42 ++++++++++++++++++++------------------ ecc/secp256k1/g1_test.go | 44 ++++++++++++++++++++-------------------- 16 files changed, 352 insertions(+), 322 deletions(-) diff --git a/ecc/bls12-377/g1_test.go b/ecc/bls12-377/g1_test.go index 1ba00d2d9d..05f45c6466 100644 --- a/ecc/bls12-377/g1_test.go +++ b/ecc/bls12-377/g1_test.go @@ -6,6 +6,7 @@ package bls12377 import ( + crand "crypto/rand" "fmt" "math/big" "math/rand/v2" @@ -700,29 +701,30 @@ func BenchmarkG1AffineBatchScalarMultiplication(b *testing.B) { } func BenchmarkG1JacScalarMultiplication(b *testing.B) { - - var scalar big.Int - r := fr.Modulus() - scalar.SetString("5243587517512619047944770508185965837690552500527637822603658699938581184513", 10) - scalar.Add(&scalar, r) - - var doubleAndAdd G1Jac - - b.Run("double and add", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g1Gen, &scalar) + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) } - }) - var glv G1Jac - b.Run("GLV", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - glv.mulGLV(&g1Gen, &scalar) - } - }) + var doubleAndAdd G1Jac + b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + doubleAndAdd.mulWindowed(&g1Gen, scalar) + } + }) + var glv G1Jac + b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + glv.mulGLV(&g1Gen, scalar) + } + }) + + } } func BenchmarkG1AffineCofactorClearing(b *testing.B) { diff --git a/ecc/bls12-377/g2_test.go b/ecc/bls12-377/g2_test.go index eee1414a77..febe968256 100644 --- a/ecc/bls12-377/g2_test.go +++ b/ecc/bls12-377/g2_test.go @@ -6,6 +6,7 @@ package bls12377 import ( + crand "crypto/rand" "fmt" "math/big" "math/rand/v2" @@ -689,29 +690,30 @@ func BenchmarkG2AffineBatchScalarMultiplication(b *testing.B) { } func BenchmarkG2JacScalarMultiplication(b *testing.B) { - - var scalar big.Int - r := fr.Modulus() - scalar.SetString("5243587517512619047944770508185965837690552500527637822603658699938581184513", 10) - scalar.Add(&scalar, r) - - var doubleAndAdd G2Jac - - b.Run("double and add", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g2Gen, &scalar) + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) } - }) - var glv G2Jac - b.Run("GLV", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - glv.mulGLV(&g2Gen, &scalar) - } - }) + var doubleAndAdd G1Jac + b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + doubleAndAdd.mulWindowed(&g1Gen, scalar) + } + }) + var glv G1Jac + b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + glv.mulGLV(&g1Gen, scalar) + } + }) + + } } func BenchmarkG2AffineCofactorClearing(b *testing.B) { diff --git a/ecc/bls12-381/g1_test.go b/ecc/bls12-381/g1_test.go index f93ea9bba6..7d2ba3742c 100644 --- a/ecc/bls12-381/g1_test.go +++ b/ecc/bls12-381/g1_test.go @@ -6,6 +6,7 @@ package bls12381 import ( + crand "crypto/rand" "fmt" "math/big" "math/rand/v2" @@ -709,29 +710,30 @@ func BenchmarkG1AffineBatchScalarMultiplication(b *testing.B) { } func BenchmarkG1JacScalarMultiplication(b *testing.B) { - - var scalar big.Int - r := fr.Modulus() - scalar.SetString("5243587517512619047944770508185965837690552500527637822603658699938581184513", 10) - scalar.Add(&scalar, r) - - var doubleAndAdd G1Jac - - b.Run("double and add", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g1Gen, &scalar) + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) } - }) - var glv G1Jac - b.Run("GLV", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - glv.mulGLV(&g1Gen, &scalar) - } - }) + var doubleAndAdd G1Jac + b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + doubleAndAdd.mulWindowed(&g1Gen, scalar) + } + }) + var glv G1Jac + b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + glv.mulGLV(&g1Gen, scalar) + } + }) + + } } func BenchmarkG1AffineCofactorClearing(b *testing.B) { diff --git a/ecc/bls12-381/g2_test.go b/ecc/bls12-381/g2_test.go index 0a1fa3ec0b..be80edb130 100644 --- a/ecc/bls12-381/g2_test.go +++ b/ecc/bls12-381/g2_test.go @@ -6,6 +6,7 @@ package bls12381 import ( + crand "crypto/rand" "fmt" "math/big" "math/rand/v2" @@ -698,29 +699,30 @@ func BenchmarkG2AffineBatchScalarMultiplication(b *testing.B) { } func BenchmarkG2JacScalarMultiplication(b *testing.B) { - - var scalar big.Int - r := fr.Modulus() - scalar.SetString("5243587517512619047944770508185965837690552500527637822603658699938581184513", 10) - scalar.Add(&scalar, r) - - var doubleAndAdd G2Jac - - b.Run("double and add", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g2Gen, &scalar) + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) } - }) - var glv G2Jac - b.Run("GLV", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - glv.mulGLV(&g2Gen, &scalar) - } - }) + var doubleAndAdd G1Jac + b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + doubleAndAdd.mulWindowed(&g1Gen, scalar) + } + }) + var glv G1Jac + b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + glv.mulGLV(&g1Gen, scalar) + } + }) + + } } func BenchmarkG2AffineCofactorClearing(b *testing.B) { diff --git a/ecc/bls24-315/g1_test.go b/ecc/bls24-315/g1_test.go index c84177401a..efc0bb9d4b 100644 --- a/ecc/bls24-315/g1_test.go +++ b/ecc/bls24-315/g1_test.go @@ -6,6 +6,7 @@ package bls24315 import ( + crand "crypto/rand" "fmt" "math/big" "math/rand/v2" @@ -700,29 +701,30 @@ func BenchmarkG1AffineBatchScalarMultiplication(b *testing.B) { } func BenchmarkG1JacScalarMultiplication(b *testing.B) { - - var scalar big.Int - r := fr.Modulus() - scalar.SetString("5243587517512619047944770508185965837690552500527637822603658699938581184513", 10) - scalar.Add(&scalar, r) - - var doubleAndAdd G1Jac - - b.Run("double and add", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g1Gen, &scalar) + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) } - }) - var glv G1Jac - b.Run("GLV", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - glv.mulGLV(&g1Gen, &scalar) - } - }) + var doubleAndAdd G1Jac + b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + doubleAndAdd.mulWindowed(&g1Gen, scalar) + } + }) + var glv G1Jac + b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + glv.mulGLV(&g1Gen, scalar) + } + }) + + } } func BenchmarkG1AffineCofactorClearing(b *testing.B) { diff --git a/ecc/bls24-315/g2_test.go b/ecc/bls24-315/g2_test.go index ea7dfcf1eb..a0934cd94f 100644 --- a/ecc/bls24-315/g2_test.go +++ b/ecc/bls24-315/g2_test.go @@ -6,6 +6,7 @@ package bls24315 import ( + crand "crypto/rand" "fmt" "math/big" "math/rand/v2" @@ -689,29 +690,30 @@ func BenchmarkG2AffineBatchScalarMultiplication(b *testing.B) { } func BenchmarkG2JacScalarMultiplication(b *testing.B) { - - var scalar big.Int - r := fr.Modulus() - scalar.SetString("5243587517512619047944770508185965837690552500527637822603658699938581184513", 10) - scalar.Add(&scalar, r) - - var doubleAndAdd G2Jac - - b.Run("double and add", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g2Gen, &scalar) + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) } - }) - var glv G2Jac - b.Run("GLV", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - glv.mulGLV(&g2Gen, &scalar) - } - }) + var doubleAndAdd G1Jac + b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + doubleAndAdd.mulWindowed(&g1Gen, scalar) + } + }) + var glv G1Jac + b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + glv.mulGLV(&g1Gen, scalar) + } + }) + + } } func BenchmarkG2AffineCofactorClearing(b *testing.B) { diff --git a/ecc/bls24-317/g1_test.go b/ecc/bls24-317/g1_test.go index 881acbfce0..e3e292e969 100644 --- a/ecc/bls24-317/g1_test.go +++ b/ecc/bls24-317/g1_test.go @@ -6,6 +6,7 @@ package bls24317 import ( + crand "crypto/rand" "fmt" "math/big" "math/rand/v2" @@ -700,29 +701,30 @@ func BenchmarkG1AffineBatchScalarMultiplication(b *testing.B) { } func BenchmarkG1JacScalarMultiplication(b *testing.B) { - - var scalar big.Int - r := fr.Modulus() - scalar.SetString("5243587517512619047944770508185965837690552500527637822603658699938581184513", 10) - scalar.Add(&scalar, r) - - var doubleAndAdd G1Jac - - b.Run("double and add", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g1Gen, &scalar) + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) } - }) - var glv G1Jac - b.Run("GLV", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - glv.mulGLV(&g1Gen, &scalar) - } - }) + var doubleAndAdd G1Jac + b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + doubleAndAdd.mulWindowed(&g1Gen, scalar) + } + }) + var glv G1Jac + b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + glv.mulGLV(&g1Gen, scalar) + } + }) + + } } func BenchmarkG1AffineCofactorClearing(b *testing.B) { diff --git a/ecc/bls24-317/g2_test.go b/ecc/bls24-317/g2_test.go index 15095806a4..b70173c4f8 100644 --- a/ecc/bls24-317/g2_test.go +++ b/ecc/bls24-317/g2_test.go @@ -6,6 +6,7 @@ package bls24317 import ( + crand "crypto/rand" "fmt" "math/big" "math/rand/v2" @@ -689,29 +690,30 @@ func BenchmarkG2AffineBatchScalarMultiplication(b *testing.B) { } func BenchmarkG2JacScalarMultiplication(b *testing.B) { - - var scalar big.Int - r := fr.Modulus() - scalar.SetString("5243587517512619047944770508185965837690552500527637822603658699938581184513", 10) - scalar.Add(&scalar, r) - - var doubleAndAdd G2Jac - - b.Run("double and add", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g2Gen, &scalar) + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) } - }) - var glv G2Jac - b.Run("GLV", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - glv.mulGLV(&g2Gen, &scalar) - } - }) + var doubleAndAdd G1Jac + b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + doubleAndAdd.mulWindowed(&g1Gen, scalar) + } + }) + var glv G1Jac + b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + glv.mulGLV(&g1Gen, scalar) + } + }) + + } } func BenchmarkG2AffineCofactorClearing(b *testing.B) { diff --git a/ecc/bn254/g1_test.go b/ecc/bn254/g1_test.go index 49bb9a1e22..79b09d629d 100644 --- a/ecc/bn254/g1_test.go +++ b/ecc/bn254/g1_test.go @@ -6,6 +6,7 @@ package bn254 import ( + crand "crypto/rand" "fmt" "math/big" "math/rand/v2" @@ -661,29 +662,30 @@ func BenchmarkG1AffineBatchScalarMultiplication(b *testing.B) { } func BenchmarkG1JacScalarMultiplication(b *testing.B) { - - var scalar big.Int - r := fr.Modulus() - scalar.SetString("5243587517512619047944770508185965837690552500527637822603658699938581184513", 10) - scalar.Add(&scalar, r) - - var doubleAndAdd G1Jac - - b.Run("double and add", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g1Gen, &scalar) + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) } - }) - var glv G1Jac - b.Run("GLV", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - glv.mulGLV(&g1Gen, &scalar) - } - }) + var doubleAndAdd G1Jac + b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + doubleAndAdd.mulWindowed(&g1Gen, scalar) + } + }) + var glv G1Jac + b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + glv.mulGLV(&g1Gen, scalar) + } + }) + + } } func BenchmarkG1JacAdd(b *testing.B) { diff --git a/ecc/bn254/g2_test.go b/ecc/bn254/g2_test.go index 4b208b505b..e56ca2188c 100644 --- a/ecc/bn254/g2_test.go +++ b/ecc/bn254/g2_test.go @@ -6,6 +6,7 @@ package bn254 import ( + crand "crypto/rand" "fmt" "math/big" "math/rand/v2" @@ -695,29 +696,30 @@ func BenchmarkG2AffineBatchScalarMultiplication(b *testing.B) { } func BenchmarkG2JacScalarMultiplication(b *testing.B) { - - var scalar big.Int - r := fr.Modulus() - scalar.SetString("5243587517512619047944770508185965837690552500527637822603658699938581184513", 10) - scalar.Add(&scalar, r) - - var doubleAndAdd G2Jac - - b.Run("double and add", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g2Gen, &scalar) + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) } - }) - var glv G2Jac - b.Run("GLV", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - glv.mulGLV(&g2Gen, &scalar) - } - }) + var doubleAndAdd G1Jac + b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + doubleAndAdd.mulWindowed(&g1Gen, scalar) + } + }) + var glv G1Jac + b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + glv.mulGLV(&g1Gen, scalar) + } + }) + + } } func BenchmarkG2AffineCofactorClearing(b *testing.B) { diff --git a/ecc/bw6-633/g1_test.go b/ecc/bw6-633/g1_test.go index 21e87ab8f2..a31b228ebd 100644 --- a/ecc/bw6-633/g1_test.go +++ b/ecc/bw6-633/g1_test.go @@ -6,6 +6,7 @@ package bw6633 import ( + crand "crypto/rand" "fmt" "math/big" "math/rand/v2" @@ -700,29 +701,30 @@ func BenchmarkG1AffineBatchScalarMultiplication(b *testing.B) { } func BenchmarkG1JacScalarMultiplication(b *testing.B) { - - var scalar big.Int - r := fr.Modulus() - scalar.SetString("5243587517512619047944770508185965837690552500527637822603658699938581184513", 10) - scalar.Add(&scalar, r) - - var doubleAndAdd G1Jac - - b.Run("double and add", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g1Gen, &scalar) + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) } - }) - var glv G1Jac - b.Run("GLV", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - glv.mulGLV(&g1Gen, &scalar) - } - }) + var doubleAndAdd G1Jac + b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + doubleAndAdd.mulWindowed(&g1Gen, scalar) + } + }) + var glv G1Jac + b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + glv.mulGLV(&g1Gen, scalar) + } + }) + + } } func BenchmarkG1AffineCofactorClearing(b *testing.B) { diff --git a/ecc/bw6-633/g2_test.go b/ecc/bw6-633/g2_test.go index 33f932e23e..602e8370c1 100644 --- a/ecc/bw6-633/g2_test.go +++ b/ecc/bw6-633/g2_test.go @@ -6,6 +6,7 @@ package bw6633 import ( + crand "crypto/rand" "fmt" "math/big" "math/rand/v2" @@ -670,29 +671,30 @@ func BenchmarkG2AffineBatchScalarMultiplication(b *testing.B) { } func BenchmarkG2JacScalarMultiplication(b *testing.B) { - - var scalar big.Int - r := fr.Modulus() - scalar.SetString("5243587517512619047944770508185965837690552500527637822603658699938581184513", 10) - scalar.Add(&scalar, r) - - var doubleAndAdd G2Jac - - b.Run("double and add", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g2Gen, &scalar) + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) } - }) - var glv G2Jac - b.Run("GLV", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - glv.mulGLV(&g2Gen, &scalar) - } - }) + var doubleAndAdd G1Jac + b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + doubleAndAdd.mulWindowed(&g1Gen, scalar) + } + }) + var glv G1Jac + b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + glv.mulGLV(&g1Gen, scalar) + } + }) + + } } func BenchmarkG2AffineCofactorClearing(b *testing.B) { diff --git a/ecc/bw6-761/g1_test.go b/ecc/bw6-761/g1_test.go index ff12e1330a..710f2261e8 100644 --- a/ecc/bw6-761/g1_test.go +++ b/ecc/bw6-761/g1_test.go @@ -6,6 +6,7 @@ package bw6761 import ( + crand "crypto/rand" "fmt" "math/big" "math/rand/v2" @@ -700,29 +701,30 @@ func BenchmarkG1AffineBatchScalarMultiplication(b *testing.B) { } func BenchmarkG1JacScalarMultiplication(b *testing.B) { - - var scalar big.Int - r := fr.Modulus() - scalar.SetString("5243587517512619047944770508185965837690552500527637822603658699938581184513", 10) - scalar.Add(&scalar, r) - - var doubleAndAdd G1Jac - - b.Run("double and add", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g1Gen, &scalar) + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) } - }) - var glv G1Jac - b.Run("GLV", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - glv.mulGLV(&g1Gen, &scalar) - } - }) + var doubleAndAdd G1Jac + b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + doubleAndAdd.mulWindowed(&g1Gen, scalar) + } + }) + var glv G1Jac + b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + glv.mulGLV(&g1Gen, scalar) + } + }) + + } } func BenchmarkG1AffineCofactorClearing(b *testing.B) { diff --git a/ecc/bw6-761/g2_test.go b/ecc/bw6-761/g2_test.go index 49eaa79fc9..5fa59673b9 100644 --- a/ecc/bw6-761/g2_test.go +++ b/ecc/bw6-761/g2_test.go @@ -6,6 +6,7 @@ package bw6761 import ( + crand "crypto/rand" "fmt" "math/big" "math/rand/v2" @@ -670,29 +671,30 @@ func BenchmarkG2AffineBatchScalarMultiplication(b *testing.B) { } func BenchmarkG2JacScalarMultiplication(b *testing.B) { - - var scalar big.Int - r := fr.Modulus() - scalar.SetString("5243587517512619047944770508185965837690552500527637822603658699938581184513", 10) - scalar.Add(&scalar, r) - - var doubleAndAdd G2Jac - - b.Run("double and add", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g2Gen, &scalar) + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) } - }) - var glv G2Jac - b.Run("GLV", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - glv.mulGLV(&g2Gen, &scalar) - } - }) + var doubleAndAdd G1Jac + b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + doubleAndAdd.mulWindowed(&g1Gen, scalar) + } + }) + var glv G1Jac + b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + glv.mulGLV(&g1Gen, scalar) + } + }) + + } } func BenchmarkG2AffineCofactorClearing(b *testing.B) { diff --git a/ecc/grumpkin/g1_test.go b/ecc/grumpkin/g1_test.go index 64325e0733..e9c3f5f08b 100644 --- a/ecc/grumpkin/g1_test.go +++ b/ecc/grumpkin/g1_test.go @@ -6,6 +6,7 @@ package grumpkin import ( + crand "crypto/rand" "fmt" "math/big" "math/rand/v2" @@ -661,29 +662,30 @@ func BenchmarkG1AffineBatchScalarMultiplication(b *testing.B) { } func BenchmarkG1JacScalarMultiplication(b *testing.B) { - - var scalar big.Int - r := fr.Modulus() - scalar.SetString("5243587517512619047944770508185965837690552500527637822603658699938581184513", 10) - scalar.Add(&scalar, r) - - var doubleAndAdd G1Jac - - b.Run("double and add", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g1Gen, &scalar) + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) } - }) - var glv G1Jac - b.Run("GLV", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - glv.mulGLV(&g1Gen, &scalar) - } - }) + var doubleAndAdd G1Jac + b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + doubleAndAdd.mulWindowed(&g1Gen, scalar) + } + }) + var glv G1Jac + b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + glv.mulGLV(&g1Gen, scalar) + } + }) + + } } func BenchmarkG1JacAdd(b *testing.B) { diff --git a/ecc/secp256k1/g1_test.go b/ecc/secp256k1/g1_test.go index 9da07feac4..ec2fa305d3 100644 --- a/ecc/secp256k1/g1_test.go +++ b/ecc/secp256k1/g1_test.go @@ -6,13 +6,12 @@ package secp256k1 import ( + crand "crypto/rand" "fmt" "math/big" "math/rand/v2" "testing" - crand "crypto/rand" - "github.com/consensys/gnark-crypto/ecc/secp256k1/fp" "github.com/consensys/gnark-crypto/ecc/secp256k1/fr" @@ -663,29 +662,30 @@ func BenchmarkG1AffineBatchScalarMultiplication(b *testing.B) { } func BenchmarkG1JacScalarMultiplication(b *testing.B) { - - var scalar big.Int - r := fr.Modulus() - scalar.SetString("5243587517512619047944770508185965837690552500527637822603658699938581184513", 10) - scalar.Add(&scalar, r) - - var doubleAndAdd G1Jac - - b.Run("double and add", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g1Gen, &scalar) + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) } - }) - var glv G1Jac - b.Run("GLV", func(b *testing.B) { - b.ResetTimer() - for j := 0; j < b.N; j++ { - glv.mulGLV(&g1Gen, &scalar) - } - }) + var doubleAndAdd G1Jac + b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + doubleAndAdd.mulWindowed(&g1Gen, scalar) + } + }) + var glv G1Jac + b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + glv.mulGLV(&g1Gen, scalar) + } + }) + + } } func BenchmarkG1JacAdd(b *testing.B) { From 006265f34720b9152539453cda2e9b8599e26286 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 25 Jun 2025 11:59:58 +0000 Subject: [PATCH 3/6] tests: benchmark for the generic method --- ecc/bls12-377/g1_test.go | 18 ++++++++++++++++++ ecc/bls12-377/g2_test.go | 18 ++++++++++++++++++ ecc/bls12-381/g1_test.go | 18 ++++++++++++++++++ ecc/bls12-381/g2_test.go | 18 ++++++++++++++++++ ecc/bls24-315/g1_test.go | 18 ++++++++++++++++++ ecc/bls24-315/g2_test.go | 18 ++++++++++++++++++ ecc/bls24-317/g1_test.go | 18 ++++++++++++++++++ ecc/bls24-317/g2_test.go | 18 ++++++++++++++++++ ecc/bn254/g1_test.go | 18 ++++++++++++++++++ ecc/bn254/g2_test.go | 18 ++++++++++++++++++ ecc/bw6-633/g1_test.go | 18 ++++++++++++++++++ ecc/bw6-633/g2_test.go | 18 ++++++++++++++++++ ecc/bw6-761/g1_test.go | 18 ++++++++++++++++++ ecc/bw6-761/g2_test.go | 18 ++++++++++++++++++ ecc/grumpkin/g1_test.go | 18 ++++++++++++++++++ ecc/secp256k1/g1_test.go | 18 ++++++++++++++++++ .../generator/ecc/template/tests/point.go.tmpl | 18 ++++++++++++++++++ 17 files changed, 306 insertions(+) diff --git a/ecc/bls12-377/g1_test.go b/ecc/bls12-377/g1_test.go index 05f45c6466..91ab2d4a02 100644 --- a/ecc/bls12-377/g1_test.go +++ b/ecc/bls12-377/g1_test.go @@ -727,6 +727,24 @@ func BenchmarkG1JacScalarMultiplication(b *testing.B) { } } +func BenchmarkG1JacScalarMultiplicationMethod(b *testing.B) { + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) + } + + var res G1Jac + b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + res.ScalarMultiplication(&g1Gen, scalar) + } + }) + } +} + func BenchmarkG1AffineCofactorClearing(b *testing.B) { var a G1Jac a.Set(&g1Gen) diff --git a/ecc/bls12-377/g2_test.go b/ecc/bls12-377/g2_test.go index febe968256..184aa5b017 100644 --- a/ecc/bls12-377/g2_test.go +++ b/ecc/bls12-377/g2_test.go @@ -716,6 +716,24 @@ func BenchmarkG2JacScalarMultiplication(b *testing.B) { } } +func BenchmarkG2JacScalarMultiplicationMethod(b *testing.B) { + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) + } + + var res G1Jac + b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + res.ScalarMultiplication(&g1Gen, scalar) + } + }) + } +} + func BenchmarkG2AffineCofactorClearing(b *testing.B) { var a G2Jac a.Set(&g2Gen) diff --git a/ecc/bls12-381/g1_test.go b/ecc/bls12-381/g1_test.go index 7d2ba3742c..ed75081501 100644 --- a/ecc/bls12-381/g1_test.go +++ b/ecc/bls12-381/g1_test.go @@ -736,6 +736,24 @@ func BenchmarkG1JacScalarMultiplication(b *testing.B) { } } +func BenchmarkG1JacScalarMultiplicationMethod(b *testing.B) { + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) + } + + var res G1Jac + b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + res.ScalarMultiplication(&g1Gen, scalar) + } + }) + } +} + func BenchmarkG1AffineCofactorClearing(b *testing.B) { var a G1Jac a.Set(&g1Gen) diff --git a/ecc/bls12-381/g2_test.go b/ecc/bls12-381/g2_test.go index be80edb130..b7f01d24fe 100644 --- a/ecc/bls12-381/g2_test.go +++ b/ecc/bls12-381/g2_test.go @@ -725,6 +725,24 @@ func BenchmarkG2JacScalarMultiplication(b *testing.B) { } } +func BenchmarkG2JacScalarMultiplicationMethod(b *testing.B) { + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) + } + + var res G1Jac + b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + res.ScalarMultiplication(&g1Gen, scalar) + } + }) + } +} + func BenchmarkG2AffineCofactorClearing(b *testing.B) { var a G2Jac a.Set(&g2Gen) diff --git a/ecc/bls24-315/g1_test.go b/ecc/bls24-315/g1_test.go index efc0bb9d4b..d651b5738f 100644 --- a/ecc/bls24-315/g1_test.go +++ b/ecc/bls24-315/g1_test.go @@ -727,6 +727,24 @@ func BenchmarkG1JacScalarMultiplication(b *testing.B) { } } +func BenchmarkG1JacScalarMultiplicationMethod(b *testing.B) { + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) + } + + var res G1Jac + b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + res.ScalarMultiplication(&g1Gen, scalar) + } + }) + } +} + func BenchmarkG1AffineCofactorClearing(b *testing.B) { var a G1Jac a.Set(&g1Gen) diff --git a/ecc/bls24-315/g2_test.go b/ecc/bls24-315/g2_test.go index a0934cd94f..0195478a0a 100644 --- a/ecc/bls24-315/g2_test.go +++ b/ecc/bls24-315/g2_test.go @@ -716,6 +716,24 @@ func BenchmarkG2JacScalarMultiplication(b *testing.B) { } } +func BenchmarkG2JacScalarMultiplicationMethod(b *testing.B) { + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) + } + + var res G1Jac + b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + res.ScalarMultiplication(&g1Gen, scalar) + } + }) + } +} + func BenchmarkG2AffineCofactorClearing(b *testing.B) { var a G2Jac a.Set(&g2Gen) diff --git a/ecc/bls24-317/g1_test.go b/ecc/bls24-317/g1_test.go index e3e292e969..e4e552f8be 100644 --- a/ecc/bls24-317/g1_test.go +++ b/ecc/bls24-317/g1_test.go @@ -727,6 +727,24 @@ func BenchmarkG1JacScalarMultiplication(b *testing.B) { } } +func BenchmarkG1JacScalarMultiplicationMethod(b *testing.B) { + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) + } + + var res G1Jac + b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + res.ScalarMultiplication(&g1Gen, scalar) + } + }) + } +} + func BenchmarkG1AffineCofactorClearing(b *testing.B) { var a G1Jac a.Set(&g1Gen) diff --git a/ecc/bls24-317/g2_test.go b/ecc/bls24-317/g2_test.go index b70173c4f8..71eedbefd8 100644 --- a/ecc/bls24-317/g2_test.go +++ b/ecc/bls24-317/g2_test.go @@ -716,6 +716,24 @@ func BenchmarkG2JacScalarMultiplication(b *testing.B) { } } +func BenchmarkG2JacScalarMultiplicationMethod(b *testing.B) { + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) + } + + var res G1Jac + b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + res.ScalarMultiplication(&g1Gen, scalar) + } + }) + } +} + func BenchmarkG2AffineCofactorClearing(b *testing.B) { var a G2Jac a.Set(&g2Gen) diff --git a/ecc/bn254/g1_test.go b/ecc/bn254/g1_test.go index 79b09d629d..b62a7eb6b0 100644 --- a/ecc/bn254/g1_test.go +++ b/ecc/bn254/g1_test.go @@ -688,6 +688,24 @@ func BenchmarkG1JacScalarMultiplication(b *testing.B) { } } +func BenchmarkG1JacScalarMultiplicationMethod(b *testing.B) { + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) + } + + var res G1Jac + b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + res.ScalarMultiplication(&g1Gen, scalar) + } + }) + } +} + func BenchmarkG1JacAdd(b *testing.B) { var a G1Jac a.Double(&g1Gen) diff --git a/ecc/bn254/g2_test.go b/ecc/bn254/g2_test.go index e56ca2188c..fad1225fb8 100644 --- a/ecc/bn254/g2_test.go +++ b/ecc/bn254/g2_test.go @@ -722,6 +722,24 @@ func BenchmarkG2JacScalarMultiplication(b *testing.B) { } } +func BenchmarkG2JacScalarMultiplicationMethod(b *testing.B) { + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) + } + + var res G1Jac + b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + res.ScalarMultiplication(&g1Gen, scalar) + } + }) + } +} + func BenchmarkG2AffineCofactorClearing(b *testing.B) { var a G2Jac a.Set(&g2Gen) diff --git a/ecc/bw6-633/g1_test.go b/ecc/bw6-633/g1_test.go index a31b228ebd..2ca78bb3f7 100644 --- a/ecc/bw6-633/g1_test.go +++ b/ecc/bw6-633/g1_test.go @@ -727,6 +727,24 @@ func BenchmarkG1JacScalarMultiplication(b *testing.B) { } } +func BenchmarkG1JacScalarMultiplicationMethod(b *testing.B) { + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) + } + + var res G1Jac + b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + res.ScalarMultiplication(&g1Gen, scalar) + } + }) + } +} + func BenchmarkG1AffineCofactorClearing(b *testing.B) { var a G1Jac a.Set(&g1Gen) diff --git a/ecc/bw6-633/g2_test.go b/ecc/bw6-633/g2_test.go index 602e8370c1..ae3c9e021d 100644 --- a/ecc/bw6-633/g2_test.go +++ b/ecc/bw6-633/g2_test.go @@ -697,6 +697,24 @@ func BenchmarkG2JacScalarMultiplication(b *testing.B) { } } +func BenchmarkG2JacScalarMultiplicationMethod(b *testing.B) { + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) + } + + var res G1Jac + b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + res.ScalarMultiplication(&g1Gen, scalar) + } + }) + } +} + func BenchmarkG2AffineCofactorClearing(b *testing.B) { var a G2Jac a.Set(&g2Gen) diff --git a/ecc/bw6-761/g1_test.go b/ecc/bw6-761/g1_test.go index 710f2261e8..d84f695752 100644 --- a/ecc/bw6-761/g1_test.go +++ b/ecc/bw6-761/g1_test.go @@ -727,6 +727,24 @@ func BenchmarkG1JacScalarMultiplication(b *testing.B) { } } +func BenchmarkG1JacScalarMultiplicationMethod(b *testing.B) { + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) + } + + var res G1Jac + b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + res.ScalarMultiplication(&g1Gen, scalar) + } + }) + } +} + func BenchmarkG1AffineCofactorClearing(b *testing.B) { var a G1Jac a.Set(&g1Gen) diff --git a/ecc/bw6-761/g2_test.go b/ecc/bw6-761/g2_test.go index 5fa59673b9..9fba115954 100644 --- a/ecc/bw6-761/g2_test.go +++ b/ecc/bw6-761/g2_test.go @@ -697,6 +697,24 @@ func BenchmarkG2JacScalarMultiplication(b *testing.B) { } } +func BenchmarkG2JacScalarMultiplicationMethod(b *testing.B) { + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) + } + + var res G1Jac + b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + res.ScalarMultiplication(&g1Gen, scalar) + } + }) + } +} + func BenchmarkG2AffineCofactorClearing(b *testing.B) { var a G2Jac a.Set(&g2Gen) diff --git a/ecc/grumpkin/g1_test.go b/ecc/grumpkin/g1_test.go index e9c3f5f08b..43b1630623 100644 --- a/ecc/grumpkin/g1_test.go +++ b/ecc/grumpkin/g1_test.go @@ -688,6 +688,24 @@ func BenchmarkG1JacScalarMultiplication(b *testing.B) { } } +func BenchmarkG1JacScalarMultiplicationMethod(b *testing.B) { + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) + } + + var res G1Jac + b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + res.ScalarMultiplication(&g1Gen, scalar) + } + }) + } +} + func BenchmarkG1JacAdd(b *testing.B) { var a G1Jac a.Double(&g1Gen) diff --git a/ecc/secp256k1/g1_test.go b/ecc/secp256k1/g1_test.go index ec2fa305d3..6266975130 100644 --- a/ecc/secp256k1/g1_test.go +++ b/ecc/secp256k1/g1_test.go @@ -688,6 +688,24 @@ func BenchmarkG1JacScalarMultiplication(b *testing.B) { } } +func BenchmarkG1JacScalarMultiplicationMethod(b *testing.B) { + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) + } + + var res G1Jac + b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + res.ScalarMultiplication(&g1Gen, scalar) + } + }) + } +} + func BenchmarkG1JacAdd(b *testing.B) { var a G1Jac a.Double(&g1Gen) diff --git a/internal/generator/ecc/template/tests/point.go.tmpl b/internal/generator/ecc/template/tests/point.go.tmpl index 5a6778f3a1..d641d39f94 100644 --- a/internal/generator/ecc/template/tests/point.go.tmpl +++ b/internal/generator/ecc/template/tests/point.go.tmpl @@ -818,6 +818,24 @@ func Benchmark{{ $TJacobian }}ScalarMultiplication(b *testing.B) { } } +func Benchmark{{ $TJacobian }}ScalarMultiplicationMethod(b *testing.B) { + for i := 0; i <= fr.Modulus().BitLen(); i += 8 { + bound := new(big.Int).Lsh(big.NewInt(1), uint(i)) + scalar, err := crand.Int(crand.Reader, bound) + if err != nil { + b.Fatalf("failed to generate random scalar: %v", err) + } + + var res G1Jac + b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { + b.ResetTimer() + for j := 0; j < b.N; j++ { + res.ScalarMultiplication(&g1Gen, scalar) + } + }) + } +} + {{if .CofactorCleaning}} func Benchmark{{ $TAffine }}CofactorClearing(b *testing.B) { var a {{ $TJacobian }} From 073b7a148f6571a2dac0198c02b1c574487a6f83 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 25 Jun 2025 14:05:09 +0000 Subject: [PATCH 4/6] tests: fix G2 benchmark --- ecc/bls12-377/g2_test.go | 12 ++++++------ ecc/bls12-381/g2_test.go | 12 ++++++------ ecc/bls24-315/g2_test.go | 12 ++++++------ ecc/bls24-317/g2_test.go | 12 ++++++------ ecc/bn254/g2_test.go | 12 ++++++------ ecc/bw6-633/g2_test.go | 12 ++++++------ ecc/bw6-761/g2_test.go | 12 ++++++------ internal/generator/ecc/template/tests/point.go.tmpl | 12 ++++++------ 8 files changed, 48 insertions(+), 48 deletions(-) diff --git a/ecc/bls12-377/g2_test.go b/ecc/bls12-377/g2_test.go index 184aa5b017..c4de84925a 100644 --- a/ecc/bls12-377/g2_test.go +++ b/ecc/bls12-377/g2_test.go @@ -697,19 +697,19 @@ func BenchmarkG2JacScalarMultiplication(b *testing.B) { b.Fatalf("failed to generate random scalar: %v", err) } - var doubleAndAdd G1Jac + var doubleAndAdd G2Jac b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g1Gen, scalar) + doubleAndAdd.mulWindowed(&g2Gen, scalar) } }) - var glv G1Jac + var glv G2Jac b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - glv.mulGLV(&g1Gen, scalar) + glv.mulGLV(&g2Gen, scalar) } }) @@ -724,11 +724,11 @@ func BenchmarkG2JacScalarMultiplicationMethod(b *testing.B) { b.Fatalf("failed to generate random scalar: %v", err) } - var res G1Jac + var res G2Jac b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - res.ScalarMultiplication(&g1Gen, scalar) + res.ScalarMultiplication(&g2Gen, scalar) } }) } diff --git a/ecc/bls12-381/g2_test.go b/ecc/bls12-381/g2_test.go index b7f01d24fe..bc517c6326 100644 --- a/ecc/bls12-381/g2_test.go +++ b/ecc/bls12-381/g2_test.go @@ -706,19 +706,19 @@ func BenchmarkG2JacScalarMultiplication(b *testing.B) { b.Fatalf("failed to generate random scalar: %v", err) } - var doubleAndAdd G1Jac + var doubleAndAdd G2Jac b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g1Gen, scalar) + doubleAndAdd.mulWindowed(&g2Gen, scalar) } }) - var glv G1Jac + var glv G2Jac b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - glv.mulGLV(&g1Gen, scalar) + glv.mulGLV(&g2Gen, scalar) } }) @@ -733,11 +733,11 @@ func BenchmarkG2JacScalarMultiplicationMethod(b *testing.B) { b.Fatalf("failed to generate random scalar: %v", err) } - var res G1Jac + var res G2Jac b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - res.ScalarMultiplication(&g1Gen, scalar) + res.ScalarMultiplication(&g2Gen, scalar) } }) } diff --git a/ecc/bls24-315/g2_test.go b/ecc/bls24-315/g2_test.go index 0195478a0a..28c358e46d 100644 --- a/ecc/bls24-315/g2_test.go +++ b/ecc/bls24-315/g2_test.go @@ -697,19 +697,19 @@ func BenchmarkG2JacScalarMultiplication(b *testing.B) { b.Fatalf("failed to generate random scalar: %v", err) } - var doubleAndAdd G1Jac + var doubleAndAdd G2Jac b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g1Gen, scalar) + doubleAndAdd.mulWindowed(&g2Gen, scalar) } }) - var glv G1Jac + var glv G2Jac b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - glv.mulGLV(&g1Gen, scalar) + glv.mulGLV(&g2Gen, scalar) } }) @@ -724,11 +724,11 @@ func BenchmarkG2JacScalarMultiplicationMethod(b *testing.B) { b.Fatalf("failed to generate random scalar: %v", err) } - var res G1Jac + var res G2Jac b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - res.ScalarMultiplication(&g1Gen, scalar) + res.ScalarMultiplication(&g2Gen, scalar) } }) } diff --git a/ecc/bls24-317/g2_test.go b/ecc/bls24-317/g2_test.go index 71eedbefd8..cfcb4e4f5b 100644 --- a/ecc/bls24-317/g2_test.go +++ b/ecc/bls24-317/g2_test.go @@ -697,19 +697,19 @@ func BenchmarkG2JacScalarMultiplication(b *testing.B) { b.Fatalf("failed to generate random scalar: %v", err) } - var doubleAndAdd G1Jac + var doubleAndAdd G2Jac b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g1Gen, scalar) + doubleAndAdd.mulWindowed(&g2Gen, scalar) } }) - var glv G1Jac + var glv G2Jac b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - glv.mulGLV(&g1Gen, scalar) + glv.mulGLV(&g2Gen, scalar) } }) @@ -724,11 +724,11 @@ func BenchmarkG2JacScalarMultiplicationMethod(b *testing.B) { b.Fatalf("failed to generate random scalar: %v", err) } - var res G1Jac + var res G2Jac b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - res.ScalarMultiplication(&g1Gen, scalar) + res.ScalarMultiplication(&g2Gen, scalar) } }) } diff --git a/ecc/bn254/g2_test.go b/ecc/bn254/g2_test.go index fad1225fb8..79767d49f7 100644 --- a/ecc/bn254/g2_test.go +++ b/ecc/bn254/g2_test.go @@ -703,19 +703,19 @@ func BenchmarkG2JacScalarMultiplication(b *testing.B) { b.Fatalf("failed to generate random scalar: %v", err) } - var doubleAndAdd G1Jac + var doubleAndAdd G2Jac b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g1Gen, scalar) + doubleAndAdd.mulWindowed(&g2Gen, scalar) } }) - var glv G1Jac + var glv G2Jac b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - glv.mulGLV(&g1Gen, scalar) + glv.mulGLV(&g2Gen, scalar) } }) @@ -730,11 +730,11 @@ func BenchmarkG2JacScalarMultiplicationMethod(b *testing.B) { b.Fatalf("failed to generate random scalar: %v", err) } - var res G1Jac + var res G2Jac b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - res.ScalarMultiplication(&g1Gen, scalar) + res.ScalarMultiplication(&g2Gen, scalar) } }) } diff --git a/ecc/bw6-633/g2_test.go b/ecc/bw6-633/g2_test.go index ae3c9e021d..d061f19b83 100644 --- a/ecc/bw6-633/g2_test.go +++ b/ecc/bw6-633/g2_test.go @@ -678,19 +678,19 @@ func BenchmarkG2JacScalarMultiplication(b *testing.B) { b.Fatalf("failed to generate random scalar: %v", err) } - var doubleAndAdd G1Jac + var doubleAndAdd G2Jac b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g1Gen, scalar) + doubleAndAdd.mulWindowed(&g2Gen, scalar) } }) - var glv G1Jac + var glv G2Jac b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - glv.mulGLV(&g1Gen, scalar) + glv.mulGLV(&g2Gen, scalar) } }) @@ -705,11 +705,11 @@ func BenchmarkG2JacScalarMultiplicationMethod(b *testing.B) { b.Fatalf("failed to generate random scalar: %v", err) } - var res G1Jac + var res G2Jac b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - res.ScalarMultiplication(&g1Gen, scalar) + res.ScalarMultiplication(&g2Gen, scalar) } }) } diff --git a/ecc/bw6-761/g2_test.go b/ecc/bw6-761/g2_test.go index 9fba115954..8c7b5106e5 100644 --- a/ecc/bw6-761/g2_test.go +++ b/ecc/bw6-761/g2_test.go @@ -678,19 +678,19 @@ func BenchmarkG2JacScalarMultiplication(b *testing.B) { b.Fatalf("failed to generate random scalar: %v", err) } - var doubleAndAdd G1Jac + var doubleAndAdd G2Jac b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g1Gen, scalar) + doubleAndAdd.mulWindowed(&g2Gen, scalar) } }) - var glv G1Jac + var glv G2Jac b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - glv.mulGLV(&g1Gen, scalar) + glv.mulGLV(&g2Gen, scalar) } }) @@ -705,11 +705,11 @@ func BenchmarkG2JacScalarMultiplicationMethod(b *testing.B) { b.Fatalf("failed to generate random scalar: %v", err) } - var res G1Jac + var res G2Jac b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - res.ScalarMultiplication(&g1Gen, scalar) + res.ScalarMultiplication(&g2Gen, scalar) } }) } diff --git a/internal/generator/ecc/template/tests/point.go.tmpl b/internal/generator/ecc/template/tests/point.go.tmpl index d641d39f94..58fdf55e8a 100644 --- a/internal/generator/ecc/template/tests/point.go.tmpl +++ b/internal/generator/ecc/template/tests/point.go.tmpl @@ -799,19 +799,19 @@ func Benchmark{{ $TJacobian }}ScalarMultiplication(b *testing.B) { b.Fatalf("failed to generate random scalar: %v", err) } - var doubleAndAdd G1Jac + var doubleAndAdd {{ $TJacobian }} b.Run(fmt.Sprintf("method=window/scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - doubleAndAdd.mulWindowed(&g1Gen, scalar) + doubleAndAdd.mulWindowed(&{{ .PointName }}Gen, scalar) } }) {{ if .GLV }} - var glv G1Jac + var glv {{ $TJacobian }} b.Run(fmt.Sprintf("method=GLV/scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - glv.mulGLV(&g1Gen, scalar) + glv.mulGLV(&{{ .PointName }}Gen, scalar) } }) {{ end }} @@ -826,11 +826,11 @@ func Benchmark{{ $TJacobian }}ScalarMultiplicationMethod(b *testing.B) { b.Fatalf("failed to generate random scalar: %v", err) } - var res G1Jac + var res {{ $TJacobian }} b.Run(fmt.Sprintf("scalarwidth=%d", i), func(b *testing.B) { b.ResetTimer() for j := 0; j < b.N; j++ { - res.ScalarMultiplication(&g1Gen, scalar) + res.ScalarMultiplication(&{{ .PointName }}Gen, scalar) } }) } From ea0c1ff44967c6756ca254a2dec36fed043dd9d4 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 25 Jun 2025 12:10:35 +0000 Subject: [PATCH 5/6] perf: add heuristic for deciding which scalar mul impl to use --- ecc/bls12-377/bls12-377.go | 8 ++++++++ ecc/bls12-381/bls12-381.go | 8 ++++++++ ecc/bls24-315/bls24-315.go | 8 ++++++++ ecc/bls24-317/bls24-317.go | 8 ++++++++ ecc/bn254/bn254.go | 8 ++++++++ ecc/bw6-633/bw6-633.go | 8 ++++++++ ecc/bw6-761/bw6-761.go | 8 ++++++++ ecc/grumpkin/grumpkin.go | 8 ++++++++ ecc/secp256k1/secp256k1.go | 9 ++++++++- 9 files changed, 72 insertions(+), 1 deletion(-) diff --git a/ecc/bls12-377/bls12-377.go b/ecc/bls12-377/bls12-377.go index 4b6ac8e250..24e34f1854 100644 --- a/ecc/bls12-377/bls12-377.go +++ b/ecc/bls12-377/bls12-377.go @@ -77,6 +77,12 @@ var lambdaGLV big.Int // in ker((u,v) → u+vλ[r]), and their determinant var glvBasis ecc.Lattice +// g1ScalarMulChoose and g2ScalarmulChoose indicate the bitlength of the scalar +// in scalar multiplication from which it is more efficient to use the GLV +// decomposition. It is computed from the GLV basis and considers the overhead +// for the GLV decomposition. It is heuristic and may change in the future. +var g1ScalarMulChoose, g2ScalarMulChoose int + // ψ o π o ψ⁻¹, where ψ:E → E' is the degree 6 iso defined over 𝔽p¹² var endo struct { u fptower.E2 @@ -129,6 +135,8 @@ func init() { lambdaGLV.SetString("91893752504881257701523279626832445440", 10) //(x₀²-1) _r := fr.Modulus() ecc.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) + g1ScalarMulChoose = fr.Bits/16 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) + g2ScalarMulChoose = fr.Bits/32 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) endo.u.A0.SetString("80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410946") endo.v.A0.SetString("216465761340224619389371505802605247630151569547285782856803747159100223055385581585702401816380679166954762214499") diff --git a/ecc/bls12-381/bls12-381.go b/ecc/bls12-381/bls12-381.go index 9f78455f99..da16dbddec 100644 --- a/ecc/bls12-381/bls12-381.go +++ b/ecc/bls12-381/bls12-381.go @@ -77,6 +77,12 @@ var lambdaGLV big.Int // in ker((u,v) → u+vλ[r]), and their determinant var glvBasis ecc.Lattice +// g1ScalarMulChoose and g2ScalarmulChoose indicate the bitlength of the scalar +// in scalar multiplication from which it is more efficient to use the GLV +// decomposition. It is computed from the GLV basis and considers the overhead +// for the GLV decomposition. It is heuristic and may change in the future. +var g1ScalarMulChoose, g2ScalarMulChoose int + // ψ o π o ψ^{-1}, where ψ:E → E' is the degree 6 iso defined over 𝔽p¹² var endo struct { u fptower.E2 @@ -128,6 +134,8 @@ func init() { lambdaGLV.SetString("228988810152649578064853576960394133503", 10) //(x₀²-1) _r := fr.Modulus() ecc.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) + g1ScalarMulChoose = fr.Bits/16 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) + g2ScalarMulChoose = fr.Bits/32 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) endo.u.A0.SetString("0") endo.u.A1.SetString("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437") diff --git a/ecc/bls24-315/bls24-315.go b/ecc/bls24-315/bls24-315.go index 3132512f3f..bddb39edd7 100644 --- a/ecc/bls24-315/bls24-315.go +++ b/ecc/bls24-315/bls24-315.go @@ -78,6 +78,12 @@ var lambdaGLV big.Int // in ker((u,v) → u+vλ[r]), and their determinant var glvBasis ecc.Lattice +// g1ScalarMulChoose and g2ScalarmulChoose indicate the bitlength of the scalar +// in scalar multiplication from which it is more efficient to use the GLV +// decomposition. It is computed from the GLV basis and considers the overhead +// for the GLV decomposition. It is heuristic and may change in the future. +var g1ScalarMulChoose, g2ScalarMulChoose int + // ψ o π o ψ⁻¹, where ψ:E → E' is the degree 6 iso defined over 𝔽p¹² var endo struct { u fptower.E4 @@ -141,6 +147,8 @@ func init() { lambdaGLV.SetString("11502027791375260645628074404575422496066855707288983427913398978447461580801", 10) // x₀⁸ _r := fr.Modulus() ecc.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) + g1ScalarMulChoose = fr.Bits/16 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) + g2ScalarMulChoose = fr.Bits/32 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) endo.u.B0.A0.SetString("17432737665785421589107433512831558061649422754130449334965277047994983947893909429238815314776") endo.v.B0.A0.SetString("13266452002786802757645810648664867986567631927642464177452792960815113608167203350720036682455") diff --git a/ecc/bls24-317/bls24-317.go b/ecc/bls24-317/bls24-317.go index f622c0634b..e6715056fc 100644 --- a/ecc/bls24-317/bls24-317.go +++ b/ecc/bls24-317/bls24-317.go @@ -78,6 +78,12 @@ var lambdaGLV big.Int // in ker((u,v) → u+vλ[r]), and their determinant var glvBasis ecc.Lattice +// g1ScalarMulChoose and g2ScalarmulChoose indicate the bitlength of the scalar +// in scalar multiplication from which it is more efficient to use the GLV +// decomposition. It is computed from the GLV basis and considers the overhead +// for the GLV decomposition. It is heuristic and may change in the future. +var g1ScalarMulChoose, g2ScalarMulChoose int + // ψ o π o ψ⁻¹, where ψ:E → E' is the degree 6 iso defined over 𝔽p¹² var endo struct { u fptower.E4 @@ -127,6 +133,8 @@ func init() { lambdaGLV.SetString("30869589236456844204538189757527902584770424025911415822847175497150445387776", 10) // x₀⁸ _r := fr.Modulus() ecc.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) + g1ScalarMulChoose = fr.Bits/16 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) + g2ScalarMulChoose = fr.Bits/32 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) endo.u.B0.A0.SetString("100835231576138384070271140557450756773581004948002542492497192760544145876107391019725843007951") endo.u.B0.A1.SetString("100835231576138384070271140557450756773581004948002542492497192760544145876107391019725843007951") diff --git a/ecc/bn254/bn254.go b/ecc/bn254/bn254.go index 9ba5f80a2b..bcf0b3ebaf 100644 --- a/ecc/bn254/bn254.go +++ b/ecc/bn254/bn254.go @@ -80,6 +80,12 @@ var lambdaGLV big.Int // in ker((u,v) → u+vλ[r]), and their determinant var glvBasis ecc.Lattice +// g1ScalarMulChoose and g2ScalarmulChoose indicate the bitlength of the scalar +// in scalar multiplication from which it is more efficient to use the GLV +// decomposition. It is computed from the GLV basis and considers the overhead +// for the GLV decomposition. It is heuristic and may change in the future. +var g1ScalarMulChoose, g2ScalarMulChoose int + // ψ o π o ψ⁻¹, where ψ:E → E' is the degree 6 iso defined over 𝔽p¹² var endo struct { u fptower.E2 @@ -133,6 +139,8 @@ func init() { lambdaGLV.SetString("4407920970296243842393367215006156084916469457145843978461", 10) // (36x₀³+18x₀²+6x₀+1) _r := fr.Modulus() ecc.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) + g1ScalarMulChoose = fr.Bits/16 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) + g2ScalarMulChoose = fr.Bits/32 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) endo.u.A0.SetString("21575463638280843010398324269430826099269044274347216827212613867836435027261") endo.u.A1.SetString("10307601595873709700152284273816112264069230130616436755625194854815875713954") diff --git a/ecc/bw6-633/bw6-633.go b/ecc/bw6-633/bw6-633.go index 7029bdce2c..3955ac4709 100644 --- a/ecc/bw6-633/bw6-633.go +++ b/ecc/bw6-633/bw6-633.go @@ -75,6 +75,12 @@ var lambdaGLV big.Int // in ker((u,v) → u+vλ[r]), and their determinant var glvBasis ecc.Lattice +// g1ScalarMulChoose and g2ScalarmulChoose indicate the bitlength of the scalar +// in scalar multiplication from which it is more efficient to use the GLV +// decomposition. It is computed from the GLV basis and considers the overhead +// for the GLV decomposition. It is heuristic and may change in the future. +var g1ScalarMulChoose, g2ScalarMulChoose int + // seed -x₀ of the curve var xGen big.Int @@ -114,6 +120,8 @@ func init() { lambdaGLV.SetString("39705142672498995661671850106945620852186608752525090699191017895721506694646055668218723303426", 10) // 1-x+2*x²-2*x³+3*x⁵-4*x⁶+4*x⁷-3*x⁸+x⁹ _r := fr.Modulus() ecc.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) + g1ScalarMulChoose = fr.Bits/16 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) + g2ScalarMulChoose = fr.Bits/32 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) // -x₀ xGen.SetString("3218079743", 10) // negative diff --git a/ecc/bw6-761/bw6-761.go b/ecc/bw6-761/bw6-761.go index 127b3e3587..de3e534f80 100644 --- a/ecc/bw6-761/bw6-761.go +++ b/ecc/bw6-761/bw6-761.go @@ -79,6 +79,12 @@ var lambdaGLV big.Int // in ker((u,v) → u+vλ[r]), and their determinant var glvBasis ecc.Lattice +// g1ScalarMulChoose and g2ScalarmulChoose indicate the bitlength of the scalar +// in scalar multiplication from which it is more efficient to use the GLV +// decomposition. It is computed from the GLV basis and considers the overhead +// for the GLV decomposition. It is heuristic and may change in the future. +var g1ScalarMulChoose, g2ScalarMulChoose int + // seed x₀ of the curve var xGen big.Int @@ -123,6 +129,8 @@ func init() { lambdaGLV.SetString("80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410945", 10) // (x⁵-3x⁴+3x³-x+1) _r := fr.Modulus() ecc.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) + g1ScalarMulChoose = fr.Bits/16 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) + g2ScalarMulChoose = fr.Bits/32 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) // x₀ xGen.SetString("9586122913090633729", 10) diff --git a/ecc/grumpkin/grumpkin.go b/ecc/grumpkin/grumpkin.go index 8bfe9c784d..25a57527c8 100644 --- a/ecc/grumpkin/grumpkin.go +++ b/ecc/grumpkin/grumpkin.go @@ -56,6 +56,12 @@ var xGen big.Int // in ker((u,v) → u+vλ[r]), and their determinant var glvBasis ecc.Lattice +// g1ScalarMulChoose and g2ScalarmulChoose indicate the bitlength of the scalar +// in scalar multiplication from which it is more efficient to use the GLV +// decomposition. It is computed from the GLV basis and considers the overhead +// for the GLV decomposition. It is heuristic and may change in the future. +var g1ScalarMulChoose, g2ScalarMulChoose int + func init() { aCurveCoeff.SetUint64(0) bCurveCoeff.SetUint64(17).Neg(&bCurveCoeff) @@ -74,6 +80,8 @@ func init() { lambdaGLV.SetString("2203960485148121921418603742825762020974279258880205651966", 10) _r := fr.Modulus() ecc.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) + g1ScalarMulChoose = fr.Bits/16 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) + g2ScalarMulChoose = fr.Bits/32 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) xGen.SetString("4965661367192848881", 10) } diff --git a/ecc/secp256k1/secp256k1.go b/ecc/secp256k1/secp256k1.go index d48d6098e5..31488d3a45 100644 --- a/ecc/secp256k1/secp256k1.go +++ b/ecc/secp256k1/secp256k1.go @@ -52,6 +52,12 @@ var lambdaGLV big.Int // in ker((u,v) → u+vλ[r]), and their determinant var glvBasis ecc.Lattice +// g1ScalarMulChoose and g2ScalarmulChoose indicate the bitlength of the scalar +// in scalar multiplication from which it is more efficient to use the GLV +// decomposition. It is computed from the GLV basis and considers the overhead +// for the GLV decomposition. It is heuristic and may change in the future. +var g1ScalarMulChoose, g2ScalarMulChoose int + func init() { aCurveCoeff.SetUint64(0) bCurveCoeff.SetUint64(7) @@ -70,7 +76,8 @@ func init() { lambdaGLV.SetString("37718080363155996902926221483475020450927657555482586988616620542887997980018", 10) // 3^((r-1)/3) _r := fr.Modulus() ecc.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) - + g1ScalarMulChoose = fr.Bits/16 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) + g2ScalarMulChoose = fr.Bits/32 + max(glvBasis.V1[0].BitLen(), glvBasis.V1[1].BitLen(), glvBasis.V2[0].BitLen(), glvBasis.V2[1].BitLen()) } // Generators return the generators of the r-torsion group, resp. in ker(pi-id), ker(Tr) From 717ae2e02bd13b4120eceb68de7dac9c8939b6bc Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 25 Jun 2025 12:13:29 +0000 Subject: [PATCH 6/6] perf: use windowed mul for small scalars --- ecc/bls12-377/g1.go | 24 ++++++++++++++--- ecc/bls12-377/g2.go | 24 ++++++++++++++--- ecc/bls12-381/g1.go | 24 ++++++++++++++--- ecc/bls12-381/g2.go | 24 ++++++++++++++--- ecc/bls24-315/g1.go | 24 ++++++++++++++--- ecc/bls24-315/g2.go | 24 ++++++++++++++--- ecc/bls24-317/g1.go | 24 ++++++++++++++--- ecc/bls24-317/g2.go | 24 ++++++++++++++--- ecc/bn254/g1.go | 24 ++++++++++++++--- ecc/bn254/g2.go | 24 ++++++++++++++--- ecc/bw6-633/g1.go | 24 ++++++++++++++--- ecc/bw6-633/g2.go | 24 ++++++++++++++--- ecc/bw6-761/g1.go | 24 ++++++++++++++--- ecc/bw6-761/g2.go | 24 ++++++++++++++--- ecc/grumpkin/g1.go | 24 ++++++++++++++--- ecc/secp256k1/g1.go | 24 ++++++++++++++--- internal/generator/ecc/template/point.go.tmpl | 26 +++++++++++++++---- 17 files changed, 341 insertions(+), 69 deletions(-) diff --git a/ecc/bls12-377/g1.go b/ecc/bls12-377/g1.go index b727642fee..3feef20207 100644 --- a/ecc/bls12-377/g1.go +++ b/ecc/bls12-377/g1.go @@ -51,7 +51,11 @@ func (p *G1Affine) SetInfinity() *G1Affine { func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) - _p.mulGLV(&_p, s) + if s.BitLen() >= g1ScalarMulChoose { + _p.mulGLV(&_p, s) + } else { + _p.mulWindowed(&_p, s) + } p.FromJacobian(&_p) return p } @@ -60,7 +64,11 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { // where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac - _p.mulGLV(&g1Gen, s) + if s.BitLen() >= g1ScalarMulChoose { + _p.mulGLV(&g1Gen, s) + } else { + _p.mulWindowed(&g1Gen, s) + } p.FromJacobian(&_p) return p } @@ -433,13 +441,21 @@ func (p *G1Jac) DoubleAssign() *G1Jac { // using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { - return p.mulGLV(q, s) + if s.BitLen() >= g1ScalarMulChoose { + return p.mulGLV(q, s) + } else { + return p.mulWindowed(q, s) + } } // ScalarMultiplicationBase computes and returns p = [s]g // where g is the prime subgroup generator. func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { - return p.mulGLV(&g1Gen, s) + if s.BitLen() >= g1ScalarMulChoose { + return p.mulGLV(&g1Gen, s) + } else { + return p.mulWindowed(&g1Gen, s) + } } diff --git a/ecc/bls12-377/g2.go b/ecc/bls12-377/g2.go index 263a8f8521..78b6138c52 100644 --- a/ecc/bls12-377/g2.go +++ b/ecc/bls12-377/g2.go @@ -57,7 +57,11 @@ func (p *G2Affine) SetInfinity() *G2Affine { func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { var _p G2Jac _p.FromAffine(a) - _p.mulGLV(&_p, s) + if s.BitLen() >= g2ScalarMulChoose { + _p.mulGLV(&_p, s) + } else { + _p.mulWindowed(&_p, s) + } p.FromJacobian(&_p) return p } @@ -66,7 +70,11 @@ func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { // where g is the affine point generating the prime subgroup. func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { var _p G2Jac - _p.mulGLV(&g2Gen, s) + if s.BitLen() >= g2ScalarMulChoose { + _p.mulGLV(&g2Gen, s) + } else { + _p.mulWindowed(&g2Gen, s) + } p.FromJacobian(&_p) return p } @@ -439,13 +447,21 @@ func (p *G2Jac) DoubleAssign() *G2Jac { // using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { - return p.mulGLV(q, s) + if s.BitLen() >= g2ScalarMulChoose { + return p.mulGLV(q, s) + } else { + return p.mulWindowed(q, s) + } } // ScalarMultiplicationBase computes and returns p = [s]g // where g is the prime subgroup generator. func (p *G2Jac) ScalarMultiplicationBase(s *big.Int) *G2Jac { - return p.mulGLV(&g2Gen, s) + if s.BitLen() >= g2ScalarMulChoose { + return p.mulGLV(&g2Gen, s) + } else { + return p.mulWindowed(&g2Gen, s) + } } diff --git a/ecc/bls12-381/g1.go b/ecc/bls12-381/g1.go index e3f7c18d74..ab00282afb 100644 --- a/ecc/bls12-381/g1.go +++ b/ecc/bls12-381/g1.go @@ -52,7 +52,11 @@ func (p *G1Affine) SetInfinity() *G1Affine { func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) - _p.mulGLV(&_p, s) + if s.BitLen() >= g1ScalarMulChoose { + _p.mulGLV(&_p, s) + } else { + _p.mulWindowed(&_p, s) + } p.FromJacobian(&_p) return p } @@ -61,7 +65,11 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { // where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac - _p.mulGLV(&g1Gen, s) + if s.BitLen() >= g1ScalarMulChoose { + _p.mulGLV(&g1Gen, s) + } else { + _p.mulWindowed(&g1Gen, s) + } p.FromJacobian(&_p) return p } @@ -442,13 +450,21 @@ func (p *G1Jac) DoubleAssign() *G1Jac { // using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { - return p.mulGLV(q, s) + if s.BitLen() >= g1ScalarMulChoose { + return p.mulGLV(q, s) + } else { + return p.mulWindowed(q, s) + } } // ScalarMultiplicationBase computes and returns p = [s]g // where g is the prime subgroup generator. func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { - return p.mulGLV(&g1Gen, s) + if s.BitLen() >= g1ScalarMulChoose { + return p.mulGLV(&g1Gen, s) + } else { + return p.mulWindowed(&g1Gen, s) + } } diff --git a/ecc/bls12-381/g2.go b/ecc/bls12-381/g2.go index 127c47a8c9..d3e315c5e2 100644 --- a/ecc/bls12-381/g2.go +++ b/ecc/bls12-381/g2.go @@ -59,7 +59,11 @@ func (p *G2Affine) SetInfinity() *G2Affine { func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { var _p G2Jac _p.FromAffine(a) - _p.mulGLV(&_p, s) + if s.BitLen() >= g2ScalarMulChoose { + _p.mulGLV(&_p, s) + } else { + _p.mulWindowed(&_p, s) + } p.FromJacobian(&_p) return p } @@ -68,7 +72,11 @@ func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { // where g is the affine point generating the prime subgroup. func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { var _p G2Jac - _p.mulGLV(&g2Gen, s) + if s.BitLen() >= g2ScalarMulChoose { + _p.mulGLV(&g2Gen, s) + } else { + _p.mulWindowed(&g2Gen, s) + } p.FromJacobian(&_p) return p } @@ -447,13 +455,21 @@ func (p *G2Jac) DoubleAssign() *G2Jac { // using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { - return p.mulGLV(q, s) + if s.BitLen() >= g2ScalarMulChoose { + return p.mulGLV(q, s) + } else { + return p.mulWindowed(q, s) + } } // ScalarMultiplicationBase computes and returns p = [s]g // where g is the prime subgroup generator. func (p *G2Jac) ScalarMultiplicationBase(s *big.Int) *G2Jac { - return p.mulGLV(&g2Gen, s) + if s.BitLen() >= g2ScalarMulChoose { + return p.mulGLV(&g2Gen, s) + } else { + return p.mulWindowed(&g2Gen, s) + } } diff --git a/ecc/bls24-315/g1.go b/ecc/bls24-315/g1.go index cff64cb634..1927391c45 100644 --- a/ecc/bls24-315/g1.go +++ b/ecc/bls24-315/g1.go @@ -51,7 +51,11 @@ func (p *G1Affine) SetInfinity() *G1Affine { func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) - _p.mulGLV(&_p, s) + if s.BitLen() >= g1ScalarMulChoose { + _p.mulGLV(&_p, s) + } else { + _p.mulWindowed(&_p, s) + } p.FromJacobian(&_p) return p } @@ -60,7 +64,11 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { // where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac - _p.mulGLV(&g1Gen, s) + if s.BitLen() >= g1ScalarMulChoose { + _p.mulGLV(&g1Gen, s) + } else { + _p.mulWindowed(&g1Gen, s) + } p.FromJacobian(&_p) return p } @@ -433,13 +441,21 @@ func (p *G1Jac) DoubleAssign() *G1Jac { // using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { - return p.mulGLV(q, s) + if s.BitLen() >= g1ScalarMulChoose { + return p.mulGLV(q, s) + } else { + return p.mulWindowed(q, s) + } } // ScalarMultiplicationBase computes and returns p = [s]g // where g is the prime subgroup generator. func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { - return p.mulGLV(&g1Gen, s) + if s.BitLen() >= g1ScalarMulChoose { + return p.mulGLV(&g1Gen, s) + } else { + return p.mulWindowed(&g1Gen, s) + } } diff --git a/ecc/bls24-315/g2.go b/ecc/bls24-315/g2.go index 1ea1a2e366..0c63de104d 100644 --- a/ecc/bls24-315/g2.go +++ b/ecc/bls24-315/g2.go @@ -57,7 +57,11 @@ func (p *G2Affine) SetInfinity() *G2Affine { func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { var _p G2Jac _p.FromAffine(a) - _p.mulGLV(&_p, s) + if s.BitLen() >= g2ScalarMulChoose { + _p.mulGLV(&_p, s) + } else { + _p.mulWindowed(&_p, s) + } p.FromJacobian(&_p) return p } @@ -66,7 +70,11 @@ func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { // where g is the affine point generating the prime subgroup. func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { var _p G2Jac - _p.mulGLV(&g2Gen, s) + if s.BitLen() >= g2ScalarMulChoose { + _p.mulGLV(&g2Gen, s) + } else { + _p.mulWindowed(&g2Gen, s) + } p.FromJacobian(&_p) return p } @@ -439,13 +447,21 @@ func (p *G2Jac) DoubleAssign() *G2Jac { // using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { - return p.mulGLV(q, s) + if s.BitLen() >= g2ScalarMulChoose { + return p.mulGLV(q, s) + } else { + return p.mulWindowed(q, s) + } } // ScalarMultiplicationBase computes and returns p = [s]g // where g is the prime subgroup generator. func (p *G2Jac) ScalarMultiplicationBase(s *big.Int) *G2Jac { - return p.mulGLV(&g2Gen, s) + if s.BitLen() >= g2ScalarMulChoose { + return p.mulGLV(&g2Gen, s) + } else { + return p.mulWindowed(&g2Gen, s) + } } diff --git a/ecc/bls24-317/g1.go b/ecc/bls24-317/g1.go index d2e59f577c..e16a9761bc 100644 --- a/ecc/bls24-317/g1.go +++ b/ecc/bls24-317/g1.go @@ -51,7 +51,11 @@ func (p *G1Affine) SetInfinity() *G1Affine { func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) - _p.mulGLV(&_p, s) + if s.BitLen() >= g1ScalarMulChoose { + _p.mulGLV(&_p, s) + } else { + _p.mulWindowed(&_p, s) + } p.FromJacobian(&_p) return p } @@ -60,7 +64,11 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { // where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac - _p.mulGLV(&g1Gen, s) + if s.BitLen() >= g1ScalarMulChoose { + _p.mulGLV(&g1Gen, s) + } else { + _p.mulWindowed(&g1Gen, s) + } p.FromJacobian(&_p) return p } @@ -433,13 +441,21 @@ func (p *G1Jac) DoubleAssign() *G1Jac { // using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { - return p.mulGLV(q, s) + if s.BitLen() >= g1ScalarMulChoose { + return p.mulGLV(q, s) + } else { + return p.mulWindowed(q, s) + } } // ScalarMultiplicationBase computes and returns p = [s]g // where g is the prime subgroup generator. func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { - return p.mulGLV(&g1Gen, s) + if s.BitLen() >= g1ScalarMulChoose { + return p.mulGLV(&g1Gen, s) + } else { + return p.mulWindowed(&g1Gen, s) + } } diff --git a/ecc/bls24-317/g2.go b/ecc/bls24-317/g2.go index d964723fa7..4a04094f36 100644 --- a/ecc/bls24-317/g2.go +++ b/ecc/bls24-317/g2.go @@ -57,7 +57,11 @@ func (p *G2Affine) SetInfinity() *G2Affine { func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { var _p G2Jac _p.FromAffine(a) - _p.mulGLV(&_p, s) + if s.BitLen() >= g2ScalarMulChoose { + _p.mulGLV(&_p, s) + } else { + _p.mulWindowed(&_p, s) + } p.FromJacobian(&_p) return p } @@ -66,7 +70,11 @@ func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { // where g is the affine point generating the prime subgroup. func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { var _p G2Jac - _p.mulGLV(&g2Gen, s) + if s.BitLen() >= g2ScalarMulChoose { + _p.mulGLV(&g2Gen, s) + } else { + _p.mulWindowed(&g2Gen, s) + } p.FromJacobian(&_p) return p } @@ -439,13 +447,21 @@ func (p *G2Jac) DoubleAssign() *G2Jac { // using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { - return p.mulGLV(q, s) + if s.BitLen() >= g2ScalarMulChoose { + return p.mulGLV(q, s) + } else { + return p.mulWindowed(q, s) + } } // ScalarMultiplicationBase computes and returns p = [s]g // where g is the prime subgroup generator. func (p *G2Jac) ScalarMultiplicationBase(s *big.Int) *G2Jac { - return p.mulGLV(&g2Gen, s) + if s.BitLen() >= g2ScalarMulChoose { + return p.mulGLV(&g2Gen, s) + } else { + return p.mulWindowed(&g2Gen, s) + } } diff --git a/ecc/bn254/g1.go b/ecc/bn254/g1.go index 6d10a8c0ca..06d54ff648 100644 --- a/ecc/bn254/g1.go +++ b/ecc/bn254/g1.go @@ -51,7 +51,11 @@ func (p *G1Affine) SetInfinity() *G1Affine { func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) - _p.mulGLV(&_p, s) + if s.BitLen() >= g1ScalarMulChoose { + _p.mulGLV(&_p, s) + } else { + _p.mulWindowed(&_p, s) + } p.FromJacobian(&_p) return p } @@ -60,7 +64,11 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { // where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac - _p.mulGLV(&g1Gen, s) + if s.BitLen() >= g1ScalarMulChoose { + _p.mulGLV(&g1Gen, s) + } else { + _p.mulWindowed(&g1Gen, s) + } p.FromJacobian(&_p) return p } @@ -431,13 +439,21 @@ func (p *G1Jac) DoubleAssign() *G1Jac { // using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { - return p.mulGLV(q, s) + if s.BitLen() >= g1ScalarMulChoose { + return p.mulGLV(q, s) + } else { + return p.mulWindowed(q, s) + } } // ScalarMultiplicationBase computes and returns p = [s]g // where g is the prime subgroup generator. func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { - return p.mulGLV(&g1Gen, s) + if s.BitLen() >= g1ScalarMulChoose { + return p.mulGLV(&g1Gen, s) + } else { + return p.mulWindowed(&g1Gen, s) + } } diff --git a/ecc/bn254/g2.go b/ecc/bn254/g2.go index c8f31ad924..c656b5c2c7 100644 --- a/ecc/bn254/g2.go +++ b/ecc/bn254/g2.go @@ -57,7 +57,11 @@ func (p *G2Affine) SetInfinity() *G2Affine { func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { var _p G2Jac _p.FromAffine(a) - _p.mulGLV(&_p, s) + if s.BitLen() >= g2ScalarMulChoose { + _p.mulGLV(&_p, s) + } else { + _p.mulWindowed(&_p, s) + } p.FromJacobian(&_p) return p } @@ -66,7 +70,11 @@ func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { // where g is the affine point generating the prime subgroup. func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { var _p G2Jac - _p.mulGLV(&g2Gen, s) + if s.BitLen() >= g2ScalarMulChoose { + _p.mulGLV(&g2Gen, s) + } else { + _p.mulWindowed(&g2Gen, s) + } p.FromJacobian(&_p) return p } @@ -452,13 +460,21 @@ func (p *G2Jac) DoubleAssign() *G2Jac { // using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { - return p.mulGLV(q, s) + if s.BitLen() >= g2ScalarMulChoose { + return p.mulGLV(q, s) + } else { + return p.mulWindowed(q, s) + } } // ScalarMultiplicationBase computes and returns p = [s]g // where g is the prime subgroup generator. func (p *G2Jac) ScalarMultiplicationBase(s *big.Int) *G2Jac { - return p.mulGLV(&g2Gen, s) + if s.BitLen() >= g2ScalarMulChoose { + return p.mulGLV(&g2Gen, s) + } else { + return p.mulWindowed(&g2Gen, s) + } } diff --git a/ecc/bw6-633/g1.go b/ecc/bw6-633/g1.go index 263a37bcc4..4c81ec4de1 100644 --- a/ecc/bw6-633/g1.go +++ b/ecc/bw6-633/g1.go @@ -51,7 +51,11 @@ func (p *G1Affine) SetInfinity() *G1Affine { func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) - _p.mulGLV(&_p, s) + if s.BitLen() >= g1ScalarMulChoose { + _p.mulGLV(&_p, s) + } else { + _p.mulWindowed(&_p, s) + } p.FromJacobian(&_p) return p } @@ -60,7 +64,11 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { // where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac - _p.mulGLV(&g1Gen, s) + if s.BitLen() >= g1ScalarMulChoose { + _p.mulGLV(&g1Gen, s) + } else { + _p.mulWindowed(&g1Gen, s) + } p.FromJacobian(&_p) return p } @@ -433,13 +441,21 @@ func (p *G1Jac) DoubleAssign() *G1Jac { // using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { - return p.mulGLV(q, s) + if s.BitLen() >= g1ScalarMulChoose { + return p.mulGLV(q, s) + } else { + return p.mulWindowed(q, s) + } } // ScalarMultiplicationBase computes and returns p = [s]g // where g is the prime subgroup generator. func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { - return p.mulGLV(&g1Gen, s) + if s.BitLen() >= g1ScalarMulChoose { + return p.mulGLV(&g1Gen, s) + } else { + return p.mulWindowed(&g1Gen, s) + } } diff --git a/ecc/bw6-633/g2.go b/ecc/bw6-633/g2.go index 9d5e404d15..552552cd75 100644 --- a/ecc/bw6-633/g2.go +++ b/ecc/bw6-633/g2.go @@ -57,7 +57,11 @@ func (p *G2Affine) SetInfinity() *G2Affine { func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { var _p G2Jac _p.FromAffine(a) - _p.mulGLV(&_p, s) + if s.BitLen() >= g2ScalarMulChoose { + _p.mulGLV(&_p, s) + } else { + _p.mulWindowed(&_p, s) + } p.FromJacobian(&_p) return p } @@ -66,7 +70,11 @@ func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { // where g is the affine point generating the prime subgroup. func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { var _p G2Jac - _p.mulGLV(&g2Gen, s) + if s.BitLen() >= g2ScalarMulChoose { + _p.mulGLV(&g2Gen, s) + } else { + _p.mulWindowed(&g2Gen, s) + } p.FromJacobian(&_p) return p } @@ -439,13 +447,21 @@ func (p *G2Jac) DoubleAssign() *G2Jac { // using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { - return p.mulGLV(q, s) + if s.BitLen() >= g2ScalarMulChoose { + return p.mulGLV(q, s) + } else { + return p.mulWindowed(q, s) + } } // ScalarMultiplicationBase computes and returns p = [s]g // where g is the prime subgroup generator. func (p *G2Jac) ScalarMultiplicationBase(s *big.Int) *G2Jac { - return p.mulGLV(&g2Gen, s) + if s.BitLen() >= g2ScalarMulChoose { + return p.mulGLV(&g2Gen, s) + } else { + return p.mulWindowed(&g2Gen, s) + } } diff --git a/ecc/bw6-761/g1.go b/ecc/bw6-761/g1.go index 7529000855..db3f863898 100644 --- a/ecc/bw6-761/g1.go +++ b/ecc/bw6-761/g1.go @@ -51,7 +51,11 @@ func (p *G1Affine) SetInfinity() *G1Affine { func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) - _p.mulGLV(&_p, s) + if s.BitLen() >= g1ScalarMulChoose { + _p.mulGLV(&_p, s) + } else { + _p.mulWindowed(&_p, s) + } p.FromJacobian(&_p) return p } @@ -60,7 +64,11 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { // where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac - _p.mulGLV(&g1Gen, s) + if s.BitLen() >= g1ScalarMulChoose { + _p.mulGLV(&g1Gen, s) + } else { + _p.mulWindowed(&g1Gen, s) + } p.FromJacobian(&_p) return p } @@ -433,13 +441,21 @@ func (p *G1Jac) DoubleAssign() *G1Jac { // using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { - return p.mulGLV(q, s) + if s.BitLen() >= g1ScalarMulChoose { + return p.mulGLV(q, s) + } else { + return p.mulWindowed(q, s) + } } // ScalarMultiplicationBase computes and returns p = [s]g // where g is the prime subgroup generator. func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { - return p.mulGLV(&g1Gen, s) + if s.BitLen() >= g1ScalarMulChoose { + return p.mulGLV(&g1Gen, s) + } else { + return p.mulWindowed(&g1Gen, s) + } } diff --git a/ecc/bw6-761/g2.go b/ecc/bw6-761/g2.go index 0a76bc44b2..cd732cd35b 100644 --- a/ecc/bw6-761/g2.go +++ b/ecc/bw6-761/g2.go @@ -57,7 +57,11 @@ func (p *G2Affine) SetInfinity() *G2Affine { func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { var _p G2Jac _p.FromAffine(a) - _p.mulGLV(&_p, s) + if s.BitLen() >= g2ScalarMulChoose { + _p.mulGLV(&_p, s) + } else { + _p.mulWindowed(&_p, s) + } p.FromJacobian(&_p) return p } @@ -66,7 +70,11 @@ func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { // where g is the affine point generating the prime subgroup. func (p *G2Affine) ScalarMultiplicationBase(s *big.Int) *G2Affine { var _p G2Jac - _p.mulGLV(&g2Gen, s) + if s.BitLen() >= g2ScalarMulChoose { + _p.mulGLV(&g2Gen, s) + } else { + _p.mulWindowed(&g2Gen, s) + } p.FromJacobian(&_p) return p } @@ -439,13 +447,21 @@ func (p *G2Jac) DoubleAssign() *G2Jac { // using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G2Jac) ScalarMultiplication(q *G2Jac, s *big.Int) *G2Jac { - return p.mulGLV(q, s) + if s.BitLen() >= g2ScalarMulChoose { + return p.mulGLV(q, s) + } else { + return p.mulWindowed(q, s) + } } // ScalarMultiplicationBase computes and returns p = [s]g // where g is the prime subgroup generator. func (p *G2Jac) ScalarMultiplicationBase(s *big.Int) *G2Jac { - return p.mulGLV(&g2Gen, s) + if s.BitLen() >= g2ScalarMulChoose { + return p.mulGLV(&g2Gen, s) + } else { + return p.mulWindowed(&g2Gen, s) + } } diff --git a/ecc/grumpkin/g1.go b/ecc/grumpkin/g1.go index 952c66b1c3..ea8e99505c 100644 --- a/ecc/grumpkin/g1.go +++ b/ecc/grumpkin/g1.go @@ -51,7 +51,11 @@ func (p *G1Affine) SetInfinity() *G1Affine { func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) - _p.mulGLV(&_p, s) + if s.BitLen() >= g1ScalarMulChoose { + _p.mulGLV(&_p, s) + } else { + _p.mulWindowed(&_p, s) + } p.FromJacobian(&_p) return p } @@ -60,7 +64,11 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { // where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac - _p.mulGLV(&g1Gen, s) + if s.BitLen() >= g1ScalarMulChoose { + _p.mulGLV(&g1Gen, s) + } else { + _p.mulWindowed(&g1Gen, s) + } p.FromJacobian(&_p) return p } @@ -433,13 +441,21 @@ func (p *G1Jac) DoubleAssign() *G1Jac { // using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { - return p.mulGLV(q, s) + if s.BitLen() >= g1ScalarMulChoose { + return p.mulGLV(q, s) + } else { + return p.mulWindowed(q, s) + } } // ScalarMultiplicationBase computes and returns p = [s]g // where g is the prime subgroup generator. func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { - return p.mulGLV(&g1Gen, s) + if s.BitLen() >= g1ScalarMulChoose { + return p.mulGLV(&g1Gen, s) + } else { + return p.mulWindowed(&g1Gen, s) + } } diff --git a/ecc/secp256k1/g1.go b/ecc/secp256k1/g1.go index 9c136ef254..a86a45d4ed 100644 --- a/ecc/secp256k1/g1.go +++ b/ecc/secp256k1/g1.go @@ -51,7 +51,11 @@ func (p *G1Affine) SetInfinity() *G1Affine { func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) - _p.mulGLV(&_p, s) + if s.BitLen() >= g1ScalarMulChoose { + _p.mulGLV(&_p, s) + } else { + _p.mulWindowed(&_p, s) + } p.FromJacobian(&_p) return p } @@ -60,7 +64,11 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { // where g is the affine point generating the prime subgroup. func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { var _p G1Jac - _p.mulGLV(&g1Gen, s) + if s.BitLen() >= g1ScalarMulChoose { + _p.mulGLV(&g1Gen, s) + } else { + _p.mulWindowed(&g1Gen, s) + } p.FromJacobian(&_p) return p } @@ -433,13 +441,21 @@ func (p *G1Jac) DoubleAssign() *G1Jac { // using the GLV technique. // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G1Jac) ScalarMultiplication(q *G1Jac, s *big.Int) *G1Jac { - return p.mulGLV(q, s) + if s.BitLen() >= g1ScalarMulChoose { + return p.mulGLV(q, s) + } else { + return p.mulWindowed(q, s) + } } // ScalarMultiplicationBase computes and returns p = [s]g // where g is the prime subgroup generator. func (p *G1Jac) ScalarMultiplicationBase(s *big.Int) *G1Jac { - return p.mulGLV(&g1Gen, s) + if s.BitLen() >= g1ScalarMulChoose { + return p.mulGLV(&g1Gen, s) + } else { + return p.mulWindowed(&g1Gen, s) + } } diff --git a/internal/generator/ecc/template/point.go.tmpl b/internal/generator/ecc/template/point.go.tmpl index ad34402788..df791eb4f7 100644 --- a/internal/generator/ecc/template/point.go.tmpl +++ b/internal/generator/ecc/template/point.go.tmpl @@ -75,7 +75,11 @@ func (p *{{ $TAffine }}) ScalarMultiplication(a *{{ $TAffine }}, s *big.Int) *{{ var _p {{ $TJacobian }} _p.FromAffine(a) {{- if .GLV}} - _p.mulGLV(&_p, s) + if s.BitLen() >= {{ .PointName }}ScalarMulChoose { + _p.mulGLV(&_p, s) + } else { + _p.mulWindowed(&_p, s) + } {{- else }} _p.mulWindowed(&_p, s) {{- end }} @@ -88,7 +92,11 @@ func (p *{{ $TAffine }}) ScalarMultiplication(a *{{ $TAffine }}, s *big.Int) *{{ func (p *{{ $TAffine }}) ScalarMultiplicationBase(s *big.Int) *{{ $TAffine }} { var _p {{ $TJacobian }} {{- if .GLV}} - _p.mulGLV(&{{ toLower .PointName}}Gen, s) + if s.BitLen() >= {{ .PointName }}ScalarMulChoose { + _p.mulGLV(&{{ toLower .PointName}}Gen, s) + } else { + _p.mulWindowed(&{{ toLower .PointName}}Gen, s) + } {{- else }} _p.mulWindowed(&{{ toLower .PointName}}Gen, s) {{- end }} @@ -523,7 +531,11 @@ func (p *{{ $TJacobian }}) DoubleAssign() *{{ $TJacobian }} { {{- end }} func (p *{{ $TJacobian }}) ScalarMultiplication(q *{{ $TJacobian }}, s *big.Int) *{{ $TJacobian }} { {{- if .GLV}} - return p.mulGLV(q, s) + if s.BitLen() >= {{ .PointName }}ScalarMulChoose { + return p.mulGLV(q, s) + } else { + return p.mulWindowed(q, s) + } {{- else }} return p.mulWindowed(q, s) {{- end }} @@ -533,9 +545,13 @@ func (p *{{ $TJacobian }}) ScalarMultiplication(q *{{ $TJacobian }}, s *big.Int) // where g is the prime subgroup generator. func (p *{{ $TJacobian }}) ScalarMultiplicationBase(s *big.Int) *{{ $TJacobian }} { {{- if .GLV}} - return p.mulGLV(&{{ toLower .PointName }}Gen, s) + if s.BitLen() >= {{ .PointName }}ScalarMulChoose { + return p.mulGLV(&{{ toLower .PointName }}Gen, s) + } else { + return p.mulWindowed(&{{ toLower .PointName }}Gen, s) + } {{- else }} - _p.mulWindowed(&{{ toLower .PointName }}Gen, s) + return p.mulWindowed(&{{ toLower .PointName }}Gen, s) {{- end }} }