# HG changeset patch
# User Martin Geisler <[EMAIL PROTECTED]>
# Date 1214215643 -7200
# Node ID 926f19ca9b83e6e803894369e654dee0e1129a0d
# Parent  dc3106ba60700a2cfa1faf1a62ac011875db2275
Multiplication using ElGamal. Warning, it is insecure!

The multiplication protocol works, but unfortunately it reveals the
input shares while computing the result...

diff --git a/viff/elgamal.py b/viff/elgamal.py
--- a/viff/elgamal.py
+++ b/viff/elgamal.py
@@ -17,6 +17,7 @@
 
 """The ElGamal crypto system."""
 
+from viff.runtime import BasicRuntime, Share, increment_pc, gather_shares
 from viff.util import rand
 from viff.field import GF
 
@@ -46,3 +47,115 @@
     gamma, delta = c
     p, a = sk
     return (pow(gamma, p - 1 - a, p) * delta) % p
+
+
+def _dummy_field(x):
+    raise Exception("This field should not be used")
+
+
+class AdditiveRuntime(BasicRuntime):
+    """Runtime for two players providing addition only."""
+
+    def add_player(self, player, protocol):
+        BasicRuntime.add_player(self, player, protocol)
+        if player.id == self.id:
+            self.player = player
+            # Size of message field.
+            self.p = self.player.pubkey[0]
+        else:
+            self.peer = player
+
+    @increment_pc
+    def share(self, inputters, number=None):
+        """Share *number* additively."""
+        assert number is None or self.id in inputters
+
+        results = []
+        for peer_id in inputters:
+            if peer_id == self.id:
+                a = rand.randint(0, self.p)
+                b = (number - a) % self.p
+
+                results.append(Share(self, _dummy_field, a))
+                pc = tuple(self.program_counter)
+                self.protocols[self.peer.id].sendData(pc, "additive_share", b)
+            else:
+                share = Share(self, _dummy_field)
+                self._expect_data(peer_id, "additive_share", share)
+                results.append(share)
+
+        # Unpack a singleton list.
+        if len(results) == 1:
+            return results[0]
+        else:
+            return results
+
+    @increment_pc
+    def open(self, share, receivers=None):
+        """Open *share* to *receivers* (defaults to both players)."""
+
+        def exchange(a):
+            pc = tuple(self.program_counter)
+            self.protocols[self.peer.id].sendData(pc, "additive_share", a)
+            result = Share(self, _dummy_field)
+            self._expect_data(self.peer.id, "additive_share", result)
+            result.addCallback(lambda b: (a + b) % self.p)
+            return result
+
+        result = share.clone()
+        self.schedule_callback(result, exchange)
+        return result
+
+    def add(self, share_a, share_b):
+        """Addition of shares.
+
+        Communication cost: none.
+        """
+        if not isinstance(share_a, Share):
+            share_a = Share(self, _dummy_field, share_a)
+        if not isinstance(share_b, Share):
+            share_b = Share(self, _dummy_field, share_b)
+
+        result = gather_shares([share_a, share_b])
+        result.addCallback(lambda (a, b): (a + b) % self.p)
+        return result
+
+
+class ElGamalRuntime(AdditiveRuntime):
+    """Runtime for two players which provides multiplication."""
+
+    def mul(self, share_a, share_b):
+        """Multiplication of shares."""
+        if not isinstance(share_a, Share):
+            share_a = Share(self, _dummy_field, share_a)
+        if not isinstance(share_b, Share):
+            share_b = Share(self, _dummy_field, share_b)
+
+        def finish_mul((a1, b1)):
+            pc = tuple(self.program_counter)
+            send_data = self.protocols[self.peer.id].sendData
+
+            # Encrypt and send our sharing to our peer.
+            enc_a1 = encrypt(a1, self.player.pubkey)
+            send_data(pc, "encrypted_share", enc_a1)
+            # and receive an encryption too.
+            enc_a2 = Share(self, _dummy_field)
+            self._expect_data(self.peer.id, "encrypted_share", enc_a2)
+
+            # Multiply a2 with b1 inside the encryption.
+            # TODO: This is unsecure and leaks b1! The recipient can
+            # just multiply with the inverse of a2.
+            enc_a2_b1 = enc_a2.addCallback(lambda (x, y): (x, b1 * y))
+            enc_a2_b1.addCallback(lambda c: send_data(pc, "encrypted_share", 
c))
+
+            result = Share(self, _dummy_field)
+            self._expect_data(self.peer.id, "encrypted_share", result)
+
+            # result contains E(a1 * b2).
+            result.addCallback(decrypt, self.player.seckey)
+            result.addCallback(lambda a1_b2: (a1 * b1 + a1_b2) % self.p)
+            return result
+
+        result = gather_shares([share_a, share_b])
+        result.addCallback(finish_mul)
+        return result
_______________________________________________
viff-patches mailing list
[email protected]
http://lists.viff.dk/listinfo.cgi/viff-patches-viff.dk

Reply via email to