Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimization idea: GEProjPoint takes a receiver #1

Open
koba-e964 opened this issue Feb 20, 2024 · 0 comments
Open

Optimization idea: GEProjPoint takes a receiver #1

koba-e964 opened this issue Feb 20, 2024 · 0 comments

Comments

@koba-e964
Copy link
Owner

After this change, GEProjPoint will need no allocations.

diff --git a/secp256k1/ge.go b/secp256k1/ge.go
index db55d52..ce90278 100644
--- a/secp256k1/ge.go
+++ b/secp256k1/ge.go
@@ -70,7 +70,7 @@ func init() {
 	projTable[0] = ProjPoint{x: gx, y: gy, z: one}
 	for i := 1; i < 256; i++ {
 		table[i] = *GEJacobianDouble(&table[i-1])
-		projTable[i] = *GEProjAdd(&projTable[i-1], &projTable[i-1])
+		projTable[i].GEProjAdd(&projTable[i-1], &projTable[i-1])
 		projTable[i].assertValid()
 	}
 }
@@ -159,8 +159,8 @@ func (p *ProjPoint) assertValid() {
 }
 
 // GEAdd computes a + b. It runs in constant-time.
-func GEAdd(a *Point, b *Point) *Point {
-	return GEProjAdd(a, b)
+func (p *Point) GEAdd(a *Point, b *Point) {
+	p.GEProjAdd(a, b)
 }
 
 // GEJacobianAdd computes a + b. It runs in constant-time.
@@ -176,7 +176,7 @@ func GEJacobianAdd(a *JacobianPoint, b *JacobianPoint) *JacobianPoint {
 }
 
 // GEProjAdd uses Algorithm 7 in https://eprint.iacr.org/2015/1060
-func GEProjAdd(a *ProjPoint, b *ProjPoint) *ProjPoint {
+func (p *ProjPoint) GEProjAdd(a *ProjPoint, b *ProjPoint) {
 	// 12 feMul + 2 feMul21 + 14 feAdd + 5 feSub
 	t0 := feMul(a.x, b.x)
 	t1 := feMul(a.y, b.y)
@@ -211,12 +211,14 @@ func GEProjAdd(a *ProjPoint, b *ProjPoint) *ProjPoint {
 	t0 = feMul(t0, t3)
 	z3 = feMul(z3, t4)
 	z3 = feAdd(z3, t0)
-	return &ProjPoint{x: x3, y: y3, z: z3}
+	p.x = x3
+	p.y = y3
+	p.z = z3
 }
 
-// GEDouble computes 2p. It runs in constant-time.
-func GEDouble(p *Point) *Point {
-	return GEProjDouble(p)
+// GEDouble computes 2*arg. It runs in constant-time.
+func (p *Point) GEDouble(arg *Point) {
+	p.GEProjDouble(arg)
 }
 
 // GEJacobianDouble computes 2p. It runs in constant-time.
@@ -241,10 +243,10 @@ func GEJacobianDouble(p *JacobianPoint) *JacobianPoint {
 	return &JacobianPoint{x: x3, y: y3, z: z3}
 }
 
-// GEProjDouble computes 2p. It runs in constant-time.
-func GEProjDouble(p *ProjPoint) *ProjPoint {
+// GEProjDouble computes 2*arg. It runs in constant-time.
+func (p *ProjPoint) GEProjDouble(arg *ProjPoint) {
 	// 12 feMul + 2 feMul21 + 14 feAdd + 5 feSub
-	return GEProjAdd(p, p)
+	p.GEProjAdd(arg, arg)
 }
 
 // If a = b != O, this function returns (0, 0, 0), which is invalid.
@@ -304,8 +306,8 @@ func GEVartimeProjPoint(n Scalar) *ProjPoint {
 }
 
 // GEPoint computes n G where G is the base point. It runs in constant-time.
-func GEPoint(n Scalar) *Point {
-	return GEProjPoint(n)
+func (p *Point) GEPoint(n Scalar) {
+	p.GEProjPoint(n)
 }
 
 func GEJacobianPoint(n Scalar) *JacobianPoint {
@@ -318,14 +320,14 @@ func GEJacobianPoint(n Scalar) *JacobianPoint {
 	return prod
 }
 
-func GEProjPoint(n Scalar) *ProjPoint {
-	prod := &ProjPoint{y: one}
+func (p *ProjPoint) GEProjPoint(n Scalar) {
+	*p = ProjPoint{y: one}
+	var prodCurrent ProjPoint
 	for i := 0; i < 256; i++ {
-		prodCurrent := GEProjAdd(prod, &projTable[i])
+		prodCurrent.GEProjAdd(p, &projTable[i])
 		cond := int(n[31-i/8]>>(i%8)) & 1
-		prod.choiceProjPoint(cond, prodCurrent, prod)
+		p.choiceProjPoint(cond, &prodCurrent, p)
 	}
-	return prod
 }
 
 func (p *JacobianPoint) choiceJacobianPoint(cond int, one *JacobianPoint, zero *JacobianPoint) {
diff --git a/secp256k1/ge_test.go b/secp256k1/ge_test.go
index 3ad76fd..7951ad1 100644
--- a/secp256k1/ge_test.go
+++ b/secp256k1/ge_test.go
@@ -24,7 +24,8 @@ func TestGEJacobianAdd(t *testing.T) {
 func TestGEProjAdd(t *testing.T) {
 	base := &ProjPoint{x: gx, y: gy, z: one}
 	zero := &ProjPoint{y: one}
-	result := GEProjAdd(base, zero)
+	var result ProjPoint
+	result.GEProjAdd(base, zero)
 	assert.Equal(t, base.Compress(), result.Compress())
 }
 
@@ -32,14 +33,17 @@ func TestGEPoint0(t *testing.T) {
 	var two Scalar
 	two[31] = 2
 	expected := GEVartimePoint(two).Compress()
-	result := GEPoint(two).Compress()
+	var point Point
+	point.GEPoint(two)
+	result := point.Compress()
 	assert.Equal(t, expected, result)
 }
 
 func TestGEPoint1(t *testing.T) {
 	expected := zero
-	result := GEPoint(Order)
-	assert.Equal(t, expected, result.z)
+	var point Point
+	point.GEPoint(Order)
+	assert.Equal(t, expected, point.z)
 }
 
 func TestGEPoint2(t *testing.T) {
@@ -47,8 +51,11 @@ func TestGEPoint2(t *testing.T) {
 	exp[31] += 1
 	one := Scalar{}
 	one[31] = 1
-	expected := GEPoint(one).Compress()
-	result := GEPoint(exp).Compress()
+	var point Point
+	point.GEPoint(one)
+	expected := point.Compress()
+	point.GEPoint(exp)
+	result := point.Compress()
 	assert.Equal(t, expected, result)
 }
 
@@ -68,7 +75,9 @@ func TestGEPoint3(t *testing.T) {
 	for _, test := range tests {
 		var sc Scalar
 		sc[31] = test.k
-		result := GEPoint(sc).Compress()
+		var point Point
+		point.GEPoint(sc)
+		result := point.Compress()
 		assert.Equal(t, test.result, result[:])
 	}
 }
@@ -120,9 +129,10 @@ func BenchmarkGEJacobianPoint_ConstantTime_Long(b *testing.B) {
 func BenchmarkGEProjPoint_ConstantTime_Short(b *testing.B) {
 	var two Scalar
 	two[31] = 2
+	var p ProjPoint
 	b.ReportAllocs()
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
-		GEProjPoint(two)
+		p.GEProjPoint(two)
 	}
 }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant