Browse Source

improve docs, handle some edge cases, use generator instead of list

also hard code the reduction table, but check it in the tests...
main
John-Mark Gurney 1 year ago
parent
commit
9391c8ce41
1 changed files with 36 additions and 9 deletions
  1. +36
    -9
      shamirss.py

+ 36
- 9
shamirss.py View File

@@ -31,7 +31,7 @@ An implementation of Shamir's Secret Sharing.


This is over GF(2^256), so unlike some other implementations that are This is over GF(2^256), so unlike some other implementations that are
over primes, it is valid for ALL values, and the output will be exactly over primes, it is valid for ALL values, and the output will be exactly
the same size as the secret. This also limits the number of shared to
the same length as the secret. This limits the number of shares to
255. 255.


Sample usage: Sample usage:
@@ -115,12 +115,17 @@ def recover_data(shares, k):
if len(shares) < k: if len(shares) < k:
raise ValueError('not enough shares to recover') raise ValueError('not enough shares to recover')


return bytes([ int(sum([ GF2p8(y[idx]) *
functools.reduce(operator.mul, [ pix * ((GF2p8(pix) - x) ** -1) for
pix, piy in shares[:k] if pix != x ], 1) for x, y in shares[:k] ],
return bytes([ int(sum(( GF2p8(y[idx]) *
functools.reduce(operator.mul, ( pix * ((GF2p8(pix) - x) ** -1) for
pix, piy in shares[:k] if pix != x ), 1) for x, y in shares[:k] ),
0)) for idx in range(len(shares[0][1]))]) 0)) for idx in range(len(shares[0][1]))])


class GF2p8: class GF2p8:
# polynomial 0x187
'''An implementation of GF(2^8). It uses the polynomial 0x187
or x^8 + x^7 + x^2 + x + 1.
'''

_invcache = (None, 1, 195, 130, 162, 126, 65, 90, 81, 54, 63, 172, 227, 104, 45, 42, 235, 155, 27, 53, 220, 30, 86, 165, 178, 116, 52, 18, 213, 100, 21, 221, 182, 75, 142, 251, 206, 233, 217, 161, 110, 219, 15, 44, 43, 14, 145, 241, 89, 215, 58, 244, 26, 19, 9, 80, 169, 99, 50, 245, 201, 204, 173, 10, 91, 6, 230, 247, 71, 191, 190, 68, 103, 123, 183, 33, 175, 83, 147, 255, 55, 8, 174, 77, 196, 209, 22, 164, 214, 48, 7, 64, 139, 157, 187, 140, 239, 129, 168, 57, 29, 212, 122, 72, 13, 226, 202, 176, 199, 222, 40, 218, 151, 210, 242, 132, 25, 179, 185, 135, 167, 228, 102, 73, 149, 153, 5, 163, 238, 97, 3, 194, 115, 243, 184, 119, 224, 248, 156, 92, 95, 186, 34, 250, 240, 46, 254, 78, 152, 124, 211, 112, 148, 125, 234, 17, 138, 93, 188, 236, 216, 39, 4, 127, 87, 23, 229, 120, 98, 56, 171, 170, 11, 62, 82, 76, 107, 203, 24, 117, 192, 253, 32, 74, 134, 118, 141, 94, 158, 237, 70, 69, 180, 252, 131, 2, 84, 208, 223, 108, 205, 60, 106, 177, 61, 200, 36, 232, 197, 85, 113, 150, 101, 28, 88, 49, 160, 38, 111, 41, 20, 31, 109, 198, 136, 249, 105, 12, 121, 166, 66, 246, 207, 37, 154, 16, 159, 189, 128, 96, 144, 47, 114, 133, 51, 59, 231, 67, 137, 225, 143, 35, 193, 181, 146, 79) _invcache = (None, 1, 195, 130, 162, 126, 65, 90, 81, 54, 63, 172, 227, 104, 45, 42, 235, 155, 27, 53, 220, 30, 86, 165, 178, 116, 52, 18, 213, 100, 21, 221, 182, 75, 142, 251, 206, 233, 217, 161, 110, 219, 15, 44, 43, 14, 145, 241, 89, 215, 58, 244, 26, 19, 9, 80, 169, 99, 50, 245, 201, 204, 173, 10, 91, 6, 230, 247, 71, 191, 190, 68, 103, 123, 183, 33, 175, 83, 147, 255, 55, 8, 174, 77, 196, 209, 22, 164, 214, 48, 7, 64, 139, 157, 187, 140, 239, 129, 168, 57, 29, 212, 122, 72, 13, 226, 202, 176, 199, 222, 40, 218, 151, 210, 242, 132, 25, 179, 185, 135, 167, 228, 102, 73, 149, 153, 5, 163, 238, 97, 3, 194, 115, 243, 184, 119, 224, 248, 156, 92, 95, 186, 34, 250, 240, 46, 254, 78, 152, 124, 211, 112, 148, 125, 234, 17, 138, 93, 188, 236, 216, 39, 4, 127, 87, 23, 229, 120, 98, 56, 171, 170, 11, 62, 82, 76, 107, 203, 24, 117, 192, 253, 32, 74, 134, 118, 141, 94, 158, 237, 70, 69, 180, 252, 131, 2, 84, 208, 223, 108, 205, 60, 106, 177, 61, 200, 36, 232, 197, 85, 113, 150, 101, 28, 88, 49, 160, 38, 111, 41, 20, 31, 109, 198, 136, 249, 105, 12, 121, 166, 66, 246, 207, 37, 154, 16, 159, 189, 128, 96, 144, 47, 114, 133, 51, 59, 231, 67, 137, 225, 143, 35, 193, 181, 146, 79)


@staticmethod @staticmethod
@@ -136,14 +141,26 @@ class GF2p8:


return r return r


# polynomial 0x187
_reduce = tuple(_makered(x, 0x87) for x in range(0, 16))
_reduce = (0, 135, 137, 14, 149, 18, 28, 155, 173, 42, 36, 163, 56, 191, 177, 54)


def __init__(self, v): def __init__(self, v):
if v >= 256:
'''v must be in the range [ 0, 255 ].

Create an element of GF(2^8).

The operators have been overloaded, so most normal math works.

It will also automatically promote non-GF2p8 numbers if
possible, e.g. GF2p8(5) + 10 works.
'''

if v >= 256 or v < 0:
raise ValueError('%d is not a member of GF(2^8)' % v) raise ValueError('%d is not a member of GF(2^8)' % v)


self._v = v
self._v = int(v)

if self._v != v:
raise ValueError('%d is not a member of GF(2^8)' % v)


# basic operations # basic operations
def __add__(self, o): def __add__(self, o):
@@ -268,11 +285,19 @@ class TestShamirSS(unittest.TestCase):
for i in range(5): for i in range(5):
self.assertEqual(val, recover_data([ a[j] for j in random.sample(range(30), 15) ], 15)) self.assertEqual(val, recover_data([ a[j] for j in random.sample(range(30), 15) ], 15))


def test_gf2p8_reduce(self):
reduce = tuple(_makered(x, 0x87) for x in range(0, 16))

if GF2p8._reduce != reduce: # pragma: no cover
print('reduce:', repr(reduce))
self.assertEqual(GF2p8._reduce, reduce)


def test_gf2p8_inv(self): def test_gf2p8_inv(self):


a = GF2p8(random.randint(0, 255)) a = GF2p8(random.randint(0, 255))


with unittest.mock.patch.object(GF2p8, '_invcache', []) as pinvc:
with unittest.mock.patch.object(GF2p8, '_invcache', ()) as pinvc:
ainv = a ** -1 ainv = a ** -1


self.assertEqual(a * ainv, 1) self.assertEqual(a * ainv, 1)
@@ -302,6 +327,8 @@ class TestShamirSS(unittest.TestCase):


def test_gf2p8_errors(self): def test_gf2p8_errors(self):
self.assertRaises(ValueError, GF2p8, 1000) self.assertRaises(ValueError, GF2p8, 1000)
self.assertRaises(ValueError, GF2p8, 40.5)
self.assertRaises(ValueError, GF2p8, -1)


def test_gf2p8(self): def test_gf2p8(self):
self.assertEqual(int(GF2p8(5)), 5) self.assertEqual(int(GF2p8(5)), 5)


Loading…
Cancel
Save