Skip to content

Commit 272349f

Browse files
committed
use tuples for calculation of multiplication
since this avoids creating new PointJacobi after every addition it makes the signing about 20% faster
1 parent b0084d9 commit 272349f

File tree

1 file changed

+54
-19
lines changed

1 file changed

+54
-19
lines changed

src/ecdsa/ellipticcurve.py

Lines changed: 54 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,12 @@ def __init__(self, curve, x, y, z, order=None, generator=False):
111111
order *= 2
112112
doubler = PointJacobi(curve, x, y, z, order)
113113
order *= 2
114-
self.__precompute.append(doubler)
114+
self.__precompute.append((doubler.x(), doubler.y()))
115115

116116
while i < order:
117117
i *= 2
118118
doubler = doubler.double().scale()
119-
self.__precompute.append(doubler)
119+
self.__precompute.append((doubler.x(), doubler.y()))
120120

121121
def __eq__(self, other):
122122
"""Compare two points with each-other."""
@@ -247,6 +247,8 @@ def _double(self, X1, Y1, Z1, p, a):
247247
"""Add a point to itself, arbitrary z."""
248248
if Z1 == 1:
249249
return self._double_with_z_1(X1, Y1, p, a)
250+
if not Z1:
251+
return 0, 0, 1
250252
# after:
251253
# http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl
252254
XX, YY = X1 * X1 % p, Y1 * Y1 % p
@@ -274,7 +276,7 @@ def double(self):
274276

275277
X3, Y3, Z3 = self._double(X1, Y1, Z1, p, a)
276278

277-
if not Y3:
279+
if not Y3 or not Z3:
278280
return INFINITY
279281
return PointJacobi(self.__curve, X3, Y3, Z3, self.__order)
280282

@@ -358,6 +360,10 @@ def __radd__(self, other):
358360

359361
def _add(self, X1, Y1, Z1, X2, Y2, Z2, p):
360362
"""add two points, select fastest method."""
363+
if not Y1 or not Z1:
364+
return X2, Y2, Z2
365+
if not Y2 or not Z2:
366+
return X1, Y1, Z1
361367
if Z1 == Z2:
362368
if Z1 == 1:
363369
return self._add_with_z_1(X1, Y1, X2, Y2, p)
@@ -394,16 +400,22 @@ def __rmul__(self, other):
394400

395401
def _mul_precompute(self, other):
396402
"""Multiply point by integer with precomputation table."""
397-
result = INFINITY
398-
for precomp in self.__precompute:
403+
X3, Y3, Z3, p = 0, 0, 1, self.__curve.p()
404+
_add = self._add
405+
for X2, Y2 in self.__precompute:
399406
if other % 2:
400407
if other % 4 >= 2:
401-
other, result = (other + 1)//2, result + (-precomp)
408+
other = (other + 1)//2
409+
X3, Y3, Z3 = _add(X3, Y3, Z3, X2, -Y2, 1, p)
402410
else:
403-
other, result = (other - 1)//2, result + precomp
411+
other = (other - 1)//2
412+
X3, Y3, Z3 = _add(X3, Y3, Z3, X2, Y2, 1, p)
404413
else:
405414
other //= 2
406-
return result
415+
416+
if not Y3 or not Z3:
417+
return INFINITY
418+
return PointJacobi(self.__curve, X3, Y3, Z3, self.__order)
407419

408420
@staticmethod
409421
def _naf(mult):
@@ -434,16 +446,24 @@ def __mul__(self, other):
434446
return self._mul_precompute(other)
435447

436448
self = self.scale()
437-
result = INFINITY
449+
X2, Y2 = self.__x, self.__y
450+
X3, Y3, Z3 = 0, 0, 1
451+
p, a = self.__curve.p(), self.__curve.a()
452+
_double = self._double
453+
_add = self._add
438454
# since adding points when at least one of them is scaled
439455
# is quicker, reverse the NAF order
440456
for i in reversed(self._naf(other)):
441-
result = result.double()
457+
X3, Y3, Z3 = _double(X3, Y3, Z3, p, a)
442458
if i < 0:
443-
result = result + (-self)
459+
X3, Y3, Z3 = _add(X3, Y3, Z3, X2, -Y2, 1, p)
444460
elif i > 0:
445-
result = result + self
446-
return result
461+
X3, Y3, Z3 = _add(X3, Y3, Z3, X2, Y2, 1, p)
462+
463+
if not Y3 or not Z3:
464+
return INFINITY
465+
466+
return PointJacobi(self.__curve, X3, Y3, Z3, self.__order)
447467

448468
@staticmethod
449469
def _leftmost_bit(x):
@@ -467,21 +487,36 @@ def mul_add(self, self_mul, other, other_mul):
467487
if not isinstance(other, PointJacobi):
468488
other = PointJacobi.from_affine(other)
469489

490+
if self.__order:
491+
self_mul = self_mul % self.__order
492+
other_mul = other_mul % self.__order
493+
470494
i = self._leftmost_bit(max(self_mul, other_mul))*2
471-
result = INFINITY
495+
X3, Y3, Z3 = 0, 0, 1
496+
p, a = self.__curve.p(), self.__curve.a()
472497
self = self.scale()
498+
X1, Y1 = self.__x, self.__y
473499
other = other.scale()
500+
X2, Y2 = other.__x, other.__y
474501
both = (self + other).scale()
502+
X4, Y4 = both.__x, both.__y
503+
_double = self._double
504+
_add = self._add
475505
while i > 1:
476-
result = result.double()
506+
X3, Y3, Z3 = _double(X3, Y3, Z3, p, a)
477507
i = i // 2
508+
478509
if self_mul & i and other_mul & i:
479-
result = result + both
510+
X3, Y3, Z3 = _add(X3, Y3, Z3, X4, Y4, 1, p)
480511
elif self_mul & i:
481-
result = result + self
512+
X3, Y3, Z3 = _add(X3, Y3, Z3, X1, Y1, 1, p)
482513
elif other_mul & i:
483-
result = result + other
484-
return result
514+
X3, Y3, Z3 = _add(X3, Y3, Z3, X2, Y2, 1, p)
515+
516+
if not Y3 or not Z3:
517+
return INFINITY
518+
519+
return PointJacobi(self.__curve, X3, Y3, Z3, self.__order)
485520

486521
def __neg__(self):
487522
"""Return negated point."""

0 commit comments

Comments
 (0)