changeset 1516:7beb12b97911

BeDOZa: Added a generate_random_shares method to PartialShareGenerator.
author Janus Dam Nielsen <janus.nielsen@alexandra.dk>
date Thu, 22 Jul 2010 12:21:19 +0200
parents 2fb1e2fc8707
children 054a27514891
files viff/bedoza_triple.py viff/test/test_bedoza_triple.py
diffstat 2 files changed, 67 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/viff/bedoza_triple.py	Wed Jul 21 15:09:55 2010 +0200
+++ b/viff/bedoza_triple.py	Thu Jul 22 12:21:19 2010 +0200
@@ -117,10 +117,13 @@
 # to get a PartialShare as input to callbacks, we need this extra level of
 # wrapper indirection.
 class PartialShare(Share):
-    def __init__(self, runtime, value, enc_shares):
-        N_squared_list = [ runtime.players[player_id].pubkey['n_square'] for player_id in runtime.players.keys()]
-        partial_share_contents = PartialShareContents(value, enc_shares, N_squared_list)
-        Share.__init__(self, runtime, value.field, partial_share_contents)
+    def __init__(self, runtime, field, value=None, enc_shares=None):
+        if value == None and enc_shares == None:
+            Share.__init__(self, runtime, field)
+        else:
+            N_squared_list = [ runtime.players[player_id].pubkey['n_square'] for player_id in runtime.players.keys()]
+            partial_share_contents = PartialShareContents(value, enc_shares, N_squared_list)
+            Share.__init__(self, runtime, field, partial_share_contents)
 
 
 class PartialShareGenerator:
@@ -143,10 +146,29 @@
         enc_share = self.paillier.encrypt(share.value)
         enc_shares = _convolute(self.runtime, enc_share)
         def create_partial_share(enc_shares, share):
-            return PartialShare(self.runtime, share, enc_shares)
+            return PartialShare(self.runtime, value.field, share, enc_shares)
         self.runtime.schedule_callback(enc_shares, create_partial_share, share)
         return enc_shares
 
+    def generate_random_shares(self, n):
+        self.runtime.increment_pc()
+        N_squared_list = [ self.runtime.players[player_id].pubkey['n_square'] for player_id in self.runtime.players]
+        shares = [PartialShare(self.runtime, self.Zp) for _ in xrange(n)]
+        for inx in xrange(n):
+            r = self.random.randint(0, self.Zp.modulus - 1)
+            ri = self.Zp(r)
+            enc_share = self.paillier.encrypt(ri.value)
+            enc_shares = _convolute(self.runtime, enc_share)
+            def create_partial_share(enc_shares, ri, s, N_squared_list):
+                s.callback(PartialShareContents(ri, enc_shares, N_squared_list))
+            self.runtime.schedule_callback(enc_shares,
+                                           create_partial_share,
+                                           ri,
+                                           shares[inx],
+                                           N_squared_list)
+            
+        return shares
+
 class ModifiedPaillier(object):
     """A slight modification of the Paillier cryptosystem.
 
--- a/viff/test/test_bedoza_triple.py	Wed Jul 21 15:09:55 2010 +0200
+++ b/viff/test/test_bedoza_triple.py	Thu Jul 22 12:21:19 2010 +0200
@@ -31,7 +31,7 @@
 from viff.config import generate_configs
 from viff.bedoza import BeDOZaRuntime, BeDOZaShare, BeDOZaKeyList
 
-from viff.bedoza_triple import TripleGenerator, PartialShare, PartialShareContents, ModifiedPaillier
+from viff.bedoza_triple import TripleGenerator, PartialShare, PartialShareContents, ModifiedPaillier, PartialShareGenerator
 from viff.bedoza_triple import _send, _convolute, _convolute_gf_elm
 
 from viff.field import FieldElement, GF
@@ -68,31 +68,6 @@
     print "player%d ------> %s" % (rt.id, msg)
 
 
-# TODO: Code duplication. There should be only one share generator, it should
-# be placed along with the tests, and it should be able to generate partial
-# as well as full bedoza shares.
-class PartialShareGenerator:
-
-    def __init__(self, Zp, runtime, random, paillier):
-        self.paillier = paillier
-        self.Zp = Zp
-        self.runtime = runtime
-        self.random = random
-
-    def generate_share(self, value):
-        r = [self.Zp(self.random.randint(0, self.Zp.modulus - 1)) # TODO: Exclusve?
-             for _ in range(self.runtime.num_players - 1)]
-        if self.runtime.id == 1:
-            share = value - sum(r)
-        else:
-            share = r[self.runtime.id - 2]
-        enc_share = self.paillier.encrypt(share.value)
-        enc_shares = _convolute(self.runtime, enc_share)
-        def create_partial_share(enc_shares, share):
-            return PartialShare(self.runtime, share, enc_shares)
-        self.runtime.schedule_callback(enc_shares, create_partial_share, share)
-        return enc_shares
-
 class BeDOZaTestCase(RuntimeTestCase):
 
     runtime_class = BeDOZaRuntime
@@ -226,6 +201,14 @@
     gen = PartialShareGenerator(Zp, runtime, share_random, paillier)
     return gen.generate_share(Zp(val))
 
+def partial_random_shares(random, runtime, Zp, n, paillier=None):
+    if not paillier:
+        paillier_random = Random(random.getrandbits(128))
+        paillier = ModifiedPaillier(runtime, paillier_random)
+    share_random = Random(random.getrandbits(128))
+    gen = PartialShareGenerator(Zp, runtime, share_random, paillier)
+    return gen.generate_random_shares(n)
+
 
 class ParialShareGeneratorTest(BeDOZaTestCase):
     num_players = 3
@@ -251,7 +234,6 @@
         runtime.schedule_callback(share, convolute)
         return share
 
-
     @protocol
     def test_encrypted_shares_decrypt_correctly(self, runtime):
         random = Random(3423993)
@@ -268,6 +250,37 @@
         runtime.schedule_callback(share, decrypt)
         return share
 
+    @protocol
+    def test_random_shares_have_correct_type(self, runtime):
+        Zp = GF(23)
+        shares = partial_random_shares(Random(23499), runtime, Zp, 7)
+        for share in shares:
+            def test(share):
+                self.assertEquals(Zp, share.value.field)
+            runtime.schedule_callback(share, test)
+            
+        return shares
+ 
+    @protocol
+    def test_encrypted_random_shares_decrypt_correctly(self, runtime):
+        random = Random(3423993)
+        modulus = 17
+        Zp = GF(modulus)
+        paillier = ModifiedPaillier(runtime, Random(random.getrandbits(128)))
+        shares = partial_random_shares(random, runtime, Zp, 7, paillier=paillier)
+        expected_result = [9,16,7,12,3,5,6]
+        for inx, share in enumerate(shares):
+            def decrypt(share, expected_result):
+                decrypted_share = paillier.decrypt(share.enc_shares[runtime.id - 1])
+                decrypted_shares = _convolute(runtime, decrypted_share)
+                def test_sum(vals, expected_result):
+                    v = Zp(sum(vals))
+                    self.assertEquals(expected_result, v)
+                runtime.schedule_callback(decrypted_shares, test_sum, expected_result)
+            runtime.schedule_callback(share, decrypt, expected_result[inx])
+            
+        return shares
+
 
 class TripleTest(BeDOZaTestCase): 
     num_players = 3