qp_client.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. from dht_common import compute_document_ID, SIZE_OF_HASH, SIZE_OF_IP_ADDRESS, SIZE_OF_OT_VALUE, SIZE_OF_KEY, SIZE_OF_SIGNATURE, SIZE_OF_TIMESTAMP
  2. from rcp_client import RCP_Client
  3. from collections import defaultdict
  4. class QP_Client(RCP_Client):
  5. def __init__(self, DHT, knownQuorum, documentSize, numNodes):
  6. RCP_Client.__init__(self, DHT, knownQuorum, documentSize, numNodes)
  7. self.fingerTableRangeAccesses = defaultdict(lambda: 0)
  8. self.fingerTableAccesses = defaultdict(lambda: 0)
  9. def get_finger_table_range_accesses(self):
  10. return self.fingerTableRangeAccesses
  11. def get_finger_table_accesses(self):
  12. return self.fingerTableAccesses
  13. # Needs to be here to use new iterative search
  14. def test_iterative_search(self):
  15. if self.DHT.get_num_nodes() == 10:
  16. retval, _, _ = self.__iterative_search__(b'\xb5\xe0\xf4\xd8\xe9\x1e\xf6i\xc4=^\xc2Y\xac\xdc\x88p\x8a+\x10t\x90\xa5\xc9\x1f\x98\xc61\xda\x7fH\x92')
  17. return retval == 7
  18. else:
  19. print("Assumed testing conditions not met; no tests run.")
  20. return False
  21. # implements a simulation of iteratively searching the DHT (captured as the dht_simulator, or here "DHT")
  22. def __iterative_search__(self, documentID):
  23. whichQuorum, numKeys, numSignatures = self.__iterative_search_prelude__(documentID)
  24. flagFound = False
  25. while not flagFound:
  26. randomNode = self.cryptogen.randrange(self.numNodes)
  27. ranges, numEntries = self.DHT.access_node(whichQuorum).get_finger_table_ranges(randomNode, numKeys, numSignatures)
  28. # Asker's ID
  29. sizeOfRequest = SIZE_OF_HASH
  30. # timestamp
  31. sizeOfRequest += SIZE_OF_TIMESTAMP
  32. # keys in request
  33. sizeOfRequest += SIZE_OF_KEY * numKeys
  34. # signatures in request
  35. sizeOfRequest += SIZE_OF_SIGNATURE * numSignatures
  36. # The set of hashes in the finger table
  37. sizeOfResponse = SIZE_OF_HASH * numEntries
  38. # Then the entrywise encrypted finger table routing information
  39. sizeOfResponse += (SIZE_OF_IP_ADDRESS * self.numNodes + SIZE_OF_KEY) * numEntries
  40. # Then the OT prime values
  41. sizeOfResponse += 2 * SIZE_OF_OT_VALUE * numEntries
  42. # Then, finally, a signature to tie it together
  43. sizeOfResponse += SIZE_OF_SIGNATURE
  44. self.numRounds += 1
  45. self.numMessagesSent += 1
  46. self.numMessagesRecv += 1
  47. self.numBytesSent += sizeOfRequest
  48. self.numBytesRecv += sizeOfResponse
  49. self.fingerTableRangeAccesses[numEntries] += 1
  50. currNode = self.DHT.access_node(whichQuorum).nodeID
  51. allOptions = ranges
  52. allOptions.append(currNode)
  53. allOptions.sort()
  54. trueOptions = [x for x in allOptions if x <= documentID]
  55. correct = max(trueOptions) if len(trueOptions) > 0 else max(allOptions)
  56. if correct == currNode:
  57. flagFound = True
  58. else:
  59. whichQuorum = self.DHT.access_node(whichQuorum).OT_get_finger_table_val(randomNode, correct)
  60. # OT prime value to be able to open one of the entries in the finger table
  61. sizeOfRequest = SIZE_OF_OT_VALUE
  62. # And a signature to confirm it's valid
  63. sizeOfRequest += SIZE_OF_SIGNATURE
  64. # The final OT prime value
  65. sizeOfResponse = SIZE_OF_OT_VALUE
  66. # And a signature to boot
  67. sizeOfResponse += SIZE_OF_SIGNATURE
  68. self.numRounds += 1
  69. self.numMessagesSent += 1
  70. self.numMessagesRecv += 1
  71. self.numBytesSent += sizeOfRequest
  72. self.numBytesRecv += sizeOfResponse
  73. self.fingerTableAccesses[numEntries] += 1
  74. numKeys += 1
  75. numSignatures += 1
  76. return whichQuorum, numKeys, numSignatures
  77. # Needs to be here to use new iterative search
  78. def insert_file(self, document):
  79. documentID = compute_document_ID(document)
  80. whichQuorum, numKeys, numSignatures = self.__iterative_search__(documentID)
  81. self.DHT.access_node(whichQuorum).insert(numKeys, numSignatures)
  82. # Asker's ID
  83. sizeOfRequest = SIZE_OF_HASH
  84. # timestamp
  85. sizeOfRequest += SIZE_OF_TIMESTAMP
  86. # keys in request
  87. sizeOfRequest += SIZE_OF_KEY * numKeys
  88. # signatures in request
  89. sizeOfRequest += SIZE_OF_SIGNATURE * numSignatures
  90. # actual document sent
  91. sizeOfRequest += self.documentSize
  92. # signature over whole thing
  93. sizeOfRequest += SIZE_OF_SIGNATURE
  94. sizeOfResponse = SIZE_OF_HASH + SIZE_OF_SIGNATURE
  95. self.numRounds += 1
  96. self.numMessagesSent += 1
  97. self.numMessagesRecv += 1
  98. self.numBytesSent += sizeOfRequest
  99. self.numBytesRecv += sizeOfResponse
  100. return documentID
  101. # Minor change from base_client; retrieving from a quorum, you should specify which specific node to retrieve from
  102. def retrieve_file(self, documentID):
  103. whichQuorum, numKeys, numSignatures = self.__iterative_search__(documentID)
  104. randomNode = self.cryptogen.randrange(self.numNodes)
  105. self.DHT.access_node(whichQuorum).retrieve(randomNode, numKeys, numSignatures)
  106. # Asker's ID
  107. sizeOfRequest = SIZE_OF_HASH
  108. # timestamp
  109. sizeOfRequest += SIZE_OF_TIMESTAMP
  110. # keys in request
  111. sizeOfRequest += SIZE_OF_KEY * numKeys
  112. # signatures in request
  113. sizeOfRequest += SIZE_OF_SIGNATURE * numSignatures
  114. # actual hash requested
  115. sizeOfRequest += SIZE_OF_HASH
  116. # signature over whole thing
  117. sizeOfRequest += SIZE_OF_SIGNATURE
  118. sizeOfResponse = self.documentSize + SIZE_OF_SIGNATURE
  119. self.numRounds += 1
  120. self.numMessagesSent += 1
  121. self.numMessagesRecv += 1
  122. self.numBytesSent += sizeOfRequest
  123. self.numBytesRecv += sizeOfResponse
  124. # TODO: Add unit tests for size calculations
  125. if __name__ == "__main__":
  126. from dht_simulator import DHT_Simulator
  127. from qp_node import QP_Quorum
  128. NUM_QUORUMS_IN_TEST = 10
  129. SIZE_OF_DOCUMENTS_IN_TEST = 1024
  130. NUM_NODES_PER_QUORUM_IN_TEST = 10
  131. testbed = DHT_Simulator(QP_Quorum, NUM_QUORUMS_IN_TEST, SIZE_OF_DOCUMENTS_IN_TEST, NUM_NODES_PER_QUORUM_IN_TEST)
  132. client = QP_Client(testbed, 0, SIZE_OF_DOCUMENTS_IN_TEST, NUM_NODES_PER_QUORUM_IN_TEST)
  133. assert client.test_iterative_search()
  134. print("Iterative search functioning correctly.")
  135. file = b'\xc3\xa7\x0c\xc3\x97!\xc3\xb2offy\x13\xc2\x81~\xc2\x9f\xc3\xb5\xc3\xa1\xc3\xb9C\xc2\x92f\xc2\x968\x01\xc2\x9183D\xc3\x84\xc3\xa9\xc3\x8e\t\x0f\xc2\xa1<\xc2\xad%G\xc3\x9dq\xc2\xb7\x1b\x7f\xc2\x82\xc3\x84\xc3\xb4\xc3\x81\x1c\xc3\x8dqgH(H\\C&\x14\xc2\x98\xc3\x93`\xc3\xbe\xc3\x95\xc3\xad\xc3\x8d\xc3\xb5\xc2\x8d.\xc2\x94D\x13IK\xc3\x9a\xc2\x8dS\xc3\x8b\xc2\xa7\xc2\xb6\xc2\x9d\x1fY\xc3\xbe\xc3\x85[\r\xc2\x85\x0e#\xc2\xb85B4\x15\xc3\xaf\xc2\x81_g\xc3\xb3;!|\xc3\xbc\xc3\xaa;\xc3\xbd(m\xc2\xbd\xc3\x96b\xc2\x88\xc3\x9d\xc2\x87N\xc3\xb9\xc3\xb5\xc3\xa54\xc2\xb6(\xc2\xa7\xc3\x950\xc3\x82\x1c\xc3\x95\xc2\x85\xc2\x983\xc3\xbfy\xc2\x89lQ\xc2\x8aN\xc2\xb0\x05\xc2\x9f\xc2\xac\xc2\xa3T+z.D1\xc2\xae\xc2\xae+\xc3\x86\xc2\xb3\xc2\xb0\xc3\x8d,\x04\xc2\x96\xc2\xa7\xc3\xba\xc2\xb4A\xc2\x95P"*\x1d\x0b\xc3\xbd!e\xc2\xaa\xc2\xa4UL\xc3\x84j\xc2\xb9>h\x01\x08\xc3\xb1\xc2\x85\xc3\x81\xc2\xb0b\xc2\x9b\x0fY\xc3\xb7V ^\xc3\xb0Z~r%\xc2\x9c\xc2\x91Q\x03+9(\x14\xc2\xa1`\x17\xc3\x8c\x18+\xc3\xb4\xc2\xb4Z&l9L\xc2\x94\xc2\xae\xc2\x83\x7fJt\xc2\xbbt\xc2\x89\n\xc2\xab\xc2\x94\xc2\x90I3\xc3\xa8\xc2\xbb\x14\xc3\x9ekM\x170}r\xc2\x9c>\xc3\xa2!\xc2\x8d\xc2\x91f\xc3\xb2\xc3\xae<v\x07\xc3\xa5V\xc2\x81\xc2\x9a\xc2\xbe\xc2\xb9\xc3\x91\xc3\x97\xc3\xb01\xc2\x82b\xc3\x82\xc3\x93\x04\xc2\xb3\xc2\xb3\x0bdtR\xc2\x80\x0e\xc2\x96\xc3\x8c\xc2\x82\xc2\xba\x15\xc3\x8aO\xc2\xae\xc2\x8a\xc2\x9b\xc2\x9d\xc3\xb4\xc2\xbc\xc2\x8d\xc2\xad\xc3\x94\xc3\xab\x1b]\xc2\xaf\xc3\xadd\xc2\xb2[\xc3\x83]\xc2\x9d\xc3\x91\x1b\xc2\x82\'\x15\xc2\xbe\xc2\xad\xc3\xaf\xc3\x80\xc2\x90\xc2\x9c<xOh;\xc2\xb3\xc3\xae\x05m5\x14\xc2\xacm\xc3\xba\xc3\xbd;R*\xc3\xae$\xc2\x9d\xc2\x8ff\x178mU\xc3\xba?\\o{\xc2\xa6\xc2\xa3+\xc3\x9c\xc2\xa5\xc2\xa4\xc2\xabFv\t\xc3\x9b>h\xc3\x82\xc2\x94\x11*\xc2\x97D`\xc3\xba\xc3\xa0\x17\xc3\xab!An\x7f\xc2\x89Rrh\xc3\x80\xc2\xaf\x1f*}j\xc2\xaf\xc2\x84\xc2\xa4\xc2\x92\xc2\x97\xc2\x83\xc2\x8cf\xc3\xb6\x1f\xc3\xadfb\xc2\xb1\xc2\xa3\xc3\x8f7\xc3\x82 \xc3\xbb\xc2\x84\xc3\xb0sh\xc2\x9d|\x7f\xc3\xbda\xc3\x84\xc2\x80\x08\xc3\x88\xc2\xa8mBi\xc2\xae)\x02}K\xc3\x9f\xc2\xa7\xc3\x95\xc3\x94[[D\n\xc2\x98AQH\xc2\xb9\xc2\xb3\xc3\xb3"\x08\xc2\x9f\xc3\x98\xc3\x91B[\xc2\x8b\xc2\x86xhMK\xc3\xbb\xc2\x83`\xc2\xa7\x02\xc3\x8a\xc3\x89\xc3\x8f\xc3\xb0\xc2\xa9\xc3\x99\xc3\x9b\xc2\xb2\xc3\x9a\xc3\xaa5\xc2\xb7T\xc2\x81\x0f\xc3\x90\x0c\xc3\xb3\x05\xc3\x8d\xc3\x85S\xc2\xbb\x17\xc3\x86\xc3\xb2\xc3\xa3\xc3\xb0V\x07\x0e\xc2\xb0y\xc2\x8e\xc2\xb1\xc3\x8f;\xc2\xb9Tc\xc3\xadM\xc2\xad\xc2\x98#\xc2\xb0\x01`\x1c\xc2\x84d'
  136. fileID = b'\xb5\xe0\xf4\xd8\xe9\x1e\xf6i\xc4=^\xc2Y\xac\xdc\x88p\x8a+\x10t\x90\xa5\xc9\x1f\x98\xc61\xda\x7fH\x92'
  137. client.insert_file(file)
  138. client.retrieve_file(fileID)
  139. print("Basic insertion/retrieval fires correctly.")