From 42a267b6163d54e4f12b0be6dc757e57b4ac4ec0 Mon Sep 17 00:00:00 2001 From: Ivan Sarno Date: Mon, 9 Jan 2017 00:40:02 +0100 Subject: [PATCH 1/8] V.5.4 --- ECL/__init__.py | 8 +++--- ECL/curve.py | 5 ++-- ECL/diffie_hellman.py | 14 ++++------ ECL/ecdsa.py | 33 +++++++++++------------- ECL/elgamal.py | 18 +++++-------- ECL/koblitz.py | 12 +++------ ECL/point.py | 2 +- ECL/point_with_order.py | 6 ++--- ECL/std_curves.py | 2 +- ECL/test.py | 4 +-- ECL/utility.py | 51 ++++++++++++++++--------------------- changelog.txt | 10 ++++++++ test/__init__.py | 0 test/diffie_hellman_test.py | 31 ++++++++++++++++++++++ test/koblitz_test.py | 8 ++++++ test/utility_test.py | 45 ++++++++++++++++++++++++++++++++ 16 files changed, 160 insertions(+), 89 deletions(-) create mode 100644 test/__init__.py create mode 100644 test/diffie_hellman_test.py create mode 100644 test/koblitz_test.py create mode 100644 test/utility_test.py diff --git a/ECL/__init__.py b/ECL/__init__.py index 478c657..b970276 100644 --- a/ECL/__init__.py +++ b/ECL/__init__.py @@ -18,18 +18,18 @@ from ECL import point, curve, std_curves, point_with_order, koblitz, elgamal, diffie_hellman, ecdsa from ECL.curve import Curve from ECL.point import Point -from ECL.utility import EclException +from ECL.utility import EclError from ECL.diffie_hellman import DiffieHellman from ECL.point_with_order import PointWOrder __author__ = 'ivansarno' -__version__ = 'V.5.2' -__all__ = ["Curve", "Point", "PointWOrder", "EclException"] +__version__ = 'V.5.4' +__all__ = ["Curve", "Point", "PointWOrder", "EclError"] __doc__ = """ ECL: library includes basic operations on Elliptic curves, 2 cipher and a digital signature protocol. includes: class: Point, PointWOrder, Curve algorithm: Diffie-Hellman, ElGamal, Koblitz, ECDSA built-in: Nist's standard curves and points -exception: EclException, DiffieHellmanError, KoblitzFailError, ECDSAError, ElGamalError +exception: EclError, DiffieHellmanError, KoblitzFailError, ECDSAError, ElGamalError """ \ No newline at end of file diff --git a/ECL/curve.py b/ECL/curve.py index e7ed637..0a6cf01 100644 --- a/ECL/curve.py +++ b/ECL/curve.py @@ -16,7 +16,7 @@ limitations under the License. """ __author__ = 'ivansarno' -__version__ = 'V.5.2' +__version__ = 'V.5.4' __doc__ = """Implementation of Prime Elliptic Curves""" @@ -62,8 +62,7 @@ def copy(self): :return: Curve copy of self :rtype: Curve """ - ris = Curve(self.__a, self.__b, self.__prime) - return ris + return Curve(self.__a, self.__b, self.__prime) def __str__(self): return "a: %x\nb: 0x%x\nprime: 0x%x\n" % (self.__a, self.__b, self.__prime) diff --git a/ECL/diffie_hellman.py b/ECL/diffie_hellman.py index aa8af63..23f4fc9 100644 --- a/ECL/diffie_hellman.py +++ b/ECL/diffie_hellman.py @@ -16,12 +16,12 @@ limitations under the License. """ from typing import Callable -from ECL.utility import EclException +from ECL.utility import EclError from ECL.point import Point from ECL.point_with_order import PointWOrder __author__ = 'ivansarno' -__version__ = 'V.5.2' +__version__ = 'V.5.4' __doc__ = """Diffie-Hellman's public key system. class: DiffieHellman @@ -39,7 +39,7 @@ class DiffieHellman: def __init__(self, base_point: PointWOrder, generator: Callable[[int], int]): """ :param base_point: Point used as base, can be used a standard point from ECL.std_curves - :param generator: random number generator, return a random int of size passed by parameter + :param generator: random number generator, return a random int of size in bits passed by parameter """ self.__point = base_point @@ -79,10 +79,6 @@ def key(self) -> Point: return self.__key -class DiffieHellmanError(EclException): +class DiffieHellmanError(EclError): """DiffieHellman algorithm fail.""" - def __init__(self, value): - self.value = value - - def __str__(self): - return self.value.__repr__() + pass diff --git a/ECL/ecdsa.py b/ECL/ecdsa.py index 5c82339..2e6e064 100644 --- a/ECL/ecdsa.py +++ b/ECL/ecdsa.py @@ -19,10 +19,10 @@ from typing import Callable, Tuple from ECL.point import Point from ECL.point_with_order import PointWOrder -from ECL.utility import inverse, EclException +from ECL.utility import inverse, EclError __author__ = 'ivansarno' -__version__ = 'V.5.2' +__version__ = 'V.5.4' __doc__ = """ECDSA digital signature algorithm classes: PrivateKey, PublicKey, Signature @@ -31,9 +31,17 @@ """ +def _standard_hash(message: bytearray) -> Tuple[int, int]: + """Default hash fun, sha512, little endian, unsigned""" + sha = hashlib.sha512() + sha.update(message) + message_hash = int.from_bytes(sha.digest(), byteorder='little', signed=False) + return message_hash, 512 + + class Signature: def __init__(self, first: int, second: int): - """This constructor is for internal use, user must resume a message from a representation string""" + """This constructor is for internal use, user must resume a message from a representation string or use deserialization""" self.__first = first self.__second = second @@ -55,7 +63,7 @@ def __repr__(self): class PublicKey: def __init__(self, base_point: PointWOrder, key_point: Point): """This constructor is for internal use, user must generates the public key from a PrivateKey object - or resume it from a representation string""" + or resume it from a representation string or use deserialization""" self.__key = key_point self.__base = base_point @@ -89,7 +97,7 @@ def check(self, message: bytearray, signature: Signature, hash_fun=_standard_has class PrivateKey: def __init__(self, base_point: PointWOrder, key: int): """This constructor is for internal use, user must generates the private key with keygen method - or resume it from a representation string""" + or resume it from a representation string or use deserialization""" self.__key = key self.__base = base_point @@ -136,18 +144,7 @@ def __repr__(self): return "ECL.ecdsa.PrivateKey( %s, 0x%x)" % (self.__base.__repr__(), self.__key) -class ECDSAError(EclException): +class ECDSAError(EclError): """ECDSAError algorithm fail.""" - def __init__(self, value): - self.value = value + pass - def __str__(self): - return self.value.__repr__() - - -def _standard_hash(message: bytearray) -> Tuple[int, int]: - """Default hash fun, sha512, little endian, unsigned""" - sha = hashlib.sha512() - sha.update(message) - message_hash = int.from_bytes(sha.digest(), byteorder='little', signed=False) - return message_hash, 512 diff --git a/ECL/elgamal.py b/ECL/elgamal.py index 125bd3f..b8346c3 100644 --- a/ECL/elgamal.py +++ b/ECL/elgamal.py @@ -18,12 +18,12 @@ from typing import Callable from ECL import koblitz -from ECL.utility import EclException +from ECL.utility import EclError from ECL.point import Point from ECL.point_with_order import PointWOrder __author__ = 'ivansarno' -__version__ = 'V.5.2' +__version__ = 'V.5.4' __doc__ = """El Gamal's cipher. classes: ElGamalMessage, PublicKey, PrivateKey @@ -34,7 +34,7 @@ class ElGamalMessage: def __init__(self, first: Point, second: Point, padding: int): - """This constructor is for internal use, user must resume a message from a representation string""" + """This constructor is for internal use, user must resume a message from a representation string or use deserialization""" self.__first = first self.__second = second self.__padding = padding @@ -61,7 +61,7 @@ def __repr__(self): class PublicKey: def __init__(self, base_point: PointWOrder, key_point: Point): """This constructor is for internal use, user must generates the public key from a PrivateKey object - or resume it from a representation string""" + or resume it from a representation string or use deserialization""" self.__key = key_point self.__base = base_point @@ -85,7 +85,7 @@ def __repr__(self): class PrivateKey: def __init__(self, base_point: PointWOrder, key: int): """This constructor is for internal use, user must generates the private key with keygen method - or resume it from a representation string""" + or resume it from a representation string or use deserialization""" self.__key = key self.__base = base_point @@ -112,10 +112,6 @@ def __repr__(self): return "ECL.elgamal.PrivateKey( %s, 0x%x)" % (self.__base.__repr__(), self.__key) -class ElGamalError(EclException): +class ElGamalError(EclError): """ElGamal algorithm fail.""" - def __init__(self, value): - self.value = value - - def __str__(self): - return self.value.__repr__() + pass diff --git a/ECL/koblitz.py b/ECL/koblitz.py index 687bac3..86f61c9 100644 --- a/ECL/koblitz.py +++ b/ECL/koblitz.py @@ -17,11 +17,11 @@ """ from typing import Tuple from ECL.curve import Curve -from ECL.utility import is_square, EclException, square_root +from ECL.utility import is_square, EclError, square_root from ECL.point import Point __author__ = 'ivansarno' -__version__ = 'V.5.2' +__version__ = 'V.5.4' __doc__ = """Implementation of Koblitz algorithm. functions: encode, decode, iterative_encode @@ -83,10 +83,6 @@ def iterative_encode(message: int, curve: Curve) -> Tuple[Point, int]: return point, padding -class KoblitzFailError(EclException): +class KoblitzFailError(EclError): """Koblitz algorithm fail, point not found.""" - def __init__(self, value): - self.value = value - - def __str__(self): - return self.value.__repr__() + pass diff --git a/ECL/point.py b/ECL/point.py index b78e2bc..346eec3 100644 --- a/ECL/point.py +++ b/ECL/point.py @@ -19,7 +19,7 @@ from ECL.utility import inverse __author__ = 'ivansarno' -__version__ = 'V.5.2' +__version__ = 'V.5.4' __doc__ = """Implementation of Point of Elliptic Curve classes: Point diff --git a/ECL/point_with_order.py b/ECL/point_with_order.py index 324b428..efc615f 100644 --- a/ECL/point_with_order.py +++ b/ECL/point_with_order.py @@ -18,12 +18,12 @@ from ECL.curve import Curve from ECL.point import Point __author__ = 'ivansarno' -__version__ = 'V.5.2' +__version__ = 'V.5.4' __doc__ = """Point with extra member, the order""" -class PointWOrder (Point): - """EC Point with order parameter. +class PointWOrder(Point): + """EC Point with order member. order == -1 is garbage value """ diff --git a/ECL/std_curves.py b/ECL/std_curves.py index 31c507a..e80f3f1 100644 --- a/ECL/std_curves.py +++ b/ECL/std_curves.py @@ -19,7 +19,7 @@ from ECL.point_with_order import PointWOrder __author__ = 'ivansarno' -__version__ = 'V.5.2' +__version__ = 'V.5.4' __doc__ = """Nist's standard curves and points (the number in the name is the bit of order) diff --git a/ECL/test.py b/ECL/test.py index d0a7fb6..15592ba 100644 --- a/ECL/test.py +++ b/ECL/test.py @@ -20,7 +20,7 @@ from ECL import utility, ecdsa, elgamal __author__ = 'ivansarno' -__version__ = 'V.5.2' +__version__ = 'V.5.4' __doc__ = """Test for package's features""" @@ -30,7 +30,7 @@ def test(curve=ECL.std_curves.CurveP192, point=ECL.std_curves.PointP192, generat result &= test_diffie_hellman(point, generator) result &= test_el_gamal_koblitz(point, generator) result &= test_ecdsa(generator=generator) - except ECL.EclException: + except ECL.EclError: print("test ERROR: EclException Raised") return False except Exception: diff --git a/ECL/utility.py b/ECL/utility.py index 9afec98..47ed4c0 100644 --- a/ECL/utility.py +++ b/ECL/utility.py @@ -20,7 +20,7 @@ from typing import Tuple __author__ = 'ivansarno' -__version__ = 'V.5.2' +__version__ = 'V.5.4' __doc__ = """ built-in random number generator, root exception, inverse calculation and modular square root. This functions are used by other modules""" @@ -29,6 +29,7 @@ def inverse(number: int, modulus: int) -> int: """Inverse operation in modular arithmetic. :return: inverse of number mod module + use iterative version of extended euclide's algorithm """ if modulus == 0: return 0 @@ -36,7 +37,7 @@ def inverse(number: int, modulus: int) -> int: while buffer[-1] != 0: buffer.append(buffer[-2] % buffer[-1]) - buffer.pop() + buffer.pop() #remove unused temorary value temp = 0 intermediate = 1 result = 1 @@ -53,32 +54,26 @@ def inverse(number: int, modulus: int) -> int: def is_square(num: int, module: int) -> bool: - """Return if num is a square mod module. + """Return if num is a square mod module when module is a prime number != 2. :return: exist y ** 2 mod module == num """ - e = module // 2 - r = pow(num, e, module) - return r == 1 + return pow(num, module >> 1, module) == 1 def generator(size: int) -> int: - """ Random Number generator for test, is not safe. + """ Random Number generator for test, is not safe. :param size: number of bit of random number :return: random int of size bit """ - temp = os.urandom(size // 8) - return int.from_bytes(temp, 'little') + temp = os.urandom(size >> 3 + 1) + return int.from_bytes(temp, 'little') -class EclException(Exception): +class EclError(Exception): """Generic ECL exception.""" - def __init__(self, value): - self.value = value - - def __str__(self): - return self.value.__repr__() + pass def square_root(number: int, prime: int) -> int: @@ -88,20 +83,18 @@ def square_root(number: int, prime: int) -> int: """ if number == 0: return 0 - if (prime % 4) == 3: - return pow(number, (prime + 1) // 4, prime) - if (prime % 8) == 5: - sign = pow(number, (prime - 1) // 4, prime) - if sign == 1: - return pow(number, (prime + 3) // 8, prime) - else: - return (2 * number) * pow((4 * number), (prime - 5) // 8, prime) + if (prime & 3) == 3: + return pow(number, (prime + 1) >> 2, prime) + if (prime & 7) == 5: + v = pow(number << 1, (prime-5) >> 3) + i = ((number * (v ** 2)) << 1) % prime + return (number * v * (i -1)) % prime r = shanks(number, prime) return r[1] def legendre_symbol(number: int, prime: int) -> int: - ls = pow(number, (prime - 1) // 2, prime) + ls = pow(number, prime >> 1, prime) if ls == prime - 1: return -1 return ls @@ -111,16 +104,16 @@ def shanks(number: int, prime: int) -> Tuple[int, int]: """Return square roots of number mod prime.""" q = prime - 1 s = 0 - while q % 2 == 0: + while q & 1 == 0: s += 1 - q //= 2 + q >>= 1 z = 1 while legendre_symbol(z, prime) != -1: z += 1 c = pow(z, q, prime) - x = pow(number, (q + 1) // 2, prime) + x = pow(number, (q + 1) >> 1, prime) t = pow(number, q, prime) m = s @@ -130,9 +123,9 @@ def shanks(number: int, prime: int) -> Tuple[int, int]: for i in range(1, m): if pow(t, e, prime) == 1: break - e *= 2 + e <<= 1 - b = pow(c, 2 ** (m - i - 1), prime) + b = pow(c, 1 << (m - i - 1), prime) x = (x * b) % prime t = (t * b * b) % prime c = (b * b) % prime diff --git a/changelog.txt b/changelog.txt index fdc7c3f..b6f1c5f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,13 @@ +Version 5.4: +1) better tests +2) test module moved in different package + +Version 5.3: +1)several optimizations and fixes +2)rename EclException in EclError + +Version 5.3 is not backward compatible + Version 5.2: ECDSA parametric hash function diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/diffie_hellman_test.py b/test/diffie_hellman_test.py new file mode 100644 index 0000000..7f60352 --- /dev/null +++ b/test/diffie_hellman_test.py @@ -0,0 +1,31 @@ +import ECL +from ECL import utility + + +def test_functionality() -> bool: + user1 = ECL.DiffieHellman(ECL.std_curves.PointP192(), utility.generator) + user2 = ECL.DiffieHellman(ECL.std_curves.PointP192(), utility.generator) + message1 = user1.step1() + message2 = user2.step1() + user2.step2(message1) + user1.step2(message2) + return user1.key == user2.key + + +def test_synch_dh(): + dh = ECL.DiffieHellman(ECL.std_curves.PointP192(), utility.generator) + r = False + try: + k = dh.key + except ECL.diffie_hellman.DiffieHellmanError: + r = True + + try: + dh.step2(ECL.std_curves.PointP192()._doubles()) + + except ECL.diffie_hellman.DiffieHellmanError: + r &= True + + +def test_diffie_hellman(): + return test_functionality() and test_synch_dh() diff --git a/test/koblitz_test.py b/test/koblitz_test.py new file mode 100644 index 0000000..bd11259 --- /dev/null +++ b/test/koblitz_test.py @@ -0,0 +1,8 @@ +import ECL +import random + + +def test_koblitz(): + n = random.randrange(20000) + point, padding = ECL.koblitz.iterative_encode(n, ECL.std_curves.CurveP192()) + return ECL.koblitz.decode(point, padding) == n and point.check(ECL.std_curves.CurveP192()) \ No newline at end of file diff --git a/test/utility_test.py b/test/utility_test.py new file mode 100644 index 0000000..7836b08 --- /dev/null +++ b/test/utility_test.py @@ -0,0 +1,45 @@ +from ECL.utility import * +import random + + +def test_inverse(): + t = 0 + while t == 0: + t = random.randint(0, 30) + return (inverse(t, 31) * t) % 31 == 1 + + +def test_is_square(): + t = 0 + while t == 0: + t = random.randint(0, 30) + s = t*t % 31 + return is_square(s, 31) + + +def test_square_root(): + t = 0 + while t == 0: + t = random.randint(0, 7) + + s = square_root(t * t % 7, 7) + r1 = s == t or 7 - t == s + + t = random.randint(0, 13) + while t == 0: + t = random.randint(0, 12) + + s = square_root(t * t % 13, 13) + r2 = s == t or 13 - t == s + + t = random.randint(0, 16) + while t == 0: + t = random.randint(0, 16) + + s = square_root(t * t % 17, 17) + r3 = s == t or 17 - t == s + return r1 and r2 and r3 + + +def test_utility(): + return test_inverse() and test_is_square() and test_square_root() From e1c1a9c9406fffeb98a246b3707b056cf90f2eb3 Mon Sep 17 00:00:00 2001 From: Ivan Sarno Date: Wed, 11 Jan 2017 19:27:07 +0100 Subject: [PATCH 2/8] V.5.4 --- {test => ECL}/diffie_hellman_test.py | 3 +++ ECL/elgamal.py | 3 ++- ECL/elgamal_test.py | 27 +++++++++++++++++++++++++++ {test => ECL}/koblitz_test.py | 0 ECL/{test.py => parametric_tests.py} | 0 ECL/rapresentation_test.py | 22 ++++++++++++++++++++++ ECL/tests.py | 0 ECL/utility.py | 4 ++-- {test => ECL}/utility_test.py | 0 test/__init__.py | 1 + 10 files changed, 57 insertions(+), 3 deletions(-) rename {test => ECL}/diffie_hellman_test.py (94%) create mode 100644 ECL/elgamal_test.py rename {test => ECL}/koblitz_test.py (100%) rename ECL/{test.py => parametric_tests.py} (100%) create mode 100644 ECL/rapresentation_test.py create mode 100644 ECL/tests.py rename {test => ECL}/utility_test.py (100%) diff --git a/test/diffie_hellman_test.py b/ECL/diffie_hellman_test.py similarity index 94% rename from test/diffie_hellman_test.py rename to ECL/diffie_hellman_test.py index 7f60352..de9827a 100644 --- a/test/diffie_hellman_test.py +++ b/ECL/diffie_hellman_test.py @@ -17,14 +17,17 @@ def test_synch_dh(): r = False try: k = dh.key + r = False except ECL.diffie_hellman.DiffieHellmanError: r = True try: dh.step2(ECL.std_curves.PointP192()._doubles()) + r &= False except ECL.diffie_hellman.DiffieHellmanError: r &= True + return r def test_diffie_hellman(): diff --git a/ECL/elgamal.py b/ECL/elgamal.py index b8346c3..4f12a18 100644 --- a/ECL/elgamal.py +++ b/ECL/elgamal.py @@ -34,7 +34,8 @@ class ElGamalMessage: def __init__(self, first: Point, second: Point, padding: int): - """This constructor is for internal use, user must resume a message from a representation string or use deserialization""" + """This constructor is for internal use, user must resume a message from a + representation string or use deserialization""" self.__first = first self.__second = second self.__padding = padding diff --git a/ECL/elgamal_test.py b/ECL/elgamal_test.py new file mode 100644 index 0000000..1a17b65 --- /dev/null +++ b/ECL/elgamal_test.py @@ -0,0 +1,27 @@ +import random +import ECL +from ECL import elgamal, utility +from ECL.elgamal import ElGamalError + + +def test_functionality() -> bool: + private = elgamal.PrivateKey.keygen(ECL.std_curves.PointP192(), utility.generator) + public = private.public_key + message = random.randrange(1) + cipher = public.encrypt(message, utility.generator) + cipher = private.decrypt(cipher) + return cipher == message + + +def test_out_of_range(): + public = elgamal.PrivateKey.keygen(ECL.std_curves.PointP192(), utility.generator).public_key + message = ECL.std_curves.PointP192().order + 200 + try: + cipher = public.encrypt(message, utility.generator) + return False + except ElGamalError: + return True + + +def test(): + return test_functionality() and test_out_of_range() diff --git a/test/koblitz_test.py b/ECL/koblitz_test.py similarity index 100% rename from test/koblitz_test.py rename to ECL/koblitz_test.py diff --git a/ECL/test.py b/ECL/parametric_tests.py similarity index 100% rename from ECL/test.py rename to ECL/parametric_tests.py diff --git a/ECL/rapresentation_test.py b/ECL/rapresentation_test.py new file mode 100644 index 0000000..77ec964 --- /dev/null +++ b/ECL/rapresentation_test.py @@ -0,0 +1,22 @@ +import ECL +from ECL import elgamal, utility, std_curves +import random + +def point_test(): + point = ECL.std_curves.PointP192() + dpoint = point._doubles() + return point == eval(point.__repr__()) and dpoint == eval(dpoint.__repr__()) + +def elgamal_test(): + private = elgamal.PrivateKey.keygen(ECL.std_curves.PointP192(), utility.generator) + public = private.public_key + message = public.encrypt(random.randrange(1), utility.generator) + rmessage = eval(message.__repr__()) + #r1 = message.first == rmessage.first and message.second == rmessage.second and message.padding == rmessage.padding + rpublic = eval(public.__repr__()) + #r2 = public. + rprivate = eval(private.__repr__()) + return vars(private) == vars(rprivate) and vars(message) == vars(rmessage) and vars(public) == vars(rpublic) + + +#def ecdsa_test(): \ No newline at end of file diff --git a/ECL/tests.py b/ECL/tests.py new file mode 100644 index 0000000..e69de29 diff --git a/ECL/utility.py b/ECL/utility.py index 47ed4c0..3256cd3 100644 --- a/ECL/utility.py +++ b/ECL/utility.py @@ -67,7 +67,7 @@ def generator(size: int) -> int: :param size: number of bit of random number :return: random int of size bit """ - temp = os.urandom(size >> 3 + 1) + temp = os.urandom(size // 8 + 1) return int.from_bytes(temp, 'little') @@ -88,7 +88,7 @@ def square_root(number: int, prime: int) -> int: if (prime & 7) == 5: v = pow(number << 1, (prime-5) >> 3) i = ((number * (v ** 2)) << 1) % prime - return (number * v * (i -1)) % prime + return (number * v * (i - 1)) % prime r = shanks(number, prime) return r[1] diff --git a/test/utility_test.py b/ECL/utility_test.py similarity index 100% rename from test/utility_test.py rename to ECL/utility_test.py diff --git a/test/__init__.py b/test/__init__.py index e69de29..8b13789 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -0,0 +1 @@ + From 4d58528b50989040d0b4c3c354000d8d66da02f1 Mon Sep 17 00:00:00 2001 From: Ivan Sarno Date: Sun, 5 Feb 2017 20:28:53 +0100 Subject: [PATCH 3/8] V.5.4 --- ECL/rapresentation_test.py | 22 ------------ ECL/tests.py => T/__init__.py | 0 {ECL => T}/diffie_hellman_test.py | 6 ++-- T/ecdsa_test.py | 56 +++++++++++++++++++++++++++++++ {ECL => T}/elgamal_test.py | 15 +++++++-- {ECL => T}/koblitz_test.py | 2 +- {ECL => T}/parametric_tests.py | 0 T/point_test.py | 12 +++++++ {ECL => T}/utility_test.py | 8 ++--- test/__init__.py | 1 - 10 files changed, 87 insertions(+), 35 deletions(-) delete mode 100644 ECL/rapresentation_test.py rename ECL/tests.py => T/__init__.py (100%) rename {ECL => T}/diffie_hellman_test.py (92%) create mode 100644 T/ecdsa_test.py rename {ECL => T}/elgamal_test.py (54%) rename {ECL => T}/koblitz_test.py (89%) rename {ECL => T}/parametric_tests.py (100%) create mode 100644 T/point_test.py rename {ECL => T}/utility_test.py (86%) delete mode 100644 test/__init__.py diff --git a/ECL/rapresentation_test.py b/ECL/rapresentation_test.py deleted file mode 100644 index 77ec964..0000000 --- a/ECL/rapresentation_test.py +++ /dev/null @@ -1,22 +0,0 @@ -import ECL -from ECL import elgamal, utility, std_curves -import random - -def point_test(): - point = ECL.std_curves.PointP192() - dpoint = point._doubles() - return point == eval(point.__repr__()) and dpoint == eval(dpoint.__repr__()) - -def elgamal_test(): - private = elgamal.PrivateKey.keygen(ECL.std_curves.PointP192(), utility.generator) - public = private.public_key - message = public.encrypt(random.randrange(1), utility.generator) - rmessage = eval(message.__repr__()) - #r1 = message.first == rmessage.first and message.second == rmessage.second and message.padding == rmessage.padding - rpublic = eval(public.__repr__()) - #r2 = public. - rprivate = eval(private.__repr__()) - return vars(private) == vars(rprivate) and vars(message) == vars(rmessage) and vars(public) == vars(rpublic) - - -#def ecdsa_test(): \ No newline at end of file diff --git a/ECL/tests.py b/T/__init__.py similarity index 100% rename from ECL/tests.py rename to T/__init__.py diff --git a/ECL/diffie_hellman_test.py b/T/diffie_hellman_test.py similarity index 92% rename from ECL/diffie_hellman_test.py rename to T/diffie_hellman_test.py index de9827a..1183aa1 100644 --- a/ECL/diffie_hellman_test.py +++ b/T/diffie_hellman_test.py @@ -12,23 +12,21 @@ def test_functionality() -> bool: return user1.key == user2.key -def test_synch_dh(): +def test_synch_dh() -> bool: dh = ECL.DiffieHellman(ECL.std_curves.PointP192(), utility.generator) r = False try: k = dh.key - r = False except ECL.diffie_hellman.DiffieHellmanError: r = True try: dh.step2(ECL.std_curves.PointP192()._doubles()) r &= False - except ECL.diffie_hellman.DiffieHellmanError: r &= True return r -def test_diffie_hellman(): +def test() -> bool: return test_functionality() and test_synch_dh() diff --git a/T/ecdsa_test.py b/T/ecdsa_test.py new file mode 100644 index 0000000..d3fa031 --- /dev/null +++ b/T/ecdsa_test.py @@ -0,0 +1,56 @@ +import random + +from ECL import std_curves +from ECL import utility +from ECL.ecdsa import * + +def test_functionality() -> bool: + base = std_curves.PointP192() + private = PrivateKey.keygen(base, utility.generator) + public = private.public_key + message = message = bytearray(random.randrange(1)) + signature = private.sign(message, utility.generator) + #true signature check + if not public.check(message, signature): + return False + #fake signatures check, should not be recognized + fake_signature = Signature(signature.first + 1, signature.second) + if public.check(message, fake_signature): + return False + fake_signature = Signature(signature.first, signature.second - 1) + if public.check(message, fake_signature): + return False + fake_signature = Signature(signature.first, 0) + if public.check(message, fake_signature): + return False + fake_signature = Signature(signature.first, base.order + 1) + if public.check(message, fake_signature): + return False + fake_signature = Signature(0, signature.second) + if public.check(message, fake_signature): + return False + fake_signature = Signature(base.order + 1, signature.second) + if public.check(message, fake_signature): + return False + return True + + +def test_rapresentation() -> bool: + private = PrivateKey.keygen(std_curves.PointP192(), utility.generator) + public = private.public_key + message = bytearray(random.randrange(1)) + signature = private.sign(message, utility.generator) + if not vars(signature) == vars(eval(signature.__repr__())): + return False + if not vars(public) == vars(eval(public.__repr__())): + return False + if not vars(private) == vars(eval(private.__repr__())): + return False + return True + + +def test() -> bool: + return test_functionality() and test_functionality() + + + diff --git a/ECL/elgamal_test.py b/T/elgamal_test.py similarity index 54% rename from ECL/elgamal_test.py rename to T/elgamal_test.py index 1a17b65..3b794ed 100644 --- a/ECL/elgamal_test.py +++ b/T/elgamal_test.py @@ -13,7 +13,7 @@ def test_functionality() -> bool: return cipher == message -def test_out_of_range(): +def test_out_of_range() -> bool: public = elgamal.PrivateKey.keygen(ECL.std_curves.PointP192(), utility.generator).public_key message = ECL.std_curves.PointP192().order + 200 try: @@ -22,6 +22,15 @@ def test_out_of_range(): except ElGamalError: return True +def test_rapresentation() -> bool: + private = elgamal.PrivateKey.keygen(ECL.std_curves.PointP192(), utility.generator) + public = private.public_key + message = public.encrypt(random.randrange(1), utility.generator) + rmessage = eval(message.__repr__()) + rpublic = eval(public.__repr__()) + rprivate = eval(private.__repr__()) + return vars(private) == vars(rprivate) and vars(message) == vars(rmessage) and vars(public) == vars(rpublic) + -def test(): - return test_functionality() and test_out_of_range() +def test() -> bool: + return test_functionality() and test_out_of_range() and test_rapresentation() diff --git a/ECL/koblitz_test.py b/T/koblitz_test.py similarity index 89% rename from ECL/koblitz_test.py rename to T/koblitz_test.py index bd11259..2f8c3f8 100644 --- a/ECL/koblitz_test.py +++ b/T/koblitz_test.py @@ -2,7 +2,7 @@ import random -def test_koblitz(): +def test_koblitz() -> bool: n = random.randrange(20000) point, padding = ECL.koblitz.iterative_encode(n, ECL.std_curves.CurveP192()) return ECL.koblitz.decode(point, padding) == n and point.check(ECL.std_curves.CurveP192()) \ No newline at end of file diff --git a/ECL/parametric_tests.py b/T/parametric_tests.py similarity index 100% rename from ECL/parametric_tests.py rename to T/parametric_tests.py diff --git a/T/point_test.py b/T/point_test.py new file mode 100644 index 0000000..3d57823 --- /dev/null +++ b/T/point_test.py @@ -0,0 +1,12 @@ +import ECL +from ECL import elgamal, utility, std_curves +import random + +def point_test(): + point = ECL.std_curves.PointP192() + dpoint = point._doubles() + return point == eval(point.__repr__()) and dpoint == eval(dpoint.__repr__()) + + + + diff --git a/ECL/utility_test.py b/T/utility_test.py similarity index 86% rename from ECL/utility_test.py rename to T/utility_test.py index 7836b08..111d157 100644 --- a/ECL/utility_test.py +++ b/T/utility_test.py @@ -2,14 +2,14 @@ import random -def test_inverse(): +def test_inverse() -> bool: t = 0 while t == 0: t = random.randint(0, 30) return (inverse(t, 31) * t) % 31 == 1 -def test_is_square(): +def test_is_square() -> bool: t = 0 while t == 0: t = random.randint(0, 30) @@ -17,7 +17,7 @@ def test_is_square(): return is_square(s, 31) -def test_square_root(): +def test_square_root() -> bool: t = 0 while t == 0: t = random.randint(0, 7) @@ -41,5 +41,5 @@ def test_square_root(): return r1 and r2 and r3 -def test_utility(): +def test_utility() -> bool: return test_inverse() and test_is_square() and test_square_root() diff --git a/test/__init__.py b/test/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/test/__init__.py +++ /dev/null @@ -1 +0,0 @@ - From 12e403c130e6f9f0aa8a65137a60d9f9ef9251a4 Mon Sep 17 00:00:00 2001 From: Ivan Sarno Date: Sun, 5 Feb 2017 20:45:32 +0100 Subject: [PATCH 4/8] V.5.4 --- T/__init__.py | 0 T/koblitz_test.py | 8 ------- T/point_test.py | 12 ---------- changelog.txt | 1 + tests/__init__.py | 23 +++++++++++++++++++ {T => tests}/diffie_hellman_test.py | 20 +++++++++++++++++ {T => tests}/ecdsa_test.py | 30 ++++++++++++++++++++----- {T => tests}/elgamal_test.py | 21 ++++++++++++++++++ tests/koblitz_test.py | 28 ++++++++++++++++++++++++ {T => tests}/parametric_tests.py | 0 tests/point_test.py | 34 +++++++++++++++++++++++++++++ {T => tests}/utility_test.py | 20 +++++++++++++++++ 12 files changed, 171 insertions(+), 26 deletions(-) delete mode 100644 T/__init__.py delete mode 100644 T/koblitz_test.py delete mode 100644 T/point_test.py create mode 100644 tests/__init__.py rename {T => tests}/diffie_hellman_test.py (56%) rename {T => tests}/ecdsa_test.py (69%) rename {T => tests}/elgamal_test.py (66%) create mode 100644 tests/koblitz_test.py rename {T => tests}/parametric_tests.py (100%) create mode 100644 tests/point_test.py rename {T => tests}/utility_test.py (58%) diff --git a/T/__init__.py b/T/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/T/koblitz_test.py b/T/koblitz_test.py deleted file mode 100644 index 2f8c3f8..0000000 --- a/T/koblitz_test.py +++ /dev/null @@ -1,8 +0,0 @@ -import ECL -import random - - -def test_koblitz() -> bool: - n = random.randrange(20000) - point, padding = ECL.koblitz.iterative_encode(n, ECL.std_curves.CurveP192()) - return ECL.koblitz.decode(point, padding) == n and point.check(ECL.std_curves.CurveP192()) \ No newline at end of file diff --git a/T/point_test.py b/T/point_test.py deleted file mode 100644 index 3d57823..0000000 --- a/T/point_test.py +++ /dev/null @@ -1,12 +0,0 @@ -import ECL -from ECL import elgamal, utility, std_curves -import random - -def point_test(): - point = ECL.std_curves.PointP192() - dpoint = point._doubles() - return point == eval(point.__repr__()) and dpoint == eval(dpoint.__repr__()) - - - - diff --git a/changelog.txt b/changelog.txt index b6f1c5f..8959bff 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,7 @@ Version 5.4: 1) better tests 2) test module moved in different package +3) old tests refactor as parametric_tests Version 5.3: 1)several optimizations and fixes diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..aa06b33 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,23 @@ +""" + Elliptic Curve Library + + Copyright 2017 Ivan Sarno + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +from tests import diffie_hellman_test, ecdsa_test, elgamal_test, koblitz_test, point_test, utility_test + + +def ecl_test(): + return diffie_hellman_test.test() and ecdsa_test.test() and elgamal_test.test() and koblitz_test.test_koblitz() \ + and point_test.test() and utility_test.test_utility() diff --git a/T/diffie_hellman_test.py b/tests/diffie_hellman_test.py similarity index 56% rename from T/diffie_hellman_test.py rename to tests/diffie_hellman_test.py index 1183aa1..49b7f34 100644 --- a/T/diffie_hellman_test.py +++ b/tests/diffie_hellman_test.py @@ -1,6 +1,26 @@ +""" + Elliptic Curve Library + + Copyright 2017 Ivan Sarno + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" import ECL from ECL import utility +__author__ = 'ivansarno' +__version__ = 'V.5.4' + def test_functionality() -> bool: user1 = ECL.DiffieHellman(ECL.std_curves.PointP192(), utility.generator) diff --git a/T/ecdsa_test.py b/tests/ecdsa_test.py similarity index 69% rename from T/ecdsa_test.py rename to tests/ecdsa_test.py index d3fa031..bd51ad3 100644 --- a/T/ecdsa_test.py +++ b/tests/ecdsa_test.py @@ -1,19 +1,40 @@ +""" + Elliptic Curve Library + + Copyright 2017 Ivan Sarno + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" import random from ECL import std_curves from ECL import utility from ECL.ecdsa import * +__author__ = 'ivansarno' +__version__ = 'V.5.4' + + def test_functionality() -> bool: base = std_curves.PointP192() private = PrivateKey.keygen(base, utility.generator) public = private.public_key - message = message = bytearray(random.randrange(1)) + message = bytearray(random.randrange(1)) signature = private.sign(message, utility.generator) - #true signature check + # true signature check if not public.check(message, signature): return False - #fake signatures check, should not be recognized + # fake signatures check, should not be recognized fake_signature = Signature(signature.first + 1, signature.second) if public.check(message, fake_signature): return False @@ -51,6 +72,3 @@ def test_rapresentation() -> bool: def test() -> bool: return test_functionality() and test_functionality() - - - diff --git a/T/elgamal_test.py b/tests/elgamal_test.py similarity index 66% rename from T/elgamal_test.py rename to tests/elgamal_test.py index 3b794ed..6846228 100644 --- a/T/elgamal_test.py +++ b/tests/elgamal_test.py @@ -1,8 +1,28 @@ +""" + Elliptic Curve Library + + Copyright 2017 Ivan Sarno + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" import random import ECL from ECL import elgamal, utility from ECL.elgamal import ElGamalError +__author__ = 'ivansarno' +__version__ = 'V.5.4' + def test_functionality() -> bool: private = elgamal.PrivateKey.keygen(ECL.std_curves.PointP192(), utility.generator) @@ -22,6 +42,7 @@ def test_out_of_range() -> bool: except ElGamalError: return True + def test_rapresentation() -> bool: private = elgamal.PrivateKey.keygen(ECL.std_curves.PointP192(), utility.generator) public = private.public_key diff --git a/tests/koblitz_test.py b/tests/koblitz_test.py new file mode 100644 index 0000000..6bbc84f --- /dev/null +++ b/tests/koblitz_test.py @@ -0,0 +1,28 @@ +""" + Elliptic Curve Library + + Copyright 2017 Ivan Sarno + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +import ECL +import random + +__author__ = 'ivansarno' +__version__ = 'V.5.4' + + +def test_koblitz() -> bool: + n = random.randrange(20000) + point, padding = ECL.koblitz.iterative_encode(n, ECL.std_curves.CurveP192()) + return ECL.koblitz.decode(point, padding) == n and point.check(ECL.std_curves.CurveP192()) diff --git a/T/parametric_tests.py b/tests/parametric_tests.py similarity index 100% rename from T/parametric_tests.py rename to tests/parametric_tests.py diff --git a/tests/point_test.py b/tests/point_test.py new file mode 100644 index 0000000..18a45f8 --- /dev/null +++ b/tests/point_test.py @@ -0,0 +1,34 @@ +""" + Elliptic Curve Library + + Copyright 2017 Ivan Sarno + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +import ECL +from ECL import elgamal, utility, std_curves +import random + +__author__ = 'ivansarno' +__version__ = 'V.5.4' + +def point_test(): + point = ECL.std_curves.PointP192() + dpoint = point._doubles() + return point == eval(point.__repr__()) and dpoint == eval(dpoint.__repr__()) + + +def test(): + return True + + diff --git a/T/utility_test.py b/tests/utility_test.py similarity index 58% rename from T/utility_test.py rename to tests/utility_test.py index 111d157..b7d9ab3 100644 --- a/T/utility_test.py +++ b/tests/utility_test.py @@ -1,6 +1,26 @@ +""" + Elliptic Curve Library + + Copyright 2017 Ivan Sarno + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" from ECL.utility import * import random +__author__ = 'ivansarno' +__version__ = 'V.5.4' + def test_inverse() -> bool: t = 0 From 0bf287cc5c24346975a5685b4d6ffc75a92435ed Mon Sep 17 00:00:00 2001 From: Ivan Sarno Date: Tue, 21 Feb 2017 18:54:03 +0100 Subject: [PATCH 5/8] V.5.4 --- ECL/ecdsa.py | 35 ++++++++++++++++++++- ECL/elgamal.py | 34 +++++++++++++++++++- ECL/koblitz.py | 2 +- ECL/point.py | 4 +-- changelog.txt | 4 ++- tests/__init__.py | 6 ++-- tests/diffie_hellman_test.py | 4 +-- tests/ecdsa_test.py | 33 ++++++++++++++++++-- tests/elgamal_test.py | 31 +++++++++++++++++-- tests/koblitz_test.py | 2 +- tests/parametric_tests.py | 60 +++++++++++++++++++++++------------- tests/point_test.py | 32 ++++++++++++++++--- tests/utility_test.py | 2 +- 13 files changed, 206 insertions(+), 43 deletions(-) diff --git a/ECL/ecdsa.py b/ECL/ecdsa.py index 2e6e064..10443da 100644 --- a/ECL/ecdsa.py +++ b/ECL/ecdsa.py @@ -41,7 +41,8 @@ def _standard_hash(message: bytearray) -> Tuple[int, int]: class Signature: def __init__(self, first: int, second: int): - """This constructor is for internal use, user must resume a message from a representation string or use deserialization""" + """This constructor is for internal use, user must resume a message from + a representation string or use deserialization""" self.__first = first self.__second = second @@ -93,6 +94,22 @@ def check(self, message: bytearray, signature: Signature, hash_fun=_standard_has p = (self.__base * u1) + (self.__key * u2) return signature.first == p.x % self.__base.order + def try_unlock_key(self, key: int): + """Try to recovers the private key associated to this public key using a possible secret number, + return None if fails. + + :return: a PrivateKey or None + :param key: a great positive number, it must be the original secret number + :rtype: PrivateKey + """ + key %= self.__base.order + if key < 2: + return None + if self.__base * key == self.__key: + return PrivateKey(self.__base, key) + else: + return None + class PrivateKey: def __init__(self, base_point: PointWOrder, key: int): @@ -115,6 +132,22 @@ def keygen(base_point: PointWOrder, generator: Callable[[int], int]): secret = generator(base_point.order.bit_length()) % base_point.order return PrivateKey(base_point, secret) + @staticmethod + def keycreate(base_point: PointWOrder, key: int): + """Create a PrivateKey from a secret number. + + :param key: secret number, it must be a great positive number + :return: a Private Key + :raise ECDSAError: bit length of order of base point > 512, or key too small + :rtype: PrivateKey + """ + if base_point.order.bit_length() > 512: + raise ECDSAError("bit length of order of base point > 512") + key %= base_point.order + if key < 2: + raise ECDSAError("key, the secret number, not pass the security tests") + return PrivateKey(base_point, key) + @property def public_key(self) -> PublicKey: return PublicKey(self.__base, self.__base * self.__key) diff --git a/ECL/elgamal.py b/ECL/elgamal.py index 4f12a18..0592872 100644 --- a/ECL/elgamal.py +++ b/ECL/elgamal.py @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. """ -from typing import Callable +from typing import Callable, Tuple from ECL import koblitz from ECL.utility import EclError @@ -79,6 +79,22 @@ def encrypt(self, message: int, generator: Callable[[int], int]) -> ElGamalMessa fact = generator(self.__base.order.bit_length()) % self.__base.order return ElGamalMessage(self.__base * fact, message + self.__key * fact, padding) + def try_unlock_key(self, key: int): + """Try to recovers the private key associated to this public key using a possible secret number, + return None if fails. + + :return: a PrivateKey or None + :param key: a great positive number, it must be the original secret number + :rtype: PrivateKey + """ + key %= self.__base.order + if key < 2: + return None + if self.__base * key == self.__key: + return PrivateKey(self.__base, key) + else: + return None + def __repr__(self): return "ECL.elgamal.PublicKey( %s, %s)" % (self.__base.__repr__(), self.__key.__repr__()) @@ -100,6 +116,22 @@ def keygen(base_point: PointWOrder, generator: Callable[[int], int]): secret = generator(base_point.order.bit_length()) % base_point.order return PrivateKey(base_point, secret) + @staticmethod + def keycreate(base_point: PointWOrder, key: int): + """Create a PrivateKey from a secret number. + + :param key: secret number, it must be a great positive number + :return: a Private Key + :raise ElGamalError: bit length of order of base point > 512, or key too small + :rtype: PrivateKey + """ + key %= base_point.order + if key < 2: + raise ElGamalError("key, the secret number, not pass the security tests") + return PrivateKey(base_point, key) + + + @property def public_key(self) -> PublicKey: return PublicKey(self.__base, self.__base * self.__key) diff --git a/ECL/koblitz.py b/ECL/koblitz.py index 86f61c9..cea57f8 100644 --- a/ECL/koblitz.py +++ b/ECL/koblitz.py @@ -35,7 +35,7 @@ def encode(message: int, padding: int, curve: Curve) -> Point: :param curve: Curve of point returned :return: Point of curve - :raise: KoblitzFailError + :raise KoblitzFailError: All curves are supported but performances depends on prime number """ diff --git a/ECL/point.py b/ECL/point.py index 346eec3..75a8d73 100644 --- a/ECL/point.py +++ b/ECL/point.py @@ -139,7 +139,7 @@ def __add__(self, other): if self.__infinite: return other.copy() elif other.__infinite: - return self.copy + return self.copy() elif self == other: return self * 2 elif are_opposites(self, other): @@ -160,7 +160,7 @@ def __sub__(self, other): if self.__infinite: return other.__neg__() elif other.__infinite: - return self.copy + return self.copy() elif are_opposites(self, other): return self * 2 elif self == other: diff --git a/changelog.txt b/changelog.txt index 8959bff..890a167 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,7 +1,9 @@ Version 5.4: 1) better tests 2) test module moved in different package -3) old tests refactor as parametric_tests +3) old tests refactored as parametric_tests +4) ElGamal and ECDSA now support private key creation and resume from user's secret number +5) bug fixes Version 5.3: 1)several optimizations and fixes diff --git a/tests/__init__.py b/tests/__init__.py index aa06b33..45fdf38 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -16,8 +16,10 @@ limitations under the License. """ from tests import diffie_hellman_test, ecdsa_test, elgamal_test, koblitz_test, point_test, utility_test +__author__ = 'ivansarno' +__version__ = 'V.1.0' def ecl_test(): - return diffie_hellman_test.test() and ecdsa_test.test() and elgamal_test.test() and koblitz_test.test_koblitz() \ - and point_test.test() and utility_test.test_utility() + return diffie_hellman_test.test_dh() and ecdsa_test.test_ecdsa() and elgamal_test.test_elgamal() and koblitz_test.test_koblitz() \ + and point_test.test_point() and utility_test.test_utility() diff --git a/tests/diffie_hellman_test.py b/tests/diffie_hellman_test.py index 49b7f34..2b1154b 100644 --- a/tests/diffie_hellman_test.py +++ b/tests/diffie_hellman_test.py @@ -19,7 +19,7 @@ from ECL import utility __author__ = 'ivansarno' -__version__ = 'V.5.4' +__version__ = 'V.1.0' def test_functionality() -> bool: @@ -48,5 +48,5 @@ def test_synch_dh() -> bool: return r -def test() -> bool: +def test_dh() -> bool: return test_functionality() and test_synch_dh() diff --git a/tests/ecdsa_test.py b/tests/ecdsa_test.py index bd51ad3..baef95b 100644 --- a/tests/ecdsa_test.py +++ b/tests/ecdsa_test.py @@ -17,12 +17,14 @@ """ import random +import ECL +from ECL import ecdsa from ECL import std_curves from ECL import utility from ECL.ecdsa import * __author__ = 'ivansarno' -__version__ = 'V.5.4' +__version__ = 'V.1.0' def test_functionality() -> bool: @@ -70,5 +72,30 @@ def test_rapresentation() -> bool: return True -def test() -> bool: - return test_functionality() and test_functionality() +def test_key_creation() -> bool: + try: + key1 = ecdsa.PrivateKey.keycreate(ECL.std_curves.PointP192(), -342) + key2 = ecdsa.PrivateKey.keycreate(ECL.std_curves.PointP192(), 1) + return False + except ECDSAError: + pass + secret = utility.generator(192) + private = ecdsa.PrivateKey.keycreate(ECL.std_curves.PointP192(), secret) + public = private.public_key + rprivate = public.try_unlock_key(-3523) + if not rprivate is None: + return False + rprivate = public.try_unlock_key(1) + if not rprivate is None: + return False + rprivate = public.try_unlock_key(secret + 1) + if not rprivate is None: + return False + rprivate = public.try_unlock_key(secret) + if rprivate == private: + return False + return True + + +def test_ecdsa() -> bool: + return test_functionality() and test_functionality() and test_key_creation() diff --git a/tests/elgamal_test.py b/tests/elgamal_test.py index 6846228..5bbe7e0 100644 --- a/tests/elgamal_test.py +++ b/tests/elgamal_test.py @@ -21,7 +21,7 @@ from ECL.elgamal import ElGamalError __author__ = 'ivansarno' -__version__ = 'V.5.4' +__version__ = 'V.1.0' def test_functionality() -> bool: @@ -53,5 +53,30 @@ def test_rapresentation() -> bool: return vars(private) == vars(rprivate) and vars(message) == vars(rmessage) and vars(public) == vars(rpublic) -def test() -> bool: - return test_functionality() and test_out_of_range() and test_rapresentation() +def test_key_creation() -> bool: + try: + key1 = elgamal.PrivateKey.keycreate(ECL.std_curves.PointP192(), -342) + key2 = elgamal.PrivateKey.keycreate(ECL.std_curves.PointP192(), 1) + return False + except ElGamalError: + pass + secret = utility.generator(192) + private = elgamal.PrivateKey.keycreate(ECL.std_curves.PointP192(), secret) + public = private.public_key + rprivate = public.try_unlock_key(-3523) + if not rprivate is None: + return False + rprivate = public.try_unlock_key(1) + if not rprivate is None: + return False + rprivate = public.try_unlock_key(secret + 1) + if not rprivate is None: + return False + rprivate = public.try_unlock_key(secret) + if rprivate == private: + return False + return True + + +def test_elgamal() -> bool: + return test_functionality() and test_out_of_range() and test_rapresentation() and test_key_creation() diff --git a/tests/koblitz_test.py b/tests/koblitz_test.py index 6bbc84f..163db02 100644 --- a/tests/koblitz_test.py +++ b/tests/koblitz_test.py @@ -19,7 +19,7 @@ import random __author__ = 'ivansarno' -__version__ = 'V.5.4' +__version__ = 'V.1.0' def test_koblitz() -> bool: diff --git a/tests/parametric_tests.py b/tests/parametric_tests.py index 15592ba..86ef432 100644 --- a/tests/parametric_tests.py +++ b/tests/parametric_tests.py @@ -17,18 +17,20 @@ """ import random import ECL +from ECL import Point +from ECL import PointWOrder from ECL import utility, ecdsa, elgamal __author__ = 'ivansarno' -__version__ = 'V.5.4' +__version__ = 'V.1.0' __doc__ = """Test for package's features""" -def test(curve=ECL.std_curves.CurveP192, point=ECL.std_curves.PointP192, generator=utility.generator) -> bool: +def test(point: PointWOrder=ECL.std_curves.PointP192(), generator=utility.generator) -> bool: try: - result = test_arithmetic(curve, point) - result &= test_diffie_hellman(point, generator) - result &= test_el_gamal_koblitz(point, generator) + result = test_arithmetic(point.copy()) + result &= test_diffie_hellman(point.copy(), generator) + result &= test_el_gamal_koblitz(point.copy(), generator) result &= test_ecdsa(generator=generator) except ECL.EclError: print("test ERROR: EclException Raised") @@ -39,9 +41,9 @@ def test(curve=ECL.std_curves.CurveP192, point=ECL.std_curves.PointP192, generat return result -def test_diffie_hellman(point=ECL.std_curves.PointP192, generator=utility.generator) -> bool: - user1 = ECL.DiffieHellman(point(), generator) - user2 = ECL.DiffieHellman(point(), generator) +def test_diffie_hellman(point: PointWOrder=ECL.std_curves.PointP192(), generator=utility.generator) -> bool: + user1 = ECL.DiffieHellman(point, generator) + user2 = ECL.DiffieHellman(point, generator) message1 = user1.step1() message2 = user2.step1() user2.step2(message1) @@ -54,8 +56,8 @@ def test_diffie_hellman(point=ECL.std_curves.PointP192, generator=utility.genera return False -def test_el_gamal_koblitz(point=ECL.std_curves.PointP192, generator=utility.generator) -> bool: - private = elgamal.PrivateKey.keygen(point(), generator) +def test_el_gamal_koblitz(point: PointWOrder=ECL.std_curves.PointP192(), generator=utility.generator) -> bool: + private = elgamal.PrivateKey.keygen(point, generator) public = private.public_key message = random.randint(1, 2**32) cipher = public.encrypt(message, generator) @@ -68,24 +70,40 @@ def test_el_gamal_koblitz(point=ECL.std_curves.PointP192, generator=utility.gene return False -def test_arithmetic(curve=ECL.std_curves.CurveP192, point=ECL.std_curves.PointP192) -> bool: - inf = ECL.point.Point.infinitepoint(curve()) - p = point() - cond1 = (p * 3) == ((p + p + p + p + p) - (p * 2)) - cond2 = (-p) == (inf - p) - if not inf and cond1 and cond2: - print("test arithmetic OK") - return True - else: +def test_arithmetic(point: Point) -> bool: + inf = point.infinitepoint(point.curve) + if point != (point + inf) or point != (point - inf): + print("test arithmetic ERROR") + return False + p = point.copy() + p._doubles() + inf2 = inf.copy() + inf2._doubles() + if point + point != p or inf2 != inf: + print("test arithmetic ERROR") + return False + if -point != inf - point: + print("test arithmetic ERROR") + return False + a = random.randrange(500) + b = random.randrange(a // 2) + p = inf.copy() + for i in range(0, a): + p += point + if point * a != p: print("test arithmetic ERROR") return False + if point * (a - b) != (point * a) - (point * b): + return False + print("test arithmetic OK") + return True -def test_ecdsa(message: bytearray=None, point=ECL.std_curves.PointP192, generator=utility.generator) -> bool: +def test_ecdsa(message: bytearray=None, point: PointWOrder=ECL.std_curves.PointP192(), generator=utility.generator) -> bool: if message is None: message = generator(2000) message = message.to_bytes(message.bit_length()//8 + 1, 'little') - priv = ecdsa.PrivateKey.keygen(point(), generator) + priv = ecdsa.PrivateKey.keygen(point, generator) pub = priv.public_key sign = priv.sign(message, generator) if not pub.check(message, sign): diff --git a/tests/point_test.py b/tests/point_test.py index 18a45f8..6e8dc2b 100644 --- a/tests/point_test.py +++ b/tests/point_test.py @@ -16,19 +16,43 @@ limitations under the License. """ import ECL -from ECL import elgamal, utility, std_curves +from ECL import * import random __author__ = 'ivansarno' -__version__ = 'V.5.4' +__version__ = 'V.1.0' -def point_test(): + +def test_rapresentation() -> bool: point = ECL.std_curves.PointP192() dpoint = point._doubles() return point == eval(point.__repr__()) and dpoint == eval(dpoint.__repr__()) -def test(): +def test_arithmetic() -> bool: + point = ECL.std_curves.PointP192() + inf = point.infinitepoint(point.curve) + if point != (point + inf) or point != (point - inf): + return False + p = point.copy() + p._doubles() + inf2 = inf.copy() + inf2._doubles() + if point + point != p or inf2 != inf: + return False + if -point != inf - point: + return False + a = random.randrange(500) + b = random.randrange(a // 2) + p = inf.copy() + for i in range(0, a): + p += point + if point * a != p: + return False + if point * (a - b) != (point * a) - (point * b): + return False return True +def test_point(): + return test_rapresentation() and test_arithmetic() diff --git a/tests/utility_test.py b/tests/utility_test.py index b7d9ab3..f861ce3 100644 --- a/tests/utility_test.py +++ b/tests/utility_test.py @@ -19,7 +19,7 @@ import random __author__ = 'ivansarno' -__version__ = 'V.5.4' +__version__ = 'V.1.0' def test_inverse() -> bool: From b03e8f8855c7dfe97eba38077a632b6af5607196 Mon Sep 17 00:00:00 2001 From: Ivan Sarno Date: Wed, 22 Feb 2017 18:41:31 +0100 Subject: [PATCH 6/8] V.5.4 --- tests/diffie_hellman_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/diffie_hellman_test.py b/tests/diffie_hellman_test.py index 2b1154b..8260f6a 100644 --- a/tests/diffie_hellman_test.py +++ b/tests/diffie_hellman_test.py @@ -34,18 +34,18 @@ def test_functionality() -> bool: def test_synch_dh() -> bool: dh = ECL.DiffieHellman(ECL.std_curves.PointP192(), utility.generator) - r = False try: k = dh.key + return False except ECL.diffie_hellman.DiffieHellmanError: - r = True + pass try: dh.step2(ECL.std_curves.PointP192()._doubles()) - r &= False + return False except ECL.diffie_hellman.DiffieHellmanError: - r &= True - return r + pass + return True def test_dh() -> bool: From 080d136ee93abfcc2efb9ee88e4c5f7e33071dd9 Mon Sep 17 00:00:00 2001 From: Ivan Sarno Date: Wed, 22 Feb 2017 18:54:49 +0100 Subject: [PATCH 7/8] V.5.4 --- ECL/utility.py | 29 ++++++++++++++++++++--------- changelog.txt | 3 ++- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/ECL/utility.py b/ECL/utility.py index 3256cd3..84f7cdd 100644 --- a/ECL/utility.py +++ b/ECL/utility.py @@ -19,6 +19,8 @@ import os from typing import Tuple +import sys + __author__ = 'ivansarno' __version__ = 'V.5.4' __doc__ = """ built-in random number generator, root exception, inverse calculation and modular square root. @@ -60,15 +62,24 @@ def is_square(num: int, module: int) -> bool: """ return pow(num, module >> 1, module) == 1 - -def generator(size: int) -> int: - """ Random Number generator for test, is not safe. - - :param size: number of bit of random number - :return: random int of size bit - """ - temp = os.urandom(size // 8 + 1) - return int.from_bytes(temp, 'little') +if sys.version_info.minor < 6: + def generator(size: int) -> int: + """ Random Number generator for test, is not safe. + + :param size: number of bit of random number + :return: random int of size bit + """ + temp = os.urandom(size // 8 + 1) + return int.from_bytes(temp, 'little') +else: + def generator(size: int) -> int: + """ Random Number generator, use Python's secrets module. + + :param size: number of bit of random number + :return: random int of size bit + """ + import secrets + return abs(secrets.randbits(size)) class EclError(Exception): diff --git a/changelog.txt b/changelog.txt index 890a167..ecb0966 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,7 +3,8 @@ Version 5.4: 2) test module moved in different package 3) old tests refactored as parametric_tests 4) ElGamal and ECDSA now support private key creation and resume from user's secret number -5) bug fixes +5) (Python 3.6+ only) Built-in random number generator use new Python's secrets module, for secure source of randomness +6) bug fixes Version 5.3: 1)several optimizations and fixes From 0e43b8b8c4edb4c15c066d804a04dd98779a4c4d Mon Sep 17 00:00:00 2001 From: Ivan Sarno Date: Fri, 28 Jul 2017 21:30:22 +0200 Subject: [PATCH 8/8] V.5.5 Various Fixes --- ECL/__init__.py | 4 ++-- ECL/curve.py | 2 +- ECL/diffie_hellman.py | 10 +++++++--- ECL/ecdsa.py | 35 +++++++++++++++++++---------------- ECL/elgamal.py | 24 ++++++++++++------------ ECL/koblitz.py | 4 ++-- ECL/point.py | 8 ++++---- ECL/point_with_order.py | 2 +- ECL/std_curves.py | 2 +- ECL/utility.py | 10 +++++----- changelog.txt | 3 +++ tests/point_test.py | 2 +- tests/utility_test.py | 36 +++++++++++++++--------------------- 13 files changed, 73 insertions(+), 69 deletions(-) diff --git a/ECL/__init__.py b/ECL/__init__.py index b970276..38bebc6 100644 --- a/ECL/__init__.py +++ b/ECL/__init__.py @@ -23,9 +23,9 @@ from ECL.point_with_order import PointWOrder __author__ = 'ivansarno' -__version__ = 'V.5.4' +__version__ = 'V.5.5' __all__ = ["Curve", "Point", "PointWOrder", "EclError"] -__doc__ = """ ECL: library includes basic operations on Elliptic curves, 2 cipher and a digital signature protocol. +__doc__ = """ ECL: library includes basic operations on Elliptic Curves, 2 ciphers and a digital signature protocol. includes: class: Point, PointWOrder, Curve diff --git a/ECL/curve.py b/ECL/curve.py index 0a6cf01..c12fb88 100644 --- a/ECL/curve.py +++ b/ECL/curve.py @@ -16,7 +16,7 @@ limitations under the License. """ __author__ = 'ivansarno' -__version__ = 'V.5.4' +__version__ = 'V.5.5' __doc__ = """Implementation of Prime Elliptic Curves""" diff --git a/ECL/diffie_hellman.py b/ECL/diffie_hellman.py index 23f4fc9..1b18768 100644 --- a/ECL/diffie_hellman.py +++ b/ECL/diffie_hellman.py @@ -16,16 +16,18 @@ limitations under the License. """ from typing import Callable + +import sys + from ECL.utility import EclError from ECL.point import Point from ECL.point_with_order import PointWOrder __author__ = 'ivansarno' -__version__ = 'V.5.4' +__version__ = 'V.5.5' __doc__ = """Diffie-Hellman's public key system. class: DiffieHellman - exception: DiffieHellmanError """ @@ -54,11 +56,13 @@ def step1(self) -> Point: :return: Point to sand to partner """ self.__secret = self.__gen(self.__point.order.bit_length()) % self.__point.order + while self.__secret < sys.maxsize: + self.__secret = self.__gen(self.__point.order.bit_length()) % self.__point.order self.__sync = True return self.__point * self.__secret def step2(self, partner_point: Point) -> Point: - """Take result of partner step1 and return the key as Point + """Take result of partner's step1 and return the key as Point :param partner_point: Point received by partner :return: the key diff --git a/ECL/ecdsa.py b/ECL/ecdsa.py index 10443da..4c1ec5f 100644 --- a/ECL/ecdsa.py +++ b/ECL/ecdsa.py @@ -17,12 +17,15 @@ """ import hashlib from typing import Callable, Tuple + +import sys + from ECL.point import Point from ECL.point_with_order import PointWOrder from ECL.utility import inverse, EclError __author__ = 'ivansarno' -__version__ = 'V.5.4' +__version__ = 'V.5.5' __doc__ = """ECDSA digital signature algorithm classes: PrivateKey, PublicKey, Signature @@ -94,28 +97,28 @@ def check(self, message: bytearray, signature: Signature, hash_fun=_standard_has p = (self.__base * u1) + (self.__key * u2) return signature.first == p.x % self.__base.order - def try_unlock_key(self, key: int): + def try_unlock_key(self, secret: int): """Try to recovers the private key associated to this public key using a possible secret number, return None if fails. :return: a PrivateKey or None - :param key: a great positive number, it must be the original secret number + :param secret: a great positive number, it must be the original secret number :rtype: PrivateKey """ - key %= self.__base.order - if key < 2: + secret %= self.__base.order + if secret < 2: return None - if self.__base * key == self.__key: - return PrivateKey(self.__base, key) + if self.__base * secret == self.__key: + return PrivateKey(self.__base, secret) else: return None class PrivateKey: - def __init__(self, base_point: PointWOrder, key: int): + def __init__(self, base_point: PointWOrder, secret: int): """This constructor is for internal use, user must generates the private key with keygen method or resume it from a representation string or use deserialization""" - self.__key = key + self.__key = secret self.__base = base_point @staticmethod @@ -128,25 +131,25 @@ def keygen(base_point: PointWOrder, generator: Callable[[int], int]): if base_point.order.bit_length() > 512: raise ECDSAError("bit length of order of base point > 512") secret = generator(base_point.order.bit_length()) % base_point.order - while secret < 2: + while secret < sys.maxsize: secret = generator(base_point.order.bit_length()) % base_point.order return PrivateKey(base_point, secret) @staticmethod - def keycreate(base_point: PointWOrder, key: int): + def keycreate(base_point: PointWOrder, secret: int): """Create a PrivateKey from a secret number. - :param key: secret number, it must be a great positive number + :param secret: secret number, it must be a great positive number :return: a Private Key :raise ECDSAError: bit length of order of base point > 512, or key too small :rtype: PrivateKey """ if base_point.order.bit_length() > 512: raise ECDSAError("bit length of order of base point > 512") - key %= base_point.order - if key < 2: - raise ECDSAError("key, the secret number, not pass the security tests") - return PrivateKey(base_point, key) + secret %= base_point.order + if secret < sys.maxsize: + raise ECDSAError("the secret number not pass the security tests") + return PrivateKey(base_point, secret) @property def public_key(self) -> PublicKey: diff --git a/ECL/elgamal.py b/ECL/elgamal.py index 0592872..d7b884c 100644 --- a/ECL/elgamal.py +++ b/ECL/elgamal.py @@ -17,13 +17,15 @@ """ from typing import Callable, Tuple +import sys + from ECL import koblitz from ECL.utility import EclError from ECL.point import Point from ECL.point_with_order import PointWOrder __author__ = 'ivansarno' -__version__ = 'V.5.4' +__version__ = 'V.5.5' __doc__ = """El Gamal's cipher. classes: ElGamalMessage, PublicKey, PrivateKey @@ -75,23 +77,23 @@ def encrypt(self, message: int, generator: Callable[[int], int]) -> ElGamalMessa message, padding = koblitz.iterative_encode(message, self.__base.curve) fact = generator(self.__base.order.bit_length()) % self.__base.order - while fact < 2: + while fact < sys.maxsize: fact = generator(self.__base.order.bit_length()) % self.__base.order return ElGamalMessage(self.__base * fact, message + self.__key * fact, padding) - def try_unlock_key(self, key: int): + def try_unlock_key(self, secret: int): """Try to recovers the private key associated to this public key using a possible secret number, return None if fails. :return: a PrivateKey or None - :param key: a great positive number, it must be the original secret number + :param secret: a great positive number, it must be the original secret number :rtype: PrivateKey """ - key %= self.__base.order - if key < 2: + secret %= self.__base.order + if secret < sys.maxsize: return None - if self.__base * key == self.__key: - return PrivateKey(self.__base, key) + if self.__base * secret == self.__key: + return PrivateKey(self.__base, secret) else: return None @@ -112,7 +114,7 @@ def keygen(base_point: PointWOrder, generator: Callable[[int], int]): :param generator: random number generator, return a positive integer with bit length passed as parameter """ secret = generator(base_point.order.bit_length()) % base_point.order - while secret < 2: + while secret < sys.maxsize: secret = generator(base_point.order.bit_length()) % base_point.order return PrivateKey(base_point, secret) @@ -126,12 +128,10 @@ def keycreate(base_point: PointWOrder, key: int): :rtype: PrivateKey """ key %= base_point.order - if key < 2: + if key < sys.maxsize: raise ElGamalError("key, the secret number, not pass the security tests") return PrivateKey(base_point, key) - - @property def public_key(self) -> PublicKey: return PublicKey(self.__base, self.__base * self.__key) diff --git a/ECL/koblitz.py b/ECL/koblitz.py index cea57f8..4489194 100644 --- a/ECL/koblitz.py +++ b/ECL/koblitz.py @@ -21,7 +21,7 @@ from ECL.point import Point __author__ = 'ivansarno' -__version__ = 'V.5.4' +__version__ = 'V.5.5' __doc__ = """Implementation of Koblitz algorithm. functions: encode, decode, iterative_encode @@ -39,7 +39,7 @@ def encode(message: int, padding: int, curve: Curve) -> Point: All curves are supported but performances depends on prime number """ - if message * (padding + 1) < curve.prime: + if message * (padding + 1) < curve.prime and padding > 0: message *= padding i = 0 x = message diff --git a/ECL/point.py b/ECL/point.py index 75a8d73..d109f70 100644 --- a/ECL/point.py +++ b/ECL/point.py @@ -19,7 +19,7 @@ from ECL.utility import inverse __author__ = 'ivansarno' -__version__ = 'V.5.4' +__version__ = 'V.5.5' __doc__ = """Implementation of Point of Elliptic Curve classes: Point @@ -120,13 +120,13 @@ def copy(self): return ris def __neg__(self): - """Arithmetic _negation of a Point. + """Arithmetic negation of a Point. :return: -self :rtype: Point """ if self.__infinite: - return self.copy() + return self.infinitepoint(self.curve) return Point(self.__curve, self.__x, -self.__y % self.__curve.prime) def __add__(self, other): @@ -211,7 +211,7 @@ def _mul(self, other: int): self.__infinite = temp.__infinite def check(self, curve: Curve) -> bool: - """Check if self is a valid point of __curve. + """Check if self is a valid point of curve. :param curve: curve whose membership tested point :return: True if self is a valid point of curve diff --git a/ECL/point_with_order.py b/ECL/point_with_order.py index efc615f..d7dddc5 100644 --- a/ECL/point_with_order.py +++ b/ECL/point_with_order.py @@ -18,7 +18,7 @@ from ECL.curve import Curve from ECL.point import Point __author__ = 'ivansarno' -__version__ = 'V.5.4' +__version__ = 'V.5.5' __doc__ = """Point with extra member, the order""" diff --git a/ECL/std_curves.py b/ECL/std_curves.py index e80f3f1..bdfc25c 100644 --- a/ECL/std_curves.py +++ b/ECL/std_curves.py @@ -19,7 +19,7 @@ from ECL.point_with_order import PointWOrder __author__ = 'ivansarno' -__version__ = 'V.5.4' +__version__ = 'V.5.5' __doc__ = """Nist's standard curves and points (the number in the name is the bit of order) diff --git a/ECL/utility.py b/ECL/utility.py index 84f7cdd..19153ff 100644 --- a/ECL/utility.py +++ b/ECL/utility.py @@ -22,7 +22,7 @@ import sys __author__ = 'ivansarno' -__version__ = 'V.5.4' +__version__ = 'V.5.5' __doc__ = """ built-in random number generator, root exception, inverse calculation and modular square root. This functions are used by other modules""" @@ -31,7 +31,7 @@ def inverse(number: int, modulus: int) -> int: """Inverse operation in modular arithmetic. :return: inverse of number mod module - use iterative version of extended euclide's algorithm + use iterative version of extended Euclide's algorithm """ if modulus == 0: return 0 @@ -39,7 +39,7 @@ def inverse(number: int, modulus: int) -> int: while buffer[-1] != 0: buffer.append(buffer[-2] % buffer[-1]) - buffer.pop() #remove unused temorary value + buffer.pop() # remove unused temporary value temp = 0 intermediate = 1 result = 1 @@ -90,14 +90,14 @@ class EclError(Exception): def square_root(number: int, prime: int) -> int: """Return square roots of number mod prime - the cases in which prime == 2 is not supported because not occurs in this program + the cases in which prime == 2 is not supported because not occurs in this library """ if number == 0: return 0 if (prime & 3) == 3: return pow(number, (prime + 1) >> 2, prime) if (prime & 7) == 5: - v = pow(number << 1, (prime-5) >> 3) + v = int(pow(number << 1, (prime-5) >> 3)) i = ((number * (v ** 2)) << 1) % prime return (number * v * (i - 1)) % prime r = shanks(number, prime) diff --git a/changelog.txt b/changelog.txt index ecb0966..ab364eb 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,6 @@ +Version 5.5 +Various Fixes + Version 5.4: 1) better tests 2) test module moved in different package diff --git a/tests/point_test.py b/tests/point_test.py index 6e8dc2b..848ab1f 100644 --- a/tests/point_test.py +++ b/tests/point_test.py @@ -42,7 +42,7 @@ def test_arithmetic() -> bool: return False if -point != inf - point: return False - a = random.randrange(500) + a = random.randrange(100) b = random.randrange(a // 2) p = inf.copy() for i in range(0, a): diff --git a/tests/utility_test.py b/tests/utility_test.py index f861ce3..b89f253 100644 --- a/tests/utility_test.py +++ b/tests/utility_test.py @@ -21,41 +21,35 @@ __author__ = 'ivansarno' __version__ = 'V.1.0' +primes = [17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, + 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, + 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, + 383, 389, 397, 401, 409] + def test_inverse() -> bool: - t = 0 - while t == 0: - t = random.randint(0, 30) - return (inverse(t, 31) * t) % 31 == 1 + p = random.choice(primes) + t = random.randint(2, p-1) + return (inverse(t, p) * t) % p == 1 def test_is_square() -> bool: - t = 0 - while t == 0: - t = random.randint(0, 30) - s = t*t % 31 - return is_square(s, 31) + p = random.choice(primes) + t = random.randint(2, p - 1) + s = t*t % p + return is_square(s, p) def test_square_root() -> bool: - t = 0 - while t == 0: - t = random.randint(0, 7) - + t = random.randint(1, 7) s = square_root(t * t % 7, 7) r1 = s == t or 7 - t == s - t = random.randint(0, 13) - while t == 0: - t = random.randint(0, 12) - + t = random.randint(1, 13) s = square_root(t * t % 13, 13) r2 = s == t or 13 - t == s - t = random.randint(0, 16) - while t == 0: - t = random.randint(0, 16) - + t = random.randint(1, 16) s = square_root(t * t % 17, 17) r3 = s == t or 17 - t == s return r1 and r2 and r3