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 wrap: on
line diff
--- a/viff/orlandi.py	Tue Oct 06 10:05:24 2009 +0200
+++ b/viff/orlandi.py	Tue Oct 06 10:05:24 2009 +0200
@@ -15,12 +15,14 @@
 # You should have received a copy of the GNU Lesser General Public
 # License along with VIFF. If not, see <http://www.gnu.org/licenses/>.
 
-from twisted.internet.defer import Deferred
+from twisted.internet.defer import Deferred, gatherResults
 
 from viff.runtime import Runtime, Share, ShareList, gather_shares
 from viff.util import rand
 from viff.constants import TEXT
 
+from hash_broadcast import HashBroadcastMixin
+
 import commitment
 commitment.set_reference_string(23434347834783478783478L, 489237823478234783478020L)
 
@@ -54,7 +56,7 @@
         Share.__init__(self, runtime, field, (value, rho, commitment))
 
 
-class OrlandiRuntime(Runtime):
+class OrlandiRuntime(Runtime, HashBroadcastMixin):
     """The Orlandi runtime.
 
     The runtime is used for sharing values (:meth:`secret_share` or
@@ -113,6 +115,27 @@
         sls.addCallbacks(combine, self.error_handler)
         return sls
 
+    def _expect_orlandi_share_xi_rhoi(self, peer_id, field):
+        xi = self._expect_share(peer_id, field)
+        rhoi1 = self._expect_share(peer_id, field)
+        rhoi2 = self._expect_share(peer_id, field)
+        sls = ShareList([xi, rhoi1, rhoi2])
+        def combine(ls):
+            expected_num = 3;
+            if len(ls) is not expected_num:
+                raise OrlandiException("Cannot share number, trying to create a share,"
+                                       " expected %s components got %s." % (expected_num, len(ls)))
+
+            s1, xi = ls[0]
+            s2, rhoi1 = ls[1]
+            s3, rhoi2 = ls[2]
+            if not (s1 and s2 and s3):
+                raise OrlandiException("Cannot share number, trying to create share "
+                                       "but a component did arrive properly.")
+            return OrlandiShare(self, field, xi, (rhoi1, rhoi2))
+        sls.addCallbacks(combine, self.error_handler)
+        return sls
+
     def secret_share(self, inputters, field, number=None, threshold=None):
         """Share the value, number, among all the parties using additive shareing.
 
@@ -186,6 +209,66 @@
             return results[0]
         return results
 
+    def open(self, share, receivers=None, threshold=None):
+        """Share reconstruction.
+
+        Every partyi broadcasts a share pair ``(x_i', rho_x,i')``.
+
+        The parties compute the sums ``x'``, ``rho_x'`` and 
+        check ``Com_ck(x',rho_x' = C_x``.
+
+        If yes, return ``x = x'``, else else return :const:`None`.
+        """
+        assert isinstance(share, Share)
+        # all players receive result by default
+        if receivers is None:
+            receivers = self.players.keys()
+        assert threshold is None
+        threshold = self.num_players - 1
+
+        field = share.field
+
+        self.program_counter[-1] += 1
+
+        def recombine_value(shares, Cx):
+            x = 0
+            rho1 = 0
+            rho2 = 0
+            for xi, rhoi1, rhoi2 in shares:
+                x += xi
+                rho1 += rhoi1
+                rho2 += rhoi2
+            Cx1 = commitment.commit(x.value, rho1.value, rho2.value)
+            if Cx1 == Cx:
+                return x
+            else:
+                raise OrlandiException("Wrong commitment for value %s, found %s expected %s." % 
+                                       (x, Cx1, Cx))
+
+        def deserialize(ls):
+            shares = [(field(long(x)), field(long(rho1)), field(long(rho2))) for x, rho1, rho2 in map(self.list_str, ls)]
+            return shares
+            
+        def exchange((xi, (rhoi1, rhoi2), Cx), receivers):
+            # Send share to all receivers.
+            ds = self.broadcast(self.players.keys(), receivers, str((str(xi.value), str(rhoi1.value), str(rhoi2.value))))
+
+            if self.id in receivers:
+                result = gatherResults(ds)
+                result.addCallbacks(deserialize, self.error_handler)
+                result.addCallbacks(recombine_value, self.error_handler, callbackArgs=(Cx,))
+                return result
+
+        result = share.clone()
+        self.schedule_callback(result, exchange, receivers)
+        result.addErrback(self.error_handler)
+
+        # do actual communication
+        self.activate_reactor()
+
+        if self.id in receivers:
+            return result
+
     def error_handler(self, ex):
         print "Error: ", ex
         return ex
--- a/viff/runtime.py	Tue Oct 06 10:05:24 2009 +0200
+++ b/viff/runtime.py	Tue Oct 06 10:05:24 2009 +0200
@@ -327,13 +327,20 @@
 
                 key = (program_counter, data_type)
 
+#                 print "Player %s has received data %s from %s with pc: %s" % (str(self.factory.runtime.id), 
+#                                                                               str(data), 
+#                                                                               str(self.peer_id),
+#                                                                               str(key))
+
                 if key in self.waiting_deferreds:
+#                    print "A deferred was waiting"
                     deq = self.waiting_deferreds[key]
                     deferred = deq.popleft()
                     if not deq:
                         del self.waiting_deferreds[key]
                     self.factory.runtime.handle_deferred_data(deferred, data)
                 else:
+#                    print "A deferred is not waiting, lets put the data on the shelf"
                     deq = self.incoming_data.setdefault(key, deque())
                     deq.append(data)
             except struct.error, e:
@@ -392,7 +399,13 @@
         """
         try:
             key = (program_counter, data_type)
-            
+
+#            print self
+#             print "Player %s has received data %s from %s with pc: %s" % (str(self.factory.runtime.id), 
+#                                                                           str(data), 
+#                                                                           str(self.peer_id),
+#                                                                           program_counter)
+                         
             if key in self.waiting_deferreds:
                 deq = self.waiting_deferreds[key]
                 deferred = deq.popleft()
@@ -741,6 +754,7 @@
         else:
             # We have not yet received anything from the other side.
             deq = self.protocols[peer_id].waiting_deferreds.setdefault(key, deque())
+#             print "The deferred %s is waiting on data from %i with key: %s" % (str(deferred), peer_id, str(key))
             deq.append(deferred)
 
     def _exchange_shares(self, peer_id, field_element):
@@ -855,7 +869,6 @@
     def handle_deferred_data(self, deferred, data):
         """Put deferred and data into the queue if the ViffReactor is running. 
         Otherwise, just execute the callback."""
-
         if self.using_viff_reactor:
             self.deferred_queue.append((deferred, data))
         else:
--- a/viff/test/test_orlandi_runtime.py	Tue Oct 06 10:05:24 2009 +0200
+++ b/viff/test/test_orlandi_runtime.py	Tue Oct 06 10:05:24 2009 +0200
@@ -53,3 +53,21 @@
             share = runtime.secret_share([1], self.Zp)
         share.addCallback(check)
         return share
+
+    @protocol
+    def test_open_secret_share(self, runtime):
+        """Test sharing and open of a number."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        def check(v):
+            self.assertEquals(v, 42)
+
+        if 1 == runtime.id:
+            x = runtime.secret_share([1], self.Zp, 42)
+        else:
+            x = runtime.secret_share([1], self.Zp)
+        d = runtime.open(x)
+        d.addCallback(check)
+        return d
+