diff --git a/src/ecdsa/ellipticcurve.py b/src/ecdsa/ellipticcurve.py index a982c1e4..f601f263 100644 --- a/src/ecdsa/ellipticcurve.py +++ b/src/ecdsa/ellipticcurve.py @@ -1185,14 +1185,15 @@ def __add__(self, other): if self == INFINITY: return other assert self.__curve == other.__curve - if self.__x == other.__x: - if (self.__y + other.__y) % self.__curve.p() == 0: + + p = self.__curve.p() + + if (self.__x - other.__x) % p == 0: + if (self.__y + other.__y) % p == 0: return INFINITY else: return self.double() - p = self.__curve.p() - l = ( (other.__y - self.__y) * numbertheory.inverse_mod(other.__x - self.__x, p) @@ -1206,13 +1207,6 @@ def __add__(self, other): def __mul__(self, other): """Multiply a point by an integer.""" - def leftmost_bit(x): - assert x > 0 - result = 1 - while result <= x: - result = 2 * result - return result // 2 - e = other if e == 0 or (self.__order and e % self.__order == 0): return INFINITY @@ -1221,26 +1215,14 @@ def leftmost_bit(x): if e < 0: return (-self) * (-e) - # From X9.62 D.3.2: - - e3 = 3 * e - negative_self = Point( - self.__curve, - self.__x, - (-self.__y) % self.__curve.p(), - self.__order, - ) - i = leftmost_bit(e3) // 2 - result = self - # print("Multiplying %s by %d (e3 = %d):" % (self, other, e3)) - while i > 1: - result = result.double() - if (e3 & i) != 0 and (e & i) == 0: - result = result + self - if (e3 & i) == 0 and (e & i) != 0: - result = result + negative_self - # print(". . . i = %d, result = %s" % ( i, result )) - i = i // 2 + i = e + temp = self + result = INFINITY + while i: + if i % 2 == 1: + result = result + temp + temp = temp.double() + i = i >> 1 return result @@ -1289,6 +1271,9 @@ def curve(self): def order(self): return self.__order + def to_affine(self): + return self + class PointEdwards(AbstractPoint): """Point on Twisted Edwards curve. diff --git a/src/ecdsa/test_ellipticcurve.py b/src/ecdsa/test_ellipticcurve.py index 864cf108..bcc0caa4 100644 --- a/src/ecdsa/test_ellipticcurve.py +++ b/src/ecdsa/test_ellipticcurve.py @@ -71,6 +71,20 @@ def test_add_and_mult_equivalence(p, m, check): assert p * m == check +# from https://github.com/tlsfuzzer/python-ecdsa/issues/373 +curve = CurveFp(p=31, a=2, b=3) +point = Point(curve, 6, 18) + + +@pytest.mark.parametrize( + "p, m, check", + [(point, n, exp) for n, exp in enumerate(add_n_times(point, 16))], + ids=["p31 test with mult {0}".format(i) for i in range(17)], +) +def test_add_and_mult_equivalence_2(p, m, check): + assert p * m == check + + class TestCurve(unittest.TestCase): @classmethod def setUpClass(cls): @@ -146,6 +160,16 @@ def setUpClass(cls): cls.c192 = CurveFp(p, -3, b) cls.p192 = Point(cls.c192, Gx, Gy, r) + def test_points_with_different_curves(self): + with self.assertRaises(AssertionError): + self.g_23 + self.p192 + + def test_add_point_to_negative(self): + self.assertIs(self.g_23 + (-self.g_23), INFINITY) + + def test_add_point_to_explicit_negative(self): + self.assertIs(self.g_23 + Point(self.c_23, 13, -7), INFINITY) + def test_p192(self): # Checking against some sample computations presented # in X9.62: