Discussion:
[PATCH 1 of 7] Added support for equality to the runtime
Sigurd Meldgaard
2008-09-17 12:45:12 UTC
Permalink
# HG changeset patch
# User Sigurd Meldgaard <***@daimi.au.dk>
# Date 1221574088 -7200
# Node ID 0ae0b7196ac880b3b0cfaaf6202650dbd7a9b1fd
# Parent 635a8d6ac335e6282f4e555e0f624195299d9297
Added support for equality to the runtime

diff -r 635a8d6ac335 -r 0ae0b7196ac8 viff/runtime.py
--- a/viff/runtime.py Sun Aug 24 23:26:45 2008 +0200
+++ b/viff/runtime.py Tue Sep 16 16:08:08 2008 +0200
@@ -131,6 +131,21 @@
"""Greater-than or equal comparison."""
# self >= other
return self.runtime.greater_than_equal(self, other)
+
+ def __eq__(self, other):
+ """
+ Equality testing
+ returns a share of 1 if self == other mod p
+ 0 otherwise
+ """
+ return self.runtime.equal(self,other)
+
+ def __neq__(self, other):
+ """
+ Negated equality testing
+ """
+ return 1 - self.runtime.equal(self,other)
+

def clone(self):
"""Clone a share.
Sigurd Meldgaard
2008-09-17 12:45:18 UTC
Permalink
# HG changeset patch
# User Sigurd Meldgaard <***@daimi.au.dk>
# Date 1221655195 -7200
# Node ID 5072e60082dc8e7ef8a034e07bd49735295b5a5e
# Parent a0c6ff492442daaf8059c0fd667d58665fad042b
Added equality to benchmark

diff -r a0c6ff492442 -r 5072e60082dc apps/benchmark.py
--- a/apps/benchmark.py Wed Sep 17 14:39:55 2008 +0200
+++ b/apps/benchmark.py Wed Sep 17 14:39:55 2008 +0200
@@ -67,6 +67,7 @@
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.config import load_config
from viff.util import find_prime
@@ -90,7 +91,7 @@
print "*" * 6


-operations = ["mul", "compToft05", "compToft07"]
+operations = ["mul", "compToft05", "compToft07", "equality"]

parser = OptionParser()
parser.add_option("-m", "--modulus",
@@ -268,6 +269,9 @@
elif options.operation == "compToft07":
operation = operator.ge
mixins.append(ComparisonToft07Mixin)
+ elif options.operation == "equality":
+ operation = operator.eq
+ mixins.append(ProbabilisticEqualityMixin)

print "Using the base runtime: %s." % base_runtime_class
print "With the following mixins:"
Sigurd Meldgaard
2008-09-17 12:45:15 UTC
Permalink
# HG changeset patch
# User Sigurd Meldgaard <***@daimi.au.dk>
# Date 1221574030 -7200
# Node ID 11c959556ba30162a738ec851ac671e804922384
# Parent 9f166758d6536eafa20326c840bd5e0278d5e4b1
Added viff.runtime.make_runtime_class
This is a funtion that creates a new runtime class with mixins

diff -r 9f166758d653 -r 11c959556ba3 viff/runtime.py
--- a/viff/runtime.py Tue Sep 16 16:11:10 2008 +0200
+++ b/viff/runtime.py Tue Sep 16 16:07:10 2008 +0200
@@ -354,7 +354,7 @@
def clientConnectionLost(self, connector, reason):
reason.trap(ConnectionDone)

-
+
def increment_pc(method):
"""Make *method* automatically increment the program counter.

@@ -532,7 +532,7 @@
print "done."

sync = self.synchronize()
- sync.addCallback(close_connections)
+ sync.addCallback(close_connections)
sync.addCallback(stop_reactor)
return sync

@@ -832,7 +832,7 @@
@increment_pc
def prss_share(self, inputters, field, element=None):
"""Creates pseudo-random secret sharings.
-
+
This protocol creates a secret sharing for each player in the
subset of players specified in *inputters*. Each inputter
provides an integer. The result is a list of shares, one for
@@ -1079,6 +1079,22 @@
result.addCallback(shamir.recombine)
return result

+def make_runtime_class(runtime_class=Runtime, mixins=None):
+ """Creates a new runtime class with *runtime_class* as a base
+ class mixing in the *mixins*.
+
+ *mixins* must be a list or tuple of mixin-classes.
+ """
+
+ if mixins==None:
+ return runtime_class
+ else:
+ # We must include at least one new-style class in bases. We
+ # include it last to avoid overriding __init__ from the other base
+ # classes.
+ bases = (runtime_class,) + tuple(mixins) + (object,)
+
+ return type("ExtendedRuntime", bases, {})

def create_runtime(id, players, threshold, options=None, runtime_class=Runtime):
"""Create a :class:`Runtime` and connect to the other players.
Sigurd Meldgaard
2008-09-17 12:45:17 UTC
Permalink
# HG changeset patch
# User Sigurd Meldgaard <***@daimi.au.dk>
# Date 1221655195 -7200
# Node ID a0c6ff492442daaf8059c0fd667d58665fad042b
# Parent 97cbc18c43f357e60231c721d03aa5ec62d8b691
Updated apps.benchmark to use make_runtime_class.

diff -r 97cbc18c43f3 -r a0c6ff492442 apps/benchmark.py
--- a/apps/benchmark.py Mon Sep 08 18:31:14 2008 +0200
+++ b/apps/benchmark.py Wed Sep 17 14:39:55 2008 +0200
@@ -62,7 +62,8 @@
from twisted.internet import reactor

from viff.field import GF, GF256
-from viff.runtime import Runtime, create_runtime, gather_shares
+from viff.runtime import Runtime, create_runtime, gather_shares, \
+ make_runtime_class
from viff.active import BasicActiveRuntime, \
TriplesHyperinvertibleMatricesMixin, TriplesPRSSMixin
from viff.comparison import ComparisonToft05Mixin, ComparisonToft07Mixin
@@ -243,41 +244,37 @@
record_stop(None, "sequential test")
self.finished(None)

+mixins = []
if options.twoplayer:
# Then there is just one possible runtime:
operation = operator.mul
- bases = [PaillierRuntime]
+ base_runtime_class = PaillierRuntime
else:
# There are several options for a multiplayer runtime:
if options.active:
- bases = [BasicActiveRuntime]
+ base_runtime_class = BasicActiveRuntime
if options.prss:
- bases.append(TriplesPRSSMixin)
+ mixins.append(TriplesPRSSMixin)
else:
- bases.append(TriplesHyperinvertibleMatricesMixin)
+ mixins.append(TriplesHyperinvertibleMatricesMixin)
else:
- bases = [Runtime]
+ base_runtime_class = Runtime

if options.operation == "mul":
operation = operator.mul
elif options.operation == "compToft05":
operation = operator.ge
- bases.append(ComparisonToft05Mixin)
+ mixins.append(ComparisonToft05Mixin)
elif options.operation == "compToft07":
operation = operator.ge
- bases.append(ComparisonToft07Mixin)
+ mixins.append(ComparisonToft07Mixin)

-print "Constructing runtime from:"
-for base in bases:
- print "- %s" % base
+print "Using the base runtime: %s." % base_runtime_class
+print "With the following mixins:"
+for mixin in mixins:
+ print "- %s" % mixin

-
-# We must include at least one new-style class in bases. We include it
-# last to avoid overriding __init__ from the other base classes.
-bases.append(object)
-
-# Dynamically created class based on the choices above:
-runtime_class = type("BenchmarkRuntime", tuple(bases), {})
+runtime_class = make_runtime_class(base_runtime_class, mixins)

if options.parallel:
benchmark = ParallelBenchmark
Sigurd Meldgaard
2008-09-17 12:45:13 UTC
Permalink
# HG changeset patch
# User Sigurd Meldgaard <***@daimi.au.dk>
# Date 1221574165 -7200
# Node ID 1ac057be46ae0eeb0f23b0c4581aede1ed49b80c
# Parent 0ae0b7196ac880b3b0cfaaf6202650dbd7a9b1fd
Probabilistic equality mix-in

diff -r 0ae0b7196ac8 -r 1ac057be46ae viff/equality.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/viff/equality.py Tue Sep 16 16:09:25 2008 +0200
@@ -0,0 +1,111 @@
+# Copyright 2008 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/>.
+
+"""Equality protocol. The mixin class defined here provide an
+:meth:`equal` method to the :class:`Runtime
+<viff.runtime.Runtime>` they are mixed with.
+"""
+
+from viff.runtime import increment_pc
+
+class ProbabilisticEqualityMixin:
+ """This class implements probabilistic constant-round secure
+ equality-testing of two numbers."""
+
+ @increment_pc
+ def equal(self, share_x, share_y):
+ """
+ Assumes p = 3 mod 4, returns a secret sharing of 1 if
+ share_x == share_y and 0 otherwise.
+
+ This is the probabilistic method based on quadratic reciprocity
+ described in: "Constant-Round Multiparty Computation for
+ Interval Test, Equality Test, and Comparison" by Takashi
+ Nishide and Kazuo Ohta, and fails with probability 1/(2**k)
+ where k is set to the security parameter of the runtime.
+
+ TODO: Make it work for any prime-modulo, the b's should be in
+ {y,1} where y is a non-square modulo p.
+
+ TODO: Make the final "and"ing of the x's more efficient as
+ described in the paper.
+ """
+
+ Zp = share_x.field
+
+ a = share_x - share_y # We will check if a == 0
+ k = self.options.security_parameter
+
+ # The b's are random numbers in {-1, 1}
+ b = [self.prss_share_random(Zp, binary=True) * 2 - 1
+ for _ in range(k)]
+ r = [self.prss_share_random(Zp) for _ in range(k)]
+ rp = [self.prss_share_random(Zp) for _ in range(k)]
+
+ # If b_i == 1 c_i will always be a square modulo p if a is zero
+ # and with probability 1/2 otherwise (except if rp == 0)
+ # If b_i == -1 it will be non-square
+ c = [self.open(a * r[j] + b[j] * rp[j] * rp[j]) for j in range(k)]
+
+ def finish(cj, bj):
+ l = legendre_mod_p(cj)
+ assert l != 0 # This will only happen with negligible probability
+ if l == 1:
+ xj = (1/Zp(2)) * (bj + 1)
+ else: # l == -1
+ assert(l == -1)
+ xj = (-1) * (1/Zp(2)) * (bj - 1)
+ return xj
+
+ x = [cj.addCallback(finish, bj) for cj, bj in zip(c, b)]
+
+ # Take the product (this is here the same as the "and") of all
+ # the x'es
+ while len(x) > 1:
+ x.append(x.pop() * x.pop())
+
+ return x[0]
+
+def legendre_mod_p(a):
+ """
+ Returns the legendre symbol legendre(a, p) where p is
+ the order of the field of a.
+
+ Precondition: p must be odd.
+
+ Input:
+ a -- a field element
+ Output:
+ int: -1 if a is not a square mod p,
+ 0 if gcd(a,p) is not 1
+ 1 if a is a square mod p.
+
+ Examples:
+ >>> legendre(GF(5)(2))
+ -1
+ >>> legendre(GF(3)(3))
+ 0
+ >>> legendre(GF(2003)(7))
+ -1
+ """
+ assert a.modulus % 2 == 1
+ b = (a ** ((a.modulus - 1)/2))
+ if b == 1:
+ return 1
+ elif b == a.modulus-1:
+ return -1
+ return 0
Sigurd Meldgaard
2008-09-17 12:45:16 UTC
Permalink
# HG changeset patch
# User Sigurd Meldgaard <***@daimi.au.dk>
# Date 1220891474 -7200
# Node ID 97cbc18c43f357e60231c721d03aa5ec62d8b691
# Parent 11c959556ba30162a738ec851ac671e804922384
Added a new application showing how to use the equality library.

diff -r 11c959556ba3 -r 97cbc18c43f3 apps/equality.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/equality.py Mon Sep 08 18:31:14 2008 +0200
@@ -0,0 +1,114 @@
+#!/usr/bin/python
+
+# Copyright 2008 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/>.
+#
+
+"""
+This program is a very simple example of a Viff program.
+It shows the secret equality testing of two numbers
+
+The program can be run as follows for each player (min 3) where 24 is
+the number we would like to compare:
+
+$ python equality.py player-X.ini -n 24
+
+Only the numbers of player 1 and player 2 are actually compared, but
+more players are necessary for the security.
+"""
+
+from optparse import OptionParser
+from twisted.internet import reactor
+
+from viff.field import GF
+from viff.runtime import Runtime, create_runtime, make_runtime_class
+from viff.config import load_config
+from viff.util import find_prime
+from viff.equality import ProbabilisticEqualityMixin
+
+
+class Protocol:
+
+ def __init__(self, runtime):
+ print "connected"
+ self.rt = runtime
+
+ # Is our player id among the two first?
+ if(runtime.id <= 2):
+ print "My number: %d." % options.number
+ # Players 1 and two are doing a sharing over the field ZP
+ # our input is options number
+ (x, y) = runtime.shamir_share([1, 2], Zp, options.number)
+ else:
+ print "I do not have a number."
+ (x, y) = runtime.shamir_share([1, 2], Zp, None)
+
+ # Do the secret computation
+ result = (x == y)
+
+ # Now open the result so that we can see it
+ result = runtime.open(result)
+
+ def finish(e):
+ print
+ if e == 1:
+ print "The two numbers where equal!"
+ else:
+ print "The two numbers where different!"\
+ " (With high probability)"
+ print
+
+
+ # When the values for the opening arrive, we can call the
+ # finish method.
+ result.addCallback(finish)
+ result.addCallback(lambda _: runtime.shutdown())
+
+
+# Parse command line arguments.
+parser = OptionParser(usage=__doc__)
+
+parser.add_option("--modulus",
+ help="lower limit for modulus (can be an expression)")
+parser.add_option("-n", "--number", type="int",
+ help="number to compare")
+
+parser.set_defaults(modulus=2**65)
+
+Runtime.add_options(parser)
+
+options, args = parser.parse_args()
+
+if len(args) == 0:
+ parser.error("you must specify a config file")
+
+Zp = GF(find_prime(options.modulus, blum=True))
+
+# Load configuration file.
+id, players = load_config(args[0])
+
+runtime_class = make_runtime_class(mixins = [ProbabilisticEqualityMixin])
+
+pre_runtime = create_runtime(id, players, 1, options,
+ runtime_class=runtime_class)
+pre_runtime.addCallback(Protocol)
+
+# Uncomment the following line to set the numbers for each player
+# options.number = [None, 12, 18, None][id]
+
+# Start the Twisted event loop.
+reactor.run()
Sigurd Meldgaard
2008-09-17 12:45:14 UTC
Permalink
# HG changeset patch
# User Sigurd Meldgaard <***@daimi.au.dk>
# Date 1221574270 -7200
# Node ID 9f166758d6536eafa20326c840bd5e0278d5e4b1
# Parent 1ac057be46ae0eeb0f23b0c4581aede1ed49b80c
Test of robabilistic equality mix-in
* * *

diff -r 1ac057be46ae -r 9f166758d653 viff/test/test_equality.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/viff/test/test_equality.py Tue Sep 16 16:11:10 2008 +0200
@@ -0,0 +1,19 @@
+# Copyright 2007, 2008 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/>.
+
+#: Declare doctests for Trial.
+__doctests__ = ['viff.equality']
diff -r 1ac057be46ae -r 9f166758d653 viff/test/test_runtime_equal.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/viff/test/test_runtime_equal.py Tue Sep 16 16:11:10 2008 +0200
@@ -0,0 +1,67 @@
+# Copyright 2008 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/>.
+
+
+"""Tests of the equality protocol(s)."""
+
+import operator
+
+from viff.equality import ProbabilisticEqualityMixin
+from viff.test.util import RuntimeTestCase, BinaryOperatorTestCase
+from viff.runtime import Runtime
+
+
+class EqualRuntime(Runtime, ProbabilisticEqualityMixin):
+ """A runtime with the equality mixin."""
+ pass
+
+
+class ProbabilisticEqualityTestDifferent(BinaryOperatorTestCase,
+ RuntimeTestCase):
+ """Testin the equality with a and b different."""
+ # Arbitrarily chosen
+ a = 12442
+ b = 91243
+ runtime_class = EqualRuntime
+ operator = operator.eq
+
+
+class ProbabilisticEqualityTestEqual(BinaryOperatorTestCase, RuntimeTestCase):
+ """Testin the equality with a and b equal."""
+ a = 4023
+ b = 4023
+ runtime_class = EqualRuntime
+ operator = operator.eq
+
+
+class ProbabilisticEqualityTestDiff1_1(BinaryOperatorTestCase,
+ RuntimeTestCase):
+ """Testin the equality with a and b different by only one."""
+ a = 0
+ b = 1
+ runtime_class = EqualRuntime
+ operator = operator.eq
+
+
+class ProbabilisticEqualityTestDiff1_2(BinaryOperatorTestCase,
+ RuntimeTestCase):
+ """Testin the equality with a and b different by only in the other
+ direction."""
+ a = 1
+ b = 0
+ runtime_class = EqualRuntime
+ operator = operator.eq
Martin Geisler
2008-09-18 18:42:33 UTC
Permalink
Updates according to advice from mgeisler, and two patches bringing
apps.benchmark up to date
Okay thanks, I have fixed a bunch of typos, added a number of periods
(full-stops), and changed other small stuff :-) The patches are now
pushed!

Could you please update NEWS and add something to the documentation
under doc/?
--
Martin Geisler

VIFF (Virtual Ideal Functionality Framework) brings easy and efficient
SMPC (Secure Multi-Party Computation) to Python. See: http://viff.dk/.
Loading...