changeset 1504:129b326c3ff1

BeDOZa: Implemented preprocessing fullmul method.
author Janus Dam Nielsen <janus.nielsen@alexandra.dk>
date Mon, 19 Jul 2010 10:46:09 +0200
parents b120a9dee885
children 60cbf0d030c7
files viff/bedoza_triple.py viff/test/test_bedoza_triple.py
diffstat 2 files changed, 94 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/viff/bedoza_triple.py	Mon Jul 19 10:42:37 2010 +0200
+++ b/viff/bedoza_triple.py	Mon Jul 19 10:46:09 2010 +0200
@@ -54,6 +54,8 @@
     Works as default for integers. If other stuff has to be
     sent, supply another serialization, deserialition.
     """
+    runtime.increment_pc()
+    
     pc = tuple(runtime.program_counter)
     for p in runtime.players:
         msg = serialize(vals[p - 1])
@@ -85,8 +87,6 @@
                  deserialize=lambda x: gf_elm.field(int(x)))
 
 
-
-
 class PartialShareContents(object):
     """A BeDOZa share without macs, e.g. < a >.
     TODO: BeDOZaShare should extend this class?
@@ -104,6 +104,13 @@
     def __str__(self):
         return "PartialShareContents(%d; %s; %s)" % (self.value, self.enc_shares, self.N_squared_list)
 
+    def __add__(self, other):
+        z = self.value + other.value
+        z_enc_shares = []
+        for x, y, N_squared in zip(self.enc_shares, other.enc_shares, self.N_squared_list):
+            z_enc_shares.append((x * y) % N_squared)
+        return PartialShareContents(z, z_enc_shares, self.N_squared_list)
+
 # In VIFF, callbacks get the *contents* of a share as input. Hence, in order
 # to get a PartialShare as input to callbacks, we need this extra level of
 # wrapper indirection.
@@ -343,9 +350,27 @@
         r.addCallback(wrap, inx, jnx)
         return r
 
-    
-    def _full_mul(self):
-        pass
+    def _full_mul(self, a, b):
+        self.runtime.increment_pc()
+        
+        def do_full_mul((contents_a, contents_b)):
+            deferreds = []
+            for inx in xrange(0, len(self.runtime.players)):
+                for jnx in xrange(0, len(self.runtime.players)):
+                    deferreds.append(self._mul(inx + 1, jnx + 1, contents_a.value, contents_b.enc_shares[jnx]))
+            def compute_share(partialShares):
+                partialShareContents = reduce(lambda x, y: x + y, partialShares)
+                pid = self.runtime.id
+                share = partialShareContents.enc_shares[pid - 1]
+                share = self.paillier.decrypt(share)
+                share = self.Zp(share)
+                return PartialShare(self.runtime, partialShareContents.value, partialShareContents.enc_shares)
+            d = gatherResults(deferreds)
+            d.addCallback(compute_share)
+            return d
+        s = gatherResults([a, b])
+        self.runtime.schedule_callback(s, do_full_mul)
+        return s
 
 
 # TODO: Represent all numbers by GF objects, Zp, Zn, etc.
--- a/viff/test/test_bedoza_triple.py	Mon Jul 19 10:42:37 2010 +0200
+++ b/viff/test/test_bedoza_triple.py	Mon Jul 19 10:46:09 2010 +0200
@@ -18,6 +18,8 @@
 import sys
 from exceptions import AssertionError
 
+import operator
+
 # We don't need secure random numbers for test purposes.
 from random import Random
 
@@ -390,6 +392,68 @@
         return r1
 
 
+class FullMulTest(BeDOZaTestCase): 
+    num_players = 3
+    
+    @protocol
+    def test_fullmul_computes_the_correct_result(self, runtime):
+        p = 17
+
+        Zp = GF(p)
+        
+        random = Random(283883)        
+        triple_generator = TripleGenerator(runtime, p, random)
+
+        paillier = triple_generator.paillier
+        
+        share_a = partial_share(random, runtime, GF(p), 6, paillier=paillier)
+        share_b = partial_share(random, runtime, GF(p), 7, paillier=paillier)
+
+        share_z = triple_generator._full_mul(share_a, share_b)
+        def check(share):
+            def test_sum(ls):
+                vals = ls[0]
+                self.assertEquals(8, Zp(sum(vals)))
+            value = _convolute(runtime, share.value.value)
+            runtime.schedule_callback(gatherResults([value]), test_sum)
+            return True
+            
+        share_z.addCallback(check)
+        return share_z
+
+    @protocol
+    def test_fullmul_encrypted_values_are_the_same_as_the_share(self, runtime):
+        p = 17
+
+        Zp = GF(p)
+        
+        random = Random(283883)        
+        triple_generator = TripleGenerator(runtime, p, random)
+
+        paillier = triple_generator.paillier
+        
+        share_a = partial_share(random, runtime, GF(p), 6, paillier=paillier)
+        share_b = partial_share(random, runtime, GF(p), 7, paillier=paillier)
+
+        share_z = triple_generator._full_mul(share_a, share_b)
+        def check(share):
+            def test_enc(enc_shares, value):
+                all_the_same, zi_enc = reduce(lambda x, y: (x[0] and x[1] == y, y), enc_shares, (True, enc_shares[0]))
+                zi_enc = triple_generator.paillier.decrypt(zi_enc)
+                self.assertEquals(value, Zp(zi_enc))
+                return True
+            all_enc_shares = []
+            for inx, enc_share in enumerate(share.enc_shares):
+                d = _convolute(runtime, enc_share)
+                if runtime.id == inx + 1:
+                    d.addCallback(test_enc, share.value)
+                all_enc_shares.append(d)
+            return gatherResults(all_enc_shares)
+            
+        share_z.addCallback(check)
+        return share_z
+
+
 missing_package = None
 if not pypaillier:
     missing_package = "pypaillier"