From 179d5280ac6c75221fa3957f6fcf776abfb0a9a4 Mon Sep 17 00:00:00 2001 From: Pavel Secehenov Date: Fri, 15 Nov 2019 07:32:57 +0300 Subject: [PATCH 1/4] Added __eq__ method to classes to improve comparison abilities --- src/ecdsa/ecdsa.py | 14 ++++++++++++++ src/ecdsa/ellipticcurve.py | 25 ++++++++++++++++--------- src/ecdsa/keys.py | 16 ++++++++++++++++ 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/ecdsa/ecdsa.py b/src/ecdsa/ecdsa.py index d03ea2c6..b8db46b9 100644 --- a/src/ecdsa/ecdsa.py +++ b/src/ecdsa/ecdsa.py @@ -119,6 +119,13 @@ def __init__(self, generator, point): if point.x() < 0 or n <= point.x() or point.y() < 0 or n <= point.y(): raise RuntimeError("Generator point has x or y out of range.") + def __eq__(self, other): + if isinstance(other, Public_key): + """Return True if the points are identical, False otherwise.""" + return self.curve == other.curve \ + and self.point == other.point + return False + def verifies(self, hash, signature): """Verify that signature is a valid signature of hash. Return True if the signature is valid. @@ -153,6 +160,13 @@ def __init__(self, public_key, secret_multiplier): self.public_key = public_key self.secret_multiplier = secret_multiplier + + def __eq__(self, other): + if isinstance(other, Private_key): + """Return True if the points are identical, False otherwise.""" + return self.public_key == other.public_key \ + and self.secret_multiplier == other.secret_multiplier + return False def sign(self, hash, random_k): """Return a signature for the provided hash, using the provided diff --git a/src/ecdsa/ellipticcurve.py b/src/ecdsa/ellipticcurve.py index e78314cc..37d7e098 100644 --- a/src/ecdsa/ellipticcurve.py +++ b/src/ecdsa/ellipticcurve.py @@ -45,6 +45,14 @@ def __init__(self, p, a, b): self.__p = p self.__a = a self.__b = b + + def __eq__(self, other): + if isinstance(other, CurveFp): + """Return True if the points are identical, False otherwise.""" + return self.__p == other.__p \ + and self.__a == other.__a \ + and self.__b == other.__b + return False def p(self): return self.__p @@ -79,15 +87,14 @@ def __init__(self, curve, x, y, order=None): def __eq__(self, other): """Return True if the points are identical, False otherwise.""" - if self.__curve == other.__curve \ - and self.__x == other.__x \ - and self.__y == other.__y: - return True - else: - return False + if isinstance(other, Point): + return self.__curve == other.__curve \ + and self.__x == other.__x \ + and self.__y == other.__y + return False def __neg__(self): - return Point(self.__curve, self.__x, self.__curve.p() - self.__y) + return Point(self.__curve, self.__x, self.__curve.p() - self.__y, self.__order) def __add__(self, other): """Add one point to another point.""" @@ -113,7 +120,7 @@ def __add__(self, other): x3 = (l * l - self.__x - other.__x) % p y3 = (l * (self.__x - x3) - self.__y) % p - return Point(self.__curve, x3, y3) + return Point(self.__curve, x3, y3, self.__order) def __mul__(self, other): """Multiply a point by an integer.""" @@ -178,7 +185,7 @@ def double(self): x3 = (l * l - 2 * self.__x) % p y3 = (l * (self.__x - x3) - self.__y) % p - return Point(self.__curve, x3, y3) + return Point(self.__curve, x3, y3, self.__order) def x(self): return self.__x diff --git a/src/ecdsa/keys.py b/src/ecdsa/keys.py index 3734cb87..8fd6bb2b 100644 --- a/src/ecdsa/keys.py +++ b/src/ecdsa/keys.py @@ -139,6 +139,13 @@ def __repr__(self): pub_key = self.to_string("compressed") return "VerifyingKey.from_string({0!r}, {1!r}, {2})".format( pub_key, self.curve, self.default_hashfunc().name) + + def __eq__(self, other): + """Return True if the points are identical, False otherwise.""" + if isinstance(other, VerifyingKey): + return self.curve == other.curve \ + and self.pubkey == other.pubkey + return False @classmethod def from_public_point(cls, point, curve=NIST192p, hashfunc=sha1): @@ -649,6 +656,15 @@ def __init__(self, _error__please_use_generate=None): self.baselen = None self.verifying_key = None self.privkey = None + + def __eq__(self, other): + """Return True if the points are identical, False otherwise.""" + if isinstance(other, SigningKey): + return self.curve == other.curve \ + and self.default_hashfunc == other.default_hashfunc \ + and self.verifying_key == other.verifying_key \ + and self.privkey == other.privkey + return False @classmethod def generate(cls, curve=NIST192p, entropy=None, hashfunc=sha1): From 907a2df3828d30f39ae598e354371c7f2b4cbfa5 Mon Sep 17 00:00:00 2001 From: Pavel Secehenov Date: Sun, 17 Nov 2019 23:08:52 +0300 Subject: [PATCH 2/4] changes after code review, tests --- .gitignore | 3 ++ src/ecdsa/ecdsa.py | 4 +-- src/ecdsa/ellipticcurve.py | 10 +++---- src/ecdsa/keys.py | 5 ++-- src/ecdsa/test_ecdsa.py | 53 +++++++++++++++++++++++++++++++++ src/ecdsa/test_ellipticcurve.py | 31 +++++++++++++++++++ src/ecdsa/test_keys.py | 23 ++++++++++++++ 7 files changed, 119 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 05fbfd4a..2e8eb6c7 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,9 @@ t/ .project .pydevproject +#vscode +.vscode + # Backup files *.swp *~ diff --git a/src/ecdsa/ecdsa.py b/src/ecdsa/ecdsa.py index b8db46b9..fae9609a 100644 --- a/src/ecdsa/ecdsa.py +++ b/src/ecdsa/ecdsa.py @@ -124,7 +124,7 @@ def __eq__(self, other): """Return True if the points are identical, False otherwise.""" return self.curve == other.curve \ and self.point == other.point - return False + return NotImplemented def verifies(self, hash, signature): """Verify that signature is a valid signature of hash. @@ -166,7 +166,7 @@ def __eq__(self, other): """Return True if the points are identical, False otherwise.""" return self.public_key == other.public_key \ and self.secret_multiplier == other.secret_multiplier - return False + return NotImplemented def sign(self, hash, random_k): """Return a signature for the provided hash, using the provided diff --git a/src/ecdsa/ellipticcurve.py b/src/ecdsa/ellipticcurve.py index 37d7e098..6249e7c8 100644 --- a/src/ecdsa/ellipticcurve.py +++ b/src/ecdsa/ellipticcurve.py @@ -52,7 +52,7 @@ def __eq__(self, other): return self.__p == other.__p \ and self.__a == other.__a \ and self.__b == other.__b - return False + return NotImplemented def p(self): return self.__p @@ -91,10 +91,10 @@ def __eq__(self, other): return self.__curve == other.__curve \ and self.__x == other.__x \ and self.__y == other.__y - return False + return NotImplemented def __neg__(self): - return Point(self.__curve, self.__x, self.__curve.p() - self.__y, self.__order) + return Point(self.__curve, self.__x, self.__curve.p() - self.__y) def __add__(self, other): """Add one point to another point.""" @@ -120,7 +120,7 @@ def __add__(self, other): x3 = (l * l - self.__x - other.__x) % p y3 = (l * (self.__x - x3) - self.__y) % p - return Point(self.__curve, x3, y3, self.__order) + return Point(self.__curve, x3, y3) def __mul__(self, other): """Multiply a point by an integer.""" @@ -185,7 +185,7 @@ def double(self): x3 = (l * l - 2 * self.__x) % p y3 = (l * (self.__x - x3) - self.__y) % p - return Point(self.__curve, x3, y3, self.__order) + return Point(self.__curve, x3, y3) def x(self): return self.__x diff --git a/src/ecdsa/keys.py b/src/ecdsa/keys.py index 8fd6bb2b..7dd2c111 100644 --- a/src/ecdsa/keys.py +++ b/src/ecdsa/keys.py @@ -145,7 +145,7 @@ def __eq__(self, other): if isinstance(other, VerifyingKey): return self.curve == other.curve \ and self.pubkey == other.pubkey - return False + return NotImplemented @classmethod def from_public_point(cls, point, curve=NIST192p, hashfunc=sha1): @@ -661,10 +661,9 @@ def __eq__(self, other): """Return True if the points are identical, False otherwise.""" if isinstance(other, SigningKey): return self.curve == other.curve \ - and self.default_hashfunc == other.default_hashfunc \ and self.verifying_key == other.verifying_key \ and self.privkey == other.privkey - return False + return NotImplemented @classmethod def generate(cls, curve=NIST192p, entropy=None, hashfunc=sha1): diff --git a/src/ecdsa/test_ecdsa.py b/src/ecdsa/test_ecdsa.py index f852d293..0b4efc55 100644 --- a/src/ecdsa/test_ecdsa.py +++ b/src/ecdsa/test_ecdsa.py @@ -60,6 +60,57 @@ def test_rejection(self): assert not self.pubk.verifies(self.msg - 1, self.sig) +class TestPublicKey(unittest.TestCase): + + @classmethod + def setUpClass(cls): + pass + + def test_equality_public_keys(self): + gen = generator_192 + x = 0xc58d61f88d905293bcd4cd0080bcb1b7f811f2ffa41979f6 + y = 0x8804dc7a7c4c7f8b5d437f5156f3312ca7d6de8a0e11867f + point = ellipticcurve.Point(gen.curve(), x, y) + pub_key1 = Public_key(gen, point) + pub_key2 = Public_key(gen, point) + self.assertEqual(pub_key1, pub_key2) + + def test_inequality_public_key(self): + gen = generator_192 + x1 = 0xc58d61f88d905293bcd4cd0080bcb1b7f811f2ffa41979f6 + y1 = 0x8804dc7a7c4c7f8b5d437f5156f3312ca7d6de8a0e11867f + point1 = ellipticcurve.Point(gen.curve(), x1, y1) + + x2 = 0x6a223d00bd22c52833409a163e057e5b5da1def2a197dd15 + y2 = 0x7b482604199367f1f303f9ef627f922f97023e90eae08abf + point2 = ellipticcurve.Point(gen.curve(), x2, y2) + + pub_key1 = Public_key(gen, point1) + pub_key2 = Public_key(gen, point2) + self.assertNotEqual(pub_key1, pub_key2) + + +class TestPrivateKey(unittest.TestCase): + + @classmethod + def setUpClass(cls): + gen = generator_192 + x = 0xc58d61f88d905293bcd4cd0080bcb1b7f811f2ffa41979f6 + y = 0x8804dc7a7c4c7f8b5d437f5156f3312ca7d6de8a0e11867f + point = ellipticcurve.Point(gen.curve(), x, y) + cls.pub_key = Public_key(gen, point) + + def test_equality_private_keys(self): + pr_key1 = Private_key(self.pub_key, 100) + pr_key2 = Private_key(self.pub_key, 100) + self.assertEqual(pr_key1, pr_key2) + + def test_inequality_private_keys(self): + pr_key1 = Private_key(self.pub_key, 100) + pr_key2 = Private_key(self.pub_key, 200) + self.assertNotEqual(pr_key1, pr_key2) + + # Testing point validity, as per ECDSAVS.pdf B.2.2: P192_POINTS = [ (generator_192, @@ -386,3 +437,5 @@ def test_sig_verify(args): assert pubkey.verifies(msg, signature) assert not pubkey.verifies(msg - 1, signature) + + diff --git a/src/ecdsa/test_ellipticcurve.py b/src/ecdsa/test_ellipticcurve.py index 33eb8eba..effe1446 100644 --- a/src/ecdsa/test_ellipticcurve.py +++ b/src/ecdsa/test_ellipticcurve.py @@ -126,3 +126,34 @@ def test_multiply(c, x1, y1, m, x3, y3): ids=["g_23 test with mult {0}".format(i) for i in range(9)]) def test_add_and_mult_equivalence(p, m, check): assert p * m == check + + +class TestCurve(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.c_23 = CurveFp(23, 1, 1) + + def test_equality_curves(self): + self.assertEqual(self.c_23, CurveFp(23, 1, 1)) + + def test_inequality_curves(self): + c192 = CurveFp(p, -3, b) + self.assertNotEqual(self.c_23, c192) + + +class TestPoint(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.c_23 = CurveFp(23, 1, 1) + cls.g_23 = Point(cls.c_23, 13, 7, 7) + + def test_equality_points(self): + self.assertEqual(self.g_23, Point(self.c_23, 13, 7, 7)) + + def test_inequality_points(self): + c = CurveFp(100, -3, 100) + p = Point(c, 100, 100, 100) + self.assertNotEqual(self.g_23, p) + \ No newline at end of file diff --git a/src/ecdsa/test_keys.py b/src/ecdsa/test_keys.py index 3f1dffe4..61d319c4 100644 --- a/src/ecdsa/test_keys.py +++ b/src/ecdsa/test_keys.py @@ -124,6 +124,7 @@ def setUpClass(cls): cls.key_bytes = unpem(key_str) assert isinstance(cls.key_bytes, bytes) cls.vk = VerifyingKey.from_pem(key_str) + cls.sk = SigningKey.from_pem(prv_key_str) def test_bytes(self): vk = VerifyingKey.from_der(self.key_bytes) @@ -156,8 +157,30 @@ def test_array_array_of_bytes_memoryview(self): vk = VerifyingKey.from_der(buffer(arr)) self.assertEqual(self.vk.to_string(), vk.to_string()) + + def test_equality_on_verifying_keys(self): + self.assertEqual(self.vk, self.sk.get_verifying_key()) +class TestSigningKey(unittest.TestCase): + """ + Verify that ecdsa.keys.SigningKey.from_der() can be used with + bytes-like objects. + """ + @classmethod + def setUpClass(cls): + prv_key_str = ( + "-----BEGIN EC PRIVATE KEY-----\n" + "MF8CAQEEGF7IQgvW75JSqULpiQQ8op9WH6Uldw6xxaAKBggqhkjOPQMBAaE0AzIA\n" + "BLiBd9CE7xf15FY5QIAoNg+fWbSk1yZOYtoGUdzkejWkxbRc9RWTQjqLVXucIJnz\n" + "bA==\n" + "-----END EC PRIVATE KEY-----\n") + cls.sk = SigningKey.from_pem(prv_key_str) + + def test_equality_on_signing_keys(self): + sk2 = SigningKey.from_secret_exponent(self.sk.privkey.secret_multiplier, self.sk.curve) + self.assertEqual(self.sk, sk2) + # test VerifyingKey.verify() prv_key_str = ( "-----BEGIN EC PRIVATE KEY-----\n" From 8e9636ddfbae1318215946fb88731807d9c65014 Mon Sep 17 00:00:00 2001 From: Pavel Secehenov Date: Tue, 19 Nov 2019 13:28:34 +0300 Subject: [PATCH 3/4] changes after code review --- src/ecdsa/ellipticcurve.py | 3 +- src/ecdsa/test_ecdsa.py | 20 ++-- src/ecdsa/test_ellipticcurve.py | 166 ++++++++++++++++---------------- 3 files changed, 95 insertions(+), 94 deletions(-) diff --git a/src/ecdsa/ellipticcurve.py b/src/ecdsa/ellipticcurve.py index 6249e7c8..9d5e6530 100644 --- a/src/ecdsa/ellipticcurve.py +++ b/src/ecdsa/ellipticcurve.py @@ -48,7 +48,7 @@ def __init__(self, p, a, b): def __eq__(self, other): if isinstance(other, CurveFp): - """Return True if the points are identical, False otherwise.""" + """Return True if the curves are identical, False otherwise.""" return self.__p == other.__p \ and self.__a == other.__a \ and self.__b == other.__b @@ -202,4 +202,3 @@ def order(self): # This one point is the Point At Infinity for all purposes: INFINITY = Point(None, None, None) - diff --git a/src/ecdsa/test_ecdsa.py b/src/ecdsa/test_ecdsa.py index 0b4efc55..200cacef 100644 --- a/src/ecdsa/test_ecdsa.py +++ b/src/ecdsa/test_ecdsa.py @@ -61,11 +61,7 @@ def test_rejection(self): class TestPublicKey(unittest.TestCase): - - @classmethod - def setUpClass(cls): - pass - + def test_equality_public_keys(self): gen = generator_192 x = 0xc58d61f88d905293bcd4cd0080bcb1b7f811f2ffa41979f6 @@ -88,6 +84,14 @@ def test_inequality_public_key(self): pub_key1 = Public_key(gen, point1) pub_key2 = Public_key(gen, point2) self.assertNotEqual(pub_key1, pub_key2) + + def test_inequality_public_key_not_implemented(self): + gen = generator_192 + x = 0xc58d61f88d905293bcd4cd0080bcb1b7f811f2ffa41979f6 + y = 0x8804dc7a7c4c7f8b5d437f5156f3312ca7d6de8a0e11867f + point = ellipticcurve.Point(gen.curve(), x, y) + pub_key = Public_key(gen, point) + self.assertNotEqual(pub_key, None) class TestPrivateKey(unittest.TestCase): @@ -110,6 +114,10 @@ def test_inequality_private_keys(self): pr_key2 = Private_key(self.pub_key, 200) self.assertNotEqual(pr_key1, pr_key2) + def test_inequality_private_keys_not_implemented(self): + pr_key = Private_key(self.pub_key, 100) + self.assertNotEqual(pr_key, None) + # Testing point validity, as per ECDSAVS.pdf B.2.2: P192_POINTS = [ @@ -437,5 +445,3 @@ def test_sig_verify(args): assert pubkey.verifies(msg, signature) assert not pubkey.verifies(msg - 1, signature) - - diff --git a/src/ecdsa/test_ellipticcurve.py b/src/ecdsa/test_ellipticcurve.py index effe1446..56e61205 100644 --- a/src/ecdsa/test_ellipticcurve.py +++ b/src/ecdsa/test_ellipticcurve.py @@ -35,25 +35,6 @@ p192 = Point(c192, Gx, Gy, r) -def test_p192(): - # Checking against some sample computations presented - # in X9.62: - d = 651056770906015076056810763456358567190100156695615665659 - Q = d * p192 - assert Q.x() == 0x62B12D60690CDCF330BABAB6E69763B471F994DD702D16A5 - - k = 6140507067065001063065065565667405560006161556565665656654 - R = k * p192 - assert R.x() == 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEAD \ - and R.y() == 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835 - - u1 = 2563697409189434185194736134579731015366492496392189760599 - u2 = 6266643813348617967186477710235785849136406323338782220568 - temp = u1 * p192 + u2 * Q - assert temp.x() == 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEAD \ - and temp.y() == 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835 - - @settings(**HYP_SETTINGS) @given(st.integers(min_value=1, max_value=r+1)) def test_p192_mult_tests(multiple): @@ -63,71 +44,6 @@ def test_p192_mult_tests(multiple): assert p1 * inv_m == p192 -def add_n_times(point, n): - ret = INFINITY - i = 0 - while i <= n: - yield ret - ret = ret + point - i += 1 - - -c_23 = CurveFp(23, 1, 1) - - -g_23 = Point(c_23, 13, 7, 7) - - -# Trivial tests from X9.62 B.3: -@pytest.mark.parametrize( - "c,x1,y1,x2,y2,x3,y3", - [(c_23, 3, 10, 9, 7, 17, 20), - (c_23, 3, 10, 3, 10, 7, 12)], - ids=["real add", "double"]) -def test_add(c, x1, y1, x2, y2, x3, y3): - """We expect that on curve c, (x1,y1) + (x2, y2 ) = (x3, y3).""" - p1 = Point(c, x1, y1) - p2 = Point(c, x2, y2) - p3 = p1 + p2 - assert p3.x() == x3 and p3.y() == y3 - - -@pytest.mark.parametrize( - "c, x1, y1, x3, y3", - [(c_23, 3, 10, 7, 12)], - ids=["real add"]) -def test_double(c, x1, y1, x3, y3): - p1 = Point(c, x1, y1) - p3 = p1.double() - assert p3.x() == x3 and p3.y() == y3 - - -def test_double_infinity(): - p1 = INFINITY - p3 = p1.double() - assert p1 == p3 - assert p3.x() == p1.x() and p3.y() == p3.y() - - -@pytest.mark.parametrize( - "c, x1, y1, m, x3, y3", - [(c_23, 3, 10, 2, 7, 12)], - ids=["multiply by 2"]) -def test_multiply(c, x1, y1, m, x3, y3): - p1 = Point(c, x1, y1) - p3 = p1 * m - assert p3.x() == x3 and p3.y() == y3 - - -# From X9.62 I.1 (p. 96): -@pytest.mark.parametrize( - "p, m, check", - [(g_23, n, exp) for n, exp in enumerate(add_n_times(g_23, 8))], - ids=["g_23 test with mult {0}".format(i) for i in range(9)]) -def test_add_and_mult_equivalence(p, m, check): - assert p * m == check - - class TestCurve(unittest.TestCase): @classmethod @@ -149,6 +65,83 @@ def setUpClass(cls): cls.c_23 = CurveFp(23, 1, 1) cls.g_23 = Point(cls.c_23, 13, 7, 7) + p = 6277101735386680763835789423207666416083908700390324961279 + r = 6277101735386680763835789423176059013767194773182842284081 + # s = 0x3045ae6fc8422f64ed579528d38120eae12196d5 + # c = 0x3099d2bbbfcb2538542dcd5fb078b6ef5f3d6fe2c745de65 + b = 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1 + Gx = 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012 + Gy = 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811 + + cls.c192 = CurveFp(p, -3, b) + cls.p192 = Point(cls.c192, Gx, Gy, r) + + def _add_n_times(self, point, n): + ret = INFINITY + i = 0 + while i <= n: + yield ret + ret = ret + point + i += 1 + + def test_p192(self): + # Checking against some sample computations presented + # in X9.62: + d = 651056770906015076056810763456358567190100156695615665659 + Q = d * self.p192 + self.assertEqual(Q.x(), 0x62B12D60690CDCF330BABAB6E69763B471F994DD702D16A5) + + k = 6140507067065001063065065565667405560006161556565665656654 + R = k * self.p192 + self.assertEqual(R.x(), 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEAD) + self.assertEqual(R.y(), 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835) + + u1 = 2563697409189434185194736134579731015366492496392189760599 + u2 = 6266643813348617967186477710235785849136406323338782220568 + temp = u1 * self.p192 + u2 * Q + self.assertEqual(temp.x(), 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEAD) + self.assertEqual(temp.y(), 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835) + + def test_double_infinity(self): + p1 = INFINITY + p3 = p1.double() + self.assertEqual(p1, p3) + self.assertEqual(p3.x(), p1.x()) + self.assertEqual(p3.y(), p3.y()) + + # From X9.62 I.1 (p. 96): + def test_add_and_mult_equivalence(self): + for n, exp in enumerate(self._add_n_times(self.g_23, 8)): + self.assertEqual(self.g_23 * n, exp) + + def test_double(self): + x1, y1, x3, y3 = (3, 10, 7, 12) + + p1 = Point(self.c_23, x1, y1) + p3 = p1.double() + self.assertEqual(p3.x(), x3) + self.assertEqual(p3.y(), y3) + + def test_multiply(self): + x1, y1, m, x3, y3 = (3, 10, 2, 7, 12) + p1 = Point(self.c_23, x1, y1) + p3 = p1 * m + self.assertEqual(p3.x(), x3) + self.assertEqual(p3.y(), y3) + + # Trivial tests from X9.62 B.3: + def test_add(self): + """We expect that on curve c, (x1,y1) + (x2, y2 ) = (x3, y3).""" + + data = [(3, 10, 9, 7, 17, 20), # real add + (3, 10, 3, 10, 7, 12)] # double + for (x1, y1, x2, y2, x3, y3) in data: + p1 = Point(self.c_23, x1, y1) + p2 = Point(self.c_23, x2, y2) + p3 = p1 + p2 + self.assertEqual(p3.x(), x3) + self.assertEqual(p3.y(), y3) + def test_equality_points(self): self.assertEqual(self.g_23, Point(self.c_23, 13, 7, 7)) @@ -156,4 +149,7 @@ def test_inequality_points(self): c = CurveFp(100, -3, 100) p = Point(c, 100, 100, 100) self.assertNotEqual(self.g_23, p) - \ No newline at end of file + + def test_inaquality_points_diff_types(self): + c = CurveFp(100, -3, 100) + self.assertNotEqual(self.g_23, c) From b8d41224c9bdbeb7007eff36674f7a5e77502b3e Mon Sep 17 00:00:00 2001 From: Pavel Secehenov Date: Tue, 19 Nov 2019 19:03:53 +0300 Subject: [PATCH 4/4] test coverage for SigningKey and VerifyingKey --- src/ecdsa/test_ellipticcurve.py | 67 ++++++++++++++++++++------------- src/ecdsa/test_keys.py | 37 ++++++++++++++++-- 2 files changed, 74 insertions(+), 30 deletions(-) diff --git a/src/ecdsa/test_ellipticcurve.py b/src/ecdsa/test_ellipticcurve.py index 56e61205..f0b35a86 100644 --- a/src/ecdsa/test_ellipticcurve.py +++ b/src/ecdsa/test_ellipticcurve.py @@ -30,10 +30,12 @@ Gx = 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012 Gy = 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811 - c192 = CurveFp(p, -3, b) p192 = Point(c192, Gx, Gy, r) +c_23 = CurveFp(23, 1, 1) +g_23 = Point(c_23, 13, 7, 7) + @settings(**HYP_SETTINGS) @given(st.integers(min_value=1, max_value=r+1)) @@ -42,7 +44,25 @@ def test_p192_mult_tests(multiple): p1 = p192 * multiple assert p1 * inv_m == p192 + + +def add_n_times(point, n): + ret = INFINITY + i = 0 + while i <= n: + yield ret + ret = ret + point + i += 1 + +# From X9.62 I.1 (p. 96): +@pytest.mark.parametrize( + "p, m, check", + [(g_23, n, exp) for n, exp in enumerate(add_n_times(g_23, 8))], + ids=["g_23 test with mult {0}".format(i) for i in range(9)]) +def test_add_and_mult_equivalence(p, m, check): + assert p * m == check + class TestCurve(unittest.TestCase): @@ -74,16 +94,8 @@ def setUpClass(cls): Gy = 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811 cls.c192 = CurveFp(p, -3, b) - cls.p192 = Point(cls.c192, Gx, Gy, r) - - def _add_n_times(self, point, n): - ret = INFINITY - i = 0 - while i <= n: - yield ret - ret = ret + point - i += 1 - + cls.p192 = Point(cls.c192, Gx, Gy, r) + def test_p192(self): # Checking against some sample computations presented # in X9.62: @@ -107,13 +119,8 @@ def test_double_infinity(self): p3 = p1.double() self.assertEqual(p1, p3) self.assertEqual(p3.x(), p1.x()) - self.assertEqual(p3.y(), p3.y()) - - # From X9.62 I.1 (p. 96): - def test_add_and_mult_equivalence(self): - for n, exp in enumerate(self._add_n_times(self.g_23, 8)): - self.assertEqual(self.g_23 * n, exp) - + self.assertEqual(p3.y(), p3.y()) + def test_double(self): x1, y1, x3, y3 = (3, 10, 7, 12) @@ -133,14 +140,22 @@ def test_multiply(self): def test_add(self): """We expect that on curve c, (x1,y1) + (x2, y2 ) = (x3, y3).""" - data = [(3, 10, 9, 7, 17, 20), # real add - (3, 10, 3, 10, 7, 12)] # double - for (x1, y1, x2, y2, x3, y3) in data: - p1 = Point(self.c_23, x1, y1) - p2 = Point(self.c_23, x2, y2) - p3 = p1 + p2 - self.assertEqual(p3.x(), x3) - self.assertEqual(p3.y(), y3) + x1, y1, x2, y2, x3, y3 = (3, 10, 9, 7, 17, 20) + p1 = Point(self.c_23, x1, y1) + p2 = Point(self.c_23, x2, y2) + p3 = p1 + p2 + self.assertEqual(p3.x(), x3) + self.assertEqual(p3.y(), y3) + + def test_add_as_double(self): + """We expect that on curve c, (x1,y1) + (x2, y2 ) = (x3, y3).""" + + x1, y1, x2, y2, x3, y3 = (3, 10, 3, 10, 7, 12) + p1 = Point(self.c_23, x1, y1) + p2 = Point(self.c_23, x2, y2) + p3 = p1 + p2 + self.assertEqual(p3.x(), x3) + self.assertEqual(p3.y(), y3) def test_equality_points(self): self.assertEqual(self.g_23, Point(self.c_23, 13, 7, 7)) diff --git a/src/ecdsa/test_keys.py b/src/ecdsa/test_keys.py index 61d319c4..a6f23389 100644 --- a/src/ecdsa/test_keys.py +++ b/src/ecdsa/test_keys.py @@ -120,11 +120,20 @@ def setUpClass(cls): "-----BEGIN PUBLIC KEY-----\n" "MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAEuIF30ITvF/XkVjlAgCg2D59ZtKTX\n" "Jk5i2gZR3OR6NaTFtFz1FZNCOotVe5wgmfNs\n" - "-----END PUBLIC KEY-----\n") + "-----END PUBLIC KEY-----\n") + cls.key_bytes = unpem(key_str) assert isinstance(cls.key_bytes, bytes) cls.vk = VerifyingKey.from_pem(key_str) cls.sk = SigningKey.from_pem(prv_key_str) + + key_str = ( + "-----BEGIN PUBLIC KEY-----\n" + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4H3iRbG4TSrsSRb/gusPQB/4YcN8\n" + "Poqzgjau4kfxBPyZimeRfuY/9g/wMmPuhGl4BUve51DsnKJFRr8psk0ieA==\n" + "-----END PUBLIC KEY-----\n" + ) + cls.vk2 = VerifyingKey.from_pem(key_str) def test_bytes(self): vk = VerifyingKey.from_der(self.key_bytes) @@ -160,6 +169,12 @@ def test_array_array_of_bytes_memoryview(self): def test_equality_on_verifying_keys(self): self.assertEqual(self.vk, self.sk.get_verifying_key()) + + def test_inequality_on_verifying_keys(self): + self.assertNotEqual(self.vk, self.vk2) + + def test_inequality_on_verifying_keys_not_implemented(self): + self.assertNotEqual(self.vk, None) class TestSigningKey(unittest.TestCase): @@ -175,11 +190,25 @@ def setUpClass(cls): "BLiBd9CE7xf15FY5QIAoNg+fWbSk1yZOYtoGUdzkejWkxbRc9RWTQjqLVXucIJnz\n" "bA==\n" "-----END EC PRIVATE KEY-----\n") - cls.sk = SigningKey.from_pem(prv_key_str) + cls.sk1 = SigningKey.from_pem(prv_key_str) + + prv_key_str = ( + "-----BEGIN EC PRIVATE KEY-----\n" + "MHcCAQEEIKlL2EAm5NPPZuXwxRf4nXMk0A80y6UUbiQ17be/qFhRoAoGCCqGSM49\n" + "AwEHoUQDQgAE4H3iRbG4TSrsSRb/gusPQB/4YcN8Poqzgjau4kfxBPyZimeRfuY/\n" + "9g/wMmPuhGl4BUve51DsnKJFRr8psk0ieA==\n" + "-----END EC PRIVATE KEY-----\n") + cls.sk2 = SigningKey.from_pem(prv_key_str) def test_equality_on_signing_keys(self): - sk2 = SigningKey.from_secret_exponent(self.sk.privkey.secret_multiplier, self.sk.curve) - self.assertEqual(self.sk, sk2) + sk = SigningKey.from_secret_exponent(self.sk1.privkey.secret_multiplier, self.sk1.curve) + self.assertEqual(self.sk1, sk) + + def test_inequality_on_signing_keys(self): + self.assertNotEqual(self.sk1, self.sk2) + + def test_inequality_on_signing_keys_not_implemented(self): + self.assertNotEqual(self.sk1, None) # test VerifyingKey.verify() prv_key_str = (