From 093d73e0a6427343c54fe807e8bd44ad7a3e75dd Mon Sep 17 00:00:00 2001 From: PaJa Date: Tue, 5 May 2015 22:03:48 +0200 Subject: [PATCH 01/11] Add test wit text and hex starting with zero --- tests/unit_tests.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/unit_tests.py b/tests/unit_tests.py index 585f2db..6a96a98 100644 --- a/tests/unit_tests.py +++ b/tests/unit_tests.py @@ -29,10 +29,18 @@ def split_and_recover_secret(self, sharer_class, m, n, secret): def test_hex_to_hex_sharing(self): recovered_secret = self.split_and_recover_secret(SecretSharer, 3, 5, "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a") + + def test_hex_with_zero_to_hex_sharing(self): + recovered_secret = self.split_and_recover_secret(SecretSharer, 3, 5, + "000ac4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a") def test_printable_ascii_to_hex_sharing(self): recovered_secret = self.split_and_recover_secret(PlaintextToHexSecretSharer, 3, 5, "correct horse battery staple") + + def test_printable_with_zero_ascii_to_hex_sharing(self): + recovered_secret = self.split_and_recover_secret(PlaintextToHexSecretSharer, 3, 5, + "000correct horse battery staple") def test_b58_to_b32_sharing(self): recovered_secret = self.split_and_recover_secret(BitcoinToB32SecretSharer, 3, 5, From a0e7bfef21a2f4a2e7d41644767311069b058f39 Mon Sep 17 00:00:00 2001 From: 0xF15E Date: Thu, 7 May 2015 23:19:32 +0200 Subject: [PATCH 02/11] Fix for conversion bug. --- secretsharing/charset.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/secretsharing/charset.py b/secretsharing/charset.py index af5b9fd..d7697e3 100644 --- a/secretsharing/charset.py +++ b/secretsharing/charset.py @@ -21,7 +21,7 @@ def int_to_charset(x, charset): x, digit = divmod(x, len(charset)) output += charset[digit] # reverse the characters in the output and return - return output[::-1] + return output def charset_to_int(s, charset): """ Turn a string into a non-negative integer. @@ -31,8 +31,10 @@ def charset_to_int(s, charset): if (set(s) - set(charset)): raise ValueError("s has chars that aren't in the charset.") output = 0 + i=0 for char in s: - output = output * len(charset) + charset.index(char) + output = output + (len(charset)**i)*charset.index(char) + i+=1 return output def change_charset(s, original_charset, target_charset): From 3f0de3d4964a2f296714c00f6985f53baee8d467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20L=C3=B6ffler?= Date: Fri, 19 Jan 2018 13:30:28 +0200 Subject: [PATCH 03/11] Add pycharm ignores --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2847011..e95a39d 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,6 @@ nosetests.xml .project .pydevproject -ignore \ No newline at end of file +# pycharm +.idea/ +.cache/ \ No newline at end of file From cd4e3ab7122bfcd7988211f69094eaa59f882003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20L=C3=B6ffler?= Date: Fri, 19 Jan 2018 14:07:48 +0200 Subject: [PATCH 04/11] Remove utilitybelt dependency --- secretsharing/polynomials.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/secretsharing/polynomials.py b/secretsharing/polynomials.py index 3530602..af5aad1 100644 --- a/secretsharing/polynomials.py +++ b/secretsharing/polynomials.py @@ -7,7 +7,17 @@ :license: MIT, see LICENSE for more details. """ -from utilitybelt import secure_randint as randint +import random + + +def randint(min_value, max_value, system_random=None): + """ Return a random integer N such that a <= N <= b. + Uses SystemRandom for generating random numbers. + (which uses os.urandom(), which pulls from /dev/urandom) + """ + if not system_random: + system_random = random.SystemRandom() + return system_random.randint(min_value, max_value) def egcd(a, b): From a06447816b3fc52e415b482c2fdc85b1cb1d1af5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20L=C3=B6ffler?= Date: Fri, 19 Jan 2018 14:08:27 +0200 Subject: [PATCH 05/11] Migrated tests to pytest style --- secretsharing/tests/__init__.py | 0 secretsharing/tests/test_sharing.py | 55 +++++++++++++++++ tests/unit_tests.py | 88 --------------------------- unit_tests.py | 94 ----------------------------- 4 files changed, 55 insertions(+), 182 deletions(-) create mode 100644 secretsharing/tests/__init__.py create mode 100644 secretsharing/tests/test_sharing.py delete mode 100644 tests/unit_tests.py delete mode 100644 unit_tests.py diff --git a/secretsharing/tests/__init__.py b/secretsharing/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/secretsharing/tests/test_sharing.py b/secretsharing/tests/test_sharing.py new file mode 100644 index 0000000..5041b03 --- /dev/null +++ b/secretsharing/tests/test_sharing.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +""" + Secret Sharing + ~~~~~ + + :copyright: (c) 2014 by Halfmoon Labs + :license: MIT, see LICENSE for more details. +""" + +import random +import pytest + +from ..charset import base64_chars +from .. import (secret_int_to_points, points_to_secret_int, + point_to_share_string, share_string_to_point, SecretSharer, + HexToHexSecretSharer, PlaintextToHexSecretSharer, + BitcoinToB58SecretSharer, BitcoinToB32SecretSharer, + BitcoinToZB32SecretSharer) + + +@pytest.fixture(params=[BitcoinToB32SecretSharer, BitcoinToB58SecretSharer, + BitcoinToZB32SecretSharer]) +def btc_sharer_class(request): + return request.param + +splits = [(2, 2), (2, 3), (4, 7), (5, 9)] + +def split_and_recover_secret(sharer_class, m, n, secret): + shares = sharer_class.split_secret(secret, m, n) + random.shuffle(shares) + for i in range(n - m): + recovered_secret = sharer_class.recover_secret(shares[i:m+i]) + assert(recovered_secret == secret) + +@pytest.mark.parametrize(['m', 'n'], splits) +def test_hex_to_hex_sharing(m, n): + split_and_recover_secret(SecretSharer, m, n, + "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a") + +@pytest.mark.parametrize(['m', 'n'], splits) +def test_printable_ascii_to_hex_sharing(m, n): + split_and_recover_secret(PlaintextToHexSecretSharer, m, n, + "0000correct horse battery staple") + +@pytest.mark.parametrize(['m', 'n'], splits) +def test_btc_sharing(btc_sharer_class, m, n): + split_and_recover_secret(btc_sharer_class, m, n, + "5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hS") + +@pytest.mark.parametrize(['m', 'n'], splits) +def test_hex_to_base64_sharing(m, n): + sharer_class = SecretSharer + sharer_class.share_charset = base64_chars + split_and_recover_secret(sharer_class, m, n, + "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a") diff --git a/tests/unit_tests.py b/tests/unit_tests.py deleted file mode 100644 index 6a96a98..0000000 --- a/tests/unit_tests.py +++ /dev/null @@ -1,88 +0,0 @@ -# -*- coding: utf-8 -*- -""" - Secret Sharing - ~~~~~ - - :copyright: (c) 2014 by Halfmoon Labs - :license: MIT, see LICENSE for more details. -""" - -import unittest -from test import test_support -import random - -from secretsharing import * - -class ShamirSharingTest(unittest.TestCase): - def setUp(self): - pass - - def tearDown(self): - pass - - def split_and_recover_secret(self, sharer_class, m, n, secret): - shares = sharer_class.split_secret(secret, m, n) - random.shuffle(shares) - recovered_secret = sharer_class.recover_secret(shares[0:m]) - assert(recovered_secret == secret) - - def test_hex_to_hex_sharing(self): - recovered_secret = self.split_and_recover_secret(SecretSharer, 3, 5, - "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a") - - def test_hex_with_zero_to_hex_sharing(self): - recovered_secret = self.split_and_recover_secret(SecretSharer, 3, 5, - "000ac4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a") - - def test_printable_ascii_to_hex_sharing(self): - recovered_secret = self.split_and_recover_secret(PlaintextToHexSecretSharer, 3, 5, - "correct horse battery staple") - - def test_printable_with_zero_ascii_to_hex_sharing(self): - recovered_secret = self.split_and_recover_secret(PlaintextToHexSecretSharer, 3, 5, - "000correct horse battery staple") - - def test_b58_to_b32_sharing(self): - recovered_secret = self.split_and_recover_secret(BitcoinToB32SecretSharer, 3, 5, - "5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hS") - - def test_b58_to_zb32_sharing(self): - recovered_secret = self.split_and_recover_secret(BitcoinToZB32SecretSharer, 3, 5, - "5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hS") - - def test_b58_to_b58_sharing(self): - recovered_secret = self.split_and_recover_secret(BitcoinToB58SecretSharer, 3, 5, - "5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hS") - - def test_hex_to_base64_sharing(self): - sharer_class = SecretSharer - sharer_class.share_charset = base64_chars - recovered_secret = self.split_and_recover_secret(sharer_class, 3, 5, - "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a") - - def test_2_of_3_sharing(self): - recovered_secret = self.split_and_recover_secret(SecretSharer, 2, 3, - "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a") - - def test_4_of_7_sharing(self): - recovered_secret = self.split_and_recover_secret(SecretSharer, 4, 7, - "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a") - - def test_5_of_9_sharing(self): - recovered_secret = self.split_and_recover_secret(SecretSharer, 5, 9, - "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a") - - def test_2_of_2_sharing(self): - recovered_secret = self.split_and_recover_secret(SecretSharer, 2, 2, - "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a") - -def test_main(): - - test_support.run_unittest( - ShamirSharingTest, - ) - -if __name__ == '__main__': - test_main() - - diff --git a/unit_tests.py b/unit_tests.py deleted file mode 100644 index 79d6566..0000000 --- a/unit_tests.py +++ /dev/null @@ -1,94 +0,0 @@ -# -*- coding: utf-8 -*- -""" - Secret Sharing - ~~~~~ - - :copyright: (c) 2014 by Halfmoon Labs - :license: MIT, see LICENSE for more details. -""" - -import random -import unittest -from test import test_support -from utilitybelt import base64_chars -from secretsharing import secret_int_to_points, points_to_secret_int, \ - point_to_share_string, share_string_to_point, SecretSharer, \ - HexToHexSecretSharer, PlaintextToHexSecretSharer, \ - BitcoinToB58SecretSharer, BitcoinToB32SecretSharer, \ - BitcoinToZB32SecretSharer - - -class ShamirSharingTest(unittest.TestCase): - def setUp(self): - pass - - def tearDown(self): - pass - - def split_and_recover_secret(self, sharer_class, m, n, secret): - shares = sharer_class.split_secret(secret, m, n) - random.shuffle(shares) - recovered_secret = sharer_class.recover_secret(shares[0:m]) - assert(recovered_secret == secret) - - def test_hex_to_hex_sharing(self): - recovered_secret = self.split_and_recover_secret( - SecretSharer, 3, 5, - "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a") - - def test_printable_ascii_to_hex_sharing(self): - recovered_secret = self.split_and_recover_secret( - PlaintextToHexSecretSharer, 3, 5, - "correct horse battery staple") - - def test_b58_to_b32_sharing(self): - recovered_secret = self.split_and_recover_secret( - BitcoinToB32SecretSharer, 3, 5, - "5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hS") - - def test_b58_to_zb32_sharing(self): - recovered_secret = self.split_and_recover_secret( - BitcoinToZB32SecretSharer, 3, 5, - "5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hS") - - def test_b58_to_b58_sharing(self): - recovered_secret = self.split_and_recover_secret( - BitcoinToB58SecretSharer, 3, 5, - "5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hS") - - def test_hex_to_base64_sharing(self): - sharer_class = SecretSharer - sharer_class.share_charset = base64_chars - recovered_secret = self.split_and_recover_secret( - sharer_class, 3, 5, - "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a") - - def test_2_of_3_sharing(self): - recovered_secret = self.split_and_recover_secret( - SecretSharer, 2, 3, - "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a") - - def test_4_of_7_sharing(self): - recovered_secret = self.split_and_recover_secret( - SecretSharer, 4, 7, - "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a") - - def test_5_of_9_sharing(self): - recovered_secret = self.split_and_recover_secret( - SecretSharer, 5, 9, - "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a") - - def test_2_of_2_sharing(self): - recovered_secret = self.split_and_recover_secret( - SecretSharer, 2, 2, - "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a") - - -def test_main(): - test_support.run_unittest( - ShamirSharingTest - ) - - -if __name__ == '__main__': - test_main() \ No newline at end of file From 08f9bce64ef34d7c13eb7c8896490480500fc99e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20L=C3=B6ffler?= Date: Fri, 19 Jan 2018 14:17:09 +0200 Subject: [PATCH 06/11] Remove utilitybelt; fix charset --- secretsharing/charset.py | 23 +++++++++++++---------- secretsharing/sharing.py | 8 ++++---- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/secretsharing/charset.py b/secretsharing/charset.py index d7697e3..e6a86c6 100644 --- a/secretsharing/charset.py +++ b/secretsharing/charset.py @@ -2,17 +2,17 @@ """ Secret Sharing ~~~~~ - - :copyright: (c) 2014 by Halfmoon Labs + :copyright: (c) 2015 by Halfmoon Labs :license: MIT, see LICENSE for more details. """ -import string +import six + def int_to_charset(x, charset): """ Turn a non-negative integer into a string. """ - if not (isinstance(x, (int, long)) and x >= 0): + if not (isinstance(x, six.integer_types) and x >= 0): raise ValueError("x must be a non-negative integer.") if x == 0: return charset[0] @@ -23,6 +23,7 @@ def int_to_charset(x, charset): # reverse the characters in the output and return return output + def charset_to_int(s, charset): """ Turn a string into a non-negative integer. """ @@ -37,22 +38,26 @@ def charset_to_int(s, charset): i+=1 return output + def change_charset(s, original_charset, target_charset): """ Convert a string from one charset to another. """ + if not isinstance(s, str): + raise ValueError('"s" must be a string.') + intermediate_integer = charset_to_int(s, original_charset) output_string = int_to_charset(intermediate_integer, target_charset) return output_string + """ Base16 includes numeric digits and the letters a through f. Here, we use the lowecase letters. """ -base16_chars = string.hexdigits[0:16] +base16_chars = '0123456789abcdef' """ The Base58 character set allows for strings that avoid visual ambiguity when typed. It consists of all the alphanumeric characters except for "0", "O", "I", and "l", which look similar in some fonts. - https://en.bitcoin.it/wiki/Base58Check_encoding """ base58_chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" @@ -60,7 +65,6 @@ def change_charset(s, original_charset, target_charset): """ The Base32 character set allows for accurate transcribing by hand. It consists of uppercase letters + numerals, excluding "0", "1", + "8", which could look similar to "O", "I", and "B" and so are omitted. - http://en.wikipedia.org/wiki/Base32 """ base32_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" @@ -69,7 +73,6 @@ def change_charset(s, original_charset, target_charset): set, except it uses lowercase letters + numerals and chooses to exclude "0", "l", "v", + "2". The set is also permuted so that easier chars occur more frequently. - http://philzimmermann.com/docs/human-oriented-base-32-encoding.txt """ zbase32_chars = "ybndrfg8ejkmcpqxot1uwisza345h769" @@ -77,7 +80,7 @@ def change_charset(s, original_charset, target_charset): """ The Base64 character set is a popular encoding for transmitting data over media that are designed for textual data. It includes all alphanumeric characters plus two bonus characters, usually "+" and "/". - http://en.wikipedia.org/wiki/Base64 """ -base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +base64_chars = ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789+/") diff --git a/secretsharing/sharing.py b/secretsharing/sharing.py index cd4e278..2e46c22 100644 --- a/secretsharing/sharing.py +++ b/secretsharing/sharing.py @@ -10,11 +10,11 @@ import string from six import integer_types -from utilitybelt import int_to_charset, charset_to_int, base58_chars, \ - base32_chars, zbase32_chars +from .charset import (int_to_charset, charset_to_int, base58_chars, + base32_chars, zbase32_chars) from .primes import get_large_enough_prime -from .polynomials import random_polynomial, \ - get_polynomial_points, modular_lagrange_interpolation +from .polynomials import (random_polynomial, get_polynomial_points, + modular_lagrange_interpolation) def secret_int_to_points(secret_int, point_threshold, num_points, prime=None): From fcab1f36c9e28d47ddea52ede01f287ed31f4574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20L=C3=B6ffler?= Date: Fri, 19 Jan 2018 17:00:45 +0200 Subject: [PATCH 07/11] Simplify primes --- secretsharing/primes.py | 41 ++++++++++++++++------------------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/secretsharing/primes.py b/secretsharing/primes.py index 417ea8b..d152a49 100644 --- a/secretsharing/primes.py +++ b/secretsharing/primes.py @@ -8,9 +8,8 @@ """ -def calculate_mersenne_primes(): - """ Returns all the mersenne primes with less than 500 digits. - All primes: +def mersenne_primes(pmax=35): + """ Returns mersenne primes up to the given exponent number: 3, 7, 31, 127, 8191, 131071, 524287, 2147483647L, 2305843009213693951L, 618970019642690137449562111L, 162259276829213363391578010288127L, 170141183460469231731687303715884105727L, @@ -18,35 +17,27 @@ def calculate_mersenne_primes(): 53113799281676709868...70835393219031728127L, (183 digits) 10407932194664399081...20710555703168729087L, (386 digits) """ - mersenne_prime_exponents = [ - 2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279 + exponents = [ + 2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, 2203, 2281, + 3217, 4253, 4423, 9689, 9941, 11213, 19937, 21701, 23209, 44497, 86243, + 110503, 132049, 216091, 756839, 859433, 1257787, 1398269, 2976221, 3021377, + 6972593, 13466917, 20996011, 24036583, 25964951, 30402457, 32582657, 37156667, + 42643801, 43112609, 57885161, 74207281 ] - primes = [] - for exp in mersenne_prime_exponents: - prime = 1 - for i in range(exp): - prime *= 2 - prime -= 1 - primes.append(prime) - return primes + return [2**exp - 1 for exp in exponents[:pmax]] -SMALLEST_257BIT_PRIME = (2**256 + 297) -SMALLEST_321BIT_PRIME = (2**320 + 27) -SMALLEST_385BIT_PRIME = (2**384 + 231) -STANDARD_PRIMES = calculate_mersenne_primes() + [ - SMALLEST_257BIT_PRIME, SMALLEST_321BIT_PRIME, SMALLEST_385BIT_PRIME -] -STANDARD_PRIMES.sort() +SP_257BIT = 2**256 + 297 +SP_321BIT = 2**320 + 27 +SP_385BIT = 2**384 + 231 +STANDARD_PRIMES = sorted(mersenne_primes() + [SP_257BIT, SP_321BIT, SP_385BIT]) -def get_large_enough_prime(batch): +def get_large_enough_prime(batch, primes=STANDARD_PRIMES): """ Returns a prime number that is greater all the numbers in the batch. """ - # build a list of primes - primes = STANDARD_PRIMES # find a prime that is greater than all the numbers in the batch for prime in primes: - numbers_greater_than_prime = [i for i in batch if i > prime] - if len(numbers_greater_than_prime) == 0: + numbers_greater_than_prime = sum(1 for i in batch if i > prime) + if not numbers_greater_than_prime: return prime return None From 7faa4e697ed2354f597d9ca131161e7ee757ee54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20L=C3=B6ffler?= Date: Fri, 19 Jan 2018 17:30:10 +0200 Subject: [PATCH 08/11] Test recovery fail on not enough shares --- secretsharing/tests/test_sharing.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/secretsharing/tests/test_sharing.py b/secretsharing/tests/test_sharing.py index 5041b03..20ce03c 100644 --- a/secretsharing/tests/test_sharing.py +++ b/secretsharing/tests/test_sharing.py @@ -31,6 +31,11 @@ def split_and_recover_secret(sharer_class, m, n, secret): for i in range(n - m): recovered_secret = sharer_class.recover_secret(shares[i:m+i]) assert(recovered_secret == secret) + recovered_secret = sharer_class.recover_secret(shares[i:m+i+1]) + assert(recovered_secret == secret) + unrecovered_secret = sharer_class.recover_secret(shares[i:m+i-1]) + assert(unrecovered_secret != secret) + @pytest.mark.parametrize(['m', 'n'], splits) def test_hex_to_hex_sharing(m, n): From d8b57519643e884ce29d5a917342938a7172b94f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20L=C3=B6ffler?= Date: Sat, 20 Jan 2018 20:19:05 +0200 Subject: [PATCH 09/11] Enable pytest --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3e07db7..51eea65 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,4 +3,4 @@ language: python python: - "2.7" -script: python unit_tests.py \ No newline at end of file +script: pytest \ No newline at end of file From ed69f7d4d3998edc5375831819990f7f293c46e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20L=C3=B6ffler?= Date: Sat, 20 Jan 2018 20:20:15 +0200 Subject: [PATCH 10/11] General code cleanup --- secretsharing/charset.py | 30 ++--------------- secretsharing/polynomials.py | 9 ------ secretsharing/primes.py | 43 ------------------------- secretsharing/sharing.py | 50 +++++++++++++++++------------ secretsharing/tests/test_sharing.py | 23 +++++++------ 5 files changed, 46 insertions(+), 109 deletions(-) delete mode 100644 secretsharing/primes.py diff --git a/secretsharing/charset.py b/secretsharing/charset.py index e6a86c6..1e2db77 100644 --- a/secretsharing/charset.py +++ b/secretsharing/charset.py @@ -1,18 +1,10 @@ -# -*- coding: utf-8 -*- -""" - Secret Sharing - ~~~~~ - :copyright: (c) 2015 by Halfmoon Labs - :license: MIT, see LICENSE for more details. -""" - -import six +from six import integer_types def int_to_charset(x, charset): """ Turn a non-negative integer into a string. """ - if not (isinstance(x, six.integer_types) and x >= 0): + if not (isinstance(x, integer_types) and x >= 0): raise ValueError("x must be a non-negative integer.") if x == 0: return charset[0] @@ -20,7 +12,6 @@ def int_to_charset(x, charset): while x > 0: x, digit = divmod(x, len(charset)) output += charset[digit] - # reverse the characters in the output and return return output @@ -31,23 +22,8 @@ def charset_to_int(s, charset): raise ValueError("s must be a string.") if (set(s) - set(charset)): raise ValueError("s has chars that aren't in the charset.") - output = 0 - i=0 - for char in s: - output = output + (len(charset)**i)*charset.index(char) - i+=1 - return output - - -def change_charset(s, original_charset, target_charset): - """ Convert a string from one charset to another. - """ - if not isinstance(s, str): - raise ValueError('"s" must be a string.') + return sum(len(charset)**i * charset.index(char) for i, char in enumerate(s)) - intermediate_integer = charset_to_int(s, original_charset) - output_string = int_to_charset(intermediate_integer, target_charset) - return output_string """ Base16 includes numeric digits and the letters a through f. Here, diff --git a/secretsharing/polynomials.py b/secretsharing/polynomials.py index af5aad1..d36a400 100644 --- a/secretsharing/polynomials.py +++ b/secretsharing/polynomials.py @@ -1,12 +1,3 @@ -# -*- coding: utf-8 -*- -""" - Secret Sharing - ~~~~~ - - :copyright: (c) 2014 by Halfmoon Labs - :license: MIT, see LICENSE for more details. -""" - import random diff --git a/secretsharing/primes.py b/secretsharing/primes.py deleted file mode 100644 index d152a49..0000000 --- a/secretsharing/primes.py +++ /dev/null @@ -1,43 +0,0 @@ -# -*- coding: utf-8 -*- -""" - Secret Sharing - ~~~~~ - - :copyright: (c) 2014 by Halfmoon Labs - :license: MIT, see LICENSE for more details. -""" - - -def mersenne_primes(pmax=35): - """ Returns mersenne primes up to the given exponent number: - 3, 7, 31, 127, 8191, 131071, 524287, 2147483647L, 2305843009213693951L, - 618970019642690137449562111L, 162259276829213363391578010288127L, - 170141183460469231731687303715884105727L, - 68647976601306097149...12574028291115057151L, (157 digits) - 53113799281676709868...70835393219031728127L, (183 digits) - 10407932194664399081...20710555703168729087L, (386 digits) - """ - exponents = [ - 2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, 2203, 2281, - 3217, 4253, 4423, 9689, 9941, 11213, 19937, 21701, 23209, 44497, 86243, - 110503, 132049, 216091, 756839, 859433, 1257787, 1398269, 2976221, 3021377, - 6972593, 13466917, 20996011, 24036583, 25964951, 30402457, 32582657, 37156667, - 42643801, 43112609, 57885161, 74207281 - ] - return [2**exp - 1 for exp in exponents[:pmax]] - -SP_257BIT = 2**256 + 297 -SP_321BIT = 2**320 + 27 -SP_385BIT = 2**384 + 231 -STANDARD_PRIMES = sorted(mersenne_primes() + [SP_257BIT, SP_321BIT, SP_385BIT]) - - -def get_large_enough_prime(batch, primes=STANDARD_PRIMES): - """ Returns a prime number that is greater all the numbers in the batch. - """ - # find a prime that is greater than all the numbers in the batch - for prime in primes: - numbers_greater_than_prime = sum(1 for i in batch if i > prime) - if not numbers_greater_than_prime: - return prime - return None diff --git a/secretsharing/sharing.py b/secretsharing/sharing.py index 2e46c22..65d1b1d 100644 --- a/secretsharing/sharing.py +++ b/secretsharing/sharing.py @@ -1,22 +1,37 @@ -# -*- coding: utf-8 -*- -""" - Secret Sharing - ~~~~~ - - :copyright: (c) 2014 by Halfmoon Labs - :license: MIT, see LICENSE for more details. -""" - import string - from six import integer_types + from .charset import (int_to_charset, charset_to_int, base58_chars, base32_chars, zbase32_chars) -from .primes import get_large_enough_prime from .polynomials import (random_polynomial, get_polynomial_points, modular_lagrange_interpolation) +def mersenne_primes(): + """ Return mersenne primes: + 3, 7, 31, 127, 8191, 131071, 524287, 2147483647L, 2305843009213693951L, ... + """ + exponents = [ + 2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, 2203, 2281, + 3217, 4253, 4423, 9689, 9941, 11213, 19937, 21701, 23209, 44497, 86243, + 110503, 132049, 216091, 756839, 859433, 1257787, 1398269, 2976221, 3021377, + 6972593, 13466917, 20996011, 24036583, 25964951, 30402457, 32582657, 37156667, + 42643801, 43112609, 57885161, 74207281 + ] + for exp in exponents: + yield 2**exp - 1 + + +def get_large_enough_prime(batch): + """ Returns a prime number that is greater all the numbers in the batch. + """ + # find a prime that is greater than all the numbers in the batch + for prime in mersenne_primes(): + numbers_greater_than_prime = sum(1 for i in batch if i > prime) + if not numbers_greater_than_prime: + return prime + + def secret_int_to_points(secret_int, point_threshold, num_points, prime=None): """ Split a secret (integer) into shares (pair of integers / x,y coords). @@ -100,8 +115,8 @@ class SecretSharer(): character set of the secrets and the character set of the shares that it expects to be dealing with. """ - secret_charset = string.hexdigits[0:16] - share_charset = string.hexdigits[0:16] + secret_charset = string.hexdigits[:16] + share_charset = string.hexdigits[:16] def __init__(self): pass @@ -128,15 +143,12 @@ def recover_secret(cls, shares): class HexToHexSecretSharer(SecretSharer): """ Standard sharer for converting hex secrets to hex shares. """ - secret_charset = string.hexdigits[0:16] - share_charset = string.hexdigits[0:16] class PlaintextToHexSecretSharer(SecretSharer): """ Good for converting secret messages into standard hex shares. """ secret_charset = string.printable - share_charset = string.hexdigits[0:16] class BitcoinToB58SecretSharer(SecretSharer): @@ -147,17 +159,15 @@ class BitcoinToB58SecretSharer(SecretSharer): share_charset = base58_chars -class BitcoinToB32SecretSharer(SecretSharer): +class BitcoinToB32SecretSharer(BitcoinToB58SecretSharer): """ Good for converting Bitcoin secret keys into shares that can be reliably and conveniently transcribed. """ - secret_charset = base58_chars share_charset = base32_chars -class BitcoinToZB32SecretSharer(SecretSharer): +class BitcoinToZB32SecretSharer(BitcoinToB58SecretSharer): """ Good for converting Bitcoin secret keys into shares that can be reliably and conveniently transcribed. """ - secret_charset = base58_chars share_charset = zbase32_chars diff --git a/secretsharing/tests/test_sharing.py b/secretsharing/tests/test_sharing.py index 20ce03c..aaae24b 100644 --- a/secretsharing/tests/test_sharing.py +++ b/secretsharing/tests/test_sharing.py @@ -1,16 +1,7 @@ -# -*- coding: utf-8 -*- -""" - Secret Sharing - ~~~~~ - - :copyright: (c) 2014 by Halfmoon Labs - :license: MIT, see LICENSE for more details. -""" - import random import pytest -from ..charset import base64_chars +from ..charset import base32_chars, base58_chars, base64_chars, int_to_charset, charset_to_int from .. import (secret_int_to_points, points_to_secret_int, point_to_share_string, share_string_to_point, SecretSharer, HexToHexSecretSharer, PlaintextToHexSecretSharer, @@ -37,21 +28,33 @@ def split_and_recover_secret(sharer_class, m, n, secret): assert(unrecovered_secret != secret) +@pytest.mark.parametrize('charset', [base32_chars, base58_chars, base64_chars], + ids=lambda x: 'Base' + str(len(x))) +def test_int_to_charset(charset): + for i in range(30, 100, 4): + secret_int = 2**i + 3*i + 7 + secret_str = int_to_charset(secret_int, charset) + assert secret_int == charset_to_int(secret_str, charset) + + @pytest.mark.parametrize(['m', 'n'], splits) def test_hex_to_hex_sharing(m, n): split_and_recover_secret(SecretSharer, m, n, "c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a") + @pytest.mark.parametrize(['m', 'n'], splits) def test_printable_ascii_to_hex_sharing(m, n): split_and_recover_secret(PlaintextToHexSecretSharer, m, n, "0000correct horse battery staple") + @pytest.mark.parametrize(['m', 'n'], splits) def test_btc_sharing(btc_sharer_class, m, n): split_and_recover_secret(btc_sharer_class, m, n, "5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hS") + @pytest.mark.parametrize(['m', 'n'], splits) def test_hex_to_base64_sharing(m, n): sharer_class = SecretSharer From a4714c10cd27ce33a82ad26dcdf19e9ba7f66846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20L=C3=B6ffler?= Date: Sat, 20 Jan 2018 20:20:36 +0200 Subject: [PATCH 11/11] Version bump --- AUTHORS | 3 ++- secretsharing/__init__.py | 11 +---------- setup.py | 3 +-- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/AUTHORS b/AUTHORS index 5406aa1..5a0e113 100644 --- a/AUTHORS +++ b/AUTHORS @@ -7,4 +7,5 @@ Development Leads Patches and Suggestions ```````````````` -- Michael Flaxman (https://github.com/mflaxman) \ No newline at end of file +- Michael Flaxman (https://github.com/mflaxman) +- Michael Loeffler (https://github.com/ml31415) diff --git a/secretsharing/__init__.py b/secretsharing/__init__.py index b1e8570..a7695a5 100644 --- a/secretsharing/__init__.py +++ b/secretsharing/__init__.py @@ -1,13 +1,4 @@ -# -*- coding: utf-8 -*- -""" - Secret Sharing - ~~~~~ - - :copyright: (c) 2014 by Halfmoon Labs - :license: MIT, see LICENSE for more details. -""" - -__version__ = '0.2.7' +__version__ = '0.2.8' from .sharing import secret_int_to_points, points_to_secret_int, \ point_to_share_string, share_string_to_point, SecretSharer, \ diff --git a/setup.py b/setup.py index 317eef3..5d43318 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setup( name='secretsharing', - version='0.2.6', + version='0.2.8', url='https://github.com/onenameio/secret-sharing', license='MIT', author='Halfmoon Labs', @@ -21,7 +21,6 @@ zip_safe=False, install_requires=[ 'six', - 'utilitybelt', ], classifiers=[ 'Intended Audience :: Developers',