viff

changeset 1224:7ed324dff36b

Implementation of the open command.
author Janus Dam Nielsen <janus.nielsen@alexandra.dk>
date Tue, 06 Oct 2009 10:05:24 +0200
parents 42d95e56edf6
children bb9566f09d3f
files viff/orlandi.py viff/runtime.py viff/test/test_orlandi_runtime.py
diffstat 3 files changed, 118 insertions(+), 4 deletions(-) [+]
line diff
     1.1 --- a/viff/orlandi.py	Tue Oct 06 10:05:24 2009 +0200
     1.2 +++ b/viff/orlandi.py	Tue Oct 06 10:05:24 2009 +0200
     1.3 @@ -15,12 +15,14 @@
     1.4  # You should have received a copy of the GNU Lesser General Public
     1.5  # License along with VIFF. If not, see <http://www.gnu.org/licenses/>.
     1.6  
     1.7 -from twisted.internet.defer import Deferred
     1.8 +from twisted.internet.defer import Deferred, gatherResults
     1.9  
    1.10  from viff.runtime import Runtime, Share, ShareList, gather_shares
    1.11  from viff.util import rand
    1.12  from viff.constants import TEXT
    1.13  
    1.14 +from hash_broadcast import HashBroadcastMixin
    1.15 +
    1.16  import commitment
    1.17  commitment.set_reference_string(23434347834783478783478L, 489237823478234783478020L)
    1.18  
    1.19 @@ -54,7 +56,7 @@
    1.20          Share.__init__(self, runtime, field, (value, rho, commitment))
    1.21  
    1.22  
    1.23 -class OrlandiRuntime(Runtime):
    1.24 +class OrlandiRuntime(Runtime, HashBroadcastMixin):
    1.25      """The Orlandi runtime.
    1.26  
    1.27      The runtime is used for sharing values (:meth:`secret_share` or
    1.28 @@ -113,6 +115,27 @@
    1.29          sls.addCallbacks(combine, self.error_handler)
    1.30          return sls
    1.31  
    1.32 +    def _expect_orlandi_share_xi_rhoi(self, peer_id, field):
    1.33 +        xi = self._expect_share(peer_id, field)
    1.34 +        rhoi1 = self._expect_share(peer_id, field)
    1.35 +        rhoi2 = self._expect_share(peer_id, field)
    1.36 +        sls = ShareList([xi, rhoi1, rhoi2])
    1.37 +        def combine(ls):
    1.38 +            expected_num = 3;
    1.39 +            if len(ls) is not expected_num:
    1.40 +                raise OrlandiException("Cannot share number, trying to create a share,"
    1.41 +                                       " expected %s components got %s." % (expected_num, len(ls)))
    1.42 +
    1.43 +            s1, xi = ls[0]
    1.44 +            s2, rhoi1 = ls[1]
    1.45 +            s3, rhoi2 = ls[2]
    1.46 +            if not (s1 and s2 and s3):
    1.47 +                raise OrlandiException("Cannot share number, trying to create share "
    1.48 +                                       "but a component did arrive properly.")
    1.49 +            return OrlandiShare(self, field, xi, (rhoi1, rhoi2))
    1.50 +        sls.addCallbacks(combine, self.error_handler)
    1.51 +        return sls
    1.52 +
    1.53      def secret_share(self, inputters, field, number=None, threshold=None):
    1.54          """Share the value, number, among all the parties using additive shareing.
    1.55  
    1.56 @@ -186,6 +209,66 @@
    1.57              return results[0]
    1.58          return results
    1.59  
    1.60 +    def open(self, share, receivers=None, threshold=None):
    1.61 +        """Share reconstruction.
    1.62 +
    1.63 +        Every partyi broadcasts a share pair ``(x_i', rho_x,i')``.
    1.64 +
    1.65 +        The parties compute the sums ``x'``, ``rho_x'`` and 
    1.66 +        check ``Com_ck(x',rho_x' = C_x``.
    1.67 +
    1.68 +        If yes, return ``x = x'``, else else return :const:`None`.
    1.69 +        """
    1.70 +        assert isinstance(share, Share)
    1.71 +        # all players receive result by default
    1.72 +        if receivers is None:
    1.73 +            receivers = self.players.keys()
    1.74 +        assert threshold is None
    1.75 +        threshold = self.num_players - 1
    1.76 +
    1.77 +        field = share.field
    1.78 +
    1.79 +        self.program_counter[-1] += 1
    1.80 +
    1.81 +        def recombine_value(shares, Cx):
    1.82 +            x = 0
    1.83 +            rho1 = 0
    1.84 +            rho2 = 0
    1.85 +            for xi, rhoi1, rhoi2 in shares:
    1.86 +                x += xi
    1.87 +                rho1 += rhoi1
    1.88 +                rho2 += rhoi2
    1.89 +            Cx1 = commitment.commit(x.value, rho1.value, rho2.value)
    1.90 +            if Cx1 == Cx:
    1.91 +                return x
    1.92 +            else:
    1.93 +                raise OrlandiException("Wrong commitment for value %s, found %s expected %s." % 
    1.94 +                                       (x, Cx1, Cx))
    1.95 +
    1.96 +        def deserialize(ls):
    1.97 +            shares = [(field(long(x)), field(long(rho1)), field(long(rho2))) for x, rho1, rho2 in map(self.list_str, ls)]
    1.98 +            return shares
    1.99 +            
   1.100 +        def exchange((xi, (rhoi1, rhoi2), Cx), receivers):
   1.101 +            # Send share to all receivers.
   1.102 +            ds = self.broadcast(self.players.keys(), receivers, str((str(xi.value), str(rhoi1.value), str(rhoi2.value))))
   1.103 +
   1.104 +            if self.id in receivers:
   1.105 +                result = gatherResults(ds)
   1.106 +                result.addCallbacks(deserialize, self.error_handler)
   1.107 +                result.addCallbacks(recombine_value, self.error_handler, callbackArgs=(Cx,))
   1.108 +                return result
   1.109 +
   1.110 +        result = share.clone()
   1.111 +        self.schedule_callback(result, exchange, receivers)
   1.112 +        result.addErrback(self.error_handler)
   1.113 +
   1.114 +        # do actual communication
   1.115 +        self.activate_reactor()
   1.116 +
   1.117 +        if self.id in receivers:
   1.118 +            return result
   1.119 +
   1.120      def error_handler(self, ex):
   1.121          print "Error: ", ex
   1.122          return ex
     2.1 --- a/viff/runtime.py	Tue Oct 06 10:05:24 2009 +0200
     2.2 +++ b/viff/runtime.py	Tue Oct 06 10:05:24 2009 +0200
     2.3 @@ -327,13 +327,20 @@
     2.4  
     2.5                  key = (program_counter, data_type)
     2.6  
     2.7 +#                 print "Player %s has received data %s from %s with pc: %s" % (str(self.factory.runtime.id), 
     2.8 +#                                                                               str(data), 
     2.9 +#                                                                               str(self.peer_id),
    2.10 +#                                                                               str(key))
    2.11 +
    2.12                  if key in self.waiting_deferreds:
    2.13 +#                    print "A deferred was waiting"
    2.14                      deq = self.waiting_deferreds[key]
    2.15                      deferred = deq.popleft()
    2.16                      if not deq:
    2.17                          del self.waiting_deferreds[key]
    2.18                      self.factory.runtime.handle_deferred_data(deferred, data)
    2.19                  else:
    2.20 +#                    print "A deferred is not waiting, lets put the data on the shelf"
    2.21                      deq = self.incoming_data.setdefault(key, deque())
    2.22                      deq.append(data)
    2.23              except struct.error, e:
    2.24 @@ -392,7 +399,13 @@
    2.25          """
    2.26          try:
    2.27              key = (program_counter, data_type)
    2.28 -            
    2.29 +
    2.30 +#            print self
    2.31 +#             print "Player %s has received data %s from %s with pc: %s" % (str(self.factory.runtime.id), 
    2.32 +#                                                                           str(data), 
    2.33 +#                                                                           str(self.peer_id),
    2.34 +#                                                                           program_counter)
    2.35 +                         
    2.36              if key in self.waiting_deferreds:
    2.37                  deq = self.waiting_deferreds[key]
    2.38                  deferred = deq.popleft()
    2.39 @@ -741,6 +754,7 @@
    2.40          else:
    2.41              # We have not yet received anything from the other side.
    2.42              deq = self.protocols[peer_id].waiting_deferreds.setdefault(key, deque())
    2.43 +#             print "The deferred %s is waiting on data from %i with key: %s" % (str(deferred), peer_id, str(key))
    2.44              deq.append(deferred)
    2.45  
    2.46      def _exchange_shares(self, peer_id, field_element):
    2.47 @@ -855,7 +869,6 @@
    2.48      def handle_deferred_data(self, deferred, data):
    2.49          """Put deferred and data into the queue if the ViffReactor is running. 
    2.50          Otherwise, just execute the callback."""
    2.51 -
    2.52          if self.using_viff_reactor:
    2.53              self.deferred_queue.append((deferred, data))
    2.54          else:
     3.1 --- a/viff/test/test_orlandi_runtime.py	Tue Oct 06 10:05:24 2009 +0200
     3.2 +++ b/viff/test/test_orlandi_runtime.py	Tue Oct 06 10:05:24 2009 +0200
     3.3 @@ -53,3 +53,21 @@
     3.4              share = runtime.secret_share([1], self.Zp)
     3.5          share.addCallback(check)
     3.6          return share
     3.7 +
     3.8 +    @protocol
     3.9 +    def test_open_secret_share(self, runtime):
    3.10 +        """Test sharing and open of a number."""
    3.11 +
    3.12 +        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
    3.13 +
    3.14 +        def check(v):
    3.15 +            self.assertEquals(v, 42)
    3.16 +
    3.17 +        if 1 == runtime.id:
    3.18 +            x = runtime.secret_share([1], self.Zp, 42)
    3.19 +        else:
    3.20 +            x = runtime.secret_share([1], self.Zp)
    3.21 +        d = runtime.open(x)
    3.22 +        d.addCallback(check)
    3.23 +        return d
    3.24 +