mirror of https://github.com/gtank/ristretto255
internal/ed25519: add vartime double-base scmul
This commit is contained in:
parent
7b8b390b63
commit
4ba8cc9326
|
@ -99,14 +99,6 @@ func (v *ProjP3) ScalarMul(x *scalar.Scalar, q *ProjP3) *ProjP3 {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set v to a*A + b*B, where B is the Ed25519 basepoint, and return v.
|
|
||||||
//
|
|
||||||
// The scalar multiplication is done in variable time.
|
|
||||||
func (v *ProjP3) VartimeDoubleBaseMul(a, b *scalar.Scalar, A *ProjP3) *ProjP3 {
|
|
||||||
panic("unimplemented")
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set v to the result of a multiscalar multiplication and return v.
|
// Set v to the result of a multiscalar multiplication and return v.
|
||||||
//
|
//
|
||||||
// The multiscalar multiplication is sum(scalars[i]*points[i]).
|
// The multiscalar multiplication is sum(scalars[i]*points[i]).
|
||||||
|
@ -162,6 +154,80 @@ func (v *ProjP3) MultiscalarMul(scalars []scalar.Scalar, points []*ProjP3) *Proj
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set v to a*A + b*B, where B is the Ed25519 basepoint, and return v.
|
||||||
|
//
|
||||||
|
// The scalar multiplication is done in variable time.
|
||||||
|
func (v *ProjP3) VartimeDoubleBaseMul(a, b *scalar.Scalar, A *ProjP3) *ProjP3 {
|
||||||
|
// Similarly to the single variable-base approach, we compute
|
||||||
|
// digits and use them with a lookup table. However, because
|
||||||
|
// we are allowed to do variable-time operations, we don't
|
||||||
|
// need constant-time lookups or constant-time digit
|
||||||
|
// computations.
|
||||||
|
//
|
||||||
|
// So we use a non-adjacent form of some width w instead of
|
||||||
|
// radix 16. This is like a binary representation (one digit
|
||||||
|
// for each binary place) but we allow the digits to grow in
|
||||||
|
// magnitude up to 2^{w-1} so that the nonzero digits are as
|
||||||
|
// sparse as possible. Intuitively, this "condenses" the
|
||||||
|
// "mass" of the scalar onto sparse coefficients (meaning
|
||||||
|
// fewer additions).
|
||||||
|
|
||||||
|
var aTable NafLookupTable5
|
||||||
|
aTable.FromP3(A)
|
||||||
|
// Because the basepoint is fixed, we can use a wider NAF
|
||||||
|
// corresponding to a bigger table.
|
||||||
|
aNaf := a.NonAdjacentForm(5)
|
||||||
|
bNaf := b.NonAdjacentForm(8)
|
||||||
|
|
||||||
|
// Find the first nonzero coefficient.
|
||||||
|
i := 255
|
||||||
|
for j := i; j >= 0; j-- {
|
||||||
|
if aNaf[j] != 0 || bNaf[j] != 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
multA := &ProjCached{}
|
||||||
|
multB := &AffineCached{}
|
||||||
|
tmp1 := &ProjP1xP1{}
|
||||||
|
tmp2 := &ProjP2{}
|
||||||
|
tmp2.Zero()
|
||||||
|
v.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.
|
||||||
|
for ; i >= 0; i-- {
|
||||||
|
tmp1.Double(tmp2)
|
||||||
|
|
||||||
|
// Only update v if we have a nonzero coeff to add in.
|
||||||
|
if aNaf[i] > 0 {
|
||||||
|
v.FromP1xP1(tmp1)
|
||||||
|
aTable.SelectInto(multA, aNaf[i])
|
||||||
|
tmp1.Add(v, multA)
|
||||||
|
} else if aNaf[i] < 0 {
|
||||||
|
v.FromP1xP1(tmp1)
|
||||||
|
aTable.SelectInto(multA, -aNaf[i])
|
||||||
|
tmp1.Sub(v, multA)
|
||||||
|
}
|
||||||
|
|
||||||
|
if bNaf[i] > 0 {
|
||||||
|
v.FromP1xP1(tmp1)
|
||||||
|
basepointNafTable.SelectInto(multB, bNaf[i])
|
||||||
|
tmp1.AddAffine(v, multB)
|
||||||
|
} else if bNaf[i] < 0 {
|
||||||
|
v.FromP1xP1(tmp1)
|
||||||
|
basepointNafTable.SelectInto(multB, -bNaf[i])
|
||||||
|
tmp1.SubAffine(v, multB)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp2.FromP1xP1(tmp1)
|
||||||
|
}
|
||||||
|
|
||||||
|
v.FromP2(tmp2)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
// Set v to the result of a multiscalar multiplication and return v.
|
// Set v to the result of a multiscalar multiplication and return v.
|
||||||
//
|
//
|
||||||
// The multiscalar multiplication is sum(scalars[i]*points[i]).
|
// The multiscalar multiplication is sum(scalars[i]*points[i]).
|
||||||
|
|
|
@ -56,6 +56,19 @@ func TestBasepointMulVsDalek(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVartimeDoubleBaseMulVsDalek(t *testing.T) {
|
||||||
|
var p ProjP3
|
||||||
|
var z scalar.Scalar
|
||||||
|
p.VartimeDoubleBaseMul(&dalekScalar, &z, &B)
|
||||||
|
if dalekScalarBasepoint.Equal(&p) != 1 {
|
||||||
|
t.Error("VartimeDoubleBaseMul fails with b=0")
|
||||||
|
}
|
||||||
|
p.VartimeDoubleBaseMul(&z, &dalekScalar, &B)
|
||||||
|
if dalekScalarBasepoint.Equal(&p) != 1 {
|
||||||
|
t.Error("VartimeDoubleBaseMul fails with a=0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestScalarMulDistributesOverAdd(t *testing.T) {
|
func TestScalarMulDistributesOverAdd(t *testing.T) {
|
||||||
scalarMulDistributesOverAdd := func(x, y scalar.Scalar) bool {
|
scalarMulDistributesOverAdd := func(x, y scalar.Scalar) bool {
|
||||||
// The quickcheck generation strategy chooses a random
|
// The quickcheck generation strategy chooses a random
|
||||||
|
@ -154,3 +167,25 @@ func TestBasepointNafTableGeneration(t *testing.T) {
|
||||||
t.Error("BasepointNafTable does not match")
|
t.Error("BasepointNafTable does not match")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVartimeDoubleBaseMulMatchesBasepointMul(t *testing.T) {
|
||||||
|
vartimeDoubleBaseMulMatchesBasepointMul := func(x, y scalar.Scalar) bool {
|
||||||
|
// FIXME opaque scalars
|
||||||
|
x[31] &= 127
|
||||||
|
y[31] &= 127
|
||||||
|
var p, q1, q2, check ProjP3
|
||||||
|
|
||||||
|
p.VartimeDoubleBaseMul(&x, &y, &B)
|
||||||
|
|
||||||
|
q1.BasepointMul(&x)
|
||||||
|
q2.BasepointMul(&y)
|
||||||
|
check.Zero()
|
||||||
|
check.Add(&q1, &q2)
|
||||||
|
|
||||||
|
return p.Equal(&check) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := quick.Check(vartimeDoubleBaseMulMatchesBasepointMul, quickCheckConfig); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue