changeset 1234:82e3597871ae

Replace the current implementation of _get_triple with a call to random triple. Implement the preprocessing interface.
author Janus Dam Nielsen <janus.nielsen@alexandra.dk>
date Wed, 07 Oct 2009 12:02:20 +0200
parents a3d5284eea19
children 3fba16c51e71
files viff/orlandi.py viff/test/test_orlandi_runtime.py
diffstat 2 files changed, 128 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/viff/orlandi.py	Wed Oct 07 12:02:12 2009 +0200
+++ b/viff/orlandi.py	Wed Oct 07 12:02:20 2009 +0200
@@ -495,8 +495,17 @@
 
         field = getattr(share_x, "field", getattr(share_y, "field", None))
 
-        a, b, c = self._get_triple(field)
-        return self._basic_multiplication(share_x, share_y, a, b, c)
+        def finish_mul((a, b, c)):
+            return self._basic_multiplication(share_x, share_y, a, b, c)
+
+        # This will be the result, a Share object.
+        result = Share(self, share_x.field)
+        # This is the Deferred we will do processing on.
+        triple = self._get_triple(field)
+        triple = self.schedule_complex_callback(triple, finish_mul)
+        # We add the result to the chains in triple.
+        triple.chainDeferred(result)
+        return result
 
     def _additive_constant(self, zero, field_element):
         """Greate an additive constant.
@@ -588,14 +597,11 @@
         return c
 
     def _get_triple(self, field):
-        n = field(0)
-        Ca = commitment.commit(6, 0, 0)
-        a = OrlandiShare(self, field, field(2), (n, n), Ca)
-        Cb = commitment.commit(12, 0, 0)
-        b = OrlandiShare(self, field, field(4), (n, n), Cb)
-        Cc = commitment.commit(72, 0, 0)
-        c = OrlandiShare(self, field, field(24), (n, n), Cc)
-        return (a, b, c)
+        c, d = self.random_triple(field, 1)
+        def f(ls):
+            return ls[0]
+        d.addCallbacks(f, self.error_handler)
+        return d
 
     def _basic_multiplication(self, share_x, share_y, triple_a, triple_b, triple_c):
         """Multiplication of shares give a triple.
@@ -1011,7 +1017,7 @@
 
         return result
 
-    def random_triple(self, field):
+    def random_triple(self, field, number_of_requested_triples):
         """Generate a list of triples ``(a, b, c)`` where ``c = a * b``.
 
         The triple ``(a, b, c)`` is secure in the Fcrs-hybrid model.
@@ -1019,15 +1025,16 @@
         """
         self.program_counter[-1] += 1
 
-        number_of_multiplications = 1
         M = []
-        
-        for x in xrange((1 + self.s_lambda) * (2 * self.d + 1) * number_of_multiplications):
+
+# print "Generating %i triples... relax, have a brak..." % ((1 + self.s_lambda) * (2 * self.d + 1) * number_of_requested_triples)
+
+        for x in xrange((1 + self.s_lambda) * (2 * self.d + 1) * number_of_requested_triples):
             M.append(self.triple_test(field))
 
         def step3(ls):
             """Coin-flip a subset test_set of M of size lambda(2d + 1)M."""
-            size = self.s_lambda * (2 * self.d + 1) * number_of_multiplications
+            size = self.s_lambda * (2 * self.d + 1) * number_of_requested_triples
             inx = 0
             p_half = field.modulus // 2
             def coin_flip(v, ls, test_set):
@@ -1235,18 +1242,18 @@
             return dls_all
 
         def step6(M_without_test_set):
-            """Partition M without test_set in number_of_multiplications
+            """Partition M without test_set in number_of_requested_triples
             random subsets M_i of size (2d + 1).
             """
             subsets = []
             size = 2 * self.d + 1
-            for x in xrange(number_of_multiplications):
+            for x in xrange(number_of_requested_triples):
                 subsets.append([])
 
             def put_in_set(v, M_without_test_set, subsets):
                 if 0 == len(M_without_test_set):
                     return subsets
-                v = v.value % number_of_multiplications
+                v = v.value % number_of_requested_triples
                 if size > len(subsets[v]):
                     subsets[v].append(M_without_test_set.pop(0))
                 r = self.random_share(field)
@@ -1295,8 +1302,11 @@
         # do actual communication
         self.activate_reactor()
 
-        return result
-
+        s = Share(self, field)
+        def f(ls, s):
+            s.callback(ls)
+        result.addCallbacks(f, self.error_handler, callbackArgs=(s,))
+        return number_of_requested_triples, s
 
     def error_handler(self, ex):
         print "Error: ", ex
--- a/viff/test/test_orlandi_runtime.py	Wed Oct 07 12:02:12 2009 +0200
+++ b/viff/test/test_orlandi_runtime.py	Wed Oct 07 12:02:20 2009 +0200
@@ -261,7 +261,7 @@
  
     runtime_class = OrlandiRuntime
 
-    timeout = 60
+    timeout = 800
 
     @protocol
     def test_shift(self, runtime):
@@ -556,13 +556,15 @@
         x2 = runtime.shift([1], self.Zp, x1)
         y2 = runtime.shift([2], self.Zp, y1)
 
-        M = []
-        for j in xrange(1, 2*runtime.d + 2):
-            M.append(_get_triple(self, self.Zp))
-        z2 = runtime.leak_tolerant_mul(x2, y2, M)
-        d = runtime.open(z2)
-        d.addCallback(check)
-        return d
+        c, sls = runtime.random_triple(self.Zp, 2*runtime.d + 1)
+
+        def cont(M):
+            z2 = runtime.leak_tolerant_mul(x2, y2, M)
+            d = runtime.open(z2)
+            d.addCallback(check)
+            return d
+        sls.addCallbacks(cont, runtime.error_handler)
+        return sls
 
         z2 = runtime._cmul(y2, x2, self.Zp)
         self.assertEquals(z2, None)
@@ -672,7 +674,94 @@
             d = gatherResults(ds)
             d.addCallback(check)
             return d
-        d = runtime.random_triple(self.Zp)
+        c, d = runtime.random_triple(self.Zp, 1)
         d.addCallbacks(open, runtime.error_handler)
         return d
 
+    @protocol
+    def test_random_triple3_parallel(self, runtime):
+        """Test the triple_combiner command."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        def check(ls):
+            for x in xrange(len(ls) // 3):
+                a = ls[x * 3]
+                b = ls[x * 3 + 1]
+                c = ls[x * 3 + 2]
+                self.assertEquals(c, a * b)
+
+        def open(ls):
+            ds = []
+            for [(a, b, c)] in ls:
+                d1 = runtime.open(a)
+                d2 = runtime.open(b)
+                d3 = runtime.open(c)
+                ds.append(d1)
+                ds.append(d2)
+                ds.append(d3)
+
+            d = gatherResults(ds)
+            d.addCallback(check)
+            return d
+        ac, a = runtime.random_triple(self.Zp, 1)
+        bc, b = runtime.random_triple(self.Zp, 1)
+        cc, c = runtime.random_triple(self.Zp, 1)
+        d = gather_shares([a, b, c])
+        d.addCallbacks(open, runtime.error_handler)
+        return d
+
+    @protocol
+    def test_random_triple_parallel(self, runtime):
+        """Test the triple_combiner command."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        def check(ls):
+            for x in xrange(len(ls) // 3):
+                a = ls[x * 3]
+                b = ls[x * 3 + 1]
+                c = ls[x * 3 + 2]
+                self.assertEquals(c, a * b)
+
+        def open(ls):
+            ds = []
+            for [(a, b, c)] in ls:
+                d1 = runtime.open(a)
+                d2 = runtime.open(b)
+                d3 = runtime.open(c)
+                ds.append(d1)
+                ds.append(d2)
+                ds.append(d3)
+
+            d = gatherResults(ds)
+            d.addCallback(check)
+            return d
+
+        a_shares = []
+        b_shares = []
+        c_shares = []
+
+        def cont(x):
+            while a_shares and b_shares:
+                a = a_shares.pop()
+                b = b_shares.pop()
+                c_shares.append(runtime.mul(a, b))
+            done = gather_shares(c_shares)
+            return done
+
+        count = 5
+
+        for i in range(count):
+            inputter = (i % len(runtime.players)) + 1
+            if inputter == runtime.id:
+                a = rand.randint(0, self.Zp.modulus)
+                b = rand.randint(0, self.Zp.modulus)
+            else:
+                a, b = None, None
+            a_shares.append(runtime.input([inputter], self.Zp, a))
+            b_shares.append(runtime.input([inputter], self.Zp, b))
+        shares_ready = gather_shares(a_shares + b_shares)
+
+        runtime.schedule_callback(shares_ready, cont)
+        return shares_ready