viff

changeset 1250:77f74e53f796

Merged with Martin.
author Marcel Keller <mkeller@cs.au.dk>
date Sat, 19 Sep 2009 15:34:01 +0200
parents 0f35ae3f503b 80125f56beaa
children 2bbab8b5597f
files viff/active.py viff/aes.py viff/passive.py viff/runtime.py
diffstat 11 files changed, 69 insertions(+), 222 deletions(-) [+]
line diff
     1.1 --- a/doc/program-counters.txt	Thu Sep 17 17:59:08 2009 +0200
     1.2 +++ b/doc/program-counters.txt	Sat Sep 19 15:34:01 2009 +0200
     1.3 @@ -88,63 +88,41 @@
     1.4  point in the execution tree. The execution tree is never explicitly
     1.5  constructed in VIFF, so a simple static numbering is not possible.
     1.6  
     1.7 -Instead we mark methods that need to increment the program counter
     1.8 -with the :func:`viff.runtime.increment_pc` decorator. The program
     1.9 -counter starts at the value ``[0]`` and the decorated method will now
    1.10 -begin by doing::
    1.11 +The program counter starts at the value ``[0]``. It is changed in two
    1.12 +cases:
    1.13  
    1.14 -  self.program_counter[-1] += 1
    1.15 -  self.program_counter.append(0)
    1.16 +* when a callback is scheduled using
    1.17 +  :meth:`viff.runtime.BasicRuntime.schedule_callback`, a new
    1.18 +  sub-program counter is allocated. A sub-program counter is simply a
    1.19 +  program counter with another digit. Because of the asynchronous
    1.20 +  network, the callback will be invoked at an unknown later time. When
    1.21 +  invoked, it sees the sub-program counter. This ensures that that the
    1.22 +  parties agree on any network traffic produced in the callback.
    1.23  
    1.24 -before it executes its body. When the body is finished, the method
    1.25 -does::
    1.26 +  When a piece of code like this::
    1.27  
    1.28 -  self.program_counter.pop()
    1.29 +    def cb(ignored):
    1.30 +        print "callback:", self.program_counter
    1.31 +    d = Deferred()
    1.32  
    1.33 -before it returns. A method :meth:`foo` defined like this::
    1.34 +    print "main:", self.program_counter
    1.35 +    self.schedule_callback(d, cb)
    1.36 +    print "main:", self.program_counter
    1.37  
    1.38 -  @increment_pc
    1.39 -  def foo(self):
    1.40 -      print "foo:", self.program_counter
    1.41 +    d.callback(None)
    1.42  
    1.43 -is thus turned into this::
    1.44 +  is executed, one will see output like this:
    1.45  
    1.46 -  def foo(self):
    1.47 -      self.program_counter[-1] += 1
    1.48 -      self.program_counter.append(0)
    1.49 -      print "foo:", self.program_counter
    1.50 -      self.program_counter.pop()
    1.51 +  .. code-block:: none
    1.52  
    1.53 -and when executed starting from the initial program counter of ``[0]``
    1.54 -we see that it prints ``foo: [1, 0]`` and leaves the program counter
    1.55 -at ``[1]`` after it returns. It is very important that the program
    1.56 -counter is left changed like this, for this means that the next call
    1.57 -to :meth:`foo` will print ``foo: [2, 0]`` and increment the program
    1.58 -counter to ``[2]``.
    1.59 +     main: [0]
    1.60 +     main: [1]
    1.61 +     callback: [0, 0]
    1.62  
    1.63 -If we have a method :meth:`bar` which calls :meth:`foo` several times::
    1.64 +* some functions depend on a unique program counter. These functions
    1.65 +  simply increase the last digit in the current program counter::
    1.66  
    1.67 -  @increment_pc
    1.68 -  def bar(self):
    1.69 -      print "bar:", self.program_counter
    1.70 -      self.foo()
    1.71 -      print "bar:", self.program_counter
    1.72 -      self.foo()
    1.73 -      print "bar:", self.program_counter
    1.74 -
    1.75 -then the result of calling :meth:`bar` will be:
    1.76 -
    1.77 -.. code-block:: none
    1.78 -
    1.79 -   bar: [1, 0]
    1.80 -   foo: [1, 1, 0]
    1.81 -   bar: [1, 1]
    1.82 -   foo: [1, 2, 0]
    1.83 -   bar: [1, 2]
    1.84 -
    1.85 -Notice how each sub-call adds another digit to the counter and how it
    1.86 -increments the counter used at the level of the caller. This system
    1.87 -ensures that all program counters are unique.
    1.88 +    self.program_counter[-1] += 1
    1.89  
    1.90  
    1.91  Alternatives
     2.1 --- a/doc/runtime.txt	Thu Sep 17 17:59:08 2009 +0200
     2.2 +++ b/doc/runtime.txt	Sat Sep 19 15:34:01 2009 +0200
     2.3 @@ -31,8 +31,6 @@
     2.4        and other messages. They serve to distinguish messages sent with
     2.5        the same program counter from one another.
     2.6  
     2.7 -   .. autofunction:: increment_pc
     2.8 -
     2.9     .. autofunction:: preprocess
    2.10  
    2.11        See also :ref:`preprocessing` for more background information.
    2.12 @@ -88,9 +86,7 @@
    2.13           different parts of the program execution never reuses the
    2.14           same program counter for different variables.
    2.15  
    2.16 -         The :func:`increment_pc` decorator is responsible for
    2.17 -         dynamically building the tree as the execution unfolds and
    2.18 -         :meth:`schedule_callback` is responsible for scheduling
    2.19 -         callbacks with the correct program counter.
    2.20 +         The :meth:`schedule_callback` method is responsible for
    2.21 +         scheduling callbacks with the correct program counter.
    2.22  
    2.23           See :ref:`program-counters` for more background information.
     3.1 --- a/viff/active.py	Thu Sep 17 17:59:08 2009 +0200
     3.2 +++ b/viff/active.py	Sat Sep 19 15:34:01 2009 +0200
     3.3 @@ -27,7 +27,7 @@
     3.4  from viff.util import rand
     3.5  from viff.matrix import Matrix, hyper
     3.6  from viff.passive import PassiveRuntime
     3.7 -from viff.runtime import Share, increment_pc, preprocess, gather_shares
     3.8 +from viff.runtime import Share, preprocess, gather_shares
     3.9  from viff.runtime import ECHO, READY, SEND
    3.10  
    3.11  
    3.12 @@ -37,7 +37,6 @@
    3.13      broadcast.
    3.14      """
    3.15  
    3.16 -    @increment_pc
    3.17      def _broadcast(self, sender, message=None):
    3.18          """Perform a Bracha broadcast.
    3.19  
    3.20 @@ -47,6 +46,8 @@
    3.21          protocol" by G. Bracha in Proc. 3rd ACM Symposium on
    3.22          Principles of Distributed Computing, 1984, pages 154-162.
    3.23          """
    3.24 +        # We need a unique program counter for each call.
    3.25 +        self.program_counter[-1] += 1
    3.26  
    3.27          result = Deferred()
    3.28          pc = tuple(self.program_counter)
    3.29 @@ -141,7 +142,6 @@
    3.30  
    3.31          return result
    3.32  
    3.33 -    @increment_pc
    3.34      def broadcast(self, senders, message=None):
    3.35          """Perform one or more Bracha broadcast(s).
    3.36  
    3.37 @@ -186,7 +186,6 @@
    3.38      #: to :const:`None` here and update it as necessary.
    3.39      _hyper = None
    3.40  
    3.41 -    @increment_pc
    3.42      def single_share_random(self, T, degree, field):
    3.43          """Share a random secret.
    3.44  
    3.45 @@ -273,7 +272,6 @@
    3.46          self.schedule_callback(result, exchange)
    3.47          return result
    3.48  
    3.49 -    @increment_pc
    3.50      def double_share_random(self, T, d1, d2, field):
    3.51          """Double-share a random secret using two polynomials.
    3.52  
    3.53 @@ -376,7 +374,6 @@
    3.54          self.schedule_callback(result, exchange)
    3.55          return result
    3.56  
    3.57 -    @increment_pc
    3.58      @preprocess("generate_triples")
    3.59      def get_triple(self, field):
    3.60          # This is a waste, but this function is only called if there
    3.61 @@ -385,7 +382,6 @@
    3.62          result.addCallback(lambda triples: triples[0])
    3.63          return result
    3.64  
    3.65 -    @increment_pc
    3.66      def generate_triples(self, field):
    3.67          """Generate multiplication triples.
    3.68  
    3.69 @@ -425,14 +421,12 @@
    3.70  class TriplesPRSSMixin:
    3.71      """Mixin class for generating multiplication triples using PRSS."""
    3.72  
    3.73 -    @increment_pc
    3.74      @preprocess("generate_triples")
    3.75      def get_triple(self, field):
    3.76          count, result = self.generate_triples(field, quantity=1)
    3.77          result.addCallback(lambda triples: triples[0])
    3.78          return result
    3.79  
    3.80 -    @increment_pc
    3.81      def generate_triples(self, field, quantity=20):
    3.82          """Generate *quantity* multiplication triples using PRSS.
    3.83  
    3.84 @@ -470,7 +464,6 @@
    3.85      :class:`ActiveRuntime` instead.
    3.86      """
    3.87  
    3.88 -    @increment_pc
    3.89      def mul(self, share_x, share_y):
    3.90          """Multiplication of shares.
    3.91  
     4.1 --- a/viff/aes.py	Thu Sep 17 17:59:08 2009 +0200
     4.2 +++ b/viff/aes.py	Sat Sep 19 15:34:01 2009 +0200
     4.3 @@ -24,7 +24,7 @@
     4.4  import operator
     4.5  
     4.6  from viff.field import GF256
     4.7 -from viff.runtime import Share, gather_shares, increment_pc
     4.8 +from viff.runtime import Share, gather_shares
     4.9  from viff.matrix import Matrix
    4.10  
    4.11  
    4.12 @@ -360,7 +360,6 @@
    4.13                      "or of shares thereof."
    4.14              return input
    4.15  
    4.16 -    @increment_pc
    4.17      def encrypt(self, cleartext, key, benchmark=False, prepare_at_once=False):
    4.18          """Rijndael encryption.
    4.19  
     5.1 --- a/viff/comparison.py	Thu Sep 17 17:59:08 2009 +0200
     5.2 +++ b/viff/comparison.py	Sat Sep 19 15:34:01 2009 +0200
     5.3 @@ -25,7 +25,7 @@
     5.4  import math
     5.5  
     5.6  from viff.util import rand, profile
     5.7 -from viff.runtime import Share, gather_shares, increment_pc
     5.8 +from viff.runtime import Share, gather_shares
     5.9  from viff.passive import PassiveRuntime
    5.10  from viff.active import ActiveRuntime
    5.11  from viff.field import GF256, FieldElement
    5.12 @@ -34,7 +34,6 @@
    5.13  class ComparisonToft05Mixin:
    5.14      """Comparison by Tomas Toft, 2005."""
    5.15  
    5.16 -    @increment_pc
    5.17      def convert_bit_share(self, share, dst_field):
    5.18          """Convert a 0/1 share into dst_field."""
    5.19          bit = rand.randint(0, 1)
    5.20 @@ -67,7 +66,6 @@
    5.21          return int_b, bit_bits
    5.22  
    5.23      @profile
    5.24 -    @increment_pc
    5.25      def greater_than_equal(self, share_a, share_b):
    5.26          """Compute ``share_a >= share_b``.
    5.27  
    5.28 @@ -100,7 +98,6 @@
    5.29          self.schedule_callback(result, self._finish_greater_than_equal, l)
    5.30          return result
    5.31  
    5.32 -    @increment_pc
    5.33      def _finish_greater_than_equal(self, results, l):
    5.34          """Finish the calculation."""
    5.35          T = results[0]
    5.36 @@ -128,7 +125,6 @@
    5.37  
    5.38          return GF256(T.bit(l)) ^ (bit_bits[l] ^ vec[0][1])
    5.39  
    5.40 -    @increment_pc
    5.41      def _diamond(self, (top_a, bot_a), (top_b, bot_b)):
    5.42          """The "diamond-operator".
    5.43  
    5.44 @@ -160,7 +156,6 @@
    5.45      elements and gives a secret result shared over Zp.
    5.46      """
    5.47  
    5.48 -    @increment_pc
    5.49      def convert_bit_share(self, share, dst_field):
    5.50          """Convert a 0/1 share into *dst_field*."""
    5.51          l = self.options.security_parameter + math.log(dst_field.modulus, 2)
    5.52 @@ -188,7 +183,6 @@
    5.53          return tmp - full_mask
    5.54  
    5.55      @profile
    5.56 -    @increment_pc
    5.57      def greater_than_equal_preproc(self, field, smallField=None):
    5.58          """Preprocessing for :meth:`greater_than_equal`."""
    5.59          if smallField is None:
    5.60 @@ -243,7 +237,6 @@
    5.61          ##################################################
    5.62  
    5.63      @profile
    5.64 -    @increment_pc
    5.65      def greater_than_equal_online(self, share_a, share_b, preproc, field):
    5.66          """Compute ``share_a >= share_b``. Result is secret shared."""
    5.67          # increment l as a, b are increased
    5.68 @@ -272,7 +265,6 @@
    5.69                                 r_modl, r_bits, z)
    5.70          return c
    5.71  
    5.72 -    @increment_pc
    5.73      def _finish_greater_than_equal(self, c, field, smallField, s_bit, s_sign,
    5.74                                 mask, r_modl, r_bits, z):
    5.75          """Finish the calculation."""
    5.76 @@ -316,7 +308,6 @@
    5.77          return (z - result) * ~field(2**l)
    5.78      # END _finish_greater_than
    5.79  
    5.80 -    @increment_pc
    5.81      def greater_than_equal(self, share_a, share_b):
    5.82          """Compute ``share_a >= share_b``.
    5.83  
     6.1 --- a/viff/equality.py	Thu Sep 17 17:59:08 2009 +0200
     6.2 +++ b/viff/equality.py	Sat Sep 19 15:34:01 2009 +0200
     6.3 @@ -20,13 +20,10 @@
     6.4  is mixed with.
     6.5  """
     6.6  
     6.7 -from viff.runtime import increment_pc
     6.8 -
     6.9  class ProbabilisticEqualityMixin:
    6.10      """This class implements probabilistic constant-round secure
    6.11      equality-testing of secret shared numbers."""
    6.12  
    6.13 -    @increment_pc
    6.14      def equal(self, share_x, share_y):
    6.15          """Equality testing with secret shared result.
    6.16  
     7.1 --- a/viff/paillier.py	Thu Sep 17 17:59:08 2009 +0200
     7.2 +++ b/viff/paillier.py	Sat Sep 19 15:34:01 2009 +0200
     7.3 @@ -27,7 +27,7 @@
     7.4  from twisted.internet.defer import Deferred, gatherResults
     7.5  import gmpy
     7.6  
     7.7 -from viff.runtime import Runtime, increment_pc, Share, gather_shares
     7.8 +from viff.runtime import Runtime, Share, gather_shares
     7.9  from viff.runtime import PAILLIER
    7.10  from viff.util import rand, find_random_prime
    7.11  
    7.12 @@ -78,7 +78,6 @@
    7.13          else:
    7.14              self.peer = player
    7.15  
    7.16 -    @increment_pc
    7.17      def prss_share_random(self, field):
    7.18          """Generate a share of a uniformly random element."""
    7.19          prfs = self.players[self.id].prfs(field.modulus)
    7.20 @@ -94,7 +93,6 @@
    7.21          """
    7.22          return self.share(inputters, field, number)
    7.23  
    7.24 -    @increment_pc
    7.25      def share(self, inputters, field, number=None):
    7.26          """Share *number* additively."""
    7.27          assert number is None or self.id in inputters
    7.28 @@ -121,7 +119,6 @@
    7.29      def output(self, share, receivers=None):
    7.30          return self.open(share, receivers)
    7.31  
    7.32 -    @increment_pc
    7.33      def open(self, share, receivers=None):
    7.34          """Open *share* to *receivers* (defaults to both players)."""
    7.35  
     8.1 --- a/viff/passive.py	Thu Sep 17 17:59:08 2009 +0200
     8.2 +++ b/viff/passive.py	Sat Sep 19 15:34:01 2009 +0200
     8.3 @@ -22,8 +22,7 @@
     8.4  import operator
     8.5  
     8.6  from viff import shamir
     8.7 -from viff.runtime import Runtime, increment_pc, Share, ShareList, \
     8.8 -     gather_shares, preprocess
     8.9 +from viff.runtime import Runtime, Share, ShareList, gather_shares, preprocess
    8.10  from viff.prss import prss, prss_lsb, prss_zero, prss_multi
    8.11  from viff.field import GF256, FieldElement
    8.12  from viff.util import rand, profile
    8.13 @@ -57,7 +56,6 @@
    8.14      def output(self, share, receivers=None, threshold=None):
    8.15          return self.open(share, receivers, threshold)
    8.16  
    8.17 -    @increment_pc
    8.18      def open(self, share, receivers=None, threshold=None):
    8.19          """Open a secret sharing.
    8.20  
    8.21 @@ -175,7 +173,6 @@
    8.22          return result
    8.23  
    8.24      @profile
    8.25 -    @increment_pc
    8.26      def mul(self, share_a, share_b):
    8.27          """Multiplication of shares.
    8.28  
    8.29 @@ -232,7 +229,6 @@
    8.30          else:
    8.31              return share * (share ** (exponent-1))
    8.32  
    8.33 -    @increment_pc
    8.34      def xor(self, share_a, share_b):
    8.35          field = share_a.field
    8.36          if not isinstance(share_b, Share):
    8.37 @@ -245,7 +241,18 @@
    8.38          else:
    8.39              return share_a + share_b - 2 * share_a * share_b
    8.40  
    8.41 -    @increment_pc
    8.42 +    def prss_key(self):
    8.43 +        """Create unique key for PRSS.
    8.44 +
    8.45 +        This increments the program counter and returns it as a tuple.
    8.46 +        Each straight-line program (typically a callback attached to
    8.47 +        some :class:`Deferred`) is executed in a context with unique
    8.48 +        starting program counter. This ensures that consequetive calls
    8.49 +        to PRSS-related methods will use unique program counters.
    8.50 +        """
    8.51 +        self.program_counter[-1] += 1
    8.52 +        return tuple(self.program_counter)
    8.53 +
    8.54      def prss_share(self, inputters, field, element=None):
    8.55          """Creates pseudo-random secret sharings.
    8.56  
    8.57 @@ -273,7 +280,7 @@
    8.58          n = self.num_players
    8.59  
    8.60          # Key used for PRSS.
    8.61 -        key = tuple(self.program_counter)
    8.62 +        key = self.prss_key()
    8.63  
    8.64          # The shares for which we have all the keys.
    8.65          all_shares = []
    8.66 @@ -314,7 +321,6 @@
    8.67          else:
    8.68              return result
    8.69  
    8.70 -    @increment_pc
    8.71      def prss_share_random(self, field, binary=False):
    8.72          """Generate shares of a uniformly random element from the field given.
    8.73  
    8.74 @@ -329,7 +335,7 @@
    8.75              modulus = field.modulus
    8.76  
    8.77          # Key used for PRSS.
    8.78 -        prss_key = tuple(self.program_counter)
    8.79 +        prss_key = self.prss_key()
    8.80          prfs = self.players[self.id].prfs(modulus)
    8.81          share = prss(self.num_players, self.id, field, prfs, prss_key)
    8.82  
    8.83 @@ -354,7 +360,6 @@
    8.84          self.schedule_callback(result, finish, share, binary)
    8.85          return result
    8.86  
    8.87 -    @increment_pc
    8.88      def prss_share_random_multi(self, field, quantity, binary=False):
    8.89          """Does the same as calling *quantity* times :meth:`prss_share_random`,
    8.90          but with less calls to the PRF. Sampling of a binary element is only
    8.91 @@ -371,13 +376,12 @@
    8.92              modulus = field.modulus
    8.93  
    8.94          # Key used for PRSS.
    8.95 -        prss_key = tuple(self.program_counter)
    8.96 +        prss_key = self.prss_key()
    8.97          prfs = self.players[self.id].prfs(modulus ** quantity)
    8.98          shares = prss_multi(self.num_players, self.id, field, prfs, prss_key,
    8.99                              modulus, quantity)
   8.100          return [Share(self, field, share) for share in shares]
   8.101  
   8.102 -    @increment_pc
   8.103      def prss_share_zero(self, field, quantity):
   8.104          """Generate *quantity* shares of the zero element from the
   8.105          field given.
   8.106 @@ -385,13 +389,12 @@
   8.107          Communication cost: none.
   8.108          """
   8.109          # Key used for PRSS.
   8.110 -        prss_key = tuple(self.program_counter)
   8.111 +        prss_key = self.prss_key()
   8.112          prfs = self.players[self.id].prfs(field.modulus)
   8.113          zero_share = prss_zero(self.num_players, self.threshold, self.id,
   8.114                                 field, prfs, prss_key, quantity)
   8.115          return [Share(self, field, zero_share[i]) for i in range(quantity)]
   8.116  
   8.117 -    @increment_pc
   8.118      def prss_double_share(self, field, quantity):
   8.119          """Make *quantity* double-sharings using PRSS.
   8.120  
   8.121 @@ -402,7 +405,6 @@
   8.122          z_2t = self.prss_share_zero(field, quantity)
   8.123          return (r_t, [r_t[i] + z_2t[i] for i in range(quantity)])
   8.124  
   8.125 -    @increment_pc
   8.126      def prss_share_bit_double(self, field):
   8.127          """Share a random bit over *field* and GF256.
   8.128  
   8.129 @@ -414,7 +416,7 @@
   8.130          n = self.num_players
   8.131          k = self.options.security_parameter
   8.132          prfs = self.players[self.id].prfs(2**k)
   8.133 -        prss_key = tuple(self.program_counter)
   8.134 +        prss_key = self.prss_key()
   8.135  
   8.136          b_p = self.prss_share_random(field, binary=True)
   8.137          r_p, r_lsb = prss_lsb(n, self.id, field, prfs, prss_key)
   8.138 @@ -427,13 +429,12 @@
   8.139          # Use r_lsb to flip b as needed.
   8.140          return (b_p, b ^ r_lsb)
   8.141  
   8.142 -    @increment_pc
   8.143      def prss_shamir_share_bit_double(self, field):
   8.144          """Shamir share a random bit over *field* and GF256."""
   8.145          n = self.num_players
   8.146          k = self.options.security_parameter
   8.147          prfs = self.players[self.id].prfs(2**k)
   8.148 -        prss_key = tuple(self.program_counter)
   8.149 +        prss_key = self.prss_key()
   8.150          inputters = range(1, self.num_players + 1)
   8.151  
   8.152          ri = rand.randint(0, 2**k - 1)
   8.153 @@ -461,7 +462,6 @@
   8.154              result.append(share)
   8.155          return result
   8.156  
   8.157 -    @increment_pc
   8.158      @preprocess("prss_powerchains")
   8.159      def prss_powerchain(self, max=7):
   8.160          """Generate a random secret share in GF256 and returns
   8.161 @@ -483,7 +483,6 @@
   8.162          """
   8.163          return self.shamir_share(inputters, field, number, threshold)
   8.164  
   8.165 -    @increment_pc
   8.166      def shamir_share(self, inputters, field, number=None, threshold=None):
   8.167          """Secret share *number* over *field* using Shamir's method.
   8.168  
     9.1 --- a/viff/runtime.py	Thu Sep 17 17:59:08 2009 +0200
     9.2 +++ b/viff/runtime.py	Sat Sep 19 15:34:01 2009 +0200
     9.3 @@ -407,25 +407,6 @@
     9.4          reason.trap(ConnectionDone)
     9.5  
     9.6  
     9.7 -def increment_pc(method):
     9.8 -    """Make *method* automatically increment the program counter.
     9.9 -
    9.10 -    Adding this decorator to a :class:`Runtime` method will ensure
    9.11 -    that the program counter is incremented correctly when entering
    9.12 -    the method.
    9.13 -    """
    9.14 -
    9.15 -    @wrapper(method)
    9.16 -    def inc_pc_wrapper(self, *args, **kwargs):
    9.17 -        try:
    9.18 -            self.program_counter[-1] += 1
    9.19 -            self.program_counter.append(0)
    9.20 -            return method(self, *args, **kwargs)
    9.21 -        finally:
    9.22 -            self.program_counter.pop()
    9.23 -    return inc_pc_wrapper
    9.24 -
    9.25 -
    9.26  def preprocess(generator):
    9.27      """Track calls to this method.
    9.28  
    9.29 @@ -623,7 +604,6 @@
    9.30          dl = DeferredList(vars)
    9.31          self.schedule_callback(dl, lambda _: self.shutdown())
    9.32  
    9.33 -    @increment_pc
    9.34      def schedule_callback(self, deferred, func, *args, **kwargs):
    9.35          """Schedule a callback on a deferred with the correct program
    9.36          counter.
    9.37 @@ -637,7 +617,9 @@
    9.38          Any extra arguments are passed to the callback as with
    9.39          :meth:`addCallback`.
    9.40          """
    9.41 +        self.program_counter[-1] += 1
    9.42          saved_pc = self.program_counter[:]
    9.43 +        saved_pc.append(0)
    9.44  
    9.45          @wrapper(func)
    9.46          def callback_wrapper(*args, **kwargs):
    9.47 @@ -673,7 +655,6 @@
    9.48          deferred.addCallback(queue_callback, self, fork)
    9.49          return self.schedule_callback(fork, func, *args, **kwargs)
    9.50  
    9.51 -    @increment_pc
    9.52      def synchronize(self):
    9.53          """Introduce a synchronization point.
    9.54  
    9.55 @@ -729,7 +710,6 @@
    9.56          self._expect_data(peer_id, SHARE, share)
    9.57          return share
    9.58  
    9.59 -    @increment_pc
    9.60      def preprocess(self, program):
    9.61          """Generate preprocess material.
    9.62  
    9.63 @@ -868,7 +848,7 @@
    9.64              self.depth_counter -= 1
    9.65              self.activation_counter = 0
    9.66  
    9.67 -    def print_transferred_data():
    9.68 +    def print_transferred_data(self):
    9.69          """Print the amount of transferred data for all connections."""
    9.70  
    9.71          for protocol in self.protocols.itervalues():
    10.1 --- a/viff/test/test_basic_runtime.py	Thu Sep 17 17:59:08 2009 +0200
    10.2 +++ b/viff/test/test_basic_runtime.py	Sat Sep 19 15:34:01 2009 +0200
    10.3 @@ -18,7 +18,6 @@
    10.4  from twisted.internet.defer import Deferred, gatherResults
    10.5  
    10.6  from viff.test.util import RuntimeTestCase, protocol
    10.7 -from viff.runtime import increment_pc
    10.8  
    10.9  
   10.10  class ProgramCounterTest(RuntimeTestCase):
   10.11 @@ -32,26 +31,14 @@
   10.12      def test_simple_operation(self, runtime):
   10.13          """Test an operation which makes no further calls.
   10.14  
   10.15 -        Each call should increment the program counter by one.
   10.16 +        No callbacks are scheduled, and so the program counter is not
   10.17 +        increased.
   10.18          """
   10.19 +        self.assertEquals(runtime.program_counter, [0])
   10.20          runtime.synchronize()
   10.21 -        self.assertEquals(runtime.program_counter, [1])
   10.22 +        self.assertEquals(runtime.program_counter, [0])
   10.23          runtime.synchronize()
   10.24 -        self.assertEquals(runtime.program_counter, [2])
   10.25 -
   10.26 -    @protocol
   10.27 -    def test_complex_operation(self, runtime):
   10.28 -        """Test an operation which makes nested calls.
   10.29 -
   10.30 -        This verifies that the program counter is only incremented by
   10.31 -        one, even for a complex operation.
   10.32 -        """
   10.33 -        # Exclusive-or is calculated as x + y - 2 * x * y, so add,
   10.34 -        # sub, and mul are called.
   10.35 -        runtime.xor(self.Zp(0), self.Zp(1))
   10.36 -        self.assertEquals(runtime.program_counter, [1])
   10.37 -        runtime.xor(self.Zp(0), self.Zp(1))
   10.38 -        self.assertEquals(runtime.program_counter, [2])
   10.39 +        self.assertEquals(runtime.program_counter, [0])
   10.40  
   10.41      @protocol
   10.42      def test_callback(self, runtime):
   10.43 @@ -62,62 +49,32 @@
   10.44          """
   10.45  
   10.46          def verify_program_counter(_):
   10.47 +            # The callback is run with its own sub-program counter.
   10.48              self.assertEquals(runtime.program_counter, [1, 0])
   10.49  
   10.50          d = Deferred()
   10.51 +
   10.52 +        self.assertEquals(runtime.program_counter, [0])
   10.53 +
   10.54 +        # Scheduling a callback increases the program counter.
   10.55          runtime.schedule_callback(d, verify_program_counter)
   10.56 -
   10.57 -        runtime.synchronize()
   10.58 -        self.assertEquals(runtime.program_counter, [2])
   10.59 +        self.assertEquals(runtime.program_counter, [1])
   10.60  
   10.61          # Now trigger verify_program_counter.
   10.62          d.callback(None)
   10.63  
   10.64      @protocol
   10.65 -    def test_nested_calls(self, runtime):
   10.66 -        """Test Runtime methods that call other methods.
   10.67 -
   10.68 -        We create a couple of functions that are used as fake methods.
   10.69 -        """
   10.70 -
   10.71 -        @increment_pc
   10.72 -        def method_a(runtime):
   10.73 -            # First top-level call, so first entry is 1. No calls to
   10.74 -            # other methods decorated with increment_pc has been made,
   10.75 -            # so the second entry is 0.
   10.76 -            self.assertEquals(runtime.program_counter, [1, 0])
   10.77 -            method_b(runtime, 1)
   10.78 -
   10.79 -            self.assertEquals(runtime.program_counter, [1, 1])
   10.80 -            method_b(runtime, 2)
   10.81 -
   10.82 -            # At this point two sub-calls has been made:
   10.83 -            self.assertEquals(runtime.program_counter, [1, 2])
   10.84 -
   10.85 -        @increment_pc
   10.86 -        def method_b(runtime, count):
   10.87 -            # This method is called twice from method_a:
   10.88 -            self.assertEquals(runtime.program_counter, [1, count, 0])
   10.89 -
   10.90 -        # Zero top-level calls:
   10.91 -        self.assertEquals(runtime.program_counter, [0])
   10.92 -        method_a(runtime)
   10.93 -
   10.94 -        # One top-level call:
   10.95 -        self.assertEquals(runtime.program_counter, [1])
   10.96 -
   10.97 -    @protocol
   10.98      def test_multiple_callbacks(self, runtime):
   10.99  
  10.100          d1 = Deferred()
  10.101          d2 = Deferred()
  10.102  
  10.103          def verify_program_counter(_, count):
  10.104 -            self.assertEquals(runtime.program_counter, [1, count, 0])
  10.105 +            self.assertEquals(runtime.program_counter, [count, 0])
  10.106  
  10.107 -        @increment_pc
  10.108          def method_a(runtime):
  10.109 -            self.assertEquals(runtime.program_counter, [1, 0])
  10.110 +            # No calls to schedule_callback yet.
  10.111 +            self.assertEquals(runtime.program_counter, [0])
  10.112  
  10.113              runtime.schedule_callback(d1, verify_program_counter, 1)
  10.114              runtime.schedule_callback(d2, verify_program_counter, 2)
    11.1 --- a/viff/test/test_thresholds.py	Thu Sep 17 17:59:08 2009 +0200
    11.2 +++ b/viff/test/test_thresholds.py	Sat Sep 19 15:34:01 2009 +0200
    11.3 @@ -91,66 +91,26 @@
    11.4      num_players = 3
    11.5      threshold = 1
    11.6  
    11.7 -
    11.8  class Players4Threshold1Test(Tests, RuntimeTestCase):
    11.9      num_players = 4
   11.10      threshold = 1
   11.11  
   11.12 -
   11.13 -class Players5Threshold1Test(Tests, RuntimeTestCase):
   11.14 -    num_players = 5
   11.15 -    threshold = 1
   11.16 -
   11.17  class Players5Threshold2Test(Tests, RuntimeTestCase):
   11.18      num_players = 5
   11.19      threshold = 2
   11.20  
   11.21 -
   11.22 -class Players6Threshold1Test(Tests, RuntimeTestCase):
   11.23 -    num_players = 6
   11.24 -    threshold = 1
   11.25 -
   11.26  class Players6Threshold2Test(Tests, RuntimeTestCase):
   11.27      num_players = 6
   11.28      threshold = 2
   11.29  
   11.30 -
   11.31 -class Players7Threshold1Test(Tests, RuntimeTestCase):
   11.32 -    num_players = 7
   11.33 -    threshold = 1
   11.34 -
   11.35 -class Players7Threshold2Test(Tests, RuntimeTestCase):
   11.36 -    num_players = 7
   11.37 -    threshold = 2
   11.38 -
   11.39  class Players7Threshold3Test(Tests, RuntimeTestCase):
   11.40      num_players = 7
   11.41      threshold = 3
   11.42  
   11.43 -class Players8Threshold1Test(Tests, RuntimeTestCase):
   11.44 -    num_players = 8
   11.45 -    threshold = 1
   11.46 -
   11.47 -class Players8Threshold2Test(Tests, RuntimeTestCase):
   11.48 -    num_players = 8
   11.49 -    threshold = 2
   11.50 -
   11.51  class Players8Threshold3Test(Tests, RuntimeTestCase):
   11.52      num_players = 8
   11.53      threshold = 3
   11.54  
   11.55 -class Players9Threshold1Test(Tests, RuntimeTestCase):
   11.56 -    num_players = 9
   11.57 -    threshold = 1
   11.58 -
   11.59 -class Players9Threshold2Test(Tests, RuntimeTestCase):
   11.60 -    num_players = 9
   11.61 -    threshold = 2
   11.62 -
   11.63 -class Players9Threshold3Test(Tests, RuntimeTestCase):
   11.64 -    num_players = 9
   11.65 -    threshold = 3
   11.66 -
   11.67  class Players9Threshold4Test(Tests, RuntimeTestCase):
   11.68      num_players = 9
   11.69      threshold = 4