def combine(shares): """Recombine a secret, if enough shares are presented. Args: shares (tuples): At least *k* tuples, each containin the index (an integer) and the share (a byte string, 16 bytes long) that were assigned to a participant. Return: The original secret, as a byte string (16 bytes long). """ shares = [[_Element(y) for y in x] for x in shares] result = _Element(0) k = len(shares) for j in range(k): x_j, y_j = shares[j] coeff_0_l = _Element(0) while not int(coeff_0_l): coeff_0_l = _Element(rng(16)) inv = coeff_0_l.inverse() for m in range(k): x_m = shares[m][0] if m != j: t = x_m * (x_j + x_m).inverse() coeff_0_l *= t result += y_j * coeff_0_l * inv return result.encode()
def pol(k, secret): """ Args: k (integer): The number of shares that must be present in order to reconstruct the secret. secret (byte string): The 16 byte string (e.g. the AES128 key) to split. """ coeffs = [_Element(rng(16)) for i in range(k - 1)] coeffs.insert(0, _Element(secret)) return coeffs
def split(k, n, secret, ssss=False): """Split a secret into ``n`` shares. The secret can be reconstructed later using just ``k`` shares out of the original ``n``. Each share must be kept confidential to the person it was assigned to. Each share is associated to an index (starting from 1). Args: k (integer): The sufficient number of shares to reconstruct the secret (``k < n``). n (integer): The number of shares that this method will create. secret (byte string): A byte string of 16 bytes (e.g. the AES 128 key). ssss (bool): If ``True``, the shares can be used with the ``ssss`` utility. Default: ``False``. Return (tuples): ``n`` tuples. A tuple is meant for each participant and it contains two items: 1. the unique index (an integer) 2. the share (a byte string, 16 bytes) """ # # We create a polynomial with random coefficients in GF(2^128): # # p(x) = \sum_{i=0}^{k-1} c_i * x^i # # c_0 is the encoded secret # coeffs = [_Element(rng(16)) for i in range(k - 1)] coeffs.append(_Element(secret)) # Each share is y_i = p(x_i) where x_i is the public index # associated to each of the n users. def make_share(user, coeffs, ssss): idx = _Element(user) share = _Element(0) for coeff in coeffs: share = idx * share + coeff if ssss: share += _Element(user)**len(coeffs) return share.encode() return [(i, make_share(i, coeffs, ssss)) for i in range(1, n + 1)]
def split(k, n, secret): """Split a secret into *n* shares. The secret can be reconstructed later when *k* shares out of the original *n* are recombined. Each share must be kept confidential to the person it was assigned to. Each share is associated to an index (starting from 1), which must be presented when the secret is recombined. Args: k (integer): The number of shares that must be present in order to reconstruct the secret. n (integer): The total number of shares to create (larger than *k*). secret (byte string): The 16 byte string (e.g. the AES128 key) to split. Return: *n* tuples, each containing the unique index (an integer) and the share (a byte string, 16 bytes long) meant for a participant. """ # # We create a polynomial with random coefficients in GF(2^128): # # p(x) = \sum_{i=0}^{k-1} c_i * x^i # # c_0 is the encoded secret # coeffs = [_Element(rng(16)) for i in range(k - 1)] coeffs.insert(0, _Element(secret)) # Each share is y_i = p(x_i) where x_i is the public index # associated to each of the n users. def make_share(user, coeffs): share, x, idx = [_Element(p) for p in (0, 1, user)] for coeff in coeffs: share += coeff * x x *= idx return share.encode() return [(i, make_share(i, coeffs)) for i in range(1, n + 1)]
def combine(shares): """Recombine a secret, if enough shares are presented. Args: shares (tuples): At least *k* tuples, each containin the index (an integer) and the share (a byte string, 16 bytes long) that were assigned to a participant. Return: The original secret, as a byte string (16 bytes long). """ # # Given k points (x,y), the interpolation polynomial of degree k-1 is: # # L(x) = \sum_{j=0}^{k-1} y_i * l_j(x) # # where: # # l_j(x) = \prod_{ \overset{0 \le m \le k-1}{m \ne j} } # \frac{x - x_m}{x_j - x_m} # # However, in this case we are purely intersted in the constant # coefficient of L(x). # shares = [[_Element(y) for y in x] for x in shares] result = _Element(0) k = len(shares) for j in range(k): x_j, y_j = shares[j] coeff_0_l = _Element(0) while not int(coeff_0_l): coeff_0_l = _Element(rng(16)) inv = coeff_0_l.inverse() for m in range(k): x_m = shares[m][0] if m != j: t = x_m * (x_j + x_m).inverse() coeff_0_l *= t result += y_j * coeff_0_l * inv return result.encode()