def _verify_double(self, shares, rvec1, rvec2, T, field, d1, d2): """Verify shares. It is checked that they correspond to polynomial of the expected degrees and that they can be recombined to the same value. If the verification succeeds, the T double shares are returned, otherwise an exception is thrown. """ si_1, si_2 = shares self._verify_single(si_1, rvec1, T, field, d1) self._verify_single(si_2, rvec2, T, field, d2) si_1 = map(lambda (i, s): (field(i + 1), s), enumerate(si_1)) si_2 = map(lambda (i, s): (field(i + 1), s), enumerate(si_2)) assert shamir.recombine(si_1[:d1+1]) == shamir.recombine(si_2[:d2+1]), \ "Shares do not recombine to the same value" return (rvec1[:T], rvec2[:T])
def _verify_double(self, shares, rvec1, rvec2, T, field, d1, d2): """Verify shares. It is checked that they correspond to polynomial of the expected degrees and that they can be recombined to the same value. If the verification succeeds, the T double shares are returned, otherwise an exception is thrown. """ si_1, si_2 = shares self._verify_single(si_1, rvec1, T, field, d1) self._verify_single(si_2, rvec2, T, field, d2) si_1 = map(lambda (i, s): (field(i+1), s), enumerate(si_1)) si_2 = map(lambda (i, s): (field(i+1), s), enumerate(si_2)) assert shamir.recombine(si_1[:d1+1]) == shamir.recombine(si_2[:d2+1]), \ "Shares do not recombine to the same value" return (rvec1[:T], rvec2[:T])
def convert_replicated_shamir(n, j, field, rep_shares): """Convert a set of replicated shares to a Shamir share. The conversion is done for player *j* (out of *n*) and will be done over *field*. """ sum = field(0) for subset, share in rep_shares: try: f_in_j = _f_in_j_cache[(field, n, j, subset)] except KeyError: all = frozenset(range(1, n + 1)) points = [(field(x), 0) for x in all - subset] + [(0, 1)] f_in_j = shamir.recombine(points, j) _f_in_j_cache[(field, n, j, subset)] = f_in_j sum += share * f_in_j return sum
def convert_replicated_shamir(n, j, field, rep_shares): """Convert a set of replicated shares to a Shamir share. The conversion is done for player *j* (out of *n*) and will be done over *field*. """ result = 0 all = frozenset(range(1, n+1)) for subset, share in rep_shares: try: f_in_j = _f_in_j_cache[(field, n, j, subset)] except KeyError: points = [(field(x), 0) for x in all-subset] points.append((0, 1)) f_in_j = shamir.recombine(points, j) _f_in_j_cache[(field, n, j, subset)] = f_in_j result += share * f_in_j return result
def open(self, a, receivers=None, threshold=None): """Open a secret sharing. The *receivers* are the players that will eventually obtain the opened result. The default is to let everybody know the result. Communication cost: every player sends one share to each receiving player. """ assert isinstance(a, Share) yield declareReturn(self, a.field) # all players receive result by default if receivers is None: receivers = self.players.keys() if threshold is None: threshold = self.threshold a = yield a # Send share to all receivers. for peer_id in receivers: if peer_id != self.id: self._send_share(peer_id, a) # Receive and recombine shares if this player is a receiver. if self.id in receivers: shares = [] for peer_id in self.players: field = type(a) if peer_id == self.id: s = Share(self, field, (field(peer_id), a)) else: s = self._expect_share(peer_id, field) s.addCallback(lambda s, peer_id: (field(peer_id), s), peer_id) # s.df.addCallback(lambda s, peer_id: (field(peer_id), s), peer_id) shares.append(s) shares = yield shares[:threshold + 1] #ToDo wait for t+1 shares only. returnValue(shamir.recombine(shares))
def prss_share(self, inputters, field, element=None): """Creates pseudo-random secret sharings. This protocol creates a secret sharing for each player in the subset of players specified in *inputters*. Each inputter provides an integer. The result is a list of shares, one for each inputter. The protocol uses the pseudo-random secret sharing technique described in the paper "Share Conversion, Pseudorandom Secret-Sharing and Applications to Secure Computation" by Ronald Cramer, Ivan Damgård, and Yuval Ishai in Proc. of TCC 2005, LNCS 3378. `Download <http://www.cs.technion.ac.il/~yuvali/pubs/CDI05.ps>`__ Communication cost: Each inputter does one broadcast. """ # Verifying parameters. if element is None: assert self.id not in inputters, "No element given." else: assert self.id in inputters, \ "Element given, but we are not sharing?" n = self.num_players # Key used for PRSS. key = self.prss_key() # The shares for which we have all the keys. all_shares = [] # Shares we calculate from doing PRSS with the other players. tmp_shares = {} prfs = self.players[self.id].dealer_prfs(field.modulus) # Compute and broadcast correction value. if self.id in inputters: for player in self.players: share = prss(n, player, field, prfs[self.id], key) all_shares.append((field(player), share)) shared = shamir.recombine(all_shares[:self.threshold + 1]) correction = element - shared # if this player is inputter then broadcast correction value # TODO: more efficient broadcast? pc = tuple(self.program_counter) for peer_id in self.players: if self.id != peer_id: self.protocols[peer_id].sendShare(pc, correction) # Receive correction value from inputters and compute share. result = [] for player in inputters: tmp_shares[player] = prss(n, self.id, field, prfs[player], key) if player == self.id: d = Share(self, field, correction) else: d = self._expect_share(player, field) d.addCallback(lambda c, s: s + c, tmp_shares[player]) result.append(d) # Unpack a singleton list. if len(result) == 1: return result[0] else: return result
def test_shamir_recombine(self): shares = [(1, 1), None, None] self.assertEquals(shamir.recombine(shares), 1)
def prss_zero(n, t, j, field, prfs, key, quantity): """Return *quantity* pseudo-random secret zero-sharings of degree 2t. >>> from field import GF >>> Zp = GF(23) >>> prfs = {frozenset([1,2]): PRF("a", 7), ... frozenset([1,3]): PRF("b", 7), ... frozenset([2,3]): PRF("c", 7)} >>> prss_zero(3, 1, 1, Zp, prfs, "key", 1) [{16}] >>> prss_zero(3, 1, 2, Zp, prfs, "key", 1) [{13}] >>> prss_zero(3, 1, 3, Zp, prfs, "key", 1) [{14}] If we recombine 2t + 1 = 3 shares we can verify that this is indeed a zero-sharing: >>> from shamir import recombine >>> recombine([(Zp(1), Zp(4)), (Zp(2), Zp(0)), (Zp(3), Zp(11))]) {0} """ # We start by generating t random numbers for each subset. This is # very similar to calling random_replicated_sharing t times, but # by doing it like this we immediatedly get the nesting we want. rep_shares = [(s, [(i+1, prf((key, i))) for i in range(t)]) for (s, prf) in prfs.iteritems() if j in s] # We then proceed with the zero-sharing. The first part is like in # a normal PRSS. result = [0] * quantity all = frozenset(range(1, n+1)) modulus = field.modulus # This is needed for correct exponentiation. j = field(j) for subset, shares in rep_shares: try: f_in_j = _f_in_j_cache[(field, n, j, subset)] except KeyError: points = [(field(x), 0) for x in all-subset] points.append((0, 1)) f_in_j = shamir.recombine(points, j) _f_in_j_cache[(field, n, j, subset)] = f_in_j # Unlike a normal PRSS we have an inner sum where we use a # degree 2t polynomial g_i which we choose as # # g_i(x) = f(x) * x**j # # since we already have the degree t polynomial f at hand. The # g_i are all linearly independent as required by the protocol # and can thus be used for the zero-sharing. for i, packed_share in shares: g_i_in_j = f_in_j * j**i for k in range(quantity): result[k] += (packed_share % modulus) * g_i_in_j packed_share /= modulus return result
# VIFF is free software: you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License (LGPL) as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # VIFF is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General # Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with VIFF. If not, see <http://www.gnu.org/licenses/>. import sys from viff import shamir from viff.field import GF, GF256 if sys.argv[1].find(":") == -1: F = GF(int(sys.argv.pop(1))) else: F = GF256 print "Field: GF%d" % F.modulus shares = [map(int, arg.split(":")) for arg in sys.argv[1:]] shares = [(F(id), F(share)) for id, share in shares] print "Shares:", shares print "Result:", shamir.recombine(shares)
def prss_share(self, inputters, field, element=None): """Creates pseudo-random secret sharings. This protocol creates a secret sharing for each player in the subset of players specified in *inputters*. Each inputter provides an integer. The result is a list of shares, one for each inputter. The protocol uses the pseudo-random secret sharing technique described in the paper "Share Conversion, Pseudorandom Secret-Sharing and Applications to Secure Computation" by Ronald Cramer, Ivan Damgård, and Yuval Ishai in Proc. of TCC 2005, LNCS 3378. `Download <http://www.cs.technion.ac.il/~yuvali/pubs/CDI05.ps>`__ Communication cost: Each inputter does one broadcast. """ # Verifying parameters. if element is None: assert self.id not in inputters, "No element given." else: assert self.id in inputters, \ "Element given, but we are not sharing?" n = self.num_players # Key used for PRSS. key = self.prss_key() # The shares for which we have all the keys. all_shares = [] # Shares we calculate from doing PRSS with the other players. tmp_shares = {} prfs = self.players[self.id].dealer_prfs(field.modulus) # Compute and broadcast correction value. if self.id in inputters: for player in self.players: share = prss(n, player, field, prfs[self.id], key) all_shares.append((field(player), share)) shared = shamir.recombine(all_shares[:self.threshold+1]) correction = element - shared # if this player is inputter then broadcast correction value # TODO: more efficient broadcast? pc = tuple(self.program_counter) for peer_id in self.players: if self.id != peer_id: self.protocols[peer_id].sendShare(pc, correction) # Receive correction value from inputters and compute share. result = [] for player in inputters: tmp_shares[player] = prss(n, self.id, field, prfs[player], key) if player == self.id: d = Share(self, field, correction) else: d = self._expect_share(player, field) d.addCallback(lambda c, s: s + c, tmp_shares[player]) result.append(d) # Unpack a singleton list. if len(result) == 1: return result[0] else: return result