viff

changeset 909:e36009fd979a

Mixin for preprocessing with hyperinvertible matrices.
author Martin Geisler <mg@daimi.au.dk>
date Mon, 15 Sep 2008 16:24:06 +0200
parents fe815100b30e
children 3f5367d1fcc7
files doc/active.txt viff/active.py viff/test/test_active_runtime.py
diffstat 3 files changed, 78 insertions(+), 72 deletions(-) [+]
line diff
     1.1 --- a/doc/active.txt	Mon Sep 15 15:57:37 2008 +0200
     1.2 +++ b/doc/active.txt	Mon Sep 15 16:24:06 2008 +0200
     1.3 @@ -9,3 +9,6 @@
     1.4  
     1.5     .. autoclass:: BrachaBroadcastMixin
     1.6        :members:
     1.7 +
     1.8 +   .. autoclass:: TriplesHyperinvertibleMatricesMixin
     1.9 +      :members:
     2.1 --- a/viff/active.py	Mon Sep 15 15:57:37 2008 +0200
     2.2 +++ b/viff/active.py	Mon Sep 15 16:24:06 2008 +0200
     2.3 @@ -167,74 +167,16 @@
     2.4          return result
     2.5  
     2.6  
     2.7 -class ActiveRuntime(Runtime):
     2.8 -    """A runtime secure against active adversaries.
     2.9 +class TriplesHyperinvertibleMatricesMixin:
    2.10 +    """Mixin class which generates multiplication triples using
    2.11 +    hyperinvertible matrices."""
    2.12  
    2.13 -    This class currently inherits most of its functionality from the
    2.14 -    normal :class:`Runtime` class and is thus **not** yet secure.
    2.15 -    """
    2.16 -
    2.17 -    def __init__(self, player, threshold, options=None):
    2.18 -        """Initialize runtime."""
    2.19 -
    2.20 -        #: A hyper-invertible matrix.
    2.21 -        #:
    2.22 -        #: It should be suitable for :attr:`num_players` players, but
    2.23 -        #: since we don't know the total number of players yet, we set
    2.24 -        #: it to :const:`None` here and update it as necessary.
    2.25 -        self._hyper = None
    2.26 -        Runtime.__init__(self, player, threshold, options)
    2.27 -
    2.28 -    @increment_pc
    2.29 -    def mul(self, share_x, share_y):
    2.30 -        """Multiplication of shares.
    2.31 -
    2.32 -        Preprocessing: 1 multiplication triple.
    2.33 -        Communication: 2 openings.
    2.34 -        """
    2.35 -        assert isinstance(share_x, Share) or isinstance(share_y, Share), \
    2.36 -            "At least one of share_x and share_y must be a Share."
    2.37 -
    2.38 -        if not isinstance(share_x, Share):
    2.39 -            # Then share_y must be a Share => local multiplication. We
    2.40 -            # clone first to avoid changing share_y.
    2.41 -            result = share_y.clone()
    2.42 -            result.addCallback(lambda y: share_x * y)
    2.43 -            return result
    2.44 -        if not isinstance(share_y, Share):
    2.45 -            # Likewise when share_y is a constant.
    2.46 -            result = share_x.clone()
    2.47 -            result.addCallback(lambda x: x * share_y)
    2.48 -            return result
    2.49 -
    2.50 -        # At this point both share_x and share_y must be Share
    2.51 -        # objects. We multiply them via a multiplication triple.
    2.52 -        def finish_mul(triple):
    2.53 -            a, b, c = triple
    2.54 -            d = self.open(share_x - a)
    2.55 -            e = self.open(share_y - b)
    2.56 -
    2.57 -            # TODO: We ought to be able to simply do
    2.58 -            #
    2.59 -            #   return d*e + d*y + e*x + c
    2.60 -            #
    2.61 -            # but that leads to infinite recursion since d and e are
    2.62 -            # Shares, not FieldElements. So we have to do a bit more
    2.63 -            # work... The following callback also leads to recursion, but
    2.64 -            # only one level since d and e are FieldElements now, which
    2.65 -            # means that we return in the above if statements.
    2.66 -            result = gather_shares([d, e])
    2.67 -            result.addCallback(lambda (d,e): d*e + d*b + e*a + c)
    2.68 -            return result
    2.69 -
    2.70 -        # This will be the result, a Share object.
    2.71 -        result = Share(self, share_x.field)
    2.72 -        # This is the Deferred we will do processing on.
    2.73 -        triple = self.prss_get_triple(share_x.field)
    2.74 -        self.schedule_callback(triple, finish_mul)
    2.75 -        # We add the result to the chains in triple.
    2.76 -        triple.chainDeferred(result)
    2.77 -        return result
    2.78 +    #: A hyper-invertible matrix.
    2.79 +    #:
    2.80 +    #: It should be suitable for :attr:`num_players` players, but
    2.81 +    #: since we don't know the total number of players yet, we set it
    2.82 +    #: to :const:`None` here and update it as necessary.
    2.83 +    _hyper = None
    2.84  
    2.85      @increment_pc
    2.86      def single_share_random(self, T, degree, field):
    2.87 @@ -466,6 +408,65 @@
    2.88          self.schedule_callback(result, make_triple)
    2.89          return T, result
    2.90  
    2.91 +
    2.92 +class ActiveRuntime(Runtime):
    2.93 +    """A runtime secure against active adversaries.
    2.94 +
    2.95 +    This class currently inherits most of its functionality from the
    2.96 +    normal :class:`Runtime` class and is thus **not** yet secure.
    2.97 +    """
    2.98 +
    2.99 +    @increment_pc
   2.100 +    def mul(self, share_x, share_y):
   2.101 +        """Multiplication of shares.
   2.102 +
   2.103 +        Preprocessing: 1 multiplication triple.
   2.104 +        Communication: 2 openings.
   2.105 +        """
   2.106 +        assert isinstance(share_x, Share) or isinstance(share_y, Share), \
   2.107 +            "At least one of share_x and share_y must be a Share."
   2.108 +
   2.109 +        if not isinstance(share_x, Share):
   2.110 +            # Then share_y must be a Share => local multiplication. We
   2.111 +            # clone first to avoid changing share_y.
   2.112 +            result = share_y.clone()
   2.113 +            result.addCallback(lambda y: share_x * y)
   2.114 +            return result
   2.115 +        if not isinstance(share_y, Share):
   2.116 +            # Likewise when share_y is a constant.
   2.117 +            result = share_x.clone()
   2.118 +            result.addCallback(lambda x: x * share_y)
   2.119 +            return result
   2.120 +
   2.121 +        # At this point both share_x and share_y must be Share
   2.122 +        # objects. We multiply them via a multiplication triple.
   2.123 +        def finish_mul(triple):
   2.124 +            a, b, c = triple
   2.125 +            d = self.open(share_x - a)
   2.126 +            e = self.open(share_y - b)
   2.127 +
   2.128 +            # TODO: We ought to be able to simply do
   2.129 +            #
   2.130 +            #   return d*e + d*y + e*x + c
   2.131 +            #
   2.132 +            # but that leads to infinite recursion since d and e are
   2.133 +            # Shares, not FieldElements. So we have to do a bit more
   2.134 +            # work... The following callback also leads to recursion, but
   2.135 +            # only one level since d and e are FieldElements now, which
   2.136 +            # means that we return in the above if statements.
   2.137 +            result = gather_shares([d, e])
   2.138 +            result.addCallback(lambda (d,e): d*e + d*b + e*a + c)
   2.139 +            return result
   2.140 +
   2.141 +        # This will be the result, a Share object.
   2.142 +        result = Share(self, share_x.field)
   2.143 +        # This is the Deferred we will do processing on.
   2.144 +        triple = self.prss_get_triple(share_x.field)
   2.145 +        self.schedule_callback(triple, finish_mul)
   2.146 +        # We add the result to the chains in triple.
   2.147 +        triple.chainDeferred(result)
   2.148 +        return result
   2.149 +
   2.150      @increment_pc
   2.151      @preprocess("generate_triple")
   2.152      def prss_get_triple(self, field):
     3.1 --- a/viff/test/test_active_runtime.py	Mon Sep 15 15:57:37 2008 +0200
     3.2 +++ b/viff/test/test_active_runtime.py	Mon Sep 15 16:24:06 2008 +0200
     3.3 @@ -21,16 +21,18 @@
     3.4  
     3.5  from viff.test.util import RuntimeTestCase, protocol, BinaryOperatorTestCase
     3.6  from viff.runtime import Share
     3.7 -from viff.active import ActiveRuntime, BrachaBroadcastMixin
     3.8 -
     3.9 +from viff.active import ActiveRuntime, BrachaBroadcastMixin, \
    3.10 +    TriplesHyperinvertibleMatricesMixin
    3.11  
    3.12  class MulTest(BinaryOperatorTestCase, RuntimeTestCase):
    3.13      operator = operator.mul
    3.14      runtime_class = ActiveRuntime
    3.15  
    3.16 +class TriplesHyper(ActiveRuntime, TriplesHyperinvertibleMatricesMixin):
    3.17 +    pass
    3.18  
    3.19 -class ActiveRuntimeTest(RuntimeTestCase):
    3.20 -    """Test for active security."""
    3.21 +class TriplesHyperTest(RuntimeTestCase):
    3.22 +    """Test for preprocessing with hyperinvertible matrices."""
    3.23  
    3.24      #: Number of players.
    3.25      #:
    3.26 @@ -38,7 +40,7 @@
    3.27      #: default threshold of t=1, we need n=4.
    3.28      num_players = 4
    3.29  
    3.30 -    runtime_class = ActiveRuntime
    3.31 +    runtime_class = TriplesHyper
    3.32  
    3.33      @protocol
    3.34      def test_single_share_random(self, runtime):