changeset 1326:f933bd327750

viff: Merged with main tree.
author Marcel Keller <mkeller@cs.au.dk>
date Fri, 23 Oct 2009 13:50:19 +0200
parents 613aa672ba5e 51280703f0c9
children 75fbb52aea09
files apps/aes.py epydoc.conf viff/active.py viff/aes.py viff/field.py viff/passive.py viff/runtime.py viff/shamir.py viff/test/test_active_runtime.py
diffstat 42 files changed, 3441 insertions(+), 629 deletions(-) [+]
line wrap: on
line diff
--- a/MANIFEST.in	Thu Oct 22 19:38:31 2009 +0200
+++ b/MANIFEST.in	Fri Oct 23 13:50:19 2009 +0200
@@ -1,5 +1,4 @@
 graft doc/api
-exclude epydoc.conf
 
 graft doc/html
 prune doc/html/.doctrees
--- a/apps/aes.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/apps/aes.py	Fri Oct 23 13:50:19 2009 +0200
@@ -111,7 +111,7 @@
 
     for i in range(options.keylength / 8):
         inputter = i % 3 + 1
-        if (inputter == id):
+        if inputter == id:
             key.append(rt.input([inputter], GF256, ord("b")))
         else:
             key.append(rt.input([inputter], GF256))
@@ -125,36 +125,34 @@
 
     if options.active:
         if options.exponentiation is False:
-            max = 301
-            js = [3 + i * 15 + j for i in range(20) for j in range(7) + [8]]
-        elif options.exponentiation == 0:
-            max = 321
-            js = [2 + i * 16 + j for i in range(20) for j in range(13)]
+            max = 461
+            js = [3 + i * 23 + j for i in range(20)
+                  for j in range(0, 14, 2) + [15]]
+        elif options.exponentiation == 0 or options.exponentiation == 3:
+            max = 561
+            js = [1 + i * 28 + j * 2 for i in range(20) for j in range(13)]
         elif options.exponentiation == 1 or options.exponentiation == 2:
-            max = 261
-            js = [1 + i * 13 + j for i in range(20) for j in range(11)]
-        elif options.exponentiation == 3:
-            max = 301
-            js = [1 + i * 15 + j for i in range(20) for j in range(13)]
+            max = 481
+            js = [1 + i * 24 + j * 2 for i in range(20) for j in range(11)]
 
         if options.exponentiation == 4:
-            pcs = [(1, 2 + 130 * options.count + 141 * i + j, 1, 0)
+            pcs = [(2, 1 + i, 2 + 2 * j)
                    for i in range(10 * options.count)
                    for j in range(140)] + \
-                  [(2, 18, k) + (121,) * i + (4 + 6 * j, l, 1, 0)
+                  [(3, 17, k) + (121,) * i + (4 + 6 * j, 1 + 2 * l)
                    for k in range(1, options.count + 1)
                    for i in range(10)
                    for j in range(20)
-                   for l in range(1, 7)]
+                   for l in range(6)]
         else:
-            pcs = [(2, 18, k) + (max,) * i + (j, 1, 0)
+            pcs = [(2, 17, k) + (max,) * i + (j,)
                    for k in range(1, options.count + 1)
                    for i in range(10)
                    for j in js]
         program_desc[("generate_triples", (GF256,))] = pcs
 
     if options.exponentiation == 4:
-        pcs = [(2, 18, k) + (121,) * i + (1 + j * 6, 0)
+        pcs = [(3, 17, k) + (121,) * i + (1 + j * 6,)
                for k in range(1, options.count + 1)
                for i in range(10)
                for j in range(20)]
--- a/apps/benchmark.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/apps/benchmark.py	Fri Oct 23 13:50:19 2009 +0200
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 
-# Copyright 2007, 2008 VIFF Development Team.
+# Copyright 2007, 2008, 2009 VIFF Development Team.
 #
 # This file is part of VIFF, the Virtual Ideal Functionality Framework.
 #
@@ -57,55 +57,59 @@
 import time
 from math import log
 from optparse import OptionParser
-import operator
-from pprint import pformat
 
 import viff.reactor
 viff.reactor.install()
 from twisted.internet import reactor
 
-from viff.field import GF, GF256, FakeGF
-from viff.runtime import Runtime, create_runtime, gather_shares, \
-    make_runtime_class
+from viff.field import GF, FakeGF
+from viff.runtime import Runtime, create_runtime, make_runtime_class
 from viff.passive import PassiveRuntime
 from viff.active import BasicActiveRuntime, \
     TriplesHyperinvertibleMatricesMixin, TriplesPRSSMixin
 from viff.comparison import ComparisonToft05Mixin, ComparisonToft07Mixin
 from viff.equality import ProbabilisticEqualityMixin
 from viff.paillier import PaillierRuntime
+from viff.orlandi import OrlandiRuntime
 from viff.config import load_config
-from viff.util import find_prime, rand
+from viff.util import find_prime
+
+from benchmark_classes import SelfcontainedBenchmarkStrategy, \
+    NeededDataBenchmarkStrategy, ParallelBenchmark, SequentialBenchmark, BinaryOperation, NullaryOperation
+
+# Hack in order to avoid Maximum recursion depth exceeded
+# exception;
+sys.setrecursionlimit(5000)
+
 
 last_timestamp = time.time()
-start = 0
 
+operations = {"mul"       : ("mul", [], BinaryOperation),
+              "compToft05": ("ge", [ComparisonToft05Mixin], BinaryOperation),
+              "compToft07": ("ge", [ComparisonToft07Mixin], BinaryOperation),
+              "eq"        : ("eq", [ProbabilisticEqualityMixin], BinaryOperation),
+              "triple_gen": ("triple_gen", [], NullaryOperation)}
 
-def record_start(what):
-    global start
-    start = time.time()
-    print "*" * 64
-    print "Started", what
+runtimes = {"PassiveRuntime": PassiveRuntime,
+            "PaillierRuntime": PaillierRuntime,
+            "BasicActiveRuntime": BasicActiveRuntime,
+            "OrlandiRuntime": OrlandiRuntime}
 
-
-def record_stop(_, what):
-    stop = time.time()
-    print
-    print "Total time used: %.3f sec" % (stop-start)
-    print "Time per %s operation: %.0f ms" % (what, 1000*(stop-start) / count)
-    print "*" * 6
-
-
-operations = ["mul", "compToft05", "compToft07", "eq"]
+mixins = {"TriplesHyperinvertibleMatricesMixin" : TriplesHyperinvertibleMatricesMixin,
+          "TriplesPRSSMixin": TriplesPRSSMixin,
+          "ComparisonToft05Mixin": ComparisonToft05Mixin,
+          "ComparisonToft07Mixin": ComparisonToft07Mixin,
+          "ProbabilisticEqualityMixin": ProbabilisticEqualityMixin}
 
 parser = OptionParser(usage="Usage: %prog [options] config_file")
 parser.add_option("-m", "--modulus",
                   help="lower limit for modulus (can be an expression)")
-parser.add_option("-a", "--active", action="store_true",
-                  help="use actively secure runtime")
-parser.add_option("--passive", action="store_false", dest="active",
-                  help="use passively secure runtime")
-parser.add_option("-2", "--twoplayer", action="store_true",
-                  help="use twoplayer runtime")
+parser.add_option("-r", "--runtime", type="choice", choices=runtimes.keys(),
+                  help="the name of the basic runtime to test")
+parser.add_option("-n", "--num_players", action="store_true", dest="num_players",
+                  help="number of players")
+parser.add_option("--mixins", type="string",
+                  help="Additional mixins which must be added to the runtime")
 parser.add_option("--prss", action="store_true",
                   help="use PRSS for preprocessing")
 parser.add_option("--hyper", action="store_false", dest="prss",
@@ -114,7 +118,7 @@
                   help="corruption threshold")
 parser.add_option("-c", "--count", type="int",
                   help="number of operations")
-parser.add_option("-o", "--operation", type="choice", choices=operations,
+parser.add_option("-o", "--operation", type="choice", choices=operations.keys(),
                   help="operation to benchmark")
 parser.add_option("-p", "--parallel", action="store_true",
                   help="execute operations in parallel")
@@ -122,17 +126,33 @@
                   help="execute operations in sequence")
 parser.add_option("-f", "--fake", action="store_true",
                   help="skip local computations using fake field elements")
+parser.add_option("--args", type="string",
+                  help=("additional arguments to the runtime, the format is "
+                        "a comma separated list of id=value pairs e.g. "
+                        "--args s=1,d=0,lambda=1"))
+parser.add_option("--needed_data", type="string",
+                  help=("name of a file containing already computed "
+                        "dictionary of needed_data. Useful for skipping "
+                        "generating the needed data, which usually "
+                        "elliminates half the execution time. Format of file: "
+                        "\"{('random_triple', (Zp,)): [(3, 1), (3, 4)]}\""))
+parser.add_option("--pc", type="string",
+                  help=("The program counter to start from when using "
+                        "explicitly provided needed_data. Format: [3,0]"))
 
 parser.set_defaults(modulus=2**65, threshold=1, count=10,
-                    active=False, twoplayer=False, prss=True,
-                    operation=operations[0], parallel=True, fake=False)
+                    runtime="PassiveRuntime", mixins="", num_players=2, prss=True,
+                    operation="mul", parallel=True, fake=False,
+                    args="", needed_data="")
+
+print "*" * 60
 
 # Add standard VIFF options.
 Runtime.add_options(parser)
 
 (options, args) = parser.parse_args()
 
-if len(args) == 0:
+if not args:
     parser.error("you must specify a config file")
 
 id, players = load_config(args[0])
@@ -146,189 +166,76 @@
 else:
     Field = GF
 
+
 Zp = Field(find_prime(options.modulus))
 print "Using field elements (%d bit modulus)" % log(Zp.modulus, 2)
 
+
 count = options.count
 print "I am player %d, will %s %d numbers" % (id, options.operation, count)
 
-# Defining the protocol as a class makes it easier to write the
-# callbacks in the order they are called. This class is a base class
-# that executes the protocol by calling the run_test method.
-class Benchmark:
 
-    def __init__(self, rt, operation):
-        self.rt = rt
-        self.operation = operation
-        self.sync_preprocess()
+# Identify the base runtime class.
+base_runtime_class = runtimes[options.runtime]
 
-    def sync_preprocess(self):
-        print "Synchronizing preprocessing"
-        sys.stdout.flush()
-        sync = self.rt.synchronize()
-        self.rt.schedule_callback(sync, self.preprocess)
+# Identify the additional mixins.
+actual_mixins = []
+if options.mixins:
+    actual_mixins = [mixins[mixin] for mixin in options.mixins.split(',')]
 
-    def preprocess(self, _):
-        program_desc = {}
 
-        if isinstance(self.rt, BasicActiveRuntime):
-            # TODO: Make this optional and maybe automatic. The
-            # program descriptions below were found by carefully
-            # studying the output reported when the benchmarks were
-            # run with no preprocessing. So they are quite brittle.
-            if self.operation == operator.mul:
-                key = ("generate_triples", (Zp,))
-                desc = [(i, 1, 0) for i in range(3, 3 + count)]
-                program_desc.setdefault(key, []).extend(desc)
-            elif isinstance(self.rt, ComparisonToft05Mixin):
-                key = ("generate_triples", (GF256,))
-                desc = sum([[(c, 64, i, 1, 1, 0) for i in range(2, 33)] +
-                            [(c, 64, i, 3, 1, 0) for i in range(17, 33)]
-                            for c in range(3 + 2*count, 3 + 3*count)],
-                           [])
-                program_desc.setdefault(key, []).extend(desc)
-            elif isinstance(self.rt, ComparisonToft07Mixin):
-                key = ("generate_triples", (Zp,))
-                desc = sum([[(c, 2, 4, i, 2, 1, 0) for i in range(1, 33)] +
-                            [(c, 2, 4, 99, 2, 1, 0)] +
-                            [(c, 2, 4, i, 1, 0) for i in range(65, 98)]
-                            for c in range(3 + 2*count, 3 + 3*count)],
-                           [])
-                program_desc.setdefault(key, []).extend(desc)
-
-        if program_desc:
-            print "Starting preprocessing"
-            record_start("preprocessing")
-            preproc = self.rt.preprocess(program_desc)
-            preproc.addCallback(record_stop, "preprocessing")
-            self.rt.schedule_callback(preproc, self.begin)
-        else:
-            print "Need no preprocessing"
-            self.begin(None)
-
-    def begin(self, _):
-        print "Runtime ready, generating shares"
-        self.a_shares = []
-        self.b_shares = []
-        for i in range(count):
-            inputter = (i % len(self.rt.players)) + 1
-            if inputter == self.rt.id:
-                a = rand.randint(0, Zp.modulus)
-                b = rand.randint(0, Zp.modulus)
-            else:
-                a, b = None, None
-            self.a_shares.append(self.rt.input([inputter], Zp, a))
-            self.b_shares.append(self.rt.input([inputter], Zp, b))
-        shares_ready = gather_shares(self.a_shares + self.b_shares)
-        self.rt.schedule_callback(shares_ready, self.sync_test)
-
-    def sync_test(self, _):
-        print "Synchronizing test start."
-        sys.stdout.flush()
-        sync = self.rt.synchronize()
-        self.rt.schedule_callback(sync, self.countdown, 3)
-
-    def countdown(self, _, seconds):
-        if seconds > 0:
-            print "Starting test in %d" % seconds
-            sys.stdout.flush()
-            reactor.callLater(1, self.countdown, None, seconds - 1)
-        else:
-            print "Starting test now"
-            sys.stdout.flush()
-            self.run_test(None)
-
-    def run_test(self, _):
-        raise NotImplemented("Override this abstract method in a sub class.")
-
-    def finished(self, _):
-        sys.stdout.flush()
-
-        if self.rt._needed_data:
-            print "Missing pre-processed data:"
-            for (func, args), pcs in self.rt._needed_data.iteritems():
-                print "* %s%s:" % (func, args)
-                print "  " + pformat(pcs).replace("\n", "\n  ")
-
-        self.rt.shutdown()
-
-# This class implements a benchmark where run_test executes all
-# operations in parallel.
-class ParallelBenchmark(Benchmark):
-
-    def run_test(self, _):
-        c_shares = []
-        record_start("parallel test")
-        while self.a_shares and self.b_shares:
-            a = self.a_shares.pop()
-            b = self.b_shares.pop()
-            c_shares.append(self.operation(a, b))
-
-        done = gather_shares(c_shares)
-        done.addCallback(record_stop, "parallel test")
-        self.rt.schedule_callback(done, self.finished)
-
-# A benchmark where the operations are executed one after each other.
-class SequentialBenchmark(Benchmark):
-
-    def run_test(self, _):
-        record_start("sequential test")
-        self.single_operation(None)
-
-    def single_operation(self, _):
-        if self.a_shares and self.b_shares:
-            a = self.a_shares.pop()
-            b = self.b_shares.pop()
-            c = self.operation(a, b)
-            self.rt.schedule_callback(c, self.single_operation)
-        else:
-            record_stop(None, "sequential test")
-            self.finished(None)
-
-mixins = []
-if options.twoplayer:
-    # Then there is just one possible runtime:
-    operation = operator.mul
-    base_runtime_class = PaillierRuntime
-else:
-    # There are several options for a multiplayer runtime:
-    if options.active:
-        base_runtime_class = BasicActiveRuntime
-        if options.prss:
-            mixins.append(TriplesPRSSMixin)
-        else:
-            mixins.append(TriplesHyperinvertibleMatricesMixin)
-    else:
-        base_runtime_class = PassiveRuntime
-
-    if options.operation == "mul":
-        operation = operator.mul
-    elif options.operation == "compToft05":
-        operation = operator.ge
-        mixins.append(ComparisonToft05Mixin)
-    elif options.operation == "compToft07":
-        operation = operator.ge
-        mixins.append(ComparisonToft07Mixin)
-    elif options.operation == "eq":
-        operation = operator.eq
-        mixins.append(ProbabilisticEqualityMixin)
+# Identify the operation and it mixin dependencies.
+operation = operations[options.operation][0]
+actual_mixins += operations[options.operation][1]
+operation_arity = operations[options.operation][2]
 
 print "Using the base runtime: %s." % base_runtime_class
-if mixins:
+if actual_mixins:
     print "With the following mixins:"
-    for mixin in mixins:
-        print "- %s" % mixin
+    for mixin in actual_mixins:
+        print "- %s" % mixin.__name__
 
-runtime_class = make_runtime_class(base_runtime_class, mixins)
+runtime_class = make_runtime_class(base_runtime_class, actual_mixins)
+
+pre_runtime = create_runtime(id, players, options.threshold,
+                             options, runtime_class)
+
+def update_args(runtime, options):
+    args = {}
+    if options.args:
+        for arg in options.args.split(','):
+            id, value = arg.split('=')
+            args[id] = long(value)
+        runtime.set_args(args)
+    return runtime
+
+
+pre_runtime.addCallback(update_args, options)
 
 if options.parallel:
     benchmark = ParallelBenchmark
 else:
     benchmark = SequentialBenchmark
 
-pre_runtime = create_runtime(id, players, options.threshold,
-                             options, runtime_class)
-pre_runtime.addCallback(benchmark, operation)
+needed_data = ""
+if options.needed_data:
+    needed_data = eval(open(options.needed_data).read())
+
+if options.needed_data and options.pc:
+    bases = (benchmark, NeededDataBenchmarkStrategy, operation_arity, object)
+    options.pc = eval(options.pc)
+else:
+    bases = (benchmark, SelfcontainedBenchmarkStrategy, operation_arity, object)
+
+print "Using the Benchmark bases:"
+for b in bases:
+    print "- %s" % b.__name__
+benchmark = type("ExtendedBenchmark", bases, {})
+
+def do_benchmark(runtime, operation, benchmark, field, count, *args):
+    benchmark(runtime, operation, field, count).benchmark(*args)
+
+pre_runtime.addCallback(do_benchmark, operation, benchmark, Zp, count, needed_data, options.pc)
 
 print "#### Starting reactor ###"
 reactor.run()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/benchmark_classes.py	Fri Oct 23 13:50:19 2009 +0200
@@ -0,0 +1,247 @@
+# Copyright 2009 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/>.
+
+import sys
+import time
+
+from pprint import pformat
+
+from twisted.internet.defer import gatherResults
+
+from viff.runtime import gather_shares
+from viff.util import rand
+
+start = 0
+
+
+def record_start(what):
+    global start
+    start = time.time()
+    print "*" * 64
+    print "Started", what
+
+
+def record_stop(x, what, count):
+    stop = time.time()
+    print
+    print "Total time used: %.3f sec" % (stop-start)
+    print "Time per %s operation: %.0f ms" % (what, 1000*(stop-start) / count)
+    print "*" * 6
+    return x
+
+
+class Benchmark(object):
+    """Abstract base class for all Benchmarks.
+
+    For concrete classes see the `ParallelBenchmark` and
+    `SequentialBenchmark` classes. A concrete class must be mixed with
+    a `BenchmarkStrategy` and an `Operator`.
+    """
+
+    def __init__(self, rt, operation, field, count):
+        self.rt = rt
+        self.operation = getattr(rt, operation)
+        self.pc = None
+        self.field = field
+        self.count = count
+
+    def preprocess(self, needed_data):
+        print "Preprocess", needed_data
+        if needed_data:
+            print "Starting preprocessing"
+            record_start("preprocessing")
+            preproc = self.rt.preprocess(needed_data)
+            preproc.addCallback(record_stop, "preprocessing", self.count)
+            return preproc
+        else:
+            print "Need no preprocessing"
+            return None
+
+    def test(self, d, termination_function):
+        self.rt.schedule_callback(d, self.generate_operation_arguments)
+        self.rt.schedule_callback(d, self.sync_test)
+        self.rt.schedule_callback(d, self.run_test)
+        self.rt.schedule_callback(d, self.sync_test)
+        self.rt.schedule_callback(d, self.finished, termination_function)
+        return d
+
+    def sync_test(self, x):
+        print "Synchronizing test start."
+        sys.stdout.flush()
+        sync = self.rt.synchronize()
+        self.rt.schedule_callback(sync, lambda y: x)
+        return sync
+
+    def run_test(self, _):
+        raise NotImplementedError
+
+    def finished(self, needed_data, termination_function):
+        sys.stdout.flush()
+
+        if self.rt._needed_data:
+            print "Missing pre-processed data:"
+            for (func, args), pcs in needed_data.iteritems():
+                print "* %s%s:" % (func, args)
+                print "  " + pformat(pcs).replace("\n", "\n  ")
+
+        return termination_function(needed_data)
+
+
+class ParallelBenchmark(Benchmark):
+    """This class implements a benchmark where run_test executes all
+    operations in parallel."""
+
+    def run_test(self, shares):
+        print "rt", self.rt.program_counter, self.pc
+        if self.pc != None:
+            self.rt.program_counter = self.pc
+        else:
+            self.pc = list(self.rt.program_counter)
+        c_shares = []
+        record_start("parallel test")
+        while not self.is_operation_done():
+            c_shares.append(self.do_operation())
+
+        done = gatherResults(c_shares)
+        done.addCallback(record_stop, "parallel test", self.count)
+        def f(x):
+            needed_data = self.rt._needed_data
+            self.rt._needed_data = {}
+            return needed_data
+        done.addCallback(f)
+        return done
+
+
+class SequentialBenchmark(Benchmark):
+    """A benchmark where the operations are executed one after each
+    other."""
+
+    def run_test(self, _, termination_function, d):
+        record_start("sequential test")
+        self.single_operation(None, termination_function)
+
+    def single_operation(self, _, termination_function):
+        if not self.is_operation_done():
+            c = self.do_operation()
+            self.rt.schedule_callback(c, self.single_operation, termination_function)
+        else:
+            record_stop(None, "sequential test", self.count)
+            self.finished(None, termination_function)
+
+
+class Operation(object):
+    """An abstract mixin which encapsulate the behaviour of an operation.
+
+    An operation can be nullary, unary, binary, etc.
+    """
+
+    def generate_operation_arguments(self, _):
+        """Generate the input need for performing the operation.
+
+        Returns: None.
+        """
+        raise NotImplementedError
+
+    def is_operation_done(self):
+        """Returns true if there are no more operations to perform.
+        Used in sequential tests.
+
+        Returns: Boolean.
+        """
+        raise NotImplementedError
+
+    def do_operation(self):
+        """Perform the operation.
+
+        Returns: A share containing the result of the operation.
+        """
+        raise NotImplementedError
+
+class BinaryOperation(Operation):
+    """A binary operation."""
+
+    def generate_operation_arguments(self, _):
+        print "Generate operation arguments", self.rt.program_counter
+        print "Runtime ready, generating shares"
+        self.a_shares = []
+        self.b_shares = []
+        for i in range(self.count):
+            inputter = (i % len(self.rt.players)) + 1
+            if inputter == self.rt.id:
+                a = rand.randint(0, self.field.modulus)
+                b = rand.randint(0, self.field.modulus)
+            else:
+                a, b = None, None
+            self.a_shares.append(self.rt.input([inputter], self.field, a))
+            self.b_shares.append(self.rt.input([inputter], self.field, b))
+        shares_ready = gather_shares(self.a_shares + self.b_shares)
+        return shares_ready
+
+    def is_operation_done(self):
+        return not (self.a_shares and self.b_shares)
+
+    def do_operation(self):
+        a = self.a_shares.pop()
+        b = self.b_shares.pop()
+        return self.operation(a, b)
+
+
+class NullaryOperation(Operation):
+    """A nullary operation."""
+
+    def generate_operation_arguments(self, _):
+        self.nullary_tests = self.count
+        return None
+
+    def is_operation_done(self):
+        return self.nullary_tests == 0
+
+    def do_operation(self):
+        self.nullary_tests -= 1
+        return self.operation(self.field)
+
+
+class BenchmarkStrategy(object):
+    """A benchmark strategy defines how the benchmark is done."""
+
+    def benchmark(self, *args):
+        raise NotImplementedError
+
+
+class SelfcontainedBenchmarkStrategy(BenchmarkStrategy):
+    """In a self contained benchmark strategy, all the needed data is
+    generated on the fly."""
+
+    def benchmark(self, *args):
+        sys.stdout.flush()
+        sync = self.rt.synchronize()
+        self.test(sync, lambda x: x)
+        self.rt.schedule_callback(sync, self.preprocess)
+        self.test(sync, lambda x: self.rt.shutdown())
+
+
+class NeededDataBenchmarkStrategy(BenchmarkStrategy):
+    """In a needed data benchmark strategy, all the needed data has to
+    have been generated before the test is run."""
+
+    def benchmark(self, needed_data, pc, *args):
+        self.pc = pc
+        sys.stdout.flush()
+        sync = self.rt.synchronize()
+        self.rt.schedule_callback(sync, lambda x: needed_data)
+        self.rt.schedule_callback(sync, self.preprocess)
+        self.test(sync, lambda x: self.rt.shutdown())
--- a/doc/active.txt	Thu Oct 22 19:38:31 2009 +0200
+++ b/doc/active.txt	Fri Oct 23 13:50:19 2009 +0200
@@ -1,6 +1,6 @@
 
-Actively Secure Protocols
-=========================
+A Thresholdbased Actively Secure Runtime
+========================================
 
 .. automodule:: viff.active
 
--- a/doc/authors.txt	Thu Oct 22 19:38:31 2009 +0200
+++ b/doc/authors.txt	Fri Oct 23 13:50:19 2009 +0200
@@ -15,6 +15,7 @@
 * Marcel Keller <mkeller@cs.au.dk>
 * Tord Reistad
 * Ivan Damgård
+* Janus Dam Nielsen <janus.nielsen@alexandra.dk>
 
 If you have been forgotten, then please checkout `the repository`_,
 add yourself to the list and `send us a patch`_!
--- a/doc/conf.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/doc/conf.py	Fri Oct 23 13:50:19 2009 +0200
@@ -63,7 +63,7 @@
 today_fmt = '%B %d, %Y'
 
 # List of documents that shouldn't be included in the build.
-unused_docs = ['api/api-objects'] # Generated by epydoc.
+unused_docs = []
 
 # If true, '()' will be appended to :func: etc. cross-reference text.
 #add_function_parentheses = True
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/constants.txt	Fri Oct 23 13:50:19 2009 +0200
@@ -0,0 +1,24 @@
+Constants Module
+================
+
+.. automodule:: viff.constants
+
+   .. attribute:: SHARE
+                  ECHO
+                  READY
+                  SEND
+                  PAILLIER
+                  TEXT
+
+      Constants used by :class:`ShareExchanger` and others when sending 
+      shares and other messages. They serve to distinguish messages sent 
+      with the same program counter from one another.
+
+   .. attribute::INCONSISTENTHASH
+                  OK
+                  HASH
+                  SIGNAL
+
+      Constants used by :class:`HashBroadcastMixin` when sending shares
+      and other messages. They serve to distinguish messages sent with
+      the same program counter from one another.
--- a/doc/development.txt	Thu Oct 22 19:38:31 2009 +0200
+++ b/doc/development.txt	Fri Oct 23 13:50:19 2009 +0200
@@ -21,7 +21,7 @@
 also work offline and take advantage of the many fast operations
 offered by Mercurial.
 
-.. _Mercurial: http://www.selenic.com/mercurial/
+.. _Mercurial: http://mercurial.selenic.com/
 
 After installing Mercurial you can checkout a copy of the source using
 this command line::
@@ -67,8 +67,7 @@
 your own address first to make sure everything looks okay. You can get
 the full list of options using ``hg help email``.
 
-.. _patchbomb: http://www.selenic.com/mercurial/
-                      wiki/index.cgi/PatchbombExtension
+.. _patchbomb: http://mercurial.selenic.com/wiki/PatchbombExtension
 
 The advantage of using patchbomb is that allows everybody to go over
 the code and comment on it before the changesets are pulled into the
@@ -77,6 +76,24 @@
 the changes into the repository, just as if the changesets had been
 pulled using ``hg pull``.
 
+Commit Messages
+"""""""""""""""
+
+Please format your commit messages as follows::
+
+   topic: terse one-line summary (60 characters max)
+
+   After the summary line, you're encouraged to provide a bigger
+   description of your changes. If your change is small or obvious
+   from the diff, you can leave this out.
+
+   Please wrap your paragraphs at ~70 characters or so. That ensures
+   that they are readily readable on a standard terminal.
+
+The *topic* in the summary line describes which part of the code the
+changeset touches. There's no fixed list of topics, but a change to
+``viff/X.py`` normally gets the "X" topic.
+
 
 Revising Changes
 ----------------
@@ -152,7 +169,7 @@
 fix any remaining conflicts.
 
 
-.. _Mercurial Queues extension: http://www.selenic.com/mercurial/
-                                       wiki/index.cgi/MqExtension
+.. _Mercurial Queues extension: http://mercurial.selenic.com/
+                                wiki/MqExtension
 
 .. LocalWords:  changeset changesets
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/hashbroadcast.txt	Fri Oct 23 13:50:19 2009 +0200
@@ -0,0 +1,12 @@
+
+An Hash Based Broadcast Protocol
+================================
+
+.. automodule:: viff.hash_broadcast
+
+   .. autoclass:: InconsistentHashException
+      :members:
+
+   .. autoclass:: HashBroadcastMixin
+      :members:
+
--- a/doc/implementation.txt	Thu Oct 22 19:38:31 2009 +0200
+++ b/doc/implementation.txt	Fri Oct 23 13:50:19 2009 +0200
@@ -13,9 +13,13 @@
    matrix
    runtime
    passive
-   active
+   active_runtimes
    paillier
    comparison
    prss
    config
    aes
+   constants
+   orlandi
+   hashbroadcast
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/orlandi.txt	Fri Oct 23 13:50:19 2009 +0200
@@ -0,0 +1,15 @@
+
+The Orlandi Runtime - An Actively Secure Protocol with Full Threshold
+=======================================================================
+
+.. automodule:: viff.orlandi
+
+   .. autoclass:: OrlandiException
+      :members:
+
+   .. autoclass:: OrlandiShare
+      :members:
+
+   .. autoclass:: OrlandiRuntime
+      :members:
+
--- a/doc/program-counters.txt	Thu Oct 22 19:38:31 2009 +0200
+++ b/doc/program-counters.txt	Fri Oct 23 13:50:19 2009 +0200
@@ -88,63 +88,41 @@
 point in the execution tree. The execution tree is never explicitly
 constructed in VIFF, so a simple static numbering is not possible.
 
-Instead we mark methods that need to increment the program counter
-with the :func:`viff.runtime.increment_pc` decorator. The program
-counter starts at the value ``[0]`` and the decorated method will now
-begin by doing::
+The program counter starts at the value ``[0]``. It is changed in two
+cases:
 
-  self.program_counter[-1] += 1
-  self.program_counter.append(0)
+* when a callback is scheduled using
+  :meth:`viff.runtime.BasicRuntime.schedule_callback`, a new
+  sub-program counter is allocated. A sub-program counter is simply a
+  program counter with another digit. Because of the asynchronous
+  network, the callback will be invoked at an unknown later time. When
+  invoked, it sees the sub-program counter. This ensures that that the
+  parties agree on any network traffic produced in the callback.
 
-before it executes its body. When the body is finished, the method
-does::
+  When a piece of code like this::
 
-  self.program_counter.pop()
+    def cb(ignored):
+        print "callback:", self.program_counter
+    d = Deferred()
 
-before it returns. A method :meth:`foo` defined like this::
+    print "main:", self.program_counter
+    self.schedule_callback(d, cb)
+    print "main:", self.program_counter
 
-  @increment_pc
-  def foo(self):
-      print "foo:", self.program_counter
+    d.callback(None)
 
-is thus turned into this::
+  is executed, one will see output like this:
 
-  def foo(self):
-      self.program_counter[-1] += 1
-      self.program_counter.append(0)
-      print "foo:", self.program_counter
-      self.program_counter.pop()
+  .. code-block:: none
 
-and when executed starting from the initial program counter of ``[0]``
-we see that it prints ``foo: [1, 0]`` and leaves the program counter
-at ``[1]`` after it returns. It is very important that the program
-counter is left changed like this, for this means that the next call
-to :meth:`foo` will print ``foo: [2, 0]`` and increment the program
-counter to ``[2]``.
+     main: [0]
+     main: [1]
+     callback: [0, 0]
 
-If we have a method :meth:`bar` which calls :meth:`foo` several times::
+* some functions depend on a unique program counter. These functions
+  simply increase the last digit in the current program counter::
 
-  @increment_pc
-  def bar(self):
-      print "bar:", self.program_counter
-      self.foo()
-      print "bar:", self.program_counter
-      self.foo()
-      print "bar:", self.program_counter
-
-then the result of calling :meth:`bar` will be:
-
-.. code-block:: none
-
-   bar: [1, 0]
-   foo: [1, 1, 0]
-   bar: [1, 1]
-   foo: [1, 2, 0]
-   bar: [1, 2]
-
-Notice how each sub-call adds another digit to the counter and how it
-increments the counter used at the level of the caller. This system
-ensures that all program counters are unique.
+    self.program_counter[-1] += 1
 
 
 Alternatives
--- a/doc/runtime.txt	Thu Oct 22 19:38:31 2009 +0200
+++ b/doc/runtime.txt	Fri Oct 23 13:50:19 2009 +0200
@@ -21,18 +21,6 @@
          or the data itself if data is received from the other player
          before we are ready to use it.
 
-   .. attribute:: SHARE
-                  ECHO
-                  READY
-                  SEND
-                  PAILLIER
-
-      Constants used by :class:`ShareExchanger` when sending shares
-      and other messages. They serve to distinguish messages sent with
-      the same program counter from one another.
-
-   .. autofunction:: increment_pc
-
    .. autofunction:: preprocess
 
       See also :ref:`preprocessing` for more background information.
@@ -88,9 +76,7 @@
          different parts of the program execution never reuses the
          same program counter for different variables.
 
-         The :func:`increment_pc` decorator is responsible for
-         dynamically building the tree as the execution unfolds and
-         :meth:`schedule_callback` is responsible for scheduling
-         callbacks with the correct program counter.
+         The :meth:`schedule_callback` method is responsible for
+         scheduling callbacks with the correct program counter.
 
          See :ref:`program-counters` for more background information.
--- a/doc/todo.txt	Thu Oct 22 19:38:31 2009 +0200
+++ b/doc/todo.txt	Fri Oct 23 13:50:19 2009 +0200
@@ -34,13 +34,6 @@
   make the other honest players crash too, thereby effectively halting
   the protocol.
 
-Self Trust
-----------
-
-Implement an (actively) secure protocol with threshold ``t = n-1``
-based on the "triples approach" of Claudio Orlandi and Jesper Buus
-Nielsen. There will soon be a paper describing the protocol.
-
 Covert Adversaries
 ------------------
 
--- a/doc/util.txt	Thu Oct 22 19:38:31 2009 +0200
+++ b/doc/util.txt	Fri Oct 23 13:50:19 2009 +0200
@@ -21,11 +21,6 @@
       :envvar:`VIFF_SEED` is defined, but empty, then no seed is used
       and a protocol run cannot be reproduced exactly.
 
-   .. envvar:: VIFF_NO_WRAP
-
-      Setting this environment variable to any value will turn
-      :func:`wrapper` into a no-op.
-
    .. envvar:: VIFF_PROFILE
 
       Defining this variable will change :func:`profile` from a no-op
--- a/epydoc.conf	Thu Oct 22 19:38:31 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-[epydoc]
-
-name: VIFF: Virtual Ideal Functionality Framework
-url: http://viff.dk/
-
-modules: viff
-exclude: test, libs
-
-output: html
-target: doc/api
-
-graph: classtree
-include-log: yes
-
-external-api: mod, func, data, const, class, exc, meth, attr, exc, file, envvar
--- a/run.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/run.py	Fri Oct 23 13:50:19 2009 +0200
@@ -105,11 +105,6 @@
         shutil.rmtree('doc/html')
     sphinx('doc/html')
 
-    # Generate API docs in doc/api.
-    if isdir('doc/api'):
-        shutil.rmtree('doc/api')
-    epydoc('doc/api')
-
     # Pack everything up with Distutils.
     execute(["python", "setup.py", "sdist", "--force-manifest",
              "--formats=bztar,gztar,zip"])
@@ -117,13 +112,6 @@
     # Generate binary Windows installer (which has no docs, though).
     execute(["python", "setup.py", "bdist", "--formats=wininst"])
 
-@command('epydoc', 'target')
-def epydoc(target):
-    """Generate API documentation using epydoc."""
-    ensure_dir(target)
-    execute(["epydoc", "-vv", "--config", "epydoc.conf"],
-            {'VIFF_NO_WRAP': 'YES', 'target': target})
-
 @command('sphinx', 'target')
 def sphinx(target):
     """Generate VIFF manual using Sphinx."""
--- a/viff/active.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/viff/active.py	Fri Oct 23 13:50:19 2009 +0200
@@ -15,9 +15,7 @@
 # You should have received a copy of the GNU Lesser General Public
 # License along with VIFF. If not, see <http://www.gnu.org/licenses/>.
 
-"""Actively secure protocols."""
-
-__docformat__ = "restructuredtext"
+"""A thresholdbased actively secure runtime."""
 
 from math import ceil
 
@@ -27,8 +25,8 @@
 from viff.util import rand
 from viff.matrix import Matrix, hyper
 from viff.passive import PassiveRuntime
-from viff.runtime import Share, increment_pc, preprocess, gather_shares
-from viff.runtime import ECHO, READY, SEND
+from viff.runtime import Share, preprocess, gather_shares
+from viff.constants import ECHO, READY, SEND
 
 
 class BrachaBroadcastMixin:
@@ -37,7 +35,6 @@
     broadcast.
     """
 
-    @increment_pc
     def _broadcast(self, sender, message=None):
         """Perform a Bracha broadcast.
 
@@ -47,6 +44,8 @@
         protocol" by G. Bracha in Proc. 3rd ACM Symposium on
         Principles of Distributed Computing, 1984, pages 154-162.
         """
+        # We need a unique program counter for each call.
+        self.increment_pc()
 
         result = Deferred()
         pc = tuple(self.program_counter)
@@ -141,7 +140,6 @@
 
         return result
 
-    @increment_pc
     def broadcast(self, senders, message=None):
         """Perform one or more Bracha broadcast(s).
 
@@ -186,7 +184,6 @@
     #: to :const:`None` here and update it as necessary.
     _hyper = None
 
-    @increment_pc
     def single_share_random(self, T, degree, field):
         """Share a random secret.
 
@@ -205,16 +202,8 @@
         si = rand.randint(0, field.modulus - 1)
 
         # Every player shares the random value with two thresholds.
-        shares = self.shamir_share(inputters, field, si, degree)
-
-        # Turn the shares into a column vector.
-        svec = Matrix([shares]).transpose()
-
-        # Apply the hyper-invertible matrix to svec1 and svec2.
-        rvec = (self._hyper * svec)
-
-        # Get back to normal lists of shares.
-        svec = svec.transpose().rows[0]
+        svec = self.shamir_share(inputters, field, si, degree)
+        rvec = self._hyper * Matrix([svec]).transpose()
         rvec = rvec.transpose().rows[0]
 
         def verify(shares):
@@ -259,7 +248,7 @@
                     else:
                         si.append(self._expect_share(peer_id, field))
                 result = gatherResults(si)
-                self.schedule_callback(result, verify)
+                result.addCallback(verify)
                 return result
             else:
                 # We cannot verify anything, so we just return the
@@ -273,7 +262,6 @@
         self.schedule_callback(result, exchange)
         return result
 
-    @increment_pc
     def double_share_random(self, T, d1, d2, field):
         """Double-share a random secret using two polynomials.
 
@@ -290,20 +278,14 @@
         si = rand.randint(0, field.modulus - 1)
 
         # Every player shares the random value with two thresholds.
-        d1_shares = self.shamir_share(inputters, field, si, d1)
-        d2_shares = self.shamir_share(inputters, field, si, d2)
-
-        # Turn the shares into a column vector.
-        svec1 = Matrix([d1_shares]).transpose()
-        svec2 = Matrix([d2_shares]).transpose()
+        svec1 = self.shamir_share(inputters, field, si, d1)
+        svec2 = self.shamir_share(inputters, field, si, d2)
 
         # Apply the hyper-invertible matrix to svec1 and svec2.
-        rvec1 = (self._hyper * svec1)
-        rvec2 = (self._hyper * svec2)
+        rvec1 = self._hyper * Matrix([svec1]).transpose()
+        rvec2 = self._hyper * Matrix([svec2]).transpose()
 
         # Get back to normal lists of shares.
-        svec1 = svec1.transpose().rows[0]
-        svec2 = svec2.transpose().rows[0]
         rvec1 = rvec1.transpose().rows[0]
         rvec2 = rvec2.transpose().rows[0]
 
@@ -362,7 +344,7 @@
                         si_1.append(self._expect_share(peer_id, field))
                         si_2.append(self._expect_share(peer_id, field))
                 result = gatherResults([gatherResults(si_1), gatherResults(si_2)])
-                self.schedule_callback(result, verify)
+                result.addCallback(verify)
                 return result
             else:
                 # We cannot verify anything, so we just return the
@@ -376,15 +358,13 @@
         self.schedule_callback(result, exchange)
         return result
 
-    @increment_pc
     @preprocess("generate_triples")
     def get_triple(self, field):
         # This is a waste, but this function is only called if there
         # are no pre-processed triples left.
-        return self.generate_triples(field, gather=False)[0]
+        return self.generate_triples(field, quantity=1, gather=False)[0]
 
-    @increment_pc
-    def generate_triples(self, field, gather=True):
+    def generate_triples(self, field, quantity=None, gather=True):
         """Generate multiplication triples.
 
         These are random numbers *a*, *b*, and *c* such that ``c =
@@ -434,13 +414,11 @@
 class TriplesPRSSMixin:
     """Mixin class for generating multiplication triples using PRSS."""
 
-    @increment_pc
     @preprocess("generate_triples")
     def get_triple(self, field):
         result = self.generate_triples(field, quantity=1, gather=False)
         return result[0]
 
-    @increment_pc
     def generate_triples(self, field, quantity=20, gather=True):
         """Generate *quantity* multiplication triples using PRSS.
 
@@ -450,6 +428,8 @@
         Returns a tuple with the number of triples generated and a
         Deferred which will yield a singleton-list with a 3-tuple.
         """
+        quantity = min(quantity, 20)
+
         a_t = self.prss_share_random_multi(field, quantity)
         b_t = self.prss_share_random_multi(field, quantity)
         r_t, r_2t = self.prss_double_share(field, quantity)
@@ -481,7 +461,9 @@
     :class:`ActiveRuntime` instead.
     """
 
-    @increment_pc
+    def get_triple(self, field):
+        raise NotImplementedError
+
     def mul(self, share_x, share_y):
         """Multiplication of shares.
 
@@ -523,7 +505,7 @@
         return result
 
 
-class ActiveRuntime(BasicActiveRuntime, TriplesPRSSMixin):
+class ActiveRuntime(TriplesPRSSMixin, BasicActiveRuntime):
     """Default mix of :class:`BasicActiveRuntime` and
     :class:`TriplesPRSSMixin`."""
     pass
--- a/viff/aes.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/viff/aes.py	Fri Oct 23 13:50:19 2009 +0200
@@ -17,14 +17,11 @@
 
 """MPC implementation of AES (Rijndael)."""
 
-__docformat__ = "restructuredtext"
-
-
 import time
 import operator
 
 from viff.field import GF256
-from viff.runtime import Share, gather_shares, increment_pc
+from viff.runtime import Share, gather_shares
 from viff.matrix import Matrix
 
 
@@ -36,15 +33,14 @@
 
     r_bits = share.runtime.prss_share_random_multi(GF256, 8, binary=True)
 
-    if (use_lin_comb):
+    if use_lin_comb:
         r = share.runtime.lin_comb([2 ** i for i in range(8)], r_bits)
     else:
-        r = reduce(lambda x,y: x + y, 
-                   [r_bits[i] * 2 ** i for i in range(8)])
+        r = sum([r_bits[i] * 2 ** i for i in range(8)])
 
     c = share.runtime.open(share + r)
     c_bits = [Share(share.runtime, GF256) for i in range(8)]
-    
+
     def decompose(byte, bits):
         value = byte.value
 
@@ -73,7 +69,7 @@
     In every case *ciphertext* will be a list of shares over GF256.
     """
 
-    def __init__(self, runtime, key_size, block_size=128, 
+    def __init__(self, runtime, key_size, block_size=128,
                  use_exponentiation=False, quiet=False):
         """Initialize Rijndael.
 
@@ -89,34 +85,33 @@
         self.n_b = block_size / 32
         self.rounds = max(self.n_k, self.n_b) + 6
         self.runtime = runtime
-        self.program_counter = runtime.program_counter
 
-        if (use_exponentiation is not False):
+        if use_exponentiation is not False:
             if (isinstance(use_exponentiation, int) and
                 use_exponentiation < len(AES.exponentiation_variants)):
                 use_exponentiation = \
                     AES.exponentiation_variants[use_exponentiation]
-            elif (use_exponentiation not in AES.exponentation_variants):
+            elif use_exponentiation not in AES.exponentation_variants:
                 use_exponentiation = "shortest_sequential_chain"
 
-            if (not quiet):
+            if not quiet:
                 print "Use %s for inversion by exponentiation." % \
                     use_exponentiation
 
-            if (use_exponentiation == "standard_square_and_multiply"):
+            if use_exponentiation == "standard_square_and_multiply":
                 self.invert = lambda byte: byte ** 254
-            elif (use_exponentiation == "shortest_chain_with_least_rounds"):
+            elif use_exponentiation == "shortest_chain_with_least_rounds":
                 self.invert = self.invert_by_exponentiation_with_less_rounds
-            elif (use_exponentiation == "chain_with_least_rounds"):
+            elif use_exponentiation == "chain_with_least_rounds":
                 self.invert = self.invert_by_exponentiation_with_least_rounds
-            elif (use_exponentiation == "masked"):
+            elif use_exponentiation == "masked":
                 self.invert = self.invert_by_masked_exponentiation
             else:
                 self.invert = self.invert_by_exponentiation
         else:
             self.invert = self.invert_by_masking
 
-            if (not quiet):
+            if not quiet:
                 print "Use inversion by masking."
 
     exponentiation_variants = ["standard_square_and_multiply",
@@ -132,7 +127,7 @@
             bits[j].addCallback(lambda x: 1 - x)
 #            bits[j] = 1 - bits[j]
 
-        while(len(bits) > 1):
+        while len(bits) > 1:
             bits.append(bits.pop(0) * bits.pop(0))
 
         # b == 1 if byte is 0, b == 0 else
@@ -142,7 +137,7 @@
         c = Share(self.runtime, GF256)
 
         def get_masked_byte(c_opened, r_related, c, r, byte):
-            if (c_opened == 0):
+            if c_opened == 0:
                 r_trial = self.runtime.prss_share_random(GF256)
                 c_trial = self.runtime.open((byte + b) * r_trial)
                 self.runtime.schedule_callback(c_trial, get_masked_byte,
@@ -241,11 +236,11 @@
 
         for h in range(len(state)):
             row = state[h]
-            
+
             for i in range(len(row)):
                 bits = bit_decompose(self.invert(row[i]))
 
-                if (use_lin_comb):
+                if use_lin_comb:
                     row[i] = self.runtime.lin_comb(sum(AES.A.rows, []),
                                                    bits * len(AES.A.rows))
                 else:
@@ -287,7 +282,7 @@
 
         assert len(state) == 4, "Wrong state size."
 
-        if (use_lin_comb):
+        if use_lin_comb:
             columns = zip(*state)
 
             for i, row in enumerate(state):
@@ -325,11 +320,11 @@
         for i in xrange(len(key), self.n_b * (new_length + 1)):
             temp = list(expanded_key[i - 1])
 
-            if (i % self.n_k == 0):
+            if i % self.n_k == 0:
                 temp.append(temp.pop(0))
                 self.byte_sub([temp])
                 temp[0] += GF256(2) ** (i / self.n_k - 1)
-            elif (self.n_k > 6 and i % self.n_k == 4):
+            elif self.n_k > 6 and i % self.n_k == 4:
                 self.byte_sub([temp])
 
             new_word = []
@@ -342,8 +337,8 @@
         return expanded_key
 
     def preprocess(self, input):
-        if (isinstance(input, str)):
-            return [Share(self.runtime, GF256, GF256(ord(c))) 
+        if isinstance(input, str):
+            return [Share(self.runtime, GF256, GF256(ord(c)))
                     for c in input]
         else:
             for byte in input:
@@ -352,14 +347,15 @@
                     "or of shares thereof."
             return input
 
-    @increment_pc
     def encrypt(self, cleartext, key, benchmark=False, prepare_at_once=False):
         """Rijndael encryption.
 
-        Cleartext and key should be either a string or a list of bytes 
+        Cleartext and key should be either a string or a list of bytes
         (possibly shared as elements of GF256)."""
 
         start = time.time()
+        self.runtime.increment_pc()
+        self.runtime.fork_pc()
 
         assert len(cleartext) == 4 * self.n_b, "Wrong length of cleartext."
         assert len(key) == 4 * self.n_k, "Wrong length of key."
@@ -370,7 +366,7 @@
         state = [cleartext[i::4] for i in xrange(4)]
         key = [key[4*i:4*i+4] for i in xrange(self.n_k)]
 
-        if (benchmark):
+        if benchmark:
             global preparation, communication
             preparation = 0
             communication = 0
@@ -411,11 +407,11 @@
             self.mix_column(state)
             self.add_round_key(state, expanded_key[i*self.n_b:(i+1)*self.n_b])
 
-            if (not prepare_at_once):
+            if not prepare_at_once:
                 trigger = get_trigger(state)
                 trigger.addCallback(progress, i, time.time())
 
-                if (i < self.rounds - 1):
+                if i < self.rounds - 1:
                     self.runtime.schedule_complex_callback(trigger, round, state, i + 1)
                 else:
                     self.runtime.schedule_complex_callback(trigger, final_round, state)
@@ -436,7 +432,7 @@
             trigger = get_trigger(state)
             trigger.addCallback(progress, self.rounds, time.time())
 
-            if (benchmark):
+            if benchmark:
                 trigger.addCallback(finish, state)
 
             # connect to final result
@@ -455,7 +451,7 @@
 
         result = [Share(self.runtime, GF256) for i in xrange(4 * self.n_b)]
 
-        if (prepare_at_once):
+        if prepare_at_once:
             for i in range(1, self.rounds):
                 round(None, state, i)
 
@@ -463,4 +459,5 @@
         else:
             round(None, state, 1)
 
+        self.runtime.unfork_pc()
         return result
--- a/viff/comparison.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/viff/comparison.py	Fri Oct 23 13:50:19 2009 +0200
@@ -20,12 +20,10 @@
 <viff.runtime.Runtime>` they are mixed with.
 """
 
-__docformat__ = "restructuredtext"
-
 import math
 
 from viff.util import rand, profile
-from viff.runtime import Share, gather_shares, increment_pc
+from viff.runtime import Share, gather_shares
 from viff.passive import PassiveRuntime
 from viff.active import ActiveRuntime
 from viff.field import GF256, FieldElement
@@ -34,7 +32,6 @@
 class ComparisonToft05Mixin:
     """Comparison by Tomas Toft, 2005."""
 
-    @increment_pc
     def convert_bit_share(self, share, dst_field):
         """Convert a 0/1 share into dst_field."""
         bit = rand.randint(0, 1)
@@ -67,7 +64,6 @@
         return int_b, bit_bits
 
     @profile
-    @increment_pc
     def greater_than_equal(self, share_a, share_b):
         """Compute ``share_a >= share_b``.
 
@@ -100,7 +96,6 @@
         self.schedule_callback(result, self._finish_greater_than_equal, l)
         return result
 
-    @increment_pc
     def _finish_greater_than_equal(self, results, l):
         """Finish the calculation."""
         T = results[0]
@@ -128,7 +123,6 @@
 
         return GF256(T.bit(l)) ^ (bit_bits[l] ^ vec[0][1])
 
-    @increment_pc
     def _diamond(self, (top_a, bot_a), (top_b, bot_b)):
         """The "diamond-operator".
 
@@ -160,7 +154,6 @@
     elements and gives a secret result shared over Zp.
     """
 
-    @increment_pc
     def convert_bit_share(self, share, dst_field):
         """Convert a 0/1 share into *dst_field*."""
         l = self.options.security_parameter + math.log(dst_field.modulus, 2)
@@ -188,7 +181,6 @@
         return tmp - full_mask
 
     @profile
-    @increment_pc
     def greater_than_equal_preproc(self, field, smallField=None):
         """Preprocessing for :meth:`greater_than_equal`."""
         if smallField is None:
@@ -243,7 +235,6 @@
         ##################################################
 
     @profile
-    @increment_pc
     def greater_than_equal_online(self, share_a, share_b, preproc, field):
         """Compute ``share_a >= share_b``. Result is secret shared."""
         # increment l as a, b are increased
@@ -272,7 +263,6 @@
                                r_modl, r_bits, z)
         return c
 
-    @increment_pc
     def _finish_greater_than_equal(self, c, field, smallField, s_bit, s_sign,
                                mask, r_modl, r_bits, z):
         """Finish the calculation."""
@@ -316,7 +306,6 @@
         return (z - result) * ~field(2**l)
     # END _finish_greater_than
 
-    @increment_pc
     def greater_than_equal(self, share_a, share_b):
         """Compute ``share_a >= share_b``.
 
--- a/viff/config.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/viff/config.py	Fri Oct 23 13:50:19 2009 +0200
@@ -29,8 +29,6 @@
 :func:`load_config` function.
 """
 
-__docformat__ = "restructuredtext"
-
 from viff.libs.configobj import ConfigObj
 from viff.prss import generate_subsets, PRF
 from viff.util import rand
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/viff/constants.py	Fri Oct 23 13:50:19 2009 +0200
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright 2009 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/>.
+
+# Constants used for communication.
+SHARE    = 0
+ECHO     = 1
+READY    = 2
+SEND     = 3
+PAILLIER = 4
+TEXT     = 5
+
+# Used by the HashBroadcastMixin
+INCONSISTENTHASH = 6
+OK               = 7
+HASH             = 8
+SIGNAL           = 9
--- a/viff/equality.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/viff/equality.py	Fri Oct 23 13:50:19 2009 +0200
@@ -20,13 +20,10 @@
 is mixed with.
 """
 
-from viff.runtime import increment_pc
-
 class ProbabilisticEqualityMixin:
     """This class implements probabilistic constant-round secure
     equality-testing of secret shared numbers."""
 
-    @increment_pc
     def equal(self, share_x, share_y):
         """Equality testing with secret shared result.
 
--- a/viff/field.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/viff/field.py	Fri Oct 23 13:50:19 2009 +0200
@@ -75,9 +75,6 @@
 ``z`` are instances of two *different* classes called ``GFElement``.
 """
 
-__docformat__ = "restructuredtext"
-
-
 from gmpy import mpz
 from math import log, ceil
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/viff/hash_broadcast.py	Fri Oct 23 13:50:19 2009 +0200
@@ -0,0 +1,173 @@
+#!/usr/bin/env python
+
+# Copyright 2009 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/>.
+
+from twisted.internet.defer import Deferred
+
+try:
+    from hashlib import sha1
+except ImportError:
+    from sha import sha as sha1
+from viff.constants import TEXT, INCONSISTENTHASH, OK, HASH, SIGNAL
+
+error_msg = "Player %i, has received an inconsistent hash %s."
+
+class InconsistentHashException(Exception):
+    pass
+
+class HashBroadcastMixin:
+    """A non-consistent broadcast scheme mainly useful for full threshold security.
+
+    A value is send using `send_value` and when received a hash is generated and
+    exchanged among the receivers. If a receiver receives a hash which is not equal
+    to the one he generated, then he sends an error signal to the others and 
+    they stop the computation. Else he sends an ok signal and the computation continues."""
+
+    def _send_message(self, pc, sender, receivers, message):
+        for peer_id in receivers:
+            self.protocols[peer_id].sendData(pc, TEXT, message)
+
+    def _receive_broadcast(self, pc, unique_pc, sender, receivers):
+        # The result.
+        result = Deferred()
+        # The message store.
+        message = []
+        # The hash store
+        g_hashes = {}
+        # The signal store
+        signals = {}
+
+        def signal_received(signal, peer_id, message, num_receivers, hashes, signals):
+            # Store the signal.
+            signals[peer_id] = long(signal)
+            # If all signals are received then check if they are OK or INCONSISTENTHASH.
+            if num_receivers == len(signals.keys()):
+                s = reduce(lambda x, y: (OK == y and OK) or INCONSISTENTHASH, signals.values())
+                if OK == s:
+                    # Make the result ready.
+                    result.callback(message[0])
+                else:
+                    raise InconsistentHashException(error_msg % (self.id, hashes))
+
+        def hash_received(h, unique_pc, peer_id, receivers, a_hashes):
+            # Store the hash.
+            a_hashes[peer_id] = h
+            # If we have received a hash from everybody, then compute the signal and send it.
+            if len(receivers) == len(a_hashes.keys()):
+                signal = OK
+                # First we check if the hashes we received are equal to the hash we computed ourselves.
+                for peer_id in receivers:
+                    if a_hashes[peer_id] == a_hashes[self.id]:
+                        signal = signal
+                    else:
+                        signal = INCONSISTENTHASH
+                # Then we send the SAME signal to everybody. 
+                for peer_id in receivers:
+                    self.protocols[peer_id].sendData(unique_pc, SIGNAL, str(signal))           
+            # The return value does not matter.
+            return None
+
+        def message_received(m, unique_pc, message, receivers, hashes):
+            # Store the message.
+            message.append(m)
+            # Compute hash of message.
+            h = sha1(m).hexdigest()
+            # Store hash.
+            hashes[self.id] = h
+            # Send the hash to all receivers.
+            for peer_id in receivers:
+                self.protocols[peer_id].sendData(unique_pc, HASH, str(h))
+
+        # Set up receivers for hashes and signals.
+        # Note, we use the unique_pc to avoid data to cross method invocation boundaries.
+        for peer_id in receivers:
+            d_hash = Deferred().addCallbacks(hash_received,
+                                             self.error_handler, 
+                                             callbackArgs=(unique_pc, peer_id, receivers, g_hashes))
+            self._expect_data_with_pc(unique_pc, peer_id, HASH, d_hash)
+            d_signal = Deferred().addCallbacks(signal_received, 
+                                               self.error_handler, 
+                                               callbackArgs=(peer_id, message, len(receivers), 
+                                                             g_hashes, signals))
+            self._expect_data_with_pc(unique_pc, peer_id, SIGNAL, d_signal)
+
+        # Set up receiving of the message.
+        d_message = Deferred().addCallbacks(message_received, 
+                                            self.error_handler, 
+                                            callbackArgs=(unique_pc, message, receivers, g_hashes))
+        self._expect_data(sender, TEXT, d_message)
+        return result
+
+
+    def broadcast(self, senders, receivers, message=None):
+        """Broadcast the messeage from senders to receivers.
+
+        Returns a list of deferreds if the calling player is among 
+        the receivers and there are multiple senders.
+        Returns a single element if there is only on sender, or the 
+        calling player is among the senders only.
+
+        The order of the resulting list is guaranteed to be the same order 
+        as the list of senders.
+
+        Senders and receivers should be lists containing the id of the senders 
+        and receivers, respectively.
+
+        Note: You send implicitly to your self."""
+        assert message is None or self.id in senders
+
+        self.program_counter[-1] += 1
+
+        pc = tuple(self.program_counter)
+        if self.id in receivers or self.id in senders:
+            results = [None] * len(senders)
+        else:
+            results = []
+
+        if self.id in senders:
+            self._send_message(pc, self.id, receivers, message)
+
+        if self.id in receivers:
+            for x in xrange(len(senders)):
+                sender = senders[x]
+                new_pc = list(self.program_counter)
+                new_pc.append(x)
+                results[x] = self._receive_broadcast(pc, tuple(new_pc), sender, receivers)
+
+        if self.id in senders and self.id not in receivers:
+            d = Deferred()
+            d.callback(message)
+            results = [d]
+
+        self.program_counter[-1] += 1
+
+        if len(results) == 1:
+            return results[0]
+
+        return results
+          
+    def list_str(self, s):
+        ls = []
+        for x in s[1:-1].split(','):
+            x = x.strip()
+            ls.append(str(x)[1:-1])
+        return ls
+
+    def error_handler(self, ex):
+        print "Error: ", ex
+        return ex
--- a/viff/matrix.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/viff/matrix.py	Fri Oct 23 13:50:19 2009 +0200
@@ -24,8 +24,6 @@
 
 from __future__ import division
 
-__docformat__ = "restructuredtext"
-
 class Matrix(object):
     """A matrix."""
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/viff/montgomery_exponentiation.py	Fri Oct 23 13:50:19 2009 +0200
@@ -0,0 +1,166 @@
+# Copyright 2009 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/>.
+
+
+def sizeinbits(a):
+    acc = 0
+    while a != 0:
+        acc += 1
+        a = a >> 1
+    return acc
+
+
+def calc_r(n):
+    """Compute r."""
+    n_size = sizeinbits(n)
+    r = 2**(n_size+1)
+
+    while gcd(r, n) != 1:
+        r = r << 1
+		
+    return r
+
+
+def calc_r_r_inv(n):
+    """Compute r and r inverse."""
+    assert (n % 2) == 1, "n must be odd."
+    n_size = sizeinbits(n)
+    r = 2**(n_size+1)
+
+    while gcd(r, n) != 1:
+        r = r << 1
+		
+    return r, inversemod(r, n)
+
+
+def calc_np(n, r):
+    """Compute n'."""
+    assert (n % 2) == 1, "n must be odd."
+    n_prime = inversemod(n, r)
+    return r - n_prime 
+
+
+def inversemod(a, n):
+    g, x, y = xgcd(a, n)
+    if g != 1:
+        raise ZeroDivisionError, (a,n)
+    assert g == 1, "a must be coprime to n."
+    return x%n
+
+
+def gcd(a, b):                                       
+    if a < 0:  a = -a
+    if b < 0:  b = -b
+    if a == 0: return b
+    if b == 0: return a
+    while b != 0: 
+        (a, b) = (b, a%b)
+    return a
+
+
+def xgcd(a, b):
+    if a == 0 and b == 0: return (0, 0, 1)
+    if a == 0: return (abs(b), 0, b/abs(b))
+    if b == 0: return (abs(a), a/abs(a), 0)
+    x_sign = 1; y_sign = 1
+    if a < 0: a = -a; x_sign = -1
+    if b < 0: b = -b; y_sign = -1
+    x = 1; y = 0; r = 0; s = 1
+    while b != 0:
+        (c, q) = (a%b, a/b)
+        (a, b, r, s, x, y) = (b, c, x-q*r, y-q*s, r, s)
+    return (a, x*x_sign, y*y_sign)
+
+
+def montgomery_exponentiation_reduction(a, r , n ):
+    return (a * r) % n
+
+
+def montgomery_product(a, b, n_prime, size_of_r, r, n):
+    t = a * b 
+    m = (t * n_prime) & r -1
+    u = (t + m * n ) >> size_of_r - 1
+    if u >= n:
+        return u -n 
+    return u
+
+
+def montgomery_exponentiation(a, x, n, n_prime, r):
+    ah = (a * r) % n 
+    xh = r % n 
+    x_s = sizeinbits(x) - 1
+    px = 2**x_s
+    size_of_r = sizeinbits(r)
+    while px != 0:
+        t = xh * xh 
+        m = (t * n_prime) & r -1
+        u = (t + m * n ) >> size_of_r - 1
+        if u >= n:
+            xh = u - n 
+        else:
+            xh = u
+        if (px & x) > 0:
+            t = ah * xh 
+            m = (t * n_prime) & r - 1
+            u = (t + m * n ) >> size_of_r - 1
+            if u >= n:
+                xh =  u -n 
+            else:
+                xh = u
+	px = px >> 1
+
+    m = (xh * n_prime) & r - 1
+    u = (xh + m * n ) >> size_of_r - 1
+    if u >= n:
+        return u - n 
+    return u
+
+def montgomery_exponentiation2(a, x, n, n_prime,  r):
+    ah = (a * r) % n 
+    xh = r % n 
+    x_s = sizeinbits(x) - 1
+    px = 2**x_s
+    size_of_r = sizeinbits(r)
+    while px != 0:
+        xh = montgomery_product(xh, xh, n_prime, size_of_r, r, n)
+        if (px & x) > 0:
+            xh = montgomery_product(ah, xh, n_prime, size_of_r, r, n)
+	px = px >> 1
+
+    x  = montgomery_product(xh, 1, n_prime, size_of_r, r, n)
+    return x
+
+
+
+
+# n = 2328734783
+# r, r_inv = calc_r(n)
+# n_prime = calc_np(n, r) 
+
+if __name__ ==  '__main__':
+    n = 2328734783
+    r, r_inv = calc_r_r_inv(n)
+    n_prime = calc_np(n, r) 
+    a = 2987
+    x = 1093874
+    print montgomery_exponentiation(a, x, n, n_prime, r)
+    print pow(a, x, n)
+    print a**x % n
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/viff/orlandi.py	Fri Oct 23 13:50:19 2009 +0200
@@ -0,0 +1,1366 @@
+# Copyright 2009 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/>.
+
+from twisted.internet.defer import Deferred, gatherResults
+
+from viff.runtime import Runtime, Share, ShareList, gather_shares, preprocess
+from viff.util import rand
+from viff.constants import TEXT, PAILLIER
+from viff.field import FieldElement
+from viff.paillier import encrypt_r, decrypt
+
+from hash_broadcast import HashBroadcastMixin
+
+try:
+    import commitment
+    commitment.set_reference_string(23434347834783478783478L,
+                                    489237823478234783478020L)
+except ImportError:
+    # The commitment module is not public, so we cannot expect the
+    # import to work. Catching the ImportError here allows the
+    # benchmark and tests to import viff.orlandi without blowing up.
+    # It is only if the OrlandiRuntime is used that things blow up.
+    pass
+
+# import logging
+# LOG_FILENAME = 'logging_example.out'
+# logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG,)
+
+class OrlandiException(Exception):
+    pass
+
+class OrlandiShare(Share):
+    """A share in the Orlandi runtime.
+
+    A share in the Orlandi runtime is a 3-tuple ``(x_i, rho_i, Cr_i)`` of:
+
+    - A share of a number, ``x_i``
+    - A tuple of two random numbers, ``rho_i = (rho_i1, rho_i2)``
+    - A commitment to the number and the random numbers, ``Cr_i``
+
+    The :class:`Runtime` operates on shares, represented by this class.
+    Shares are asynchronous in the sense that they promise to attain a
+    value at some point in the future.
+
+    Shares overload the arithmetic operations so that ``x = a + b``
+    will create a new share *x*, which will eventually contain the
+    sum of *a* and *b*. Each share is associated with a
+    :class:`Runtime` and the arithmetic operations simply call back to
+    that runtime.
+    """
+
+    def __init__(self, runtime, field, value=None, rho=None, commitment=None):
+        self.share = value
+        self.rho = rho
+        self.commitment = commitment
+        Share.__init__(self, runtime, field, (value, rho, commitment))
+
+
+class OrlandiRuntime(Runtime, HashBroadcastMixin):
+    """The Orlandi runtime.
+
+    The runtime is used for sharing values (:meth:`secret_share` or
+    :meth:`shift`) into :class:`OrlandiShare` object and opening such
+    shares (:meth:`open`) again. Calculations on shares is normally
+    done through overloaded arithmetic operations, but it is also
+    possible to call :meth:`add`, :meth:`mul`, etc. directly if one
+    prefers.
+
+    Each player in the protocol uses a :class:`Runtime` object. To
+    create an instance and connect it correctly with the other
+    players, please use the :func:`create_runtime` function instead of
+    instantiating a Runtime directly. The :func:`create_runtime`
+    function will take care of setting up network connections and
+    return a :class:`Deferred` which triggers with the
+    :class:`Runtime` object when it is ready.
+    """
+
+    def __init__(self, player, threshold=None, options=None):
+        """Initialize runtime."""
+        Runtime.__init__(self, player, threshold, options)
+        self.threshold = self.num_players - 1
+        self.s = 1
+        self.d = 0
+        self.s_lambda = 1
+
+    def compute_delta(self, d):
+        def product(j):
+            pt = 1
+            pn = 1
+            for k in xrange(1, 2 * d + 2):
+                if k != j:
+                    pt *= k
+                    pn *= k - j
+            return pt // pn
+
+        delta = []
+        for j in xrange(1, 2 * d + 2):
+            delta.append(product(j))
+        return delta
+
+    def output(self, share, receivers=None, threshold=None):
+        return self.open(share, receivers, threshold)
+
+    def _send_orlandi_share(self, other_id, pc, xi, rhoi, Cx):
+        """Send the share *xi*, *rhoi*, and the commitment *Cx* to
+        party *other_id*."""
+        self.protocols[other_id].sendShare(pc, xi)
+        self.protocols[other_id].sendShare(pc, rhoi[0])
+        self.protocols[other_id].sendShare(pc, rhoi[1])
+        self.protocols[other_id].sendData(pc, TEXT, repr(Cx))
+
+    def _expect_orlandi_share(self, peer_id, field):
+        """Waits for a number ``x``, ``rho``, and the commitment for
+        ``x``."""
+        xi = self._expect_share(peer_id, field)
+        Cx = Deferred()
+        rhoi1 = self._expect_share(peer_id, field)
+        rhoi2 = self._expect_share(peer_id, field)
+        self._expect_data(peer_id, TEXT, Cx)
+        sls = ShareList([xi, rhoi1, rhoi2, Cx])
+        def combine(ls):
+            expected_num = 4;
+            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]
+            s4, Cx = ls[3]
+            Cxx = commitment.deserialize(Cx)
+            if not (s1 and s2 and s3 and s4):
+                raise OrlandiException("Cannot share number, trying to create share,"
+                                       " but a component did arrive properly.")
+            return OrlandiShare(self, field, xi, (rhoi1, rhoi2), Cxx)
+        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 sharing.
+
+        To share an element ``x in Z_p``, choose random ``x_1, ...,
+        x_n-1 in Z_p``, define ``x_n = x - SUM_i=1^n-1 x_i mod p``.
+
+        Choose random values ``rho_x1, ..., rho_xn in (Z_p)^2``,
+        define ``rho_x = SUM_i=1^n rho_x,i`` and ``C_x = Com_ck(x,
+        p_x)``.
+
+        Send ``[x]_i = (x_i, rho_xi, C_x)`` to party ``P_i``.
+        """
+        assert number is None or self.id in inputters
+        self.threshold = self.num_players - 1
+
+        self.program_counter[-1] += 1
+
+        def additive_shares_with_rho(x):
+            """Returns a tuple of a list of tuples (player id, share,
+            rho) and rho.
+
+            Chooses random elements ``x_1, ..., x_n-1`` in field and
+            ``x_n`` st. ``x_n = x - Sum_i=1^n-1 x_i``.
+
+            Chooses random pair of elements ``rho_1, ..., rho_n in
+            Z_p^2`` and define ``rho_n = Sum_i=1^n rho_i``.
+
+            Returns a pair of ``((player id, x_i, rho_i), rho)``.
+            """
+            shares = []
+            rhos = []
+            sum = 0
+            rho1 = 0
+            rho2 = 0
+            for i in xrange(1, self.num_players):
+                xi = field(rand.randint(0, field.modulus - 1))
+                rhoi1 = field(rand.randint(0, field.modulus - 1))
+                rhoi2 = field(rand.randint(0, field.modulus - 1))
+                sum += xi
+                rho1 += rhoi1
+                rho2 += rhoi2
+                shares.append((i, xi, (rhoi1, rhoi2)))
+            xn = field(x) - sum
+            rhon1 = field(rand.randint(0, field.modulus - 1))
+            rhon2 = field(rand.randint(0, field.modulus - 1))
+            shares.append((self.num_players, xn, (rhon1, rhon2)))
+            rho1 += rhon1
+            rho2 += rhon2
+            return shares, (rho1, rho2)
+
+        # Send ``[x]_i = (x_i, rho_x,i, C_x)`` to party ``P_i``.
+        results = []
+        for peer_id in inputters:
+            if peer_id == self.id:
+                pc = tuple(self.program_counter)
+                shares, rho = additive_shares_with_rho(number)
+                Cx = commitment.commit(number, rho[0].value, rho[1].value)
+                # Distribute the shares
+                the_others = []
+                for other_id, xi, rhoi in shares:
+                    if other_id == self.id:
+                        results.append(OrlandiShare(self, field, xi, rhoi, Cx))
+                    else:
+                        # Send ``xi``, ``rhoi``, and commitment
+                        self._send_orlandi_share(other_id, pc, xi, rhoi, Cx)
+            else:
+                # Expect ``xi``, ``rhoi``, and commitment
+                results.append(self._expect_orlandi_share(peer_id, field))
+        # do actual communication
+        self.activate_reactor()
+        # Unpack a singleton list.
+        if len(results) == 1:
+            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:
+                #return x
+                raise OrlandiException("Wrong commitment for value %s, %s, %s, found %s expected %s." %
+                                       (x, rho1, rho2, 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 random_share(self, field):
+        """Generate a random share in the field, field.
+
+        To generate a share of a random element ``r in Z_p``, party
+        ``P_i`` chooses at random ``r_i, rho_ri in Z_p X (Z_p)^2`` and
+        broadcast ``C_r^i = Com_ck(r_i, rho_ri)``.
+
+        Every party computes ``C_r = PRODUCT_i=1^n C_r^i = Com_ck(r,
+        rho_r)``, where ``r_i = SUM_i=1^n r_i and rho_r = SUM_i=1^n
+        rho_ri``.
+
+        Party ``P_i sets [r]_i = (r_i, rho_ri, C_r)``.
+        """
+        self.program_counter[-1] += 1
+
+        # P_i chooses at random r_i, rho_ri in Z_p x (Z_p)^2
+        ri = field(rand.randint(0, field.modulus - 1))
+        rhoi1 = field(rand.randint(0, field.modulus - 1))
+        rhoi2 = field(rand.randint(0, field.modulus - 1))
+
+        # compute C_r^i = Com_ck(r_i, rho_ri).
+        Cri = commitment.commit(ri.value, rhoi1, rhoi2)
+
+        # Broadcast C_r^i.
+        sls = gatherResults(self.broadcast(self.players.keys(), self.players.keys(), repr(Cri)))
+
+        def compute_commitment(ls):
+            Cr = ls.pop()
+            for Cri in ls:
+                Cr = Cr * Cri
+            return OrlandiShare(self, field, ri, (rhoi1, rhoi2), Cr)
+
+        def deserialize(ls):
+            return [ commitment.deserialize(x) for x in ls ]
+
+        sls.addCallbacks(deserialize, self.error_handler)
+        sls.addCallbacks(compute_commitment, self.error_handler)
+
+        s = Share(self, field)
+        # We add the result to the chains in triple.
+        sls.chainDeferred(s)
+
+        # do actual communication
+        self.activate_reactor()
+
+        return s
+
+    def add(self, share_a, share_b):
+        """Addition of shares.
+
+        Communication cost: none.
+
+        Each party ``P_i`` computes::
+
+          [z]_i = [x]_i + [y]_i
+                = (x_i + y_i mod p, rho_xi + rho_yi mod p, C_x * C_y)
+
+        """
+        def is_share(s, field):
+            if not isinstance(s, Share):
+                if not isinstance(s, FieldElement):
+                    s = field(s)
+                (v, rhov, Cv) = self._additive_constant(field(0), s)
+                return OrlandiShare(self, field, v, rhov, Cv)
+            return s
+
+        # Either share_a or share_b must have an attribute called "field".
+        field = getattr(share_a, "field", getattr(share_b, "field", None))
+
+        share_a = is_share(share_a, field)
+        share_b = is_share(share_b, field)
+
+        # Add rho_xi and rho_yi and compute the commitment.
+        def compute_sums((x, y)):
+            (zi, (rhozi1, rhozi2), Cz) = self._plus(x, y)
+            return OrlandiShare(self, field, zi, (rhozi1, rhozi2), Cz)
+
+        result = gather_shares([share_a, share_b])
+        result.addCallbacks(compute_sums, self.error_handler)
+        return result
+
+    def sub(self, share_a, share_b):
+        """Subtraction of shares.
+
+        Communication cost: none.
+
+        Each party ``P_i`` computes::
+
+          [z]_i = [x]_i - [y]_i
+                = (x_i - y_i mod p, rho_x,i - rho_y,i mod p, C_x * C_y)
+
+        """
+        def is_share(s, field):
+            if not isinstance(s, Share):
+                if not isinstance(s, FieldElement):
+                    s = field(s)
+                (v, rhov, Cv) = self._additive_constant(field(0), s)
+                return OrlandiShare(self, field, v, rhov, Cv)
+            return s
+
+        # Either share_a or share_b must have an attribute called "field".
+        field = getattr(share_a, "field", getattr(share_b, "field", None))
+
+        share_a = is_share(share_a, field)
+        share_b = is_share(share_b, field)
+
+        # Subtract xi and yi, rhoxi and rhoyi, and compute the commitment
+        def compute_subs((x, y)):
+            zi, (rhozi1, rhozi2), Cz = self._minus(x, y)
+            return OrlandiShare(self, field, zi, (rhozi1, rhozi2), Cz)
+
+        result = gather_shares([share_a, share_b])
+        result.addCallbacks(compute_subs, self.error_handler)
+        return result
+
+    def input(self, inputters, field, number=None, threshold=None):
+        """Input *number* to the computation.
+
+        The input is shared using the :meth:`shift` method.
+        """
+        return self.shift(inputters, field, number)
+
+
+    def shift(self, inputters, field, number=None):
+        """Shift of a share.
+
+        Useful for input.
+
+        Communication cost: ???.
+
+        Assume the parties are given a random share ``[r]`` by a
+        trusted dealer. Then we denote the following protocol but
+        ``[x] = Shift(P_i, x, [r])``.
+
+        1. ``r = OpenTo(P_i, [r]``
+
+        2. ``P_i broadcasts Delta = r - x``
+
+        3. ``[x] = [r] - Delta``
+        """
+        # TODO: Communitcation costs?
+        assert (self.id in inputters and number != None) or (self.id not in inputters)
+
+        self.program_counter[-1] += 1
+
+        results = []
+        def hack(_, peer_id):
+            # Assume the parties are given a random share [r] by a
+            # trusted dealer.
+            share_r = self.random_share(field)
+            # 1. r = OpenTo(P_i, [r])
+            open_r = self.open(share_r, [peer_id])
+            def subtract_delta(delta, share_r):
+                delta = field(long(delta))
+                x = self.sub(share_r, delta)
+                return x
+            if peer_id == self.id:
+                def g(r, x):
+                    delta = r - x
+                    delta = self.broadcast([peer_id], self.players.keys(),
+                                           str(delta.value))
+                    self.schedule_callback(delta, subtract_delta, share_r)
+                    delta.addErrback(self.error_handler)
+                    return delta
+                self.schedule_callback(open_r, g, number)
+                open_r.addErrback(self.error_handler)
+                return open_r
+            else:
+                d = Deferred()
+                def g(_, peer_id, share_r):
+                    delta = self.broadcast([peer_id], self.players.keys())
+                    self.schedule_callback(delta, subtract_delta, share_r)
+                    delta.addErrback(self.error_handler)
+                    return delta
+                self.schedule_callback(d, g, peer_id, share_r)
+                d.addErrback(self.error_handler)
+                d.callback(None)
+                return d
+
+        for peer_id in inputters:
+            s = Share(self, field)
+            self.schedule_callback(s, hack, peer_id)
+            s.addErrback(self.error_handler)
+            s.callback(None)
+            results.append(s)
+
+        # do actual communication
+        self.activate_reactor()
+
+        if len(results) == 1:
+             return results[0]
+        return results
+
+    def mul(self, share_x, share_y):
+        """Multiplication of shares.
+
+        Communication cost: ???.
+        """
+        # TODO: Communication cost?
+        assert isinstance(share_x, Share) or isinstance(share_y, Share), \
+            "At least one of share_x and share_y must be a Share."
+
+        self.program_counter[-1] += 1
+
+        field = getattr(share_x, "field", getattr(share_y, "field", None))
+
+        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.
+
+        Any additive constant can be interpreted as:
+        ``[c]_1 = (c, 0, Com_ck(c,0))`` and
+        ``[c]_i = (0, 0, Com_ck(c,0)) for i != 1``.
+        """
+        v = zero
+        if self.id == 1:
+            v = field_element
+        Cx = commitment.commit(field_element.value, zero.value, zero.value)
+        return (v, (zero, zero), Cx)
+
+    def _plus(self, x, y):
+        """Addition of share-tuples *x* and *y*.
+
+        Each party ``P_i`` computes:
+        ``[x]_i = (x_i, rho_xi, C_x)``
+        ``[y]_i = (y_i, rho_yi, C_y)``
+        ``[z]_i = [x]_i + [y]_i
+                = (x_i + y_i mod p, rho_xi + rho_yi mod p, C_x * C_y)``.
+        """
+        (xi, (rhoxi1, rhoxi2), Cx) = x
+        (yi, (rhoyi1, rhoyi2), Cy) = y
+        zi = xi + yi
+        rhozi1 = rhoxi1 + rhoyi1
+        rhozi2 = rhoxi2 + rhoyi2
+        Cz = Cx * Cy
+        return (zi, (rhozi1, rhozi2), Cz)
+
+    def _minus(self, x, y):
+        """Subtraction of share-tuples *x* and *y*.
+
+        Each party ``P_i`` computes:
+        ``[x]_i = (x_i, rho_x,i, C_x)``
+        ``[y]_i = (y_i, rho_y,i, C_y)``
+        ``[z]_i = [x]_i - [y]_i
+                = (x_i - y_i mod p, rho_x,i - rho_y,i mod p, C_x / C_y)``.
+        """
+        xi, (rhoxi1, rhoxi2), Cx = x
+        yi, (rhoyi1, rhoyi2), Cy = y
+        zi = xi - yi
+        rhozi1 = rhoxi1 - rhoyi1
+        rhozi2 = rhoxi2 - rhoyi2
+        Cz = Cx / Cy
+        return (zi, (rhozi1, rhozi2), Cz)
+
+    def _cmul(self, share_x, share_y, field):
+        """Multiplication of a share with a constant.
+
+        Either share_x or share_y must be an OrlandiShare but not
+        both. Returns None if both share_x and share_y are
+        OrlandiShares.
+        """
+        def constant_multiply(x, c):
+            assert(isinstance(c, FieldElement))
+            zi, rhoz, Cx = self._const_mul(c.value, x)
+            return OrlandiShare(self, field, zi, rhoz, Cx)
+        if not isinstance(share_x, Share):
+            # Then share_y must be a Share => local multiplication. We
+            # clone first to avoid changing share_y.
+            assert isinstance(share_y, Share), \
+                "At least one of the arguments must be a share."
+            result = share_y.clone()
+            result.addCallback(constant_multiply, share_x)
+            return result
+        if not isinstance(share_y, Share):
+            # Likewise when share_y is a constant.
+            assert isinstance(share_x, Share), \
+                "At least one of the arguments must be a share."
+            result = share_x.clone()
+            result.addCallback(constant_multiply, share_y)
+            return result
+        return None
+
+    def _const_mul(self, c, x):
+        """Multiplication of a share-tuple with a constant c."""
+        assert(isinstance(c, long) or isinstance(c, int))
+        xi, (rhoi1, rhoi2), Cx = x
+        zi = xi * c
+        rhoz = (rhoi1 * c, rhoi2 * c)
+        Cz = Cx**c
+        return (zi, rhoz, Cz)
+
+    def _get_share(self, field, value):
+        Cc = commitment.commit(value * 3, 0, 0)
+        c = OrlandiShare(self, field, field(value), (field(0), field(0)), Cc)
+        return c
+
+    @preprocess("random_triple")
+    def _get_triple(self, field):
+        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.
+
+        Communication cost: ???.
+
+        ``d = Open([x] - [a])``
+        ``e = Open([y] - [b])``
+        ``[z] = e[x] + d[y] - [de] + [c]``
+        """
+        assert isinstance(share_x, Share) or isinstance(share_y, Share), \
+            "At least one of share_x and share_y must be a Share."
+
+        self.program_counter[-1] += 1
+
+        field = getattr(share_x, "field", getattr(share_y, "field", None))
+        n = field(0)
+
+        cmul_result = self._cmul(share_x, share_y, field)
+        if cmul_result is  not None:
+            return cmul_result
+
+        def multiply((x, y, d, e, c)):
+            # [de]
+            de = self._additive_constant(field(0), d * e)
+            # e[x]
+            t1 = self._const_mul(e.value, x)
+            # d[y]
+            t2 = self._const_mul(d.value, y)
+            # d[y] - [de]
+            t3 = self._minus(t2, de)
+            # d[y] - [de] + [c]
+            t4 = self._plus(t3, c)
+            # [z] = e[x] + d[y] - [de] + [c]
+            zi, rhoz, Cz = self._plus(t1, t4)
+            return OrlandiShare(self, field, zi, rhoz, Cz)
+
+        # d = Open([x] - [a])
+        d = self.open(share_x - triple_a)
+        # e = Open([y] - [b])
+        e = self.open(share_y - triple_b)
+        result = gather_shares([share_x, share_y, d, e, triple_c])
+        result.addCallbacks(multiply, self.error_handler)
+
+        # do actual communication
+        self.activate_reactor()
+
+        return result
+
+    def sum_poly(self, j, ls):
+        exp  = j
+        fj, (rhoj1, rhoj2), Cfj = ls[0]
+        x    = fj*exp
+        rho1 = rhoj1 * exp
+        rho2 = rhoj2 * exp
+        Cx   = Cfj**exp
+        exp *= j
+
+        for (fj, (rhoj1, rhoj2), Cfj) in ls[1:]:
+            x += fj * exp
+            rho1 += rhoj1 * exp
+            rho2 += rhoj2 * exp
+            Cx = Cx * (Cfj**exp)
+            exp *= j
+        return x, (rho1, rho2), Cx
+
+    def leak_tolerant_mul(self, share_x, share_y, M):
+        """Leak tolerant multiplication of shares.
+
+        Communication cost: ???.
+
+        Assuming a set of multiplicative triples:
+        ``M = ([a_i], [b_i], [c_i]) for 1 <= i <= 2d + 1``.
+
+        1. ``for i = 1, ..., d do [f_i] = rand(), [g_i] = rand()``
+
+        2. Compute::
+
+             for j = 1, ..., 2d+1 do
+             [F_j] = [x] + SUM_i=1^d [f_i]*j^i
+             and
+             [G_j] = [y] + SUM_i=1^d [g_i]*j^i
+
+        3. ``for j = 1, ..., 2d+1 do [H_j] = Mul([F_j], [G_j], [a_j],
+           [b_j], [c_j])``
+
+        4. compute ``[H_0] = SUM_j=1^2d+1 delta_j[H_j]`` where
+           ``delta_j = PRODUCT_k=1, k!=j^2d+1 k/(k-j)``
+
+        5. output ``[z] = [H_0]``
+        """
+        assert isinstance(share_x, Share) or isinstance(share_y, Share), \
+            "At least one of share_x and share_y must be a Share."
+
+        self.program_counter[-1] += 1
+
+        field = getattr(share_x, "field", getattr(share_y, "field", None))
+        n = field(0)
+
+        cmul_result = self._cmul(share_x, share_y, field)
+        if cmul_result is not None:
+            return cmul_result
+
+        # 1. for i = 1, ..., d do [f_i] = rand(), [g_i] = rand()
+        d = (len(M) - 1) // 2
+        deltas = self.compute_delta(d)
+        f = []
+        g = []
+        for x in xrange(d):
+            f.append(self.random_share(field))
+            g.append(self.random_share(field))
+
+        def compute_polynomials(t):
+            x, y = t[0]
+            f = []
+            g = []
+            if 1 in t:
+                f = t[1]
+            if 2 in t:
+                g = t[2]
+#             print "==> poly", self.id
+#             print "x:", x
+#             print "y:", y
+#             print "f:", f
+#             print "g:", g
+            # 2) for j = 1, ..., 2d+1 do
+            # [F_j] = [x] + SUM_i=1^d [f_i]*j^i
+            # and
+            # [G_j] = [y] + SUM_i=1^d [g_i]*j^i
+            h0i, rhoh0, Ch0 = self._additive_constant(field(0), n)
+            H0 = OrlandiShare(self, field, h0i, rhoh0, Ch0)
+            xi, (rhoxi1, rhoxi2), Cx = x
+            yi, (rhoyi1, rhoyi2), Cy = y
+
+            for j in xrange(1, 2*d + 2):
+                Fji = xi
+                rho1_Fji = rhoxi1
+                rho2_Fji = rhoxi2
+                C_Fji = Cx
+                if f != []:
+                    # SUM_i=1^d [f_i]*j^i
+                    vi, (rhovi1, rhovi2), Cv = self.sum_poly(j, f)
+                    # [F_j] = [x] + SUM_i=1^d [f_i]*j^i
+                    Fji += vi
+                    rho1_Fji += rhovi1
+                    rho2_Fji += rhovi2
+                    C_Fji *= Cv
+                Gji = yi
+                rho1_Gji = rhoyi1
+                rho2_Gji = rhoyi2
+                C_Gji = Cy
+                if g != []:
+                    # SUM_i=1^d [g_i]*j^i
+                    wi, (rhowi1, rhowi2), Cw = self.sum_poly(j, g)
+                    # [G_j] = [y] + SUM_i=1^d [g_i]*j^i
+                    Gji += wi
+                    rho1_Gji += rhowi1
+                    rho2_Gji += rhowi2
+                    C_Gji *= Cw
+                Fj = OrlandiShare(self, field, Fji, (rho1_Fji, rho2_Fji), C_Fji)
+                Gj = OrlandiShare(self, field, Gji, (rho1_Gji, rho2_Gji), C_Gji)
+                a, b, c = M.pop(0)
+
+                # [H_j] = Mul([F_j], [G_j], [a_j], [b_j], [c_j])
+                Hj = self._basic_multiplication(Fj, Gj, a, b, c)
+                dj = self._cmul(field(deltas[j - 1]), Hj, field)
+                H0 = H0 + dj
+            # 5) output [z] = [H_0]
+            return H0
+
+        ls = [gather_shares([share_x, share_y])]
+        if g:
+            ls.append(gather_shares(g))
+        if f:
+            ls.append(gather_shares(f))
+        result = gather_shares(ls)
+        self.schedule_callback(result, compute_polynomials)
+        result.addErrback(self.error_handler)
+
+        # do actual communication
+        self.activate_reactor()
+
+        return result
+
+    def triple_gen(self, field):
+        """Generate a triple ``a, b, c`` s.t. ``c = a * b``.
+
+        1. Every party ``P_i`` chooses random values ``a_i, r_i in Z_p
+           X (Z_p)^2``, compute ``alpha_i = Enc_eki(a_i)`` and ``Ai =
+           Com_ck(a_i, r_i)``, and broadcast them.
+
+        2. Every party ``P_j`` does:
+
+           a. choose random ``b_j, s_j in Z_p X (Z_p)^2``.
+
+           b. compute ``B_j = ``Com_ck(b_j, s_j)`` and broadcast it.
+
+           c. ``P_j`` do towards every other party:
+
+                i. choose random ``d_ij in Z_p^3``
+
+                ii. compute and send
+                    ``gamma_ij = alpha_i^b_j Enc_ek_i(1;1)^d_ij`` to ``P_i``.
+
+
+        3. Every party ``P_i`` does:
+
+           a. compute ``c_i = SUM_j Dec_sk_i(gamma_ij) - SUM_j d_ij mod p``
+
+           b. pick random ``t_i in (Z_p)^2``, compute and
+              broadcast ``C_i = Com_ck(c_i, t_i)``
+
+        4. Everyone computes:
+           ``(A, B, C) = (PRODUCT_i A_i, PRODUCT_i B_i, PRODUCT_i C_i)``
+
+        5. Every party ``P_i`` outputs shares ``[a_i] = (a_i, r_i, A)``,
+           ``[b_i] = (b_i, s_i, B)``, and ``[c_i] = (c_i, t_i, C)``.
+
+        """
+        self.program_counter[-1] += 1
+
+        def random_number(p):
+            return field(rand.randint(0, p - 1))
+
+        def product(ls):
+            """Compute the product of the elements in the list *ls*."""
+            b = commitment.deserialize(ls[0])
+            for x in ls[1:]:
+                b *= commitment.deserialize(x)
+            return b
+
+        def sum(ls):
+            """Compute the sum of the elements in the list *ls*."""
+            b = field(0)
+            for x in ls:
+                b += x
+            return b
+
+        def step45(Cs, alphas, gammas, alpha_randomness,
+                   As, Bs, ai, bi, ci, r, s, t, dijs):
+            """4) Everyone computes:
+                  ``A = PRODUCT_i A_i``
+                  ``B = PRODUCT_i B_i``
+                  ``C = PRODUCT_i C_i``
+
+               5) Every party ``P_i`` outputs shares ``[a_i] = (a_i, r_i, A)``,
+                  ``[b_i] = (b_i, s_i, B)``, and ``[c_i] = (c_i, t_i, C)``.
+            """
+            A = product(As)
+            B = product(Bs)
+            C = product(Cs)
+            a = OrlandiShare(self, field, ai, r, A)
+            b = OrlandiShare(self, field, bi, s, B)
+            c = OrlandiShare(self, field, ci, t, C)
+            return (a, b, c, (alphas, alpha_randomness, gammas, dijs))
+
+        def decrypt_gammas(ls):
+            """Decrypt all the elements of the list *ls*."""
+            rs = []
+            for x in ls:
+                rs.append(field(decrypt(x, self.players[self.id].seckey)))
+            return rs
+
+        def step3(gammas, alphas, alpha_randomness, As, Bs, ai, bi, r, s, dijs):
+            """3) Every party ``P_i`` does:
+                  (a) compute
+                  ``c_i = SUM_j Dec_sk_i(gamma_ij) - SUM_j d_ji mod p``
+
+                  (b) pick random ``t_i in (Z_p)^2``, compute and
+                      broadcast ``C_i = Com_ck(c_i, t_i)``
+            """
+            # c_i = SUM_j Dec_sk_i(gamma_ij) - SUM_j d_ji mod p.
+            ls = decrypt_gammas(gammas)
+            ci = sum(ls) - sum(dijs)
+            # (b) pick random t_i in (Z_p)^2.
+            t1 = random_number(field. modulus)
+            t2 = random_number(field. modulus)
+            t = (t1, t2)
+            # C_i = Com_ck(c_i, t_i).
+            Ci = commitment.commit(ci.value, t1.value, t2.value)
+
+            # Broadcast Ci.
+            Cs = self.broadcast(self.players.keys(), self.players.keys(),
+                                repr(Ci))
+            result = gatherResults(Cs)
+            result.addCallbacks(step45, self.error_handler,
+                                callbackArgs=(alphas, gammas, alpha_randomness,
+                                              As, Bs, ai, bi, ci, r, s, t, dijs))
+            return result
+
+        def step2c(Bs, As, alphas, alpha_randomness, ai, bj, r, s):
+            """(c) P_j do, towards every other party:
+                   i. choose random d_i,j in Z_p^3
+                   ii. compute and send
+            gamma_ij = alpha_i^b_j Enc_ek_i(1;1)^d_ij to P_i.
+            """
+
+            # (c) P_j do, towards every other party:
+            dijs = [None] * len(self.players.keys())
+            results = [None] * len(self.players.keys())
+            pc = tuple(self.program_counter)
+            for pi in self.players.keys():
+                n = self.players[pi].pubkey[0]
+                nsq = n * n
+                # choose random d_i,j in Z_p^3
+                dij = random_number(field.modulus**3)
+                # Enc_ek_i(1;1)^d_ij
+                enc = encrypt_r(1, 1, self.players[pi].pubkey)
+                t1 = pow(enc, dij.value, nsq)
+                # alpha_i^b_j.
+                t2 = pow(alphas[pi - 1], bj.value, nsq)
+                # gamma_ij = alpha_i^b_j Enc_ek_i(1;1)^d_ij
+                gammaij = (t2) * (t1) % nsq
+                # Broadcast gamma_ij
+                if pi != self.id:
+                    self.protocols[pi].sendData(pc, PAILLIER, str(gammaij))
+                    d = Deferred()
+                    d.addCallbacks(lambda value: long(value), self.error_handler)
+                    self._expect_data(pi, PAILLIER, d)
+                else:
+                    d = Deferred()
+                    d.callback(gammaij)
+                dijs[pi - 1] = dij
+                results[pi - 1] = d
+            result = gatherResults(results)
+            self.schedule_callback(result, step3, alphas, alpha_randomness,
+                                   As, Bs, ai, bj, r, s, dijs)
+            result.addErrback(self.error_handler)
+            return result
+
+        def step2ab((alphas, As), ai, r, alpha_randomness):
+            """2) Every party P_j does:
+                  (a) choose random b_j, s_j in Z_p X (Z_p)^2.
+
+                  (b) compute B_j = Com_ck(b_j, s_j) and broadcast it.
+            """
+            # (a) choose random b_j, s_j in Z_p X (Z_p)^2.
+            bj = random_number(field.modulus)
+            s1 = random_number(field.modulus)
+            s2 = random_number(field.modulus)
+            # (b) compute B_j = Com_ck(b_j, s_j).
+            Bj = commitment.commit(bj.value, s1.value, s2.value)
+
+            # Broadcast B_j.
+            results = self.broadcast(self.players.keys(), self.players.keys(), repr(Bj))
+            result = gatherResults(results)
+            self.schedule_callback(result, step2c, As, alphas, alpha_randomness,
+                                   ai, bj, r, (s1, s2))
+            result.addErrback(self.error_handler)
+            return result
+
+        # 1) Every party P_i chooses random values a_i, r_i in Z_p X (Z_p)^2,
+        #    compute alpha_i = Enc_eki(a_i) and Ai = Com_ck(a_i, r_i), and
+        #    broadcast them.
+
+        # Every party P_i chooses random values a_i, r_i in Z_p X (Z_p)^2
+        ai = random_number(field.modulus)
+        r1 = random_number(field.modulus)
+        r2 = random_number(field.modulus)
+
+        # compute alpha_i = Enc_eki(a_i)
+        n, g = self.players[self.id].pubkey
+        alpha_randomness = rand.randint(1, long(n))
+        alphai = encrypt_r(ai.value, alpha_randomness, (n, g))
+        # and A_i = Com_ck(a_i, r_i).
+        Ai = commitment.commit(ai.value, r1.value, r2.value)
+
+        # broadcast alpha_i and A_i.
+        ds = self.broadcast(sorted(self.players.keys()),
+                            sorted(self.players.keys()),
+                            str(alphai) + ":" + repr(Ai))
+
+        result = gatherResults(ds)
+        def split_alphas_and_As(ls):
+            alphas = []
+            As = []
+            for x in ls:
+                alpha, Ai = x.split(':')
+                alphas.append(long(alpha))
+                As.append(Ai)
+            return alphas, As
+        self.schedule_callback(result, split_alphas_and_As)
+        self.schedule_callback(result, step2ab, ai, (r1, r2), alpha_randomness)
+        result.addErrback(self.error_handler)
+        return result
+
+    def triple_test(self, field):
+        """Generate a triple ``(a, b, c)`` where ``c = a * b``.
+
+        The triple ``(a, b, c)`` is checked against the
+        triple ``(x, y, z)`` and a random value ``r``.
+
+        """
+        triple1 = self.triple_gen(field)
+        triple2 = self.triple_gen(field)
+        r = self.open(self.random_share(field))
+
+        def check((v, oa, ob, oc, ox, oy, oz), a, b, c, ec):
+            if v is 0:
+                return None
+            return (a, b, c, ec)
+
+        def compute_value(((a, b, c, ec), (x, y, z, _), r)):
+            oa = self.open(a)
+            ob = self.open(b)
+            oc = self.open(c)
+            ox = self.open(x)
+            oy = self.open(y)
+            oz = self.open(z)
+            l = self._cmul(r, x, field)
+            m = self._cmul(r, y, field)
+            n = self._cmul(r*r, z, field)
+            d = c - self._basic_multiplication(a, b, l, m, n)
+            r = gather_shares([d, oa, ob, oc, ox, oy, oz])
+            r.addCallbacks(check, self.error_handler, callbackArgs=(a, b, c, ec))
+            return r
+
+        result = gatherResults([triple1, triple2, r])
+        self.schedule_callback(result, compute_value)
+        result.addErrback(self.error_handler)
+
+        # do actual communication
+        self.activate_reactor()
+
+        return result
+
+    def random_triple(self, field, quantity=1):
+        """Generate a list of triples ``(a, b, c)`` where ``c = a * b``.
+
+        The triple ``(a, b, c)`` is secure in the Fcrs-hybrid model.
+
+        """
+        self.program_counter[-1] += 1
+
+        M = []
+
+# print "Generating %i triples... relax, have a break..." % ((1 + self.s_lambda) * (2 * self.d + 1) * quantity)
+
+        for x in xrange((1 + self.s_lambda) * (2 * self.d + 1) * quantity):
+            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) * quantity
+            inx = 0
+            p_half = field.modulus // 2
+            def coin_flip(v, ls, test_set):
+                candidate = ls.pop(0)
+                if p_half > v:
+                    test_set.append(candidate)
+                else:
+                    ls.append(candidate)
+                if size > len(test_set):
+                    r = self.random_share(field)
+                    r = self.output(r)
+                    self.schedule_callback(r, coin_flip, ls, test_set)
+                    r.addErrback(self.error_handler)
+                    return r
+                return ls, test_set
+            r = self.random_share(field)
+            r = self.output(r)
+            self.schedule_callback(r, coin_flip, ls, [])
+            r.addErrback(self.error_handler)
+            return r
+
+        def step45(lists):
+            """For all i in test_set the parties reveal
+            the randomness used for TripleTest() and checks that
+            the randomness is consistent with the actual values."""
+            M_without_test_set = lists[0]
+            T = lists[1]
+
+            def defer_share(xi, (rho1, rho2), commitment):
+                d1 = Deferred()
+                d2 = Deferred()
+                d3 = Deferred()
+                d4 = Deferred()
+                d1.callback(xi)
+                d2.callback(rho1)
+                d3.callback(rho2)
+                d4.callback(commitment)
+                return gatherResults([d1, d2, d3, d4])
+
+            def get_share(x, ls):
+                share = ls[x * 4]
+                rho1 = ls[x * 4 + 1]
+                rho2 = ls[x * 4 + 2]
+                commitment = ls[x * 4 + 3]
+                return (share, rho1, rho2, commitment)
+
+            def send_share(player_id, pc, a):
+                self._send_orlandi_share(player_id, pc, a.share, a.rho, a.commitment)
+
+            def receive_shares(player_id):
+                Cx = Deferred()
+                xi = self._expect_share(player_id, field)
+                rho1 = self._expect_share(player_id, field)
+                rho2 = self._expect_share(player_id, field)
+                self._expect_data(player_id, TEXT, Cx)
+                Cx.addCallbacks(lambda Cx: commitment.deserialize(Cx),
+                                        self.error_handler)
+                return gatherResults([xi, rho1, rho2, Cx])
+
+            def send_long(player_id, pc, l):
+                self.protocols[player_id].sendData(pc, TEXT, str(l))
+
+            def receive_long(player_id):
+                l = Deferred()
+                self._expect_data(player_id, TEXT, l)
+                l.addCallbacks(lambda x: long(x), self.error_handler)
+                return l
+
+            def defer_value(l):
+                d = Deferred()
+                d.callback(l)
+                return d
+
+            def check((ais, bis, cis, alpha_randomness, dijs), alphas, gammas):
+                """So if B receives ai, bi, dij, ri, si, and the
+                randomness used in the computation of alpha, he then
+                checks that:
+
+                1) the alpha_i he received is equals to the encryption
+                   of ai and the commitment he received, Ai, is equal
+                   to the commitment of ai and ri
+
+                2) the commitment he received, Bj, is equal to the
+                   commitment of bj and sj
+
+                3) the gammaij he received is equal to the gammaij he
+                   now computes based on the values he reveives
+
+                4) a, b, c is a triple, a * b = c
+
+                5) ai, bi < p and dij < p^3
+                """
+                a = 0
+                a_rho1 = 0
+                a_rho2 = 0
+                b = 0
+                b_rho1 = 0
+                b_rho2 = 0
+                c = 0
+                c_rho1 = 0
+                c_rho2 = 0
+
+                for x in xrange(len(ais)):
+                    (ai, a_rhoi1, a_rhoi2, A) = ais[x]
+                    (bi, b_rhoi1, b_rhoi2, B) = bis[x]
+                    (ci, c_rhoi1, c_rhoi2, C) = cis[x]
+                    # 5) ai, bi < p...
+                    if ai >= field.modulus:
+                        raise OrlandiException("Inconsistent share ai, ai >= p: %i" % ai)
+                    if bi >= field.modulus:
+                        raise OrlandiException("Inconsistent share bi, bi >= p: %i" % bi)
+                    a += ai
+                    a_rho1 += a_rhoi1
+                    a_rho2 += a_rhoi2
+                    b += bi
+                    b_rho1 += b_rhoi1
+                    b_rho2 += b_rhoi2
+                    c += ci
+                    c_rho1 += c_rhoi1
+                    c_rho2 += c_rhoi2
+                    # 1) the alpha_i he received is equals to the encryption of ai...
+                    alphai = encrypt_r(ai.value, alpha_randomness[x],
+                                       self.players[x + 1].pubkey)
+                    if not(alphas[x] == alphai):
+                        raise OrlandiException("Inconsistent alpha from player %i, %i, %i" % (x + 1, alphas[x], alphai))
+
+                A1 = commitment.commit(a.value, a_rho1.value, a_rho2.value)
+                B1 = commitment.commit(b.value, b_rho1.value, b_rho2.value)
+                C1 = commitment.commit(c.value, c_rho1.value, c_rho2.value)
+
+                # 1) ... and the commitment he received, Ai, is equal
+                # to the commitment of ai and ri.
+                if A1 != A:
+                    raise OrlandiException("Inconsistent commitment for value %s, found %s expected %s." % (a, A1, A))
+                # 2) the commitment he received, Bj, is equal to the
+                # commitment of bj and sj.
+                if B1 != B:
+                    raise OrlandiException("Inconsistent commitment for value %s, found %s expected %s." % (b, B1, B))
+                if C1 != C:
+                    raise OrlandiException("Inconsistent commitment for value %s, found %s expected %s." % (c, C1, C))
+                # 4) a, b, c is a triple, a * b = c
+                if a * b != c:
+                    raise OrlandiException("Inconsistent triple, %i * %i does not equals %i." % (a, b, c))
+
+
+                # 3) the gammaij he received is equal to the gammaij
+                # he now computes based on the values he reveives
+                for j in xrange(len(ais)):
+                    n = self.players[self.id].pubkey[0]
+                    nsq = n * n
+                    dij = dijs[j]
+                    # 5) ... and dij < p^3.
+                    if dij >= (field.modulus**3):
+                        raise OrlandiException("Inconsistent random value dij %i from player %i" % (dij, j + 1))
+                    # Enc_ek_i(1;1)^d_ij
+                    enc = encrypt_r(1, 1, self.players[self.id].pubkey)
+                    t1 = pow(enc, dij.value, nsq)
+                    # alpha_i^b_j.
+                    t2 = pow(alphas[self.id - 1], bis[j][0].value, nsq)
+                    # gamma_ij = alpha_i^b_j Enc_ek_i(1;1)^d_ij
+                    gammaij = (t2) * (t1) % nsq
+                    if gammaij != gammas[j]:
+                        raise OrlandiException("Inconsistent gammaij, %i, %i" % (gammaij, gammas[j]))
+
+                return True
+
+            dls_all = []
+            for (a, b, c, (alphas, alpha_randomness, gammas, dijs)) in T:
+                ds_a = [None] * len(self.players)
+                ds_b = [None] * len(self.players)
+                ds_c = [None] * len(self.players)
+                ds_alpha_randomness = [None] * len(self.players)
+                ds_dijs = [None] * len(self.players)
+                pc = tuple(self.program_counter)
+
+                for player_id in xrange(1, len(self.players.keys()) + 1):
+                    if player_id == self.id:
+                        ds_a[player_id - 1] = defer_share(a.share, a.rho, a.commitment)
+                        ds_b[player_id - 1] = defer_share(b.share, b.rho, b.commitment)
+                        ds_c[player_id - 1] = defer_share(c.share, c.rho, c.commitment)
+                        ds_alpha_randomness[player_id - 1] = defer_value(alpha_randomness)
+                        ds_dijs[player_id - 1] = defer_value(dijs[player_id - 1])
+                    # Receive and recombine shares if this player is a
+                    # receiver.
+                    else:
+                        send_share(player_id, pc, a)
+                        send_share(player_id, pc, b)
+                        send_share(player_id, pc, c)
+                        send_long(player_id, pc, alpha_randomness)
+                        self.protocols[player_id].sendShare(pc, dijs[player_id - 1])
+
+                        ds_a[player_id - 1] = receive_shares(player_id)
+                        ds_b[player_id - 1] = receive_shares(player_id)
+                        ds_c[player_id - 1] = receive_shares(player_id)
+                        ds_alpha_randomness[player_id - 1] = receive_long(player_id)
+                        ds_dijs[player_id - 1] = self._expect_share(player_id, field)
+                dls_a = gatherResults(ds_a)
+                dls_b = gatherResults(ds_b)
+                dls_c = gatherResults(ds_c)
+                dls_dijs = gatherResults(ds_dijs)
+                dls_alpha_randomness = gatherResults(ds_alpha_randomness)
+
+            dls = gatherResults([dls_a, dls_b, dls_c, dls_alpha_randomness, dls_dijs])
+            dls.addCallbacks(check, self.error_handler, callbackArgs=[alphas, gammas])
+            dls_all.append(dls)
+
+            def result(x):
+                ls = []
+                for a, b, c, _ in M_without_test_set:
+                    ls.append((a, b, c))
+                return ls
+
+            dls_all = gatherResults(dls_all)
+            dls_all.addCallbacks(result, self.error_handler)
+            return dls_all
+
+        def step6(M_without_test_set):
+            """Partition M without test_set in quantity random subsets
+            M_i of size (2d + 1).
+            """
+            subsets = []
+            size = 2 * self.d + 1
+            for x in xrange(quantity):
+                subsets.append([])
+
+            def put_in_set(v, M_without_test_set, subsets):
+                if 0 == len(M_without_test_set):
+                    return subsets
+                v = v.value % quantity
+                if size > len(subsets[v]):
+                    subsets[v].append(M_without_test_set.pop(0))
+                r = self.random_share(field)
+                r = self.output(r)
+                self.schedule_callback(r, put_in_set, M_without_test_set, subsets)
+                r.addErrback(self.error_handler)
+                return r
+            r = self.random_share(field)
+            r = self.output(r)
+            self.schedule_callback(r, put_in_set, M_without_test_set, subsets)
+            r.addErrback(self.error_handler)
+            return r
+
+
+        def step7(Msets):
+            """For i = 1,...,M do:
+            a) [a] <- Fpp(rand,...), [b] <- Fpp(rand,...)
+            b) [r] <- Fpp(rand,...),
+            c) [c] <- LTMUL([a], [b], M_i)
+            d) Open([c] + [r])
+            """
+            ds = []
+            for Mi in Msets:
+                a = self.random_share(field)
+                b = self.random_share(field)
+                r = self.random_share(field)
+                c = self.leak_tolerant_mul(a, b, Mi)
+                d = self.open(c + r)
+                def return_abc(x, a, b, c):
+                    return a, b, c
+                d.addCallbacks(return_abc, self.error_handler, callbackArgs=(a, b, c))
+                ds.append(d)
+            result = gather_shares(ds)
+            def triples(ls):
+                return ls
+            result.addCallbacks(triples, self.error_handler)
+            return result
+
+        result = gatherResults(M)
+        self.schedule_callback(result, step3)
+        result.addErrback(self.error_handler)
+        self.schedule_callback(result, step45)
+        self.schedule_callback(result, step6)
+        self.schedule_callback(result, step7)
+
+        # do actual communication
+        self.activate_reactor()
+
+        s = Share(self, field)
+        # We add the result to the chains in result.
+        result.chainDeferred(s)
+
+        return quantity, s
+
+    def error_handler(self, ex):
+        print "Error: ", ex
+        return ex
+
+    def set_args(self, args):
+        """args is a dictionary."""
+        self.s = args['s']
+        self.d = args['d']
+        self.s_lambda = args['lambda']
--- a/viff/paillier.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/viff/paillier.py	Fri Oct 23 13:50:19 2009 +0200
@@ -27,8 +27,8 @@
 from twisted.internet.defer import Deferred, gatherResults
 import gmpy
 
-from viff.runtime import Runtime, increment_pc, Share, gather_shares
-from viff.runtime import PAILLIER
+from viff.runtime import Runtime, Share, gather_shares
+from viff.constants import PAILLIER
 from viff.util import rand, find_random_prime
 
 def L(u, n):
@@ -78,7 +78,6 @@
         else:
             self.peer = player
 
-    @increment_pc
     def prss_share_random(self, field):
         """Generate a share of a uniformly random element."""
         prfs = self.players[self.id].prfs(field.modulus)
@@ -94,13 +93,15 @@
         """
         return self.share(inputters, field, number)
 
-    @increment_pc
     def share(self, inputters, field, number=None):
         """Share *number* additively."""
         assert number is None or self.id in inputters
 
         results = []
         for peer_id in inputters:
+            # Unique program counter per input.
+            self.increment_pc()
+
             if peer_id == self.id:
                 a = field(rand.randint(0, field.modulus - 1))
                 b = number - a
@@ -121,7 +122,6 @@
     def output(self, share, receivers=None):
         return self.open(share, receivers)
 
-    @increment_pc
     def open(self, share, receivers=None):
         """Open *share* to *receivers* (defaults to both players)."""
 
--- a/viff/passive.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/viff/passive.py	Fri Oct 23 13:50:19 2009 +0200
@@ -22,8 +22,7 @@
 import operator
 
 from viff import shamir
-from viff.runtime import Runtime, increment_pc, Share, ShareList, \
-     gather_shares, preprocess
+from viff.runtime import Runtime, Share, ShareList, gather_shares, preprocess
 from viff.prss import prss, prss_lsb, prss_zero, prss_multi
 from viff.field import GF256, FieldElement
 from viff.util import rand, profile
@@ -57,7 +56,6 @@
     def output(self, share, receivers=None, threshold=None):
         return self.open(share, receivers, threshold)
 
-    @increment_pc
     def open(self, share, receivers=None, threshold=None):
         """Open a secret sharing.
 
@@ -175,7 +173,6 @@
         return result
 
     @profile
-    @increment_pc
     def mul(self, share_a, share_b):
         """Multiplication of shares.
 
@@ -232,7 +229,6 @@
         else:
             return share * (share ** (exponent-1))
 
-    @increment_pc
     def xor(self, share_a, share_b):
         field = share_a.field
         if not isinstance(share_b, Share):
@@ -245,7 +241,18 @@
         else:
             return share_a + share_b - 2 * share_a * share_b
 
-    @increment_pc
+    def prss_key(self):
+        """Create unique key for PRSS.
+
+        This increments the program counter and returns it as a tuple.
+        Each straight-line program (typically a callback attached to
+        some :class:`Deferred`) is executed in a context with unique
+        starting program counter. This ensures that consequetive calls
+        to PRSS-related methods will use unique program counters.
+        """
+        self.increment_pc()
+        return tuple(self.program_counter)
+
     def prss_share(self, inputters, field, element=None):
         """Creates pseudo-random secret sharings.
 
@@ -273,7 +280,7 @@
         n = self.num_players
 
         # Key used for PRSS.
-        key = tuple(self.program_counter)
+        key = self.prss_key()
 
         # The shares for which we have all the keys.
         all_shares = []
@@ -314,7 +321,6 @@
         else:
             return result
 
-    @increment_pc
     def prss_share_random(self, field, binary=False):
         """Generate shares of a uniformly random element from the field given.
 
@@ -329,7 +335,7 @@
             modulus = field.modulus
 
         # Key used for PRSS.
-        prss_key = tuple(self.program_counter)
+        prss_key = self.prss_key()
         prfs = self.players[self.id].prfs(modulus)
         share = prss(self.num_players, self.id, field, prfs, prss_key)
 
@@ -354,7 +360,6 @@
         self.schedule_callback(result, finish, share, binary)
         return result
 
-    @increment_pc
     def prss_share_random_multi(self, field, quantity, binary=False):
         """Does the same as calling *quantity* times :meth:`prss_share_random`,
         but with less calls to the PRF. Sampling of a binary element is only
@@ -371,13 +376,12 @@
             modulus = field.modulus
 
         # Key used for PRSS.
-        prss_key = tuple(self.program_counter)
+        prss_key = self.prss_key()
         prfs = self.players[self.id].prfs(modulus ** quantity)
         shares = prss_multi(self.num_players, self.id, field, prfs, prss_key,
                             modulus, quantity)
         return [Share(self, field, share) for share in shares]
 
-    @increment_pc
     def prss_share_zero(self, field, quantity):
         """Generate *quantity* shares of the zero element from the
         field given.
@@ -385,13 +389,12 @@
         Communication cost: none.
         """
         # Key used for PRSS.
-        prss_key = tuple(self.program_counter)
+        prss_key = self.prss_key()
         prfs = self.players[self.id].prfs(field.modulus)
         zero_share = prss_zero(self.num_players, self.threshold, self.id,
                                field, prfs, prss_key, quantity)
         return [Share(self, field, zero_share[i]) for i in range(quantity)]
 
-    @increment_pc
     def prss_double_share(self, field, quantity):
         """Make *quantity* double-sharings using PRSS.
 
@@ -402,7 +405,6 @@
         z_2t = self.prss_share_zero(field, quantity)
         return (r_t, [r_t[i] + z_2t[i] for i in range(quantity)])
 
-    @increment_pc
     def prss_share_bit_double(self, field):
         """Share a random bit over *field* and GF256.
 
@@ -414,7 +416,7 @@
         n = self.num_players
         k = self.options.security_parameter
         prfs = self.players[self.id].prfs(2**k)
-        prss_key = tuple(self.program_counter)
+        prss_key = self.prss_key()
 
         b_p = self.prss_share_random(field, binary=True)
         r_p, r_lsb = prss_lsb(n, self.id, field, prfs, prss_key)
@@ -427,13 +429,12 @@
         # Use r_lsb to flip b as needed.
         return (b_p, b ^ r_lsb)
 
-    @increment_pc
     def prss_shamir_share_bit_double(self, field):
         """Shamir share a random bit over *field* and GF256."""
         n = self.num_players
         k = self.options.security_parameter
         prfs = self.players[self.id].prfs(2**k)
-        prss_key = tuple(self.program_counter)
+        prss_key = self.prss_key()
         inputters = range(1, self.num_players + 1)
 
         ri = rand.randint(0, 2**k - 1)
@@ -461,7 +462,6 @@
             result.append(share)
         return result
 
-    @increment_pc
     @preprocess("prss_powerchains")
     def prss_powerchain(self, max=7):
         """Generate a random secret share in GF256 and returns
@@ -472,6 +472,7 @@
     def prss_powerchains(self, max=7, quantity=20):
         """Does *quantity* times the same as :meth:`prss_powerchain`.
         Used for preprocessing."""
+        quantity = min(quantity, 20)
         shares = self.prss_share_random_multi(GF256, quantity)
         return [gatherResults(self.powerchain(share, max)) for share in shares]
 
@@ -482,7 +483,6 @@
         """
         return self.shamir_share(inputters, field, number, threshold)
 
-    @increment_pc
     def shamir_share(self, inputters, field, number=None, threshold=None):
         """Secret share *number* over *field* using Shamir's method.
 
@@ -525,6 +525,9 @@
 
         results = []
         for peer_id in inputters:
+            # Unique program counter per input.
+            self.increment_pc()
+
             if peer_id == self.id:
                 pc = tuple(self.program_counter)
                 shares = shamir.share(field(number), threshold,
--- a/viff/prss.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/viff/prss.py	Fri Oct 23 13:50:19 2009 +0200
@@ -40,9 +40,6 @@
 `Download <http://www.cs.technion.ac.il/~yuvali/pubs/CDI05.ps>`__.
 """
 
-__docformat__ = "restructuredtext"
-
-
 import sha
 from math import ceil
 from binascii import hexlify
--- a/viff/reactor.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/viff/reactor.py	Fri Oct 23 13:50:19 2009 +0200
@@ -19,8 +19,6 @@
 
 """VIFF reactor to have control over the scheduling."""
 
-__docformat__ = "restructuredtext"
-
 from twisted.internet.selectreactor import SelectReactor
 
 
@@ -42,7 +40,7 @@
         self.runUntilCurrent()
         t2 = self.timeout()
 
-        if (t2 is not None):
+        if t2 is not None:
             t = min(t, self.running and t2)
 
         SelectReactor.doIteration(self, t)
--- a/viff/runtime.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/viff/runtime.py	Fri Oct 23 13:50:19 2009 +0200
@@ -31,16 +31,16 @@
 """
 from __future__ import division
 
-__docformat__ = "restructuredtext"
-
 import time
 import struct
 from optparse import OptionParser, OptionGroup
 from collections import deque
 import os
+import sys
 
 from viff.field import GF256, FieldElement
 from viff.util import wrapper, rand, deep_wait, track_memory_usage, begin, end
+from viff.constants import SHARE
 import viff.reactor
 
 from twisted.internet import reactor
@@ -51,13 +51,6 @@
 from twisted.internet.protocol import ReconnectingClientFactory, ServerFactory
 from twisted.protocols.basic import Int16StringReceiver
 
-# Constants used by ShareExchanger.
-SHARE    = 0
-ECHO     = 1
-READY    = 2
-SEND     = 3
-PAILLIER = 4
-
 
 class Share(Deferred):
     """A shared number.
@@ -382,6 +375,65 @@
         """Disconnect this protocol instance."""
         self.transport.loseConnection()
 
+class SelfShareExchanger(ShareExchanger):
+
+    def __init__(self, id, factory):
+        ShareExchanger.__init__(self)
+        self.peer_id = id
+        self.factory = factory
+
+    def stringReceived(self, program_counter, data_type, data):
+        """Called when a share is received.
+
+        The string received is unpacked into the program counter, and
+        a data part. The data is passed the appropriate Deferred in
+        :class:`self.incoming_data`.
+        """
+        try:
+            key = (program_counter, data_type)
+                         
+            if key in self.waiting_deferreds:
+                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:
+                deq = self.incoming_data.setdefault(key, deque())
+                deq.append(data)
+        except struct.error, e:
+            self.factory.runtime.abort(self, e)
+
+    def sendData(self, program_counter, data_type, data):
+        """Send data to the self.id."""
+        self.stringReceived(program_counter, data_type, data)
+
+    def loseConnection(self):
+        """Disconnect this protocol instance."""
+        self.lost_connection.callback(self)
+        return None
+
+
+class SelfShareExchangerFactory(ReconnectingClientFactory, ServerFactory):
+    """Factory for creating SelfShareExchanger protocols."""
+
+    protocol = SelfShareExchanger
+    maxDelay = 3
+    factor = 1.234567 # About half of the Twisted default
+
+    def __init__(self, runtime):
+        """Initialize the factory."""
+        self.runtime = runtime
+
+    def identify_peer(self, protocol):
+        raise Exception("Is identify_peer necessary?")
+
+    def clientConnectionLost(self, connector, reason):
+        reason.trap(ConnectionDone)
+
+class FakeTransport(object):
+    def close(self):
+        return True
 
 class ShareExchangerFactory(ReconnectingClientFactory, ServerFactory):
     """Factory for creating ShareExchanger protocols."""
@@ -407,25 +459,6 @@
         reason.trap(ConnectionDone)
 
 
-def increment_pc(method):
-    """Make *method* automatically increment the program counter.
-
-    Adding this decorator to a :class:`Runtime` method will ensure
-    that the program counter is incremented correctly when entering
-    the method.
-    """
-
-    @wrapper(method)
-    def inc_pc_wrapper(self, *args, **kwargs):
-        try:
-            self.program_counter[-1] += 1
-            self.program_counter.append(0)
-            return method(self, *args, **kwargs)
-        finally:
-            self.program_counter.pop()
-    return inc_pc_wrapper
-
-
 def preprocess(generator):
     """Track calls to this method.
 
@@ -444,6 +477,7 @@
 
         @wrapper(method)
         def preprocess_wrapper(self, *args, **kwargs):
+            self.increment_pc()
             pc = tuple(self.program_counter)
             try:
                 return self._pool.pop(pc)
@@ -451,7 +485,11 @@
                 key = (generator, args)
                 pcs = self._needed_data.setdefault(key, [])
                 pcs.append(pc)
-                return method(self, *args, **kwargs)
+                self.fork_pc()
+                try:
+                    return method(self, *args, **kwargs)
+                finally:
+                    self.unfork_pc()
 
         return preprocess_wrapper
     return preprocess_decorator
@@ -554,7 +592,9 @@
         self.players = {}
         # Add ourselves, but with no protocol since we wont be
         # communicating with ourselves.
-        self.add_player(player, None)
+        protocol = SelfShareExchanger(self.id, SelfShareExchangerFactory(self))
+        protocol.transport = FakeTransport()
+        self.add_player(player, protocol)
 
         #: Queue of deferreds and data.
         self.deferred_queue = deque()
@@ -564,15 +604,15 @@
         #: Record the recursion depth.
         self.depth_counter = 0
         self.max_depth = 0
+        #: Recursion depth limit by experiment, including security margin.
+        self.depth_limit = int(sys.getrecursionlimit() / 50)
         #: Use deferred queues only if the ViffReactor is running.
         self.using_viff_reactor = isinstance(reactor, viff.reactor.ViffReactor)
 
     def add_player(self, player, protocol):
         self.players[player.id] = player
         self.num_players = len(self.players)
-        # There is no protocol for ourselves, so we wont add that:
-        if protocol is not None:
-            self.protocols[player.id] = protocol
+        self.protocols[player.id] = protocol
 
     def shutdown(self):
         """Shutdown the runtime.
@@ -623,7 +663,18 @@
         dl = DeferredList(vars)
         self.schedule_callback(dl, lambda _: self.shutdown())
 
-    @increment_pc
+    def increment_pc(self):
+        """Increment the program counter."""
+        self.program_counter[-1] += 1
+
+    def fork_pc(self):
+        """Fork the program counter."""
+        self.program_counter.append(0)
+
+    def unfork_pc(self):
+        """Leave a fork of the program counter."""
+        self.program_counter.pop()
+
     def schedule_callback(self, deferred, func, *args, **kwargs):
         """Schedule a callback on a deferred with the correct program
         counter.
@@ -637,6 +688,7 @@
         Any extra arguments are passed to the callback as with
         :meth:`addCallback`.
         """
+        self.increment_pc()
         saved_pc = self.program_counter[:]
 
         @wrapper(func)
@@ -645,6 +697,7 @@
             try:
                 current_pc = self.program_counter[:]
                 self.program_counter[:] = saved_pc
+                self.fork_pc()
                 return func(*args, **kwargs)
             finally:
                 self.program_counter[:] = current_pc
@@ -673,7 +726,6 @@
         deferred.addCallback(queue_callback, self, fork)
         return self.schedule_callback(fork, func, *args, **kwargs)
 
-    @increment_pc
     def synchronize(self):
         """Introduce a synchronization point.
 
@@ -682,6 +734,7 @@
         adding callbacks to the returned :class:`Deferred`, one can
         divide a protocol execution into disjoint phases.
         """
+        self.increment_pc()
         shares = [self._exchange_shares(player, GF256(0))
                   for player in self.players]
         result = gather_shares(shares)
@@ -689,10 +742,12 @@
         return result
 
     def _expect_data(self, peer_id, data_type, deferred):
-        assert peer_id != self.id, "Do not expect data from yourself!"
         # Convert self.program_counter to a hashable value in order to
         # use it as a key in self.protocols[peer_id].incoming_data.
         pc = tuple(self.program_counter)
+        return self._expect_data_with_pc(pc, peer_id, data_type, deferred)
+
+    def _expect_data_with_pc(self, pc, peer_id, data_type, deferred):
         key = (pc, data_type)
 
         if key in self.protocols[peer_id].incoming_data:
@@ -729,7 +784,6 @@
         self._expect_data(peer_id, SHARE, share)
         return share
 
-    @increment_pc
     def preprocess(self, program):
         """Generate preprocess material.
 
@@ -749,25 +803,37 @@
         example of a method fulfilling this interface.
         """
 
-        def update(results, program_counters):
+        def update(results, program_counters, start_time, count, what):
+            stop = time.time()
+
+            print
+            print "Total time used: %.3f sec" % (stop - start_time)
+            print "Time per %s operation: %.0f ms" % (what, 1000*(stop - start_time) / count)
+            print "*" * 6
+
             # Update the pool with pairs of program counter and data.
             self._pool.update(zip(program_counters, results))
 
         wait_list = []
         for ((generator, args), program_counters) in program.iteritems():
             print "Preprocessing %s (%d items)" % (generator, len(program_counters))
+            self.increment_pc()
+            self.fork_pc()
             func = getattr(self, generator)
+            count = 0
+            start_time = time.time()
 
-            block_size = 20
             while program_counters:
-                results = []
-                while len(results) < len(program_counters) and \
-                          len(results) < block_size:
-                    results += func(*args)
+                count += 1
+                self.increment_pc()
+                self.fork_pc()
+                results = func(quantity=len(program_counters), *args)
+                self.unfork_pc()
                 ready = gatherResults(results)
-                ready.addCallback(update, program_counters[:len(results)])
+                ready.addCallback(update, program_counters[:len(results)], start_time, count, generator)
                 del program_counters[:len(results)]
                 wait_list.append(ready)
+            self.unfork_pc()
         return gatherResults(wait_list)
 
     def input(self, inputters, field, number=None):
@@ -779,7 +845,7 @@
         listed in *inputters*, then a :class:`Share` is given back
         directly.
         """
-        raise NotImplemented("Override this abstract method in a subclass.")
+        raise NotImplementedError
 
     def output(self, share, receivers=None):
         """Open *share* to *receivers* (defaults to all players).
@@ -787,7 +853,7 @@
         Returns a :class:`Share` to players with IDs in *receivers*
         and :const:`None` to the remaining players.
         """
-        raise NotImplemented("Override this abstract method in a subclass.")
+        raise NotImplementedError
 
     def add(self, share_a, share_b):
         """Secure addition.
@@ -795,7 +861,7 @@
         At least one of the arguments must be a :class:`Share`, the
         other can be a :class:`FieldElement` or a (possible long)
         Python integer."""
-        raise NotImplemented("Override this abstract method in a subclass.")
+        raise NotImplementedError
 
     def mul(self, share_a, share_b):
         """Secure multiplication.
@@ -803,7 +869,7 @@
         At least one of the arguments must be a :class:`Share`, the
         other can be a :class:`FieldElement` or a (possible long)
         Python integer."""
-        raise NotImplemented("Override this abstract method in a subclass.")
+        raise NotImplementedError
 
     def handle_deferred_data(self, deferred, data):
         """Put deferred and data into the queue if the ViffReactor is running. 
@@ -828,7 +894,7 @@
     def process_queue(self, queue):
         """Execute the callbacks of the deferreds in *queue*."""
 
-        while(queue):
+        while queue:
             deferred, data = queue.popleft()
             deferred.callback(data)
 
@@ -850,13 +916,16 @@
             if self.depth_counter > self.max_depth:
                 # Record the maximal depth reached.
                 self.max_depth = self.depth_counter
+                if self.depth_counter >= self.depth_limit:
+                    print "Recursion depth limit reached."
 
-            reactor.doIteration(0)
+            if self.depth_counter < self.depth_limit:
+                reactor.doIteration(0)
 
             self.depth_counter -= 1
             self.activation_counter = 0
 
-    def print_transferred_data():
+    def print_transferred_data(self):
         """Print the amount of transferred data for all connections."""
 
         for protocol in self.protocols.itervalues():
--- a/viff/shamir.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/viff/shamir.py	Fri Oct 23 13:50:19 2009 +0200
@@ -20,9 +20,6 @@
 (11): 612-613.
 """
 
-__docformat__ = "restructuredtext"
-
-
 import operator
 from viff.util import rand, fake
 
--- a/viff/test/test_basic_runtime.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/viff/test/test_basic_runtime.py	Fri Oct 23 13:50:19 2009 +0200
@@ -18,7 +18,6 @@
 from twisted.internet.defer import Deferred, gatherResults
 
 from viff.test.util import RuntimeTestCase, protocol
-from viff.runtime import increment_pc
 
 
 class ProgramCounterTest(RuntimeTestCase):
@@ -29,31 +28,18 @@
         self.assertEquals(runtime.program_counter, [0])
 
     @protocol
-    def test_simple_operation(self, runtime):
-        """Test an operation which makes no further calls.
+    def test_synchronize(self, runtime):
+        """Test whether synchronize increases the program counter.
 
-        Each call should increment the program counter by one.
-        """
+        Every synchronize operation should have its unique program
+        counter."""
+        self.assertEquals(runtime.program_counter, [0])
         runtime.synchronize()
         self.assertEquals(runtime.program_counter, [1])
         runtime.synchronize()
         self.assertEquals(runtime.program_counter, [2])
 
     @protocol
-    def test_complex_operation(self, runtime):
-        """Test an operation which makes nested calls.
-
-        This verifies that the program counter is only incremented by
-        one, even for a complex operation.
-        """
-        # Exclusive-or is calculated as x + y - 2 * x * y, so add,
-        # sub, and mul are called.
-        runtime.xor(self.Zp(0), self.Zp(1))
-        self.assertEquals(runtime.program_counter, [1])
-        runtime.xor(self.Zp(0), self.Zp(1))
-        self.assertEquals(runtime.program_counter, [2])
-
-    @protocol
     def test_callback(self, runtime):
         """Test a scheduled callback.
 
@@ -62,62 +48,32 @@
         """
 
         def verify_program_counter(_):
+            # The callback is run with its own sub-program counter.
             self.assertEquals(runtime.program_counter, [1, 0])
 
         d = Deferred()
+
+        self.assertEquals(runtime.program_counter, [0])
+
+        # Scheduling a callback increases the program counter.
         runtime.schedule_callback(d, verify_program_counter)
-
-        runtime.synchronize()
-        self.assertEquals(runtime.program_counter, [2])
+        self.assertEquals(runtime.program_counter, [1])
 
         # Now trigger verify_program_counter.
         d.callback(None)
 
     @protocol
-    def test_nested_calls(self, runtime):
-        """Test Runtime methods that call other methods.
-
-        We create a couple of functions that are used as fake methods.
-        """
-
-        @increment_pc
-        def method_a(runtime):
-            # First top-level call, so first entry is 1. No calls to
-            # other methods decorated with increment_pc has been made,
-            # so the second entry is 0.
-            self.assertEquals(runtime.program_counter, [1, 0])
-            method_b(runtime, 1)
-
-            self.assertEquals(runtime.program_counter, [1, 1])
-            method_b(runtime, 2)
-
-            # At this point two sub-calls has been made:
-            self.assertEquals(runtime.program_counter, [1, 2])
-
-        @increment_pc
-        def method_b(runtime, count):
-            # This method is called twice from method_a:
-            self.assertEquals(runtime.program_counter, [1, count, 0])
-
-        # Zero top-level calls:
-        self.assertEquals(runtime.program_counter, [0])
-        method_a(runtime)
-
-        # One top-level call:
-        self.assertEquals(runtime.program_counter, [1])
-
-    @protocol
     def test_multiple_callbacks(self, runtime):
 
         d1 = Deferred()
         d2 = Deferred()
 
         def verify_program_counter(_, count):
-            self.assertEquals(runtime.program_counter, [1, count, 0])
+            self.assertEquals(runtime.program_counter, [count, 0])
 
-        @increment_pc
         def method_a(runtime):
-            self.assertEquals(runtime.program_counter, [1, 0])
+            # No calls to schedule_callback yet.
+            self.assertEquals(runtime.program_counter, [0])
 
             runtime.schedule_callback(d1, verify_program_counter, 1)
             runtime.schedule_callback(d2, verify_program_counter, 2)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/viff/test/test_hash_broadcast.py	Fri Oct 23 13:50:19 2009 +0200
@@ -0,0 +1,180 @@
+# Copyright 2009 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/>.
+
+from twisted.internet.defer import Deferred, DeferredList
+
+from viff.test.util import RuntimeTestCase, protocol
+from viff.field import GF
+
+from viff.comparison import Toft05Runtime
+from viff.hash_broadcast import HashBroadcastMixin
+
+class BroadcastRuntime(Toft05Runtime, HashBroadcastMixin):
+    """Mix of :class:`Toft05Runtime` and
+    :class:`HashBroadcastRuntime`."""
+    pass
+
+class HashBroadcastTest(RuntimeTestCase):
+    """Test for the hash broadcast mixin."""
+
+    # Number of players.
+    num_players = 3
+
+    runtime_class = BroadcastRuntime
+
+    timeout = 10
+    @protocol
+    def test_send(self, runtime):
+        """Test of send a value."""
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        value = 42
+
+        receivers = [2, 3]
+        if 1 == runtime.id:
+            d = runtime.broadcast([1], receivers, str(value))
+        else:
+            d = runtime.broadcast([1], receivers)
+        def check(x):
+            self.assertEquals(int(x), 42)
+        d.addCallback(check)
+        return d
+            
+
+    @protocol
+    def test_send_two_senders_in_parallel(self, runtime):
+        """Test of send a value."""
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        def check(ls):
+            for s, x in ls:
+                self.assertEquals(int(x), 42)
+            return ls
+
+        value = 42
+
+        receivers = [2, 3]
+        if 1 == runtime.id:
+            d1 = runtime.broadcast([1], receivers, str(value))
+        else:
+            d1 = runtime.broadcast([1], receivers)
+
+        if 2 == runtime.id:
+            d2 = runtime.broadcast([2], [3], str(value))
+        else:
+            d2 = runtime.broadcast([2], [3])
+
+        ds = [d1]
+        if [] != d2:
+            ds.append(d2)
+        dls = DeferredList(ds)
+        dls.addCallback(check)
+        return dls
+            
+    @protocol
+    def test_send_multiple_senders_in_one_burst(self, runtime):
+        """Test of send a value."""
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        value = 42
+        if 1 == runtime.id:
+            value = 7
+
+        if 1 == runtime.id or 3 == runtime.id:
+            ds = runtime.broadcast([1, 3], [2], str(value))
+
+        if 2 == runtime.id:
+            ds = runtime.broadcast([1, 3], [2])
+            dls = DeferredList(ds)
+            def check(ls):
+                self.assertEquals(int(ls[0][1]), 7)
+                self.assertEquals(int(ls[1][1]), 42)
+                return ls
+            dls.addCallback(check)
+            return dls
+        return None
+            
+
+    @protocol
+    def test_sender_in_receivers(self, runtime):
+        """Test of send a value."""
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        value = 42
+        if 1 == runtime.id:
+            d = runtime.broadcast([1], [1, 2, 3], str(value))
+        else:
+            d = runtime.broadcast([1], [1, 2, 3])
+
+        def check(x):
+            self.assertEquals(int(x), 42)
+            return x
+        d.addCallback(check)
+        return d
+
+    @protocol
+    def test_complex(self, runtime):
+        def check(ls):
+            for x, v in ls:
+                self.assertEquals(runtime.list_str(v), ['7', '9', '13'])
+            
+        receivers = [1, 2, 3]
+        def exchange((xi, rhoi1, rhoi2)):
+            # Send share to all receivers.
+            ds = runtime.broadcast(receivers, receivers, str((str(xi), str(rhoi1), str(rhoi2))))
+            dls = DeferredList(ds)
+            dls.addCallbacks(check, runtime.error_handler)
+            return dls
+
+        result = Deferred()
+        result.addCallbacks(exchange, runtime.error_handler)
+        result.callback((7, 9, 13))
+        return result
+
+    @protocol
+    def test_complex2(self, runtime):
+        def check(ls):
+            if (2 == runtime.id) or (1 == runtime.id):
+                self.assertEquals(ls[0][1], "V1")
+                self.assertEquals(ls[1][1], "V1")
+                self.assertEquals(ls[2][1], "V1")
+                self.assertEquals(ls[3][1], "V2")
+            else:
+                self.assertEquals(ls[0][1], "V1")
+                self.assertEquals(ls[1][1], "V1")
+                self.assertEquals(ls[2][1], "V1")
+                self.assertEquals(ls[3][1], "V2")
+                self.assertEquals(ls[4][1], "V2")
+        field = self.Zp
+        results = []
+        results += runtime.broadcast(runtime.players.keys(), runtime.players.keys(), "V1")
+        if runtime.id in [1, 2]:
+            v = runtime.broadcast([1, 2], [3], "V2")
+            if isinstance(v, list):
+                results += v
+            else:
+                results.append(v)
+        else:
+            results += runtime.broadcast([1, 2], [3])
+        if 3 == runtime.id:
+            results += [runtime.broadcast([3], runtime.players.keys(), str(7))]
+        else:
+            results += [runtime.broadcast([3], runtime.players.keys())]
+        dls = DeferredList(results)
+        runtime.schedule_callback(dls, check)
+        dls.addErrback(runtime.error_handler)
+        return dls
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/viff/test/test_orlandi_runtime.py	Fri Oct 23 13:50:19 2009 +0200
@@ -0,0 +1,774 @@
+# Copyright 2009 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/>.
+
+from twisted.internet.defer import gatherResults, DeferredList
+
+from viff.test.util import RuntimeTestCase, protocol
+from viff.runtime import gather_shares
+try:
+    from viff.orlandi import OrlandiRuntime, OrlandiShare
+    import commitment
+except ImportError:
+    commitment = None
+    OrlandiRuntime = None
+    OrlandiShare = None
+
+from viff.field import FieldElement, GF
+
+from viff.util import rand
+
+
+def _get_triple(runtime, field):
+    n = field(0)
+    Ca = commitment.commit(6, 0, 0)
+    a = OrlandiShare(runtime, field, field(2), (n, n), Ca)
+    Cb = commitment.commit(12, 0, 0)
+    b = OrlandiShare(runtime, field, field(4), (n, n), Cb)
+    Cc = commitment.commit(72, 0, 0)
+    c = OrlandiShare(runtime, field, field(24), (n, n), Cc)
+    return (a, b, c)
+
+
+class OrlandiBasicCommandsTest(RuntimeTestCase):
+    """Test for basic commands."""
+
+    # Number of players.
+    num_players = 3
+
+    runtime_class = OrlandiRuntime
+
+    @protocol
+    def test_secret_share(self, runtime):
+        """Test sharing of random numbers."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        def check((xi, (rho1, rho2), Cr)):
+            # Check that we got the expected number of shares.
+            self.assert_type(xi, FieldElement)
+            self.assert_type(rho1, FieldElement)
+            self.assert_type(rho2, FieldElement)
+            self.assert_type(Cr, commitment.Commitment)
+
+        if 1 == runtime.id:
+            share = runtime.secret_share([1], self.Zp, 42)
+        else:
+            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
+
+    @protocol
+    def test_random_share(self, runtime):
+        """Test creation of a random shared number."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        def check(v):
+            self.assertEquals(True, True)
+
+        x = runtime.random_share(self.Zp)
+        d = runtime.open(x)
+        d.addCallback(check)
+        return d
+
+    @protocol
+    def test_sum(self, runtime):
+        """Test addition of two numbers."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        x1 = 42
+        y1 = 7
+
+        def check(v):
+            self.assertEquals(v, x1 + y1)
+
+        if 1 == runtime.id:
+            x2 = runtime.secret_share([1], self.Zp, x1)
+        else:
+            x2 = runtime.secret_share([1], self.Zp)
+
+        if 3 == runtime.id:
+            y2 = runtime.secret_share([3], self.Zp, y1)
+        else:
+            y2 = runtime.secret_share([3], self.Zp)
+
+        z2 = runtime.add(x2, y2)
+        d = runtime.open(z2)
+        d.addCallback(check)
+        return d
+
+    @protocol
+    def test_sum_plus(self, runtime):
+        """Test addition of two numbers."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        x1 = 42
+        y1 = 7
+
+        def check(v):
+            self.assertEquals(v, x1 + y1)
+
+        if 1 == runtime.id:
+            x2 = runtime.secret_share([1], self.Zp, x1)
+        else:
+            x2 = runtime.secret_share([1], self.Zp)
+
+        if 3 == runtime.id:
+            y2 = runtime.secret_share([3], self.Zp, y1)
+        else:
+            y2 = runtime.secret_share([3], self.Zp)
+
+        z2 = x2 + y2
+        d = runtime.open(z2)
+        d.addCallback(check)
+        return d
+
+    @protocol
+    def test_sum_constant(self, runtime):
+        """Test addition of two numbers."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        x1 = 42
+        y1 = 7
+
+        def check(v):
+            self.assertEquals(v, x1 + y1)
+
+        if 1 == runtime.id:
+            x2 = runtime.secret_share([1], self.Zp, x1)
+        else:
+            x2 = runtime.secret_share([1], self.Zp)
+
+        z2 = x2 + y1
+        d = runtime.open(z2)
+        d.addCallback(check)
+        return d
+
+    @protocol
+    def test_sub(self, runtime):
+        """Test subtration of two numbers."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        x1 = 42
+        y1 = 7
+
+        def check(v):
+            self.assertEquals(v, x1 - y1)
+
+        if 1 == runtime.id:
+            x2 = runtime.secret_share([1], self.Zp, x1)
+        else:
+            x2 = runtime.secret_share([1], self.Zp)
+
+        if 3 == runtime.id:
+            y2 = runtime.secret_share([3], self.Zp, y1)
+        else:
+            y2 = runtime.secret_share([3], self.Zp)
+
+        z2 = runtime.sub(x2, y2)
+        d = runtime.open(z2)
+        d.addCallback(check)
+        return d
+
+    @protocol
+    def test_sub_minus(self, runtime):
+        """Test subtration of two numbers."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        x1 = 42
+        y1 = 7
+
+        def check(v):
+            self.assertEquals(v, x1 - y1)
+
+        if 1 == runtime.id:
+            x2 = runtime.secret_share([1], self.Zp, x1)
+        else:
+            x2 = runtime.secret_share([1], self.Zp)
+
+        if 3 == runtime.id:
+            y2 = runtime.secret_share([3], self.Zp, y1)
+        else:
+            y2 = runtime.secret_share([3], self.Zp)
+
+        z2 = x2 - y2
+        d = runtime.open(z2)
+        d.addCallback(check)
+        return d
+
+    @protocol
+    def test_sub_constant(self, runtime):
+        """Test subtration of two numbers."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        x1 = 42
+        y1 = 7
+
+        def check(v):
+            self.assertEquals(v, x1 - y1)
+
+        if 1 == runtime.id:
+            x2 = runtime.secret_share([1], self.Zp, x1)
+        else:
+            x2 = runtime.secret_share([1], self.Zp)
+
+        z2 = x2 - y1
+        d = runtime.open(z2)
+        d.addCallback(check)
+        return d
+
+
+class OrlandiAdvancedCommandsTest(RuntimeTestCase):
+    """Test for advanced commands."""
+
+    # Number of players.
+    num_players = 3
+
+    runtime_class = OrlandiRuntime
+
+    timeout = 60
+
+    @protocol
+    def test_shift(self, runtime):
+        """Test addition of the shift command."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        def check(v):
+            self.assertEquals(v, 42)
+
+        x = runtime.shift([2], self.Zp, 42)
+        d = runtime.open(x)
+        d.addCallback(check)
+        return d
+
+    @protocol
+    def test_shift_two_inputters(self, runtime):
+        """Test addition of the shift command."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        def check(v):
+            self.assertEquals(v, 42)
+
+        x, y = runtime.shift([1,3], self.Zp, 42)
+        d1 = runtime.open(x)
+        d1.addCallback(check)
+        d2 = runtime.open(y)
+        d2.addCallback(check)
+        return DeferredList([d1, d2])
+
+    @protocol
+    def test_shift_two_consequtive_inputters(self, runtime):
+        """Test addition of the shift command."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        def r1(ls):
+            x, y = ls
+            self.assertEquals(runtime.program_counter, [4])
+
+        x = runtime.shift([1], self.Zp, 42)
+        y = runtime.shift([2], self.Zp, 42)
+        r = gather_shares([x, y])
+        r.addCallback(r1)
+        return r
+
+    @protocol
+    def test_shift_two_consequtive_inputters2(self, runtime):
+        """Test addition of the shift command."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        def check(v):
+            self.assertEquals(v, 42)
+
+        def r1((x, y)):
+            self.assertEquals(x, 42)
+            self.assertEquals(y, 42)
+
+        x = runtime.shift([1], self.Zp, 42)
+        y = runtime.shift([2], self.Zp, 42)
+        r = gather_shares([runtime.open(x), runtime.open(y)])
+        r.addCallback(r1)
+        return r
+
+    @protocol
+    def test_input(self, runtime):
+        """Test of many uses of the input command."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        count = 9
+
+        a_shares = []
+        b_shares = []
+        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)
+        return shares_ready
+
+    @protocol
+    def test_basic_multiply(self, runtime):
+        """Test multiplication of two numbers."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        x1 = 42
+        y1 = 7
+
+        def check(v):
+            self.assertEquals(v, x1 * y1)
+
+        x2 = runtime.shift([2], self.Zp, x1)
+        y2 = runtime.shift([3], self.Zp, y1)
+
+        a, b, c = _get_triple(self, self.Zp)
+        z2 = runtime._basic_multiplication(x2, y2, a, b, c)
+        d = runtime.open(z2)
+        d.addCallback(check)
+        return d
+
+    @protocol
+    def test_mul_mul(self, runtime):
+        """Test multiplication of two numbers."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        x1 = 42
+        y1 = 7
+
+        def check(v):
+            self.assertEquals(v, x1 * y1)
+
+        x2 = runtime.shift([2], self.Zp, x1)
+        y2 = runtime.shift([3], self.Zp, y1)
+
+        z2 = x2 * y2
+        d = runtime.open(z2)
+        d.addCallback(check)
+        return d
+
+    @protocol
+    def test_basic_multiply_constant_right(self, runtime):
+        """Test multiplication of two numbers."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        x1 = 42
+        y1 = 7
+
+        def check(v):
+            self.assertEquals(v, x1 * y1)
+
+        x2 = runtime.shift([1], self.Zp, x1)
+
+        a, b, c = _get_triple(self, self.Zp)
+        z2 = runtime._basic_multiplication(x2, self.Zp(y1), a, b, c)
+        d = runtime.open(z2)
+        d.addCallback(check)
+        return d
+
+    @protocol
+    def test_basic_multiply_constant_left(self, runtime):
+        """Test multiplication of two numbers."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        x1 = 42
+        y1 = 7
+
+        def check(v):
+            self.assertEquals(v, x1 * y1)
+
+        x2 = runtime.shift([1], self.Zp, x1)
+
+        a, b, c = _get_triple(self, self.Zp)
+        z2 = runtime._basic_multiplication(self.Zp(y1), x2, a, b, c)
+        d = runtime.open(z2)
+        d.addCallback(check)
+        return d
+
+    @protocol
+    def test_constant_multiplication_constant_left(self, runtime):
+        """Test multiplication of two numbers."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        x1 = 42
+        y1 = 7
+
+        def check(v):
+            self.assertEquals(v, x1 * y1)
+
+        x2 = runtime.shift([1], self.Zp, x1)
+
+        z2 = runtime._cmul(self.Zp(y1), x2, self.Zp)
+        d = runtime.open(z2)
+        d.addCallback(check)
+        return d
+
+    @protocol
+    def test_constant_multiplication_constant_right(self, runtime):
+        """Test multiplication of two numbers."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        x1 = 42
+        y1 = 7
+
+        def check(v):
+            self.assertEquals(v, x1 * y1)
+
+        x2 = runtime.shift([1], self.Zp, x1)
+
+        z2 = runtime._cmul(x2, self.Zp(y1), self.Zp)
+        d = runtime.open(z2)
+        d.addCallback(check)
+        return d
+
+    @protocol
+    def test_constant_multiplication_constant_None(self, runtime):
+        """Test multiplication of two numbers."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        x1 = 42
+        y1 = 7
+
+        x2 = runtime.shift([1], self.Zp, x1)
+        y2 = runtime.shift([1], self.Zp, y1)
+
+    @protocol
+    def test_sum_poly1(self, runtime):
+        """Test implementation of sum_poly."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        f = []
+        f.append((self.Zp(7), (self.Zp(7), self.Zp(7)), self.Zp(7)))
+        f.append((self.Zp(9), (self.Zp(9), self.Zp(9)), self.Zp(9)))
+        f.append((self.Zp(13), (self.Zp(13), self.Zp(13)), self.Zp(13)))
+
+        x, (rho1, rho2), Cx = runtime.sum_poly(1, f)
+        self.assertEquals(x, 29)
+        self.assertEquals(rho1, 29)
+        self.assertEquals(rho2, 29)
+        self.assertEquals(Cx, 819)
+        return x
+
+    @protocol
+    def test_sum_poly2(self, runtime):
+        """Test implementation of sum_poly."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        Cf1 = commitment.commit(21, 21, 21)
+        Cf2 = commitment.commit(27, 27, 27)
+        Cf3 = commitment.commit(39, 39, 39)
+
+        f = []
+        f.append((self.Zp(7), (self.Zp(7), self.Zp(7)), Cf1))
+        f.append((self.Zp(9), (self.Zp(9), self.Zp(9)), Cf2))
+        f.append((self.Zp(13), (self.Zp(13), self.Zp(13)), Cf3))
+
+        x, (rho1, rho2), Cx = runtime.sum_poly(3, f)
+        self.assertEquals(x, 453)
+        self.assertEquals(rho1, 453)
+        self.assertEquals(rho2, 453)
+        self.assertEquals(Cx, Cf1**3 * Cf2**9 * Cf3**27)
+        return x
+
+    @protocol
+    def test_delta(self, runtime):
+        """Test implementation of compute_delta."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        delta = runtime.compute_delta(3)
+        self.assertEquals(delta[0], 7)
+        self.assertEquals(delta[1], -21)
+        self.assertEquals(delta[2], 35)
+        self.assertEquals(delta[3], -35)
+        self.assertEquals(delta[4], 21)
+        self.assertEquals(delta[5], -7)
+        self.assertEquals(delta[6], 1)
+
+        return delta
+
+    @protocol
+    def test_leak_mul(self, runtime):
+        """Test leaktolerant multiplication of two numbers."""
+        commitment.set_reference_string(long(2), long(6))
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        x1 = 42
+        y1 = 7
+
+        runtime.s = 1
+        runtime.d = 0
+        runtime.s_lambda = 1
+
+        def check(v):
+            self.assertEquals(v, x1 * y1)
+
+        x2 = runtime.shift([1], self.Zp, x1)
+        y2 = runtime.shift([2], self.Zp, y1)
+
+        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)
+        return z2
+
+class TripleGenTest(RuntimeTestCase):
+    """Test for generation of triples."""
+
+    # Number of players.
+    num_players = 3
+
+    runtime_class = OrlandiRuntime
+
+    timeout = 1600
+
+    @protocol
+    def test_tripleGen(self, runtime):
+        """Test the triple_gen command."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        def check((a, b, c)):
+            self.assertEquals(c, a * b)
+
+        def open((a, b, c, _)):
+            d1 = runtime.open(a)
+            d2 = runtime.open(b)
+            d3 = runtime.open(c)
+            d = gatherResults([d1, d2, d3])
+            d.addCallback(check)
+            return d
+        d = runtime.triple_gen(self.Zp)
+        d.addCallbacks(open, runtime.error_handler)
+        return d
+
+    @protocol
+    def test_tripleGen2(self, runtime):
+        """Test the triple_gen command."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        def check((a, b, c, dx, dy, dz)):
+            self.assertEquals(c, a * b)
+            self.assertEquals(dz, dx * dy)
+
+        def open(((a, b, c, control), (x, y, z, _))):
+            d1 = runtime.open(a)
+            d2 = runtime.open(b)
+            d3 = runtime.open(c)
+            dx = runtime.open(x)
+            dy = runtime.open(y)
+            dz = runtime.open(z)
+            d = gatherResults([d1, d2, d3, dx, dy, dz])
+            d.addCallback(check)
+            return d
+        t1 = runtime.triple_gen(self.Zp)
+        t2 = runtime.triple_gen(self.Zp)
+        d = gatherResults([t1, t2])
+        d.addCallbacks(open, runtime.error_handler)
+        return d
+
+    @protocol
+    def test_tripleTest(self, runtime):
+        """Test the triple_test command."""
+
+        self.Zp = GF(6277101735386680763835789423176059013767194773182842284081)
+
+        def check((a, b, c)):
+            self.assertEquals(c, a * b)
+
+        def open((a, b, c, _)):
+            d1 = runtime.open(a)
+            d2 = runtime.open(b)
+            d3 = runtime.open(c)
+            d = gatherResults([d1, d2, d3])
+            d.addCallback(check)
+            return d
+        d = runtime.triple_test(self.Zp)
+        d.addCallbacks(open, runtime.error_handler)
+        return d
+
+    @protocol
+    def test_random_triple(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
+        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
+
+if not commitment:
+    OrlandiAdvancedCommandsTest.skip = "Skipped due to missing commitment module."
+    OrlandiBasicCommandsTest.skip = "Skipped due to missing commitment module."
+    TripleGenTest.skip = "Skipped due to missing commitment module."
--- a/viff/test/test_runtime.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/viff/test/test_runtime.py	Fri Oct 23 13:50:19 2009 +0200
@@ -27,10 +27,11 @@
 from random import Random
 import operator
 
-from twisted.internet.defer import gatherResults
+from twisted.internet.defer import gatherResults, Deferred, DeferredList
 
 from viff.field import GF256
 from viff.runtime import Share
+from viff.constants import SHARE
 from viff.comparison import Toft05Runtime
 from viff.test.util import RuntimeTestCase, BinaryOperatorTestCase, protocol
 
@@ -191,6 +192,49 @@
 
         return gatherResults([opened_a, opened_b, opened_c])
 
+    @protocol
+    def test_send_receive_self(self, runtime):
+        """Test send and receive of values."""
+        value = 42
+        
+        pc = tuple(runtime.program_counter)
+        runtime.protocols[runtime.id].sendData(pc, SHARE, str(value))
+
+        d = Deferred()
+        runtime._expect_data(runtime.id, SHARE, d)
+        def check(x):
+            self.assertEquals(int(x), value)
+            return x
+        d.addCallback(check)
+        return d
+
+    @protocol
+    def test_send_receive_self2(self, runtime):
+        """Test send and receive of values."""
+        value = 42
+        
+        pc = tuple(runtime.program_counter)
+        for peer_id in runtime.players:
+            data = str(value)
+            runtime.protocols[peer_id].sendData(pc, SHARE, data)
+
+        ds = []
+        for peer_id in runtime.players:
+            d = Deferred()
+            runtime._expect_data(peer_id, SHARE, d)
+            ds.append(d)
+
+        dls = DeferredList(ds)
+        def check(ls):
+            for s, x in ls:
+                self.assertEquals(int(x), value)
+            return ls
+
+        dls.addCallback(check)
+        return dls
+
+
+
 
 class ConvertBitShareTest(RuntimeTestCase):
     runtime_class = Toft05Runtime
--- a/viff/test/test_thresholds.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/viff/test/test_thresholds.py	Fri Oct 23 13:50:19 2009 +0200
@@ -91,66 +91,26 @@
     num_players = 3
     threshold = 1
 
-
 class Players4Threshold1Test(Tests, RuntimeTestCase):
     num_players = 4
     threshold = 1
 
-
-class Players5Threshold1Test(Tests, RuntimeTestCase):
-    num_players = 5
-    threshold = 1
-
 class Players5Threshold2Test(Tests, RuntimeTestCase):
     num_players = 5
     threshold = 2
 
-
-class Players6Threshold1Test(Tests, RuntimeTestCase):
-    num_players = 6
-    threshold = 1
-
 class Players6Threshold2Test(Tests, RuntimeTestCase):
     num_players = 6
     threshold = 2
 
-
-class Players7Threshold1Test(Tests, RuntimeTestCase):
-    num_players = 7
-    threshold = 1
-
-class Players7Threshold2Test(Tests, RuntimeTestCase):
-    num_players = 7
-    threshold = 2
-
 class Players7Threshold3Test(Tests, RuntimeTestCase):
     num_players = 7
     threshold = 3
 
-class Players8Threshold1Test(Tests, RuntimeTestCase):
-    num_players = 8
-    threshold = 1
-
-class Players8Threshold2Test(Tests, RuntimeTestCase):
-    num_players = 8
-    threshold = 2
-
 class Players8Threshold3Test(Tests, RuntimeTestCase):
     num_players = 8
     threshold = 3
 
-class Players9Threshold1Test(Tests, RuntimeTestCase):
-    num_players = 9
-    threshold = 1
-
-class Players9Threshold2Test(Tests, RuntimeTestCase):
-    num_players = 9
-    threshold = 2
-
-class Players9Threshold3Test(Tests, RuntimeTestCase):
-    num_players = 9
-    threshold = 3
-
 class Players9Threshold4Test(Tests, RuntimeTestCase):
     num_players = 9
     threshold = 4
--- a/viff/test/util.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/viff/test/util.py	Fri Oct 23 13:50:19 2009 +0200
@@ -22,7 +22,7 @@
 from twisted.internet import reactor
 
 from viff.passive import PassiveRuntime
-from viff.runtime import Share, ShareExchanger, ShareExchangerFactory
+from viff.runtime import Share, ShareExchanger, ShareExchangerFactory, SelfShareExchanger, SelfShareExchangerFactory, FakeTransport
 from viff.field import GF
 from viff.config import generate_configs, load_config
 from viff.util import rand
@@ -220,7 +220,13 @@
                     # fire.
                     sentinel = loopbackAsync(server, client)
                     self.close_sentinels.append(sentinel)
-
+            else:
+                protocol = SelfShareExchanger(id, SelfShareExchangerFactory(runtime))
+                protocol.transport = FakeTransport()
+                # Keys for when we are the client and when we are the server.
+                server_key = (id, id)
+                # Store a protocol used when we are the server.
+                self.protocols[server_key] = protocol     
 
 class BinaryOperatorTestCase:
     """Test a binary operator.
--- a/viff/util.py	Thu Oct 22 19:38:31 2009 +0200
+++ b/viff/util.py	Fri Oct 23 13:50:19 2009 +0200
@@ -22,8 +22,6 @@
 ensures that a protocol run can be reproduced at a later time.
 """
 
-__docformat__ = "restructuredtext"
-
 import os
 import time
 import random
@@ -64,29 +62,15 @@
     It is important to use this decorator on any wrapper functions in
     order to ensure that they end up with correct :attr:`__name__` and
     :attr:`__doc__` attributes.
-
-    In addition, if the environment variable :envvar:`VIFF_NO_WRAP` is
-    defined, then the wrapper functions will be turned into functions
-    that *do not* wrap -- instead they let their argument function
-    through unchanged. This is done so that epydoc and Sphinx can see
-    the true function arguments when generating documentation. Just
-    remember that your code will break if :envvar:`VIFF_NO_WRAP` is
-    set, so it should only be used when documentation is being
-    generated.
     """
-    if os.environ.get('VIFF_NO_WRAP'):
-        # Return a decorator which ignores the functions it is asked
-        # to decorate and instead returns func:
-        return lambda _: func
-    else:
-        # Return a decorator which does nothing to the function it is
-        # asked to decorate, except update the __name__ and __doc__
-        # attributes to match the original wrapped function.
-        def decorator(f):
-            f.__name__ = func.__name__
-            f.__doc__ = func.__doc__
-            return f
-        return decorator
+    # Return a decorator which does nothing to the function it is
+    # asked to decorate, except update the __name__ and __doc__
+    # attributes to match the original wrapped function.
+    def decorator(f):
+        f.__name__ = func.__name__
+        f.__doc__ = func.__doc__
+        return f
+    return decorator
 
 def fake(replacement):
     """Replace a function with a fake version.