def share_secret(self, secret): '''Takes a GF256 element (or int [0,255]) and splits it into n Shamir Secret Shares where >t secret shares are required to reconstruct the shared value ''' if type(secret) != GF256: secret = GF256(secret) coefficients = [secret] + [randelement() for _ in range(self.t)] return [Share(i+1, evaluate_polynomial(coefficients, GF256(i+1))) for i in range(self.n)]
def _lagrange_interpolation(points, x): y = GF256(0) for j in range(len(points)): l = GF256(1) for m in range(len(points)): if m != j: l *= (x - points[m][0]) / (points[j][0] - points[m][0]) y += points[j][1] * l return y
def get_lagrange_coefficients(n): xs = [GF256(i+1) for i in range(n)] coeffs = [] for i in range(n): x = xs[i] num = GF256(1) denom = GF256(1) for k in range(n): if k != i: num = num * (GF256(0) - xs[k]) denom = denom * (x - xs[k]) coeffs.append(num/denom) return coeffs
def __finish_mul(self, s1, s2, ep_shares, rho_shares, c): epsilon = self.reconstruct_secret(ep_shares) rho = self.reconstruct_secret(rho_shares) v1 = s2.scalar_mul(epsilon) v2 = s1.scalar_mul(rho) v3 = v1+v2+c er = epsilon*rho return v3.scalar_shift(GF256(0)-er)
def share_bitstring_secret(self, bits): '''Takes an arbitrary string of bits and splits the data among n parties. Each party receives an ordered list of l Shamir Secret Shares where l = length of bitstring. ''' output = [[] for _ in range(self.n)] for b in bits: s = GF256(0) if b=='1': s = GF256(1) elif b=='0': pass else: raise ValueError("not a valid bitstring") shares = self.share_secret(s) for i in range(self.n): output[i].append(shares[i]) return output
def reconstruct_secret(self, shares): '''Takes a set of >t shares and interpolates the unique polynomial passing through them to recover the secret value at f(0). ''' assert len(shares) > self.t, "not enough shares for interpolation" secret = GF256(0) for i in range(len(shares)): x = GF256(shares[i].x) num = shares[i].y denom = GF256(1) for k in range(len(shares)): if k != i: num = num * (GF256(0) - GF256(shares[k].x)) denom = denom * (x - GF256(shares[k].x)) secret += num/denom return secret
def _mix_columns(self, state): new_state = copy.deepcopy(state) row_num = 0 for row in state.bytes: column_num = 0 for column in row: new_state[0][column_num] = int(GF256(2) * GF256(state[0][column_num])) ^ \ int(GF256(3) * GF256(state[1][column_num])) ^ \ state[2][column_num] ^ \ state[3][column_num] new_state[1][column_num] = state[0][column_num] ^ \ int(GF256(2) * GF256(state[1][column_num])) ^ \ int(GF256(3) * GF256(state[2][column_num])) ^ \ state[3][column_num] new_state[2][column_num] = state[0][column_num] ^ \ state[1][column_num] ^ \ int(GF256(2) * GF256(state[2][column_num])) ^ \ int(GF256(3) * GF256(state[3][column_num])) new_state[3][column_num] = int(GF256(3) * GF256(state[0][column_num])) ^ \ state[1][column_num] ^ \ state[2][column_num] ^ \ int(GF256(2) * GF256(state[3][column_num])) column_num += 1 row_num += 1 return new_state
def scalar_mul(self, scalar): if type(scalar) != GF256: scalar = GF256(scalar) return Share(self.x, self.y * scalar)
def scalar_shift(self, scalar): if type(scalar) != GF256: scalar = GF256(scalar) return Share(self.x, self.y + scalar)
def __init__(self, x, y): assert x < 256, "player index too large" if type(y) != GF256: y = GF256(y) self.x = x self.y = y
def getsecondroundtableaccessindex(plaintext, key): global Sbox x2 = Sbox[plaintext[0] ^ key[0]] ^ Sbox[plaintext[5] ^ key[5]] ^ int( GF256(2) * GF256(Sbox[plaintext[10] ^ key[10]])) ^ int( GF256(3) * GF256(Sbox[plaintext[15] ^ key[15]])) ^ Sbox[key[15]] ^ key[2] x5 = Sbox[plaintext[4] ^ key[4]] ^ int( GF256(2) * GF256(Sbox[plaintext[9] ^ key[9]])) ^ int( GF256(3) * GF256(Sbox[plaintext[14] ^ key[14]])) ^ Sbox[ plaintext[3] ^ key[3]] ^ Sbox[key[14]] ^ key[1] ^ key[5] x8 = int(GF256(2) * GF256(Sbox[plaintext[8] ^ key[8]])) ^ int( GF256(3) * GF256(Sbox[plaintext[13] ^ key[13]])) ^ Sbox[ plaintext[2] ^ key[2]] ^ Sbox[plaintext[7] ^ key[7]] ^ Sbox[ key[13]] ^ key[0] ^ key[4] ^ key[8] ^ 1 x15 = int(GF256(3) * GF256(Sbox[plaintext[12] ^ key[12]])) ^ Sbox[ plaintext[1] ^ key[1]] ^ Sbox[plaintext[6] ^ key[6]] ^ int( GF256(2) * GF256(Sbox[plaintext[11] ^ key[11]])) ^ Sbox[ key[12]] ^ key[15] ^ key[3] ^ key[7] ^ key[11] return [x2, x5, x8, x15]
def lagrange(x0, x1, y0, y1): #havent done the mod operation using a prime number,how ever can be done if required return int(((GF256(0) - (GF256(x1)) / (GF256(x0) - GF256(x1))) * GF256(y0)) + ((GF256(0) - (GF256(x0)) / (GF256(x1) - GF256(x0))) * GF256(y1)))
def _inv_mix_columns(self, state): inv_state = copy.deepcopy(state) row_num = 0 for row in state.bytes: column_num = 0 for column in row: inv_state[0][column_num] = int(GF256(0x0e) * GF256(state[0][column_num])) ^ \ int(GF256(0x0b) * GF256(state[1][column_num])) ^ \ int(GF256(0x0d) * GF256(state[2][column_num])) ^ \ int(GF256(0x09) * GF256(state[3][column_num])) inv_state[1][column_num] = int(GF256(0x09) * GF256(state[0][column_num])) ^ \ int(GF256(0x0e) * GF256(state[1][column_num])) ^ \ int(GF256(0x0b) * GF256(state[2][column_num])) ^ \ int(GF256(0x0d) * GF256(state[3][column_num])) inv_state[2][column_num] = int(GF256(0x0d) * GF256(state[0][column_num])) ^ \ int(GF256(0x09) * GF256(state[1][column_num])) ^ \ int(GF256(0x0e) * GF256(state[2][column_num])) ^ \ int(GF256(0x0b) * GF256(state[3][column_num])) inv_state[3][column_num] = int(GF256(0x0b) * GF256(state[0][column_num])) ^ \ int(GF256(0x0d) * GF256(state[1][column_num])) ^ \ int(GF256(0x09) * GF256(state[2][column_num])) ^ \ int(GF256(0x0e) * GF256(state[3][column_num])) column_num += 1 row_num += 1 return inv_state
def _split_secret_byte(secret, threshold, shares): coefficients = _create_random_polynomial(threshold - 1, secret) return [(x, int(_evaluate_polynomial(coefficients, GF256(x)))) for x in range(1, shares + 1)]
def _evaluate_polynomial(coefficients, x): return sum((coefficient * x**GF256(exponent) for exponent, coefficient in enumerate(coefficients)), GF256(0))
def _create_random_polynomial(degree, free_coefficient): coefficients = [GF256(free_coefficient)] coefficients.extend([GF256(_random.randrange(256)) for _ in range(degree)]) return coefficients
def mul(a, b): a = util.hex_to_dec(a) b = util.hex_to_dec(b) c = util.bin_to_hex(str(GF256(a) * GF256(b))[8:16]) return c
def randelement(): return GF256(__randrange(0, 255))
def _recover_secret_byte(shares): return int( _lagrange_interpolation([(GF256(x), GF256(y)) for x, y in shares], GF256(0)))
def _add_share_byte(shares, x): points = [(GF256(x), GF256(y)) for x, y in shares] return int(_lagrange_interpolation(points, GF256(x)))
def y_x(a0, a1, x): return int((GF256(a0) + GF256(a1) * GF256(x)))