gfalg generates and recovers a secret via Shamir Secret Sharing!

This commit is contained in:
Ethan L. Miller 2020-09-02 16:29:38 -07:00
parent 043dbbb1a2
commit 5aaa3e7361

View File

@ -0,0 +1,85 @@
#!/usr/bin/env python3
import sys
import secrets
from galois import GaloisNumber as GN
import galois
from collections import namedtuple
gf = galois.GaloisFieldLog (8)
def _gf_unpack (v):
return tuple(GN(b, gf) for b in v)
def _gf_pack (v):
return b''.join ([b.to_bytes() for b in v])
class Secret:
value_len = 32
def __init__ (self, value = None):
if not value:
self.value = secrets.token_bytes (Secret.value_len)
elif type(value) == str:
self.value = bytes.fromhex (value)
elif type(value) == bytes:
self.value = value
else:
raise ValueError("Secret must be bytes or hex string")
if len (self.value) != Secret.value_len:
raise ValueError("Secret must be exactly {0} bytes long".format (Secret.value_len))
def __str__ (self):
return self.value.hex ()
def __repr__ (self):
return str(self)
def __len__ (self):
return len (self.value)
class SSS_Share:
def __init__ (self, share_id, secret):
if not 0 < share_id < 254:
raise ValueError("Invalid share ID")
if type(secret) != Secret:
raise ValueError ("Invalid secret")
self.share_id = share_id
self.secret = secret
def __str__ (self):
return 'ID {0:2}: {1}'.format (self.share_id, self.secret)
def __repr__ (self):
return str(self)
def _lagrange_interpolate (x, shares):
pass
def sss_generate_shares (secret, min_shares, share_ids):
if any ([not 1 <= x <= 254 for x in share_ids]):
raise ValueError ("Share IDs must be between 1-254")
coeff = list()
coeff.append (_gf_unpack (secret.value))
for i in range (0, min_shares-1):
coeff.append (_gf_unpack (Secret().value))
shares = list()
for i in share_ids:
v = GN(i, gf)
m = GN(1, gf)
accum = [GN(0, gf)] * len (secret)
for a in coeff:
accum = m.mul_region (a, accum)
m *= v
shares.append (SSS_Share(i, Secret (_gf_pack(accum))))
return shares
def sss_recover_secret (shares):
shrs = tuple (_gf_unpack (s.secret.value) for s in shares)
ids = tuple (GN(x.share_id, gf) for x in shares)
accum = [GN(0, gf)] * len(shares[0].secret)
for (x, shr) in zip (ids, shrs):
prod = GN(1, gf)
for i in ids:
if i != x:
prod *= i / (i - x)
accum = prod.mul_region (shr, accum)
return Secret (_gf_pack (accum))
def sss_generate_new_share (shares, share_id):
pass