changeset 1550:c8e7c5ee1583

BeDOZa: Restructured tests for better code reuse. This changeset also contains further implementation of the zero-knowledge protocol, which is, however, not working yet.
author Thomas P Jakobsen <tpj@cs.au.dk>
date Fri, 24 Sep 2010 14:21:36 +0200
parents 9a89c3397c9a
children 38793a845e3f
files viff/bedoza/modified_paillier.py viff/bedoza/util.py viff/bedoza/zero_knowledge.py viff/test/bedoza/test_bedoza_runtime.py viff/test/bedoza/test_bedoza_triple.py viff/test/bedoza/test_zero_knowledge.py viff/test/bedoza/util.py
diffstat 7 files changed, 406 insertions(+), 163 deletions(-) [+]
line wrap: on
line diff
--- a/viff/bedoza/modified_paillier.py	Thu Sep 23 10:07:35 2010 +0200
+++ b/viff/bedoza/modified_paillier.py	Fri Sep 24 14:21:36 2010 +0200
@@ -47,15 +47,20 @@
             return y
         else:
             return y - n
-
-    def encrypt(self, value, player_id=None):
-        """Encrypt using public key of player player_id.
-
-        Defaults to own public key.
-        """
+     
+    def _verify_input(self, value, player_id):
         assert isinstance(value, int) or isinstance(value, long), \
             "paillier: encrypts only integers and longs, got %s" % \
                 value.__class__
+
+    def encrypt_with_randomness(self, value, randomness, player_id=None):
+        """Encrypt using public key of player player_id using the
+        given randomness.
+
+        Defaults to own public key.
+
+        """
+        self._verify_input(value, player_id)
         if not player_id:
             player_id = self.runtime.id
         n = self.runtime.players[player_id].pubkey['n']
@@ -65,8 +70,23 @@
             "paillier: plaintext %d outside legal range [-(n-1)/2 " \
             "; (n-1)/2] = [%d ; %d]"  % (value, min, max)
         pubkey = self.runtime.players[player_id].pubkey
-        randomness = self.random.randint(1, long(n))
-        return pypaillier.encrypt_r(self._f(value, n), randomness, pubkey)
+        return randomness, pypaillier.encrypt_r(self._f(value, n), randomness, pubkey) 
+
+    def encrypt_r(self, value, player_id=None):
+       """As encrypt_with_randomness, but generates its own randomness."""
+       self._verify_input(value, player_id)
+       if not player_id:
+           player_id = self.runtime.id
+       n = self.runtime.players[player_id].pubkey['n']
+       randomness = self.random.randint(1, long(n))
+       return self.encrypt_with_randomness(value, randomness, player_id=player_id)
+
+
+    def encrypt(self, value, player_id=None):
+        """As encrypt_r, but doesn't return randomness used, only
+        encrypted value."""
+        return self.encrypt_r(value, player_id=player_id)[1]
+
 
     def decrypt(self, enc_value):
         """Decrypt using own private key."""
--- a/viff/bedoza/util.py	Thu Sep 23 10:07:35 2010 +0200
+++ b/viff/bedoza/util.py	Fri Sep 24 14:21:36 2010 +0200
@@ -61,3 +61,16 @@
 
 def fast_pow(a, b, modulus):
     return long(pow(mpz(a), b, modulus))
+
+
+def rand_int_signed(random, lim):
+    """Returns a pseudo-uniformly distributed random integer a
+    such that abs(a) <= lim.
+
+    random: A random generator.
+    """
+    # TODO: This is probably not the fastes way to do it.
+    res = random.randint(0, lim)
+    if random.choice([True, False]):
+        res = -res
+    return res
--- a/viff/bedoza/zero_knowledge.py	Thu Sep 23 10:07:35 2010 +0200
+++ b/viff/bedoza/zero_knowledge.py	Fri Sep 24 14:21:36 2010 +0200
@@ -15,43 +15,160 @@
 # You should have received a copy of the GNU Lesser General Public
 # License along with VIFF. If not, see <http://www.gnu.org/licenses/>.
 
+import gmpy
+import hashlib
+
+from viff.runtime import gatherResults
+from viff.bedoza.util import rand_int_signed
 
 class ZKProof(object):
     """Protocol proving that a player's plaintexts are of limited size.
     
-    This is a zero-knowledge protocol in which player player_id inputs s
-    ciphertexts c[i] = E(x[j], r[j]), i = 1, ..., s, created using the
-    modified Paillier cipher and proves to the other players that the x[i]'s
-    are of limited size, e.g. that abs(x[i]) <= 2**k.
+    This is a zero-knowledge protocol in which player with prover_id
+    inputs s ciphertexts c[i] = E(x[j], r[j]), i = 1, ..., s, created
+    using the modified Paillier cipher and proves to the other players
+    that the x[i]'s are of limited size, e.g. that abs(x[i]) <= 2**k.
     
-    Zn is the plaintext field of player player_id's modified Paillier cipher.
-    
-    While player player_id must input the ciphertexts, the other players
-    should call the method with c = None.
-    
+    Zn is the plaintext field of player prover_id's modified Paillier
+    cipher.
     """
     
-    def __init__(self, player_id, Zn, c=None):
-        self.player_id = player_id
+    def __init__(self, s, prover_id, Zn, k, runtime, c, random=None, paillier=None, x=None, r=None):
+        """
+        random: a random source (e.g. viff.util.Random)
+
+        All players must submit c, but only the player with id
+        prover_id should submit x and r.
+        """
+        self.x = x
+        self.r = r
+        self.s = s
+        self.m = 2 * s - 1
+        self.prover_id = prover_id
         self.Zn = Zn
+        self.k = k
+        self.runtime = runtime
         self.c = c
-        self.e = None
+        self.paillier = paillier
+        self.random = random
 
-    def start():
+
+
+    def start(self):
+        if self.runtime.id == self.prover_id:
+            self._generate_proof()
+        deferred_proof = self._get_proof_broadcasted_by_prover()
+        self.runtime.schedule_callback(deferred_proof, self._verify_proof)
+        return deferred_proof
+
+    def _generate_proof(self):
+        self._generate_u_v_and_d()
+        self._generate_e()
+        self._generate_Z_and_W()
+
+    def _verify_proof(self, serialized_proof):
+        # The prover don't need to prove to himself.
+        if self.runtime.id == self.prover_id:
+            #print 'x', len(self.x)
+            #print 'e', len(self.e)
+            #print 'u', len(self.u)
+            return
+        self._deserialize_proof(serialized_proof)
+        self._generate_e()
+        q = self._vec_mul(self.d, self._vec_pow_E(self.c))
         
-        pass
 
-    def _set_e(self, e):
-        self.e = e
-        self.s = len(e)
-        self.m = 2 * len(e) - 1
 
-    def _generate_challenge(self):
-        # TODO: Implement.
-        self.e = [0, 0, 1, 0, 1]
-        self.s = len(e)
-        self.m = 2 * len(e) - 1
+        #print 'Z', len(self.Z)
+        #print 'W', len(self.W)
+        
 
+        for j in xrange(self.m):
+            pass
+            #print
+            #print '---'
+            #print self.runtime.id,  self.paillier.encrypt_with_randomness(self.Z[j], self.W[j])[1]
+            #print self.runtime.id, q[j]
+
+            # TODO: Verify!
+
+
+    def _generate_u_v_and_d(self):
+        self.u, self.v, self.d = [], [], []
+        for i in range(self.m):
+            ui = rand_int_signed(self.random, 2**(2 * self.k))
+            vi, di = self.paillier.encrypt_r(ui)
+            self.u.append(ui)
+            self.v.append(vi)
+            self.d.append(di)
+
+    def _generate_Z_and_W(self):
+        self.Z = self._vec_add(self.u, self._vec_mul_E(self.x))
+        self.W = self._vec_mul(self.v, self._vec_pow_E(self.r))
+        
+    def _get_proof_broadcasted_by_prover(self):
+        serialized_proof = None
+        if self.runtime.id == self.prover_id:
+            # TODO: Should we somehow compress message for improved performance?
+            serialized_proof = self._serialize_proof()
+        deferred_proof = self._broadcast(serialized_proof)
+        return deferred_proof
+
+    def _serialize_proof(self):
+        return repr([self.d, self.Z, self.W])
+
+    def _deserialize_proof(self, serialized_proof):
+        # We remove quotes before evaluation in order to get a list.
+        proof = eval(serialized_proof[1:-1])
+        self.d = proof[0]
+        self.Z = proof[1]
+        self.W = proof[2]
+
+    def _extract_bits(self, string, no_of_bits):
+        """Returns list of first no_of_bits from the given string."""
+        word_size = 8 # No of bits in char.
+        assert no_of_bits <= word_size * len(string), "Not enough bits"
+        res = []
+        if no_of_bits == 0:
+            return res
+        no_of_chars = 1 + no_of_bits / word_size
+        for c in string[:no_of_chars]:
+            digits = [int(v) for v in gmpy.digits(ord(c), 2).zfill(word_size)]
+            if len(res) + word_size >= no_of_bits:
+                return res + digits[:no_of_bits - len(res)]
+            res += digits
+        return res
+
+
+    def _generate_e(self):
+        """Generating an s-bit challenge e by the Fiat-Shamir heuristic.
+        
+        In other security models, generating the challenge requires
+        interaction.
+       
+        The challenge is a list of 0's and 1's of length s.
+        """
+        # This can be easily fixed by using the hash as seed for a
+        # secure prng.
+        assert self.s <= 160, "Error: Algorithm only supports s <= 160"
+        assert hasattr(self, 'c')
+        assert hasattr(self, 'd')
+        h = hashlib.sha1()
+        for c, d in zip(self.c, self.d):
+            h.update(repr(c))
+            h.update(repr(d))
+        hash = h.digest()
+        self.e = self._extract_bits(hash, self.s)
+
+
+    def _broadcast(self, values):
+        msg = repr(values) if self.prover_id == self.runtime.id else None
+        return self.runtime.broadcast(
+            [self.prover_id], self.runtime.players.keys(), message=msg)
+
+    def _err_handler(self, err):
+        print err
+        return err # raise or what?
 
     def _E(self, row, col):
         """Computes the value of the entry in the matrix E at the given row
@@ -66,18 +183,32 @@
         else:
             return 0
 
-    def vec_add(self, x, y):
-        return [xi + yi for x, y in zip(x,y)]
+    def _vec_add(self, x, y):
+        return [x + y for x, y in zip(x,y)]
+
+    def _vec_mul_E(self, x):
+        """Takes an s x 1 vector x and returns the m x 1 vector xE."""
+        # TODO: This could probably be optimized since we know the
+        # structure of E.
+        res = []
+        for j in xrange(self.m):
+            t = 0
+            for i in xrange(self.s):
+                t = t + x[i] * self._E(j, i)
+            res.append(t)
+        return res
     
-    def vec_mul(self, x, y):
-        return [xi * yi for x, y in zip(x,y)]
+    def _vec_mul(self, x, y):
+        return [x * y for x, y in zip(x,y)]
 
-    def vec_pow_E(self, y):
+    def _vec_pow_E(self, y):
         """Computes and returns the m := 2s-1 length vector y**E."""
         assert self.s == len(y), \
             "not same length: %d != %d" % (self.s, len(y))
-        res = [self.Zn(1)] * self.m
-        for j in range(2 * self.s - 1):
+        #res = [self.Zn(1)] * self.m
+        # TODO: Should do all computations over some field.
+        res = [1] * self.m
+        for j in range(self.m):
             for i in range(self.s):
                 if self._E(j, i) == 1:
                     res[j] *= y[i]
--- a/viff/test/bedoza/test_bedoza_runtime.py	Thu Sep 23 10:07:35 2010 +0200
+++ b/viff/test/bedoza/test_bedoza_runtime.py	Fri Sep 24 14:21:36 2010 +0200
@@ -36,28 +36,10 @@
 from viff.bedoza.bedoza_triple import TripleGenerator
 from viff.bedoza.zero_knowledge import ZKProof
 
-# The PyPaillier and commitment packages are not standard parts of VIFF so we
-# skip them instead of letting them fail if the packages are not available. 
-try:
-    import pypaillier
-except ImportError:
-    pypaillier = None
+from viff.test.bedoza.util import BeDOZaTestCase, skip_if_missing_packages
 
-# HACK: The paillier keys that are available as standard in VIFF tests
-# are not suited for use with pypaillier. Hence, we use NaClPaillier
-# to generate test keys. This confusion will disappear when pypaillier
-# replaces the current Python-based paillier implementation.
-from viff.paillierutil import NaClPaillier
 
-# HACK^2: Currently, the NaClPaillier hack only works when triple is
-# imported. It should ideally work without the triple package.
-try:
-    import tripple
-except ImportError:
-    tripple = None
-
-
-class BeDOZaBasicCommandsTest(RuntimeTestCase):
+class BeDOZaBasicCommandsTest(BeDOZaTestCase):
     """Test for basic commands."""
 
     # Number of players.
@@ -65,16 +47,6 @@
 
     timeout = 3
 
-    runtime_class = BeDOZaRuntime
-
-    # TODO: During test, we would like generation of Paillier keys to
-    # be deterministic. How do we obtain that?
-    def generate_configs(self, *args):
-        # In production, paillier keys should be something like 2000
-        # bit. For test purposes, it is ok to use small keys.
-        # TODO: paillier freezes if key size is too small, e.g. 13.
-        return generate_configs(paillier=NaClPaillier(250), *args)
-
     def setUp(self):
         RuntimeTestCase.setUp(self)
         self.Zp = GF(17)
@@ -528,35 +500,4 @@
         return d
 
 
-# TODO: Move to test.bedoza.test_zero_knowledge.
-class BeDOZaZeroKnowledgeTest(RuntimeTestCase):
-
-    num_players = 3
-
-    timeout = 3
-
-    runtime_class = BeDOZaRuntime
-
-    def test_zk_matrix_entries_are_correct(self):
-        zk = ZKProof(None, None)
-        zk._set_e([1, 0, 0, 1, 1])
-        for i in range(zk.s):
-            for j in range(zk.m):
-                if j >= i and j < i + zk.s:
-                    self.assertEquals(zk.e[j - i], zk._E(j, i))
-                else:
-                    self.assertEquals(0, zk._E(j, i))
-
-    def test_vec_pow_is_correct(self):
-        Zn = GF(17)
-        y = [Zn(i) for i in range(1, 6)]
-        zk = ZKProof(None, Zn)
-        zk._set_e([1, 0, 1, 1, 0])
-        y_pow_E = zk.vec_pow_E(y)
-        self.assertEquals([Zn(v) for v in [1, 2, 3, 8, 13, 12, 3, 5, 1]],
-                          y_pow_E)
-def skip_tests(module_name):
-    BeDOZaBasicCommandsTest.skip = "Skipped due to missing " + module_name + " module."
-
-if not pypaillier:
-    skip_tests("pypaillier")
+skip_if_missing_packages(BeDOZaBasicCommandsTest)
--- a/viff/test/bedoza/test_bedoza_triple.py	Thu Sep 23 10:07:35 2010 +0200
+++ b/viff/test/bedoza/test_bedoza_triple.py	Fri Sep 24 14:21:36 2010 +0200
@@ -25,12 +25,14 @@
 
 from twisted.internet.defer import gatherResults, Deferred, DeferredList
 
-from viff.test.util import RuntimeTestCase, protocol
+from viff.test.util import protocol
 from viff.constants import TEXT
 from viff.runtime import gather_shares, Share
 from viff.config import generate_configs
 
-from viff.bedoza.bedoza import BeDOZaRuntime, BeDOZaShare
+from viff.test.bedoza.util import BeDOZaTestCase, skip_if_missing_packages
+
+from viff.bedoza.bedoza import BeDOZaShare
 from viff.bedoza.keylist import BeDOZaKeyList
 from viff.bedoza.bedoza_triple import TripleGenerator, ModifiedPaillier
 from viff.bedoza.share_generators import PartialShareGenerator, ShareGenerator
@@ -41,53 +43,10 @@
 from viff.field import FieldElement, GF
 from viff.config import generate_configs
 
-
 # Ok to use non-secure random generator in tests.
 #from viff.util import rand
 import random
 
-# The PyPaillier and commitment packages are not standard parts of VIFF so we
-# skip them instead of letting them fail if the packages are not available. 
-try:
-    import pypaillier
-except ImportError:
-    pypaillier = None
-
-# HACK: The paillier keys that are available as standard in VIFF tests
-# are not suited for use with pypaillier. Hence, we use NaClPaillier
-# to generate test keys. This confusion will disappear when pypaillier
-# replaces the current Python-based paillier implementation.
-from viff.paillierutil import NaClPaillier
-
-# HACK^2: Currently, the NaClPaillier hack only works when triple is
-# imported. It should ideally work without the triple package.
-try:
-    import tripple
-except ImportError:
-    tripple = None
-
-
-
-def _log(rt, msg):
-    print "player%d ------> %s" % (rt.id, msg)
-
-
-class BeDOZaTestCase(RuntimeTestCase):
-
-    runtime_class = BeDOZaRuntime
-
-    def setUp(self):
-        RuntimeTestCase.setUp(self)
-        self.security_parameter = 32
-
-    # TODO: During test, we would like generation of Paillier keys to
-    # be deterministic. How do we obtain that?
-    def generate_configs(self, *args):
-        # In production, paillier keys should be something like 2000
-        # bit. For test purposes, it is ok to use small keys.
-        # TODO: paillier freezes if key size is too small, e.g. 13.
-        return generate_configs(paillier=NaClPaillier(250), *args)
-
 
 class DataTransferTest(BeDOZaTestCase):
     num_players = 3
@@ -615,21 +574,12 @@
         return d
         
 
-
-missing_package = None
-if not pypaillier:
-    missing_package = "pypaillier"
-if not tripple:
-    missing_package = "tripple"
-if missing_package:
-    test_cases = [ModifiedPaillierTest,
-                  PartialShareGeneratorTest,
-                  TripleTest,
-                  DataTransferTest,
-                  MulTest,
-                  FullMulTest,
-                  ShareGeneratorTest,
-                  AddMacsTest
-                  ]
-    for test_case in test_cases:
-        test_case.skip =  "Skipped due to missing %s package." % missing_package
+skip_if_missing_packages(
+    ModifiedPaillierTest,
+    PartialShareGeneratorTest,
+    TripleTest,
+    DataTransferTest,
+    MulTest,
+    FullMulTest,
+    ShareGeneratorTest,
+    AddMacsTest)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/viff/test/bedoza/test_zero_knowledge.py	Fri Sep 24 14:21:36 2010 +0200
@@ -0,0 +1,127 @@
+# Copyright 2010 VIFF Development Team.
+#
+# This file is part of VIFF, the Virtual Ideal Functionality Framework.
+#
+# VIFF is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License (LGPL) as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# VIFF is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
+# Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with VIFF. If not, see <http://www.gnu.org/licenses/>.
+
+
+# We don't need secure random numbers for test purposes.
+from random import Random
+
+from viff.field import GF
+from viff.bedoza.modified_paillier import ModifiedPaillier
+from viff.bedoza.zero_knowledge import ZKProof
+from viff.bedoza.util import rand_int_signed
+
+from viff.test.util import protocol
+from viff.test.bedoza.util import BeDOZaTestCase, skip_if_missing_packages
+
+
+class BeDOZaZeroKnowledgeTest(BeDOZaTestCase):
+
+    num_players = 3
+
+    def test_zk_matrix_entries_are_correct(self):
+        s = 5
+        zk = ZKProof(s, None, None, 0, None, None)
+        zk.e = [1, 0, 0, 1, 1]
+        for i in range(zk.s):
+            for j in range(zk.m):
+                if j >= i and j < i + zk.s:
+                    self.assertEquals(zk.e[j - i], zk._E(j, i))
+                else:
+                    self.assertEquals(0, zk._E(j, i))
+
+    def test_vec_pow_is_correct(self):
+        s, Zn = 5, GF(17)
+        y = [Zn(i) for i in range(1, 6)]
+        zk = ZKProof(s, None, Zn, 0, None, None)
+        zk.e = [1, 0, 1, 1, 0]
+        y_pow_E = zk._vec_pow_E(y)
+        self.assertEquals([Zn(v) for v in [1, 2, 3, 8, 13, 12, 3, 5, 1]],
+                          y_pow_E)
+
+    def test_vec_mul_E_is_correct(self):
+        s, Zn = 5, GF(17)
+        y = [Zn(i) for i in range(1, 6)]
+        zk = ZKProof(s, None, Zn, 0, None, None)
+        zk.e = [1, 0, 1, 1, 0]
+        x = [1, 2, 0, 1, 0]
+        x_mul_E = zk._vec_mul_E(x)
+        self.assertEquals([v for v in [1, 2, 1, 4, 2, 1, 1, 0, 0]], x_mul_E)
+
+    @protocol
+    def test_broadcast(self, runtime):
+        zk = ZKProof(0, 2, None, 0, runtime, None)
+        res = zk._broadcast([5, 6, 7])
+        def verify(res):
+            self.assertEquals(eval(res), [5, 6, 7])
+        runtime.schedule_callback(res, verify)
+        return res
+
+    @protocol
+    def test_proof(self, runtime):
+        k, s, random, Zn = 5, 5, Random(342344), GF(17)
+
+        paillier = ModifiedPaillier(runtime, Random(random.getrandbits(128)))
+        x, r, c = self._generate_test_ciphertexts(paillier, random, k, s)
+        zk = ZKProof(s, 1, Zn, k, runtime, c, paillier=paillier, random=random, x=x, r=r)
+        zk.e = [1, 0, 0, 1, 1]
+        deferred_proof = zk.start()
+        return deferred_proof
+
+    def test_extract_bits(self):
+        s = 5
+        zk = ZKProof(s, None, None, 0, None, None)
+        self.assertEquals([], zk._extract_bits('test', 0))
+        self.assertEquals([0], zk._extract_bits('test', 1))
+        self.assertEquals([0, 1], zk._extract_bits('test', 2))
+        self.assertEquals([0, 1, 1, 1, 0, 1, 0], zk._extract_bits('test', 7))
+        self.assertEquals([0, 1, 1, 1, 0, 1, 0, 0], zk._extract_bits('test', 8))
+        self.assertEquals([0, 1, 1, 1, 0, 1, 0, 0, 0], zk._extract_bits('test', 9))
+        self.assertEquals([0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1], zk._extract_bits('test', 14))
+
+    def test_generate_e_generates_e_of_right_length(self):
+        s = 5
+        c = [1, 1, 0, 0, 1, 0, 1, 0, 1]
+        zk = ZKProof(s, None, None, 0, None, c)
+        zk.d = [1, 0, 0, 1, 1, 0, 1, 1, 1]
+        zk._generate_e()
+        self.assertEquals(5, len(zk.e))
+
+    def test_generate_e_is_deterministic(self):
+        s = 5
+        c = [1, 1, 0, 0, 1, 0, 1, 0, 1]
+        zk = ZKProof(s, None, None, 0, None, c)
+        zk.d = [1, 0, 0, 1, 1, 0, 1, 1, 1]
+        zk._generate_e()
+        e1 = zk.e
+        zk._generate_e()
+        self.assertEquals(e1, zk.e)
+
+    def _generate_test_ciphertexts(self, paillier, random, k, s):
+        xs, rs, cs = [], [], []
+        for i in range(s):
+            x = rand_int_signed(random, 2**k)
+            r, c = paillier.encrypt_r(x)
+            xs.append(x)
+            rs.append(r)
+            cs.append(c)
+        return xs, rs, cs
+            
+
+# TODO: Test succeeding proof.
+# TODO: Test failing proof.
+
+skip_if_missing_packages(BeDOZaZeroKnowledgeTest)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/viff/test/bedoza/util.py	Fri Sep 24 14:21:36 2010 +0200
@@ -0,0 +1,61 @@
+
+from viff.test.util import RuntimeTestCase
+from viff.config import generate_configs
+
+from viff.bedoza.bedoza import BeDOZaRuntime
+
+# HACK: The paillier keys that are available as standard in VIFF tests
+# are not suited for use with pypaillier. Hence, we use NaClPaillier
+# to generate test keys. This confusion will disappear when pypaillier
+# replaces the current Python-based paillier implementation.
+from viff.paillierutil import NaClPaillier
+
+# HACK^2: Currently, the NaClPaillier hack only works when triple is
+# imported. It should ideally work without the triple package.
+try:
+    import tripple
+except ImportError:
+    tripple = None
+
+# The PyPaillier and commitment packages are not standard parts of VIFF so we
+# skip them instead of letting them fail if the packages are not available. 
+try:
+    import pypaillier
+except ImportError:
+    pypaillier = None
+
+
+
+def log(rt, msg):
+    print "player%d ------> %s" % (rt.id, msg)
+
+
+class BeDOZaTestCase(RuntimeTestCase):
+
+    runtime_class = BeDOZaRuntime
+
+    def setUp(self):
+        RuntimeTestCase.setUp(self)
+        self.security_parameter = 32
+
+    # TODO: During test, we would like generation of Paillier keys to
+    # be deterministic. How do we obtain that?
+    def generate_configs(self, *args):
+        # In production, paillier keys should be something like 2000
+        # bit. For test purposes, it is ok to use small keys.
+        # TODO: paillier freezes if key size is too small, e.g. 13.
+        return generate_configs(paillier=NaClPaillier(250), *args)
+
+
+def skip_if_missing_packages(*test_cases):
+    """Skipts the given list of test cases if some of the required
+    external viff packages (tripple, pypaillier) is not available.
+    """
+    missing = []
+    if not pypaillier:
+        missing.append("pypaillier")
+    if not tripple:
+        missing.append("tripple")
+    if missing:
+        for test_case in test_cases:
+            test_case.skip =  "Skipped due to missing packages: %s" % missing