Skip to content

Commit c5a2807

Browse files
committed
extra: add Point.Select, Point.Double, and Point.ScalarMultSlow
Fixes #49
1 parent f146c81 commit c5a2807

File tree

2 files changed

+73
-0
lines changed

2 files changed

+73
-0
lines changed

extra.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,3 +349,48 @@ func (v *Point) VarTimeMultiScalarMult(scalars []*Scalar, points []*Point) *Poin
349349
v.fromP2(tmp2)
350350
return v
351351
}
352+
353+
// Select sets v to a if cond == 1 and to b if cond == 0.
354+
func (v *Point) Select(a, b *Point, cond int) *Point {
355+
v.x.Select(&a.x, &b.x, cond)
356+
v.y.Select(&a.y, &b.y, cond)
357+
v.z.Select(&a.z, &b.z, cond)
358+
v.t.Select(&a.t, &b.t, cond)
359+
return v
360+
}
361+
362+
// Double sets v = p + p, and returns v.
363+
func (v *Point) Double(p *Point) *Point {
364+
checkInitialized(p)
365+
366+
pp := new(projP2).FromP3(p)
367+
p1 := new(projP1xP1).Double(pp)
368+
return v.fromP1xP1(p1)
369+
}
370+
371+
func (v *Point) addCached(p *Point, qCached *projCached) *Point {
372+
result := new(projP1xP1).Add(p, qCached)
373+
return v.fromP1xP1(result)
374+
}
375+
376+
// ScalarMultSlow sets v = x * q, and returns v. It doesn't precompute a large
377+
// table, so it is considerably slower, but requires less memory.
378+
//
379+
// The scalar multiplication is done in constant time.
380+
func (v *Point) ScalarMultSlow(x *Scalar, q *Point) *Point {
381+
checkInitialized(q)
382+
383+
s := x.Bytes()
384+
qCached := new(projCached).FromP3(q)
385+
v.Set(NewIdentityPoint())
386+
t := new(Point)
387+
388+
for i := 255; i >= 0; i-- {
389+
v.Double(v)
390+
t.addCached(v, qCached)
391+
cond := (s[i/8] >> (i % 8)) & 1
392+
v.Select(t, v, int(cond))
393+
}
394+
395+
return v
396+
}

extra_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,34 @@ func TestVarTimeMultiScalarMultMatchesBaseMult(t *testing.T) {
169169
}
170170
}
171171

172+
func TestScalarMultSlowMatchesMult(t *testing.T) {
173+
scalarMultSlowMatchesMult := func(x, y Scalar) bool {
174+
p := NewGeneratorPoint()
175+
p.ScalarMultSlow(&x, p)
176+
p.ScalarMultSlow(&y, p)
177+
178+
q := NewGeneratorPoint()
179+
q.ScalarMult(&x, B)
180+
q.ScalarMult(&y, q)
181+
182+
checkOnCurve(t, p, q)
183+
return p.Equal(q) == 1
184+
}
185+
186+
if err := quick.Check(scalarMultSlowMatchesMult, quickCheckConfig(32)); err != nil {
187+
t.Error(err)
188+
}
189+
}
190+
191+
func BenchmarkScalarMultSlow(b *testing.B) {
192+
var p Point
193+
x := dalekScalar
194+
195+
for i := 0; i < b.N; i++ {
196+
p.ScalarMultSlow(x, B)
197+
}
198+
}
199+
172200
func BenchmarkMultiScalarMultSize8(t *testing.B) {
173201
var p Point
174202
x := dalekScalar

0 commit comments

Comments
 (0)