def __realMix(self, message, path, tempProcess=None): temp = message.permute(self.permutation[path]) result = Vector([ CyclicGroupVector.scalarMultiply(temp.at(i), self.S[path].array.at(i)) for i in range(0, self.b) ]) if not self.__finalNode(path): self.__toNextNode( path, Message(self.realMixCallback[path], [v.vector for v in result.vector])) else: self.network.broadcastToNodes( self.id, Message(self.mixCommitCallback[path], [v.vector for v in result.vector])) temp = CyclicGroupVector.multiply(self.decryptionShare[path], self.mixMessageComponents[path]) if tempProcess is not None: temp = tempProcess(temp) result = Vector([ CyclicGroupVector.scalarMultiply(result.at(i), temp.at(i)) for i in range(0, self.b) ]) self.network.sendToNH( Message(self.realPostProcessCallback[path], [True, [v.vector for v in result.vector]])) return Status.OK
def readResponse(self, message): # un-blind the response and store it for future reference responseVector = CyclicGroupVector.scalarMultiply( CyclicGroupVector(vector=message.payload), self.keyManager.getCombinedKey(type=KeyManager.RESPONSE, inverse=True)) self.callbackHandler.responseHandler(self, responseVector) self.responseGot = responseVector.copyVector() return Status.OK
def readMessage(self, message): index = message.payload[0] # the payload is the message (mapped to cyclic group members) messageVector = CyclicGroupVector(vector=message.payload[1]) # compute a response and send it to the mixnet responseVector = self.callbackHandler.messageHandler( self, messageVector) # store message and response for future reference self.messageGot = messageVector.copyVector() self.responseSent = responseVector.copyVector() self.network.sendToNH( Message(Callback.USER_RESPONSE, [index, responseVector.vector])) return Status.OK
def realRetMix(self, message): def tempProcess(temp): return self.__returnPathKeyBlinding(temp) return self.__realMix(message=Vector( vector=[CyclicGroupVector(vector=v) for v in message.payload]), path='RET', tempProcess=tempProcess)
def realForMixCommit(self, message): def resultProcess(decrShare): return decrShare return self.__realMixCommit(message=Vector( vector=[CyclicGroupVector(vector=v) for v in message.payload]), path='FOR', resultProcess=resultProcess)
def realRetMixCommit(self, message): def resultProcess(decrShare): return self.__returnPathKeyBlinding(decrShare) return self.__realMixCommit(message=Vector( vector=[CyclicGroupVector(vector=v) for v in message.payload]), path='RET', resultProcess=resultProcess)
def __appendDecrShare(self, payload, path): if self.decryptionShares[path] is None: self.decryptionShares[path] = payload else: if self.mixResult[path] is None: self.decryptionShares[path] = CyclicGroupVector.multiply( self.decryptionShares[path], payload) else: self.decryptionShares[path] = payload
def realForPreProcess(self, message): code = message.callback cyclicVector = CyclicGroupVector(vector=message.payload) self.sendersBuffer.scalarMultiply(cyclicVector) if self.isLastCall(code): self.network.sendToFirstNode( Message(Callback.REAL_FOR_MIX, self.sendersBuffer.getMessages())) return Status.OK
def getUserResponse(self, message): index = message.payload[0] response = CyclicGroupVector(vector=message.payload[1]) self.receiversBuffer.addUserMessage(index, response) if self.receiversBuffer.isFull(): self.network.sendToLastNode( Message(Callback.REAL_RET_MIX, self.receiversBuffer.getMessages())) return Status.OK
def realForPreProcess(self, message): self.senders = message.payload cyclicVector = self.keyManager.getNextKeys(ids=self.senders, type=KeyManager.MESSAGE, inverse=False) product = CyclicGroupVector.multiply(cyclicVector, self.r.array) self.network.sendToNH( Message(Callback.REAL_FOR_PREPROCESS, product.vector)) return Status.OK
def __realPostProcess(self, message, path, getUsersCallback): code = message.callback isLastNode = message.payload[0] # the last node send the mix results along with his decryption share if isLastNode: self.mixResult[path] = Vector(vector=[ CyclicGroupVector(vector=v) for v in message.payload[1] ]) else: self.__appendDecrShare( CyclicGroupVector(vector=message.payload[1]), path) # gradually un-blind messages if self.mixResult[path] is not None and self.decryptionShares[ path] is not None: self.mixResult[path] = Vector([ CyclicGroupVector.scalarMultiply( self.mixResult[path].at(i), self.decryptionShares[path].at(i)) for i in range(0, self.b) ]) # when they are un-blinded, send to users if self.isLastCall(code): users = getUsersCallback() for i in range(0, self.b): if path == 'FOR': # in the forward path, also send the index # the response will contain this index, so the NH will know which slot to associate it with # NOTE: as an alternative, the NH could wait for a response before he delivers the next message # that way, the index is not needed to be sent payload = [i, self.mixResult[path].at(i).vector] else: payload = self.mixResult[path].at(i).vector self.network.sendToUser( users[i], Message(self.sendCallback[path], payload)) else: if path == 'RET': self.reset() return Status.OK
def sendMessage(self, userId, messageId, messageVector): # store the message for future reference self.messageSent = messageVector.copyVector() # append the userId (the receiver) # the NH will read this id (after the message is un-blinded) and route the message accordingly messageVector.append(userId) # blind the message with the combined key and send it to the NH combinedKey = self.keyManager.getCombinedKey(type=KeyManager.MESSAGE, inverse=True) blindMessage = CyclicGroupVector.scalarMultiply( messageVector, combinedKey) self.network.sendToNH( Message(Callback.USER_MESSAGE, [self.id, messageId, blindMessage.vector]))
def getUserMessage(self, message): senderId = message.payload[0] messageId = message.payload[1] blindMessage = CyclicGroupVector(vector=message.payload[2]) self.sendersBuffer.addUser(senderId, messageId, blindMessage) self.network.sendToUser( senderId, Message(Callback.USER_MESSAGE_STATUS, (messageId, MessageStatus.PENDING))) if self.sendersBuffer.isFull(): for senderId, messageId in zip(self.sendersBuffer.getUsers(), self.sendersBuffer.getMessageIds()): self.network.sendToUser( senderId, Message(Callback.USER_MESSAGE_STATUS, (messageId, MessageStatus.SENT))) self.network.broadcastToNodes( self.id, Message(Callback.REAL_FOR_PREPROCESS, self.sendersBuffer.getUsers())) return Status.OK
def __returnPathKeyBlinding(self, temp): return CyclicGroupVector.multiply( temp, self.keyManager.getNextKeys(ids=self.senders, type=KeyManager.RESPONSE, inverse=False))
def getNextKeys(self, ids, type, inverse): return CyclicGroupVector( vector=[self.getNextKey(id, type, inverse) for id in ids])
def messageHandler(self, user, message): return CyclicGroupVector.random()
def realForMix(self, message): return self.__realMix(message=Vector( vector=[CyclicGroupVector(vector=v) for v in message.payload]), path='FOR')
def scalarMultiply(self, cyclicVector): for i in range(0, self.b): self.messages[i] = CyclicGroupVector.scalarMultiply( self.messages[i], cyclicVector.at(i))
def preReturnPostProcess(self, message): return self.__prePostProcess( randomComponents=CyclicGroupVector(vector=message.payload), path='RET')