Added unsafe VarTime methods for ScalarMult, ScalarBaseMult

This commit is contained in:
DataHoarder 2023-05-20 10:29:51 +02:00
parent 8c58ed0e35
commit e42c4b5eb9
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
2 changed files with 181 additions and 0 deletions

81
unsafe.go Normal file
View file

@ -0,0 +1,81 @@
package edwards25519
// UnsafeVarTimeScalarMult sets v = x * q, and returns v., and returns v. Execution time depends on the inputs.
// Deprecated: Unsafe for private operations
func (v *Point) UnsafeVarTimeScalarMult(x *Scalar, q *Point) *Point {
checkInitialized(q)
// Build lookup table for point q
var table nafLookupTable5
table.FromP3(q)
// Compute a NAF for scalar x
naf := x.nonAdjacentForm(5)
multiple := &projCached{}
tmp1 := &projP1xP1{}
tmp2 := &projP2{}
tmp2.Zero()
// Move from high to low bits, doubling the accumulator
// at each iteration and checking whether there is a nonzero
// coefficient to look up a multiple of.
//
// Skip trying to find the first nonzero coefficent, because
// searching might be more work than a few extra doublings.
for i := 255; i >= 0; i-- {
tmp1.Double(tmp2)
if naf[i] > 0 {
v.fromP1xP1(tmp1)
table.SelectInto(multiple, naf[i])
tmp1.Add(v, multiple)
} else if naf[i] < 0 {
v.fromP1xP1(tmp1)
table.SelectInto(multiple, -naf[i])
tmp1.Sub(v, multiple)
}
tmp2.FromP1xP1(tmp1)
}
v.fromP2(tmp2)
return v
}
// UnsafeVarTimeScalarBaseMult sets v = x * B, where B is the canonical generator, and returns v. Execution time depends on the inputs.
// Deprecated: Unsafe for private operations
// This is not faster than ScalarBaseMult
func (v *Point) UnsafeVarTimeScalarBaseMult(x *Scalar) *Point {
basepointNafTable := basepointNafTable()
// Because the basepoint is fixed, we can use a wider NAF
// corresponding to a bigger table.
naf := x.nonAdjacentForm(8)
multiple := &affineCached{}
tmp1 := &projP1xP1{}
tmp2 := &projP2{}
tmp2.Zero()
// Move from high to low bits, doubling the accumulator
// at each iteration and checking whether there is a nonzero
// coefficient to look up a multiple of.
//
// Skip trying to find the first nonzero coefficent, because
// searching might be more work than a few extra doublings.
for i := 255; i >= 0; i-- {
tmp1.Double(tmp2)
if naf[i] > 0 {
v.fromP1xP1(tmp1)
basepointNafTable.SelectInto(multiple, naf[i])
tmp1.AddAffine(v, multiple)
} else if naf[i] < 0 {
v.fromP1xP1(tmp1)
basepointNafTable.SelectInto(multiple, -naf[i])
tmp1.SubAffine(v, multiple)
}
tmp2.FromP1xP1(tmp1)
}
v.fromP2(tmp2)
return v
}

100
unsafe_test.go Normal file
View file

@ -0,0 +1,100 @@
package edwards25519
import (
"testing"
"testing/quick"
)
func TestUnsafeVarTimeScalarMultMatchesScalarBaseMult(t *testing.T) {
unsafeVarTimeScalarMultMatchesScalarMult := func(x Scalar) bool {
var p, check Point
p.UnsafeVarTimeScalarMult(&x, B)
check.ScalarBaseMult(&x)
checkOnCurve(t, &p, &check)
return p.Equal(&check) == 1
}
if err := quick.Check(unsafeVarTimeScalarMultMatchesScalarMult, quickCheckConfig32); err != nil {
t.Error(err)
}
}
func TestUnsafeVarTimeScalarBaseMultMatchesScalarBaseMult(t *testing.T) {
unsafeVarTimeScalarBaseMultMatchesScalarMult := func(x Scalar) bool {
var p, check Point
p.UnsafeVarTimeScalarBaseMult(&x)
check.ScalarBaseMult(&x)
checkOnCurve(t, &p, &check)
return p.Equal(&check) == 1
}
if err := quick.Check(unsafeVarTimeScalarBaseMultMatchesScalarMult, quickCheckConfig32); err != nil {
t.Error(err)
}
}
func TestUnsafeVarTimeScalarMultNonIdentityPoint(t *testing.T) {
// Check whether p.ScalarMult and q.ScalaBaseMult give the same,
// when p and q are originally set to the base point.
unsafeVarTimeScalarMultNonIdentityPoint := func(x Scalar) bool {
var p, q Point
p.Set(B)
q.Set(B)
p.UnsafeVarTimeScalarMult(&x, B)
q.ScalarBaseMult(&x)
checkOnCurve(t, &p, &q)
return p.Equal(&q) == 1
}
if err := quick.Check(unsafeVarTimeScalarMultNonIdentityPoint, quickCheckConfig32); err != nil {
t.Error(err)
}
}
func TestUnsafeVarTimeScalarBaseMultNonIdentityPoint(t *testing.T) {
// Check whether p.ScalarMult and q.ScalaBaseMult give the same,
// when p and q are originally set to the base point.
unsafeVarTimeScalarBaseMultNonIdentityPoint := func(x Scalar) bool {
var p, q Point
p.Set(B)
q.Set(B)
p.UnsafeVarTimeScalarBaseMult(&x)
q.ScalarBaseMult(&x)
checkOnCurve(t, &p, &q)
return p.Equal(&q) == 1
}
if err := quick.Check(unsafeVarTimeScalarBaseMultNonIdentityPoint, quickCheckConfig32); err != nil {
t.Error(err)
}
}
func BenchmarkUnsafeVarTimeScalarMult(b *testing.B) {
var p Point
for i := 0; i < b.N; i++ {
p.UnsafeVarTimeScalarMult(dalekScalar, B)
}
}
func BenchmarkUnsafeVarTimeScalarBaseMult(b *testing.B) {
var p Point
for i := 0; i < b.N; i++ {
p.UnsafeVarTimeScalarBaseMult(dalekScalar)
}
}