# HG changeset patch # User Laman # Date 2020-04-10 12:49:31 # Node ID 37a1df17b9a1dd0295168b526076d083ca4ea9f0 # Parent cc4182acd584298b8d855d02c4b3ea46babb3e3e changed naming to snake case. sadly no love for camel case in this world diff --git a/src/cli.py b/src/cli.py --- a/src/cli.py +++ b/src/cli.py @@ -9,8 +9,8 @@ def run(): parser = ArgumentParser() subparsers = parser.add_subparsers() - buildSplitParser(subparsers.add_parser("split")) - buildJoinParser(subparsers.add_parser("join")) + build_split_parser(subparsers.add_parser("split")) + build_join_parser(subparsers.add_parser("join")) parser.set_defaults(func=lambda _: parser.error("missing command")) @@ -18,11 +18,11 @@ def run(): args.func(args) -def buildSplitParser(parser): +def build_split_parser(parser): parser.add_argument("-k", type=int, required=True, help="number of shares necessary for recovering the secret") parser.add_argument("-n", type=int, required=True, help="number of generated shares") - encoding=parser.add_mutually_exclusive_group() + encoding = parser.add_mutually_exclusive_group() encoding.add_argument("--hex", action="store_true", help="encode shares' bytes as a hexadecimal string") encoding.add_argument("--b32", action="store_true", help="encode shares' bytes as a base32 string") encoding.add_argument("--b64", action="store_true", help="encode shares' bytes as a base64 string") @@ -31,8 +31,8 @@ def buildSplitParser(parser): parser.set_defaults(func=_generate) -def buildJoinParser(parser): - encoding=parser.add_mutually_exclusive_group() +def build_join_parser(parser): + encoding = parser.add_mutually_exclusive_group() encoding.add_argument("--hex", action="store_true", help="decode shares' bytes from a hexadecimal string") encoding.add_argument("--b32", action="store_true", help="decode shares' bytes from a base32 string") encoding.add_argument("--b64", action="store_true", help="decode shares' bytes from a base64 string") @@ -43,7 +43,7 @@ def buildJoinParser(parser): def _generate(args): - encoding = getEncoding(args) or "b32" + encoding = get_encoding(args) or "b32" try: shares = generate(args.secret, args.k, args.n, encoding) @@ -54,14 +54,14 @@ def _generate(args): def _reconstruct(args): - encoding = getEncoding(args) + encoding = get_encoding(args) try: print(reconstruct(*args.share, encoding=encoding, raw=args.raw)) except SException as e: print(e) -def getEncoding(args): +def get_encoding(args): if args.hex: return "hex" elif args.b32: return "b32" elif args.b64: return "b64" diff --git a/src/condensed.py b/src/condensed.py --- a/src/condensed.py +++ b/src/condensed.py @@ -30,7 +30,7 @@ L[1] = 0 inv = [E[255-L[i]] if i!=0 else None for i in range(256)] # multiplicative inverse -def getConstantCoef(*points): +def get_constant_coef(*points): """Compute constant polynomial coefficient given the points. See https://en.wikipedia.org/wiki/Shamir's_Secret_Sharing#Computationally_Efficient_Approach""" @@ -55,26 +55,26 @@ import binascii class SException(Exception): pass -def reconstructRaw(*shares): +def reconstruct_raw(*shares): """Tries to recover the secret from its shares. :param shares: ((i, (bytes) share), ...) :return: (bytes) reconstructed secret. Too few shares returns garbage.""" - secretLen = len(shares[0][1]) - res = [None]*secretLen - for i in range(secretLen): + secret_len = len(shares[0][1]) + res = [None]*secret_len + for i in range(secret_len): points = [(x, s[i]) for (x, s) in shares] - res[i] = (getConstantCoef(*points)) + res[i] = (get_constant_coef(*points)) return bytes(res) def reconstruct(*shares): - """Wraps reconstructRaw. + """Wraps reconstruct_raw. :param shares: ((str) share, ...) :return: (str) reconstructed secret. Too few shares returns garbage.""" - bs = reconstructRaw(*(decode(s) for s in shares)) + bs = reconstruct_raw(*(decode(s) for s in shares)) try: return bs.decode(encoding="utf-8") except UnicodeDecodeError: @@ -83,13 +83,13 @@ def reconstruct(*shares): def decode(share): try: - (i, _, shareStr) = share.partition(".") + (i, _, share_str) = share.partition(".") i = int(i) if not 1<=i<=255: raise SException("Malformed share: Failed 1<=k<=255, k={0}".format(i)) - shareBytes = base64.b32decode(shareStr) - return (i, shareBytes) + share_bytes = base64.b32decode(share_str) + return (i, share_bytes) except (ValueError, binascii.Error): raise SException('Malformed share: share="{0}"'.format(share)) diff --git a/src/gf256.py b/src/gf256.py --- a/src/gf256.py +++ b/src/gf256.py @@ -23,7 +23,7 @@ for i in range(256): L[acc] = i acc = _gfmul(acc, g) L[1] = 0 -inv = [E[255-L[i]] if i != 0 else None for i in range(256)] # multiplicative inverse +INV = [E[255-L[i]] if i!=0 else None for i in range(256)] # multiplicative inverse def gfmul(a, b): @@ -40,14 +40,14 @@ def evaluate(coefs, x): :param coefs: [a0, a1, ...].""" res = 0 - xK = 1 + xk = 1 for a in coefs: - res ^= gfmul(a, xK) - xK = gfmul(xK, x) + res ^= gfmul(a, xk) + xk = gfmul(xk, x) return res -def getConstantCoef(*points): +def get_constant_coef(*points): """Compute constant polynomial coefficient given the points. See https://en.wikipedia.org/wiki/Shamir's_Secret_Sharing#Computationally_Efficient_Approach""" @@ -59,6 +59,6 @@ def getConstantCoef(*points): for j in range(k): if i==j: continue (xj, yj) = points[j] - prod = gfmul(prod, (gfmul(xj, inv[xj^x]))) + prod = gfmul(prod, (gfmul(xj, INV[xj^x]))) res ^= gfmul(y, prod) return res diff --git a/src/shamira.py b/src/shamira.py --- a/src/shamira.py +++ b/src/shamira.py @@ -15,41 +15,41 @@ class DecodingException(SException): pas class MalformedShare(SException): pass -def _shareByte(secretB, k, n): +def _share_byte(secret_b, k, n): if not k<=n<255: raise InvalidParams("Failed k<=n<255, k={0}, n={1}".format(k, n)) # we might be concerned with zero coefficients degenerating our polynomial, but there's no reason - we still need k shares to determine it is the case - coefs = [int(secretB)]+[int(b) for b in os.urandom(k-1)] + coefs = [int(secret_b)]+[int(b) for b in os.urandom(k-1)] points = [gf256.evaluate(coefs, i) for i in range(1, n+1)] return points -def generateRaw(secret, k, n): +def generate_raw(secret, k, n): """Splits secret into shares. :param secret: (bytes) :param k: number of shares necessary for secret recovery. 1 <= k <= n :param n: (int) number of shares generated. 1 <= n < 255 :return: [(i, (bytes) share), ...]""" - shares = [_shareByte(b, k, n) for b in secret] + shares = [_share_byte(b, k, n) for b in secret] return [(i+1, bytes([s[i] for s in shares])) for i in range(n)] -def reconstructRaw(*shares): +def reconstruct_raw(*shares): """Tries to recover the secret from its shares. :param shares: ((i, (bytes) share), ...) :return: (bytes) reconstructed secret. Too few shares returns garbage.""" - secretLen = len(shares[0][1]) - res = [None]*secretLen - for i in range(secretLen): + secret_len = len(shares[0][1]) + res = [None]*secret_len + for i in range(secret_len): points = [(x, s[i]) for (x, s) in shares] - res[i] = (gf256.getConstantCoef(*points)) + res[i] = (gf256.get_constant_coef(*points)) return bytes(res) def generate(secret, k, n, encoding="b32"): - """Wraps generateRaw(). + """Wraps generate_raw(). :param secret: (str or bytes) :param k: number of shares necessary for secret recovery @@ -58,21 +58,21 @@ def generate(secret, k, n, encoding="b32 :return: [(str) share, ...]""" if isinstance(secret,str): secret = secret.encode("utf-8") - shares = generateRaw(secret, k, n) + shares = generate_raw(secret, k, n) return [encode(s, encoding) for s in shares] def reconstruct(*shares, encoding="", raw=False): - """Wraps reconstructRaw. + """Wraps reconstruct_raw. :param shares: ((str) share, ...) :param encoding: {hex, b32, b64, ""} encoding of share strings. If not provided or empty, the function tries to guess it. :param raw: (bool) whether to return bytes (True) or str (False) :return: (str or bytes) reconstructed secret. Too few shares returns garbage.""" if not encoding: - encoding = detectEncoding(shares) + encoding = detect_encoding(shares) - bs = reconstructRaw(*(decode(s, encoding) for s in shares)) + bs = reconstruct_raw(*(decode(s, encoding) for s in shares)) try: return bs if raw else bs.decode(encoding="utf-8") except UnicodeDecodeError: @@ -89,20 +89,20 @@ def encode(share, encoding="b32"): def decode(share, encoding="b32"): try: - (i, _, shareStr) = share.partition(".") + (i, _, share_str) = share.partition(".") i = int(i) if not 1<=i<=255: raise MalformedShare("Malformed share: Failed 1<=k<=255, k={0}".format(i)) if encoding=="hex": f = base64.b16decode elif encoding=="b32": f = base64.b32decode else: f = base64.b64decode - shareBytes = f(shareStr) - return (i, shareBytes) + share_bytes = f(share_str) + return (i, share_bytes) except (ValueError, binascii.Error): raise MalformedShare('Malformed share: share="{0}", encoding="{1}"'.format(share, encoding)) -def detectEncoding(shares): +def detect_encoding(shares): classes = [ (re.compile(r"\d+\.([0-9A-F]{2})+"), "hex"), (re.compile(r"\d+\.([A-Z2-7]{8})*([A-Z2-7]{8}|[A-Z2-7]{2}={6}|[A-Z2-7]{4}={4}|[A-Z2-7]{5}={3}|[A-Z2-7]{7}={1})"), "b32"), diff --git a/src/tests/test_condensed.py b/src/tests/test_condensed.py --- a/src/tests/test_condensed.py +++ b/src/tests/test_condensed.py @@ -5,7 +5,7 @@ import random from unittest import TestCase from gf256 import _gfmul, evaluate -from shamira import generateRaw, generate +from shamira import generate_raw, generate from condensed import * @@ -21,47 +21,47 @@ class TestCondensed(TestCase): def tearDownClass(cls): os.urandom = cls._urandom - def testGfmul(self): + def test_gfmul(self): for a in range(256): for b in range(256): self.assertEqual(_gfmul(a, b), gfmul(a, b)) - def testGetConstantCoef(self): - self.assertEqual(getConstantCoef((1, 1), (2, 2), (3, 3)), 0) + def test_get_constant_coef(self): + self.assertEqual(get_constant_coef((1, 1), (2, 2), (3, 3)), 0) random.seed(17) - randomMatches = 0 + random_matches = 0 for i in range(10): k = random.randint(2, 255) # exact - res = self.checkCoefsMatch(k, k) + res = self.check_coefs_match(k, k) self.assertEqual(res[0], res[1]) # overdetermined - res = self.checkCoefsMatch(k, 256) + res = self.check_coefs_match(k, 256) self.assertEqual(res[0], res[1]) # underdetermined => random - res = self.checkCoefsMatch(k, k-1) + res = self.check_coefs_match(k, k-1) if res[0]==res[1]: - randomMatches += 1 - self.assertLess(randomMatches, 2) # with a chance (255/256)**10=0.96 there should be no match + random_matches += 1 + self.assertLess(random_matches, 2) # with a chance (255/256)**10=0.96 there should be no match - def checkCoefsMatch(self, k, m): + def check_coefs_match(self, k, m): coefs = [random.randint(0, 255) for i in range(k)] points = [(j, evaluate(coefs, j)) for j in range(1, 256)] random.shuffle(points) - return (getConstantCoef(*points[:m]), coefs[0]) + return (get_constant_coef(*points[:m]), coefs[0]) - def testGenerateReconstructRaw(self): + def test_generate_reconstruct_raw(self): for (k, n) in [(2, 3), (254, 254)]: - shares = generateRaw(b"abcd", k, n) + shares = generate_raw(b"abcd", k, n) random.shuffle(shares) - self.assertEqual(reconstructRaw(*shares[:k]), b"abcd") - self.assertNotEqual(reconstructRaw(*shares[:k-1]), b"abcd") + self.assertEqual(reconstruct_raw(*shares[:k]), b"abcd") + self.assertNotEqual(reconstruct_raw(*shares[:k-1]), b"abcd") - def testGenerateReconstruct(self): + def test_generate_reconstruct(self): for secret in ["abcde", "ěščřžý"]: for (k, n) in [(2, 3), (254, 254)]: with self.subTest(sec=secret, k=k, n=n): @@ -76,7 +76,7 @@ class TestCondensed(TestCase): with self.assertRaises(SException): reconstruct(*shares) - def testDecode(self): + def test_decode(self): with self.assertRaises(SException): decode("AAA") decode("1.") diff --git a/src/tests/test_gf256.py b/src/tests/test_gf256.py --- a/src/tests/test_gf256.py +++ b/src/tests/test_gf256.py @@ -9,7 +9,7 @@ from gf256 import * class TestGF256(TestCase): - def test_gfmul(self): + def test__gfmul(self): self.assertEqual(_gfmul(0, 0), 0) self.assertEqual(_gfmul(1, 1), 1) self.assertEqual(_gfmul(2, 2), 4) @@ -17,45 +17,45 @@ class TestGF256(TestCase): self.assertEqual(_gfmul(0x53, 0xca), 0x01) self.assertEqual(_gfmul(0xff, 0xff), 0x13) - def testGfmul(self): + def test_gfmul(self): for a in range(256): for b in range(256): self.assertEqual(_gfmul(a, b), gfmul(a, b)) - def testEvaluate(self): + def test_evaluate(self): for x in range(256): (a0, a1, a2, a3) = (x, x>>1, x>>2, x>>3) self.assertEqual(evaluate([17], x), 17) # constant polynomial self.assertEqual(evaluate([a0, a1, a2, a3], 0), x) # any polynomial at 0 self.assertEqual(evaluate([a0, a1, a2, a3], 1), a0^a1^a2^a3) # polynomial at 1 == sum of coefficients - def testGetConstantCoef(self): - self.assertEqual(getConstantCoef((1, 1), (2, 2), (3, 3)), 0) + def test_get_constant_coef(self): + self.assertEqual(get_constant_coef((1, 1), (2, 2), (3, 3)), 0) random.seed(17) - randomMatches = 0 + random_matches = 0 for i in range(10): k = random.randint(2, 255) # exact - res = self.checkCoefsMatch(k, k) + res = self.check_coefs_match(k, k) self.assertEqual(res[0], res[1]) # overdetermined - res = self.checkCoefsMatch(k, 256) + res = self.check_coefs_match(k, 256) self.assertEqual(res[0], res[1]) # underdetermined => random - res = self.checkCoefsMatch(k, k-1) + res = self.check_coefs_match(k, k-1) if res[0]==res[1]: - randomMatches += 1 - self.assertLess(randomMatches, 2) # with a chance (255/256)**10=0.96 there should be no match + random_matches += 1 + self.assertLess(random_matches, 2) # with a chance (255/256)**10=0.96 there should be no match - def checkCoefsMatch(self, k, m): + def check_coefs_match(self, k, m): coefs = [random.randint(0, 255) for i in range(k)] points = [(j, evaluate(coefs, j)) for j in range(1, 256)] random.shuffle(points) - return (getConstantCoef(*points[:m]), coefs[0]) + return (get_constant_coef(*points[:m]), coefs[0]) if __name__=='__main__': diff --git a/src/tests/test_shamira.py b/src/tests/test_shamira.py --- a/src/tests/test_shamira.py +++ b/src/tests/test_shamira.py @@ -3,7 +3,7 @@ import random from unittest import TestCase -from shamira import _shareByte +from shamira import _share_byte from shamira import * @@ -19,28 +19,28 @@ class TestShamira(TestCase): def tearDownClass(cls): os.urandom = cls._urandom - def test_shareByte(self): + def test_share_byte(self): with self.assertRaises(InvalidParams): # too few shares - _shareByte(b"a", 5, 4) + _share_byte(b"a", 5, 4) with self.assertRaises(InvalidParams): # too many shares - _shareByte(b"a", 5, 255) + _share_byte(b"a", 5, 255) with self.assertRaises(ValueError): # not castable to int - _shareByte("x", 2, 3) + _share_byte("x", 2, 3) - vals = _shareByte(ord(b"a"), 2, 3) + vals = _share_byte(ord(b"a"), 2, 3) points = list(zip(range(1, 256), vals)) - self.assertEqual(gf256.getConstantCoef(*points), ord(b"a")) - self.assertEqual(gf256.getConstantCoef(*points[:2]), ord(b"a")) - self.assertNotEqual(gf256.getConstantCoef(*points[:1]), ord(b"a")) # underdetermined => random + self.assertEqual(gf256.get_constant_coef(*points), ord(b"a")) + self.assertEqual(gf256.get_constant_coef(*points[:2]), ord(b"a")) + self.assertNotEqual(gf256.get_constant_coef(*points[:1]), ord(b"a")) # underdetermined => random - def testGenerateReconstructRaw(self): + def test_generate_reconstruct_raw(self): for (k, n) in [(2, 3), (254, 254)]: - shares = generateRaw(b"abcd", k, n) + shares = generate_raw(b"abcd", k, n) random.shuffle(shares) - self.assertEqual(reconstructRaw(*shares[:k]), b"abcd") - self.assertNotEqual(reconstructRaw(*shares[:k-1]), b"abcd") + self.assertEqual(reconstruct_raw(*shares[:k]), b"abcd") + self.assertNotEqual(reconstruct_raw(*shares[:k-1]), b"abcd") - def testGenerateReconstruct(self): + def test_generate_reconstruct(self): for encoding in ["hex", "b32", "b64"]: for secret in [b"abcd", "abcde", "ěščřžý"]: for (k, n) in [(2, 3), (254, 254)]: @@ -56,13 +56,13 @@ class TestShamira(TestCase): with self.assertRaises(DecodingException): reconstruct(*shares) - def testEncode(self): + def test_encode(self): share = (2, b"\x00\x01\x02") - for (encoding, encodedStr) in [("hex", '000102'), ("b32", 'AAAQE==='), ("b64", 'AAEC')]: + for (encoding, encoded_str) in [("hex", '000102'), ("b32", 'AAAQE==='), ("b64", 'AAEC')]: with self.subTest(enc=encoding): - self.assertEqual(encode(share, encoding), "2."+encodedStr) + self.assertEqual(encode(share, encoding), "2."+encoded_str) - def testDecode(self): + def test_decode(self): with self.assertRaises(MalformedShare): decode("AAA") decode("1.") @@ -95,8 +95,8 @@ class TestShamira(TestCase): ]: with self.subTest(shares=shares): with self.assertRaises(DetectionException): - detectEncoding(shares) - self.assertEqual(detectEncoding(["10.00010203"]), "hex") - self.assertEqual(detectEncoding(["2.AAAQEAY="]), "b32") - self.assertEqual(detectEncoding(["3.AAECAw=="]), "b64") - self.assertEqual(detectEncoding(["3.AAECAwQF", "1.00010203"]), "b64") + detect_encoding(shares) + self.assertEqual(detect_encoding(["10.00010203"]), "hex") + self.assertEqual(detect_encoding(["2.AAAQEAY="]), "b32") + self.assertEqual(detect_encoding(["3.AAECAw=="]), "b64") + self.assertEqual(detect_encoding(["3.AAECAwQF", "1.00010203"]), "b64")