viff

view viff/hash_broadcast.py @ 1430:0164b895d948

Hash_broadcast: Removed the signal round since it does not improve security.
author Janus Dam Nielsen <janus.nielsen@alexandra.dk>
date Tue Feb 02 17:08:16 2010 +0100 (2 years ago)
parents 878eeda73dab
children 6d838b2d24a2
line source
1 #!/usr/bin/env python
3 # Copyright 2009 VIFF Development Team.
4 #
5 # This file is part of VIFF, the Virtual Ideal Functionality Framework.
6 #
7 # VIFF is free software: you can redistribute it and/or modify it
8 # under the terms of the GNU Lesser General Public License (LGPL) as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
11 #
12 # VIFF is distributed in the hope that it will be useful, but WITHOUT
13 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
15 # Public License for more details.
16 #
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with VIFF. If not, see <http://www.gnu.org/licenses/>.
20 from twisted.internet.defer import Deferred
22 try:
23 from hashlib import sha1
24 except ImportError:
25 from sha import sha as sha1
26 from viff.constants import TEXT, INCONSISTENTHASH, OK, HASH
28 error_msg = "Player %i, has received an inconsistent hash %s."
30 class InconsistentHashException(Exception):
31 pass
33 class HashBroadcastMixin:
34 """A weak-crusader broadcast scheme.
36 A value is send using `send_value` and when received a hash is
37 generated and exchanged among the receivers. If a receiver
38 receives a hash which is not equal to the one he generated, then
39 he aborts. Else he returns the received value and the computation
40 continues."""
42 def _send_message(self, pc, sender, receivers, message):
43 for peer_id in receivers:
44 self.protocols[peer_id].sendData(pc, TEXT, message)
46 def _receive_broadcast(self, pc, unique_pc, sender, receivers):
47 # The result.
48 result = Deferred()
49 # The message store.
50 message = []
51 # The hash store
52 g_hashes = {}
54 def hash_received(h, unique_pc, peer_id, receivers, a_hashes):
55 # Store the hash.
56 a_hashes[peer_id] = h
57 # If we have received a hash from everybody, then compute check them.
58 if len(receivers) == len(a_hashes.keys()):
59 # We check if the hashes we received are equal to
60 # the hash we computed ourselves.
61 s = reduce(lambda x, y: (a_hashes[self.id] == y and x) or INCONSISTENTHASH, [OK] + a_hashes.values())
62 if OK == s:
63 # Make the result ready.
64 result.callback(message[0])
65 else:
66 raise InconsistentHashException(error_msg % (self.id, a_hashes.values()))
68 def message_received(m, unique_pc, message, receivers, hashes):
69 # Store the message.
70 message.append(m)
71 # Compute hash of message.
72 h = sha1(m).hexdigest()
73 # Store hash.
74 hashes[self.id] = h
75 # Send the hash to all receivers.
76 for peer_id in receivers:
77 self.protocols[peer_id].sendData(unique_pc, HASH, str(h))
79 # Set up receiver for hashes.
80 # Note, we use the unique_pc to avoid data to cross
81 # method invocation boundaries.
82 for peer_id in receivers:
83 d_hash = Deferred().addCallbacks(hash_received,
84 self.error_handler,
85 callbackArgs=(unique_pc, peer_id, receivers, g_hashes))
86 self._expect_data_with_pc(unique_pc, peer_id, HASH, d_hash)
88 # Set up receiving of the message.
89 d_message = Deferred().addCallbacks(message_received,
90 self.error_handler,
91 callbackArgs=(unique_pc, message, receivers, g_hashes))
92 self._expect_data(sender, TEXT, d_message)
93 return result
96 def broadcast(self, senders, receivers, message=None):
97 """Broadcast the messeage from senders to receivers.
99 Returns a list of deferreds if the calling player is among
100 the receivers and there are multiple senders.
101 Returns a single element if there is only on sender, or the
102 calling player is among the senders only.
104 The order of the resulting list is guaranteed to be the same order
105 as the list of senders.
107 Senders and receivers should be lists containing the id of the senders
108 and receivers, respectively.
110 Note: You send implicitly to your self."""
111 assert message is None or self.id in senders
113 self.program_counter[-1] += 1
115 pc = tuple(self.program_counter)
116 if self.id in receivers or self.id in senders:
117 results = [None] * len(senders)
118 else:
119 results = []
121 if self.id in senders:
122 self._send_message(pc, self.id, receivers, message)
124 if self.id in receivers:
125 for x in xrange(len(senders)):
126 sender = senders[x]
127 new_pc = list(self.program_counter)
128 new_pc.append(x)
129 results[x] = self._receive_broadcast(pc, tuple(new_pc), sender, receivers)
131 if self.id in senders and self.id not in receivers:
132 d = Deferred()
133 d.callback(message)
134 results = [d]
136 self.program_counter[-1] += 1
138 if len(results) == 1:
139 return results[0]
141 return results
143 def list_str(self, s):
144 ls = []
145 for x in s[1:-1].split(','):
146 x = x.strip()
147 ls.append(str(x)[1:-1])
148 return ls
150 def error_handler(self, ex):
151 print "Error: ", ex
152 return ex