Python-ELMO is a Python library which offers an encapsulation of the binary tool ELMO, in order to manipulate it easily in Python and SageMath script.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

project_base.py 7.6KB

  1. import os, re
  2. import socket
  3. from protocol import SocketTool
  4. import numpy as np
  5. def to_hex(v, nb_bits=16):
  6. try:
  7. v_hex = v.hex()
  8. except AttributeError:
  9. v_hex = hex(v)[2:]
  10. return '0'*(nb_bits//4-len(v_hex)) + v_hex
  11. def split_octet(hexstr):
  12. return [hexstr[i:i+2] for i in range(0, len(hexstr), 2)]
  13. def to_signed_hex(v, nb_bits=16):
  14. return split_octet(to_hex(v & (2**nb_bits-1), nb_bits=nb_bits))
  15. def write(_input, uintXX, nb_bits=16):
  16. uintXX = to_signed_hex(uintXX, nb_bits=nb_bits)
  17. for i in range(nb_bits//8):
  18. _input.write(uintXX[i]+'\n')
  19. def write_list(_input, uint16_list):
  20. for uint16 in uint16_list:
  21. write(_input, uint16)
  22. def launch_simulation(quiet=False, **kwargs):
  23. try:
  24. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  25. s.connect(('localhost', 5000))
  26. SocketTool.send_data(s, kwargs)
  27. if not SocketTool.get_ack(s):
  28. raise RuntimeError("The request has been refused !")
  29. else:
  30. data = SocketTool.get_data(s)
  31. if data['error'] and not quiet:
  32. raise Exception("The simulation return an error")
  33. return data['output'], data['error']
  34. s.close()
  35. except IOError:
  36. raise RuntimeError("The connection refused. Has the ELMO server been switch on ?")
  37. class SimulationProject:
  38. _nb_bits_for_nb_challenges = 16
  39. _project_directory = None
  40. ### Define the project
  41. @classmethod
  42. def get_project_directory(cl):
  43. if cl._project_directory:
  44. return cl._project_directory
  45. else:
  46. raise NotImplementedError()
  47. @classmethod
  48. def set_project_directory(cl, project_directory):
  49. cl._project_directory = project_directory
  50. @classmethod
  51. def get_project_label(cl):
  52. return cl.get_project_directory()
  53. @classmethod
  54. def get_make_directory(cl):
  55. return ''
  56. @classmethod
  57. def get_binary(cl):
  58. raise NotImplementedError()
  59. @classmethod
  60. def get_parameters_names(cl):
  61. return set()
  62. @classmethod
  63. def adapt_project(cl, parameters):
  64. return
  65. def get_challenge_format(self):
  66. raise NotImplementedError()
  67. ### Tools to realize the simulation of the project
  68. def __init__(self, challenges=None):
  69. self.elmo_folder = os.path.dirname(os.path.abspath(__file__))+'/elmo'
  70. self.challenges = challenges
  71. self.is_executed = False
  72. def set_challenges(self, challenges):
  73. self.challenges = challenges
  74. def get_writable_input_file(self):
  75. return open('{}/input.txt'.format(self.elmo_folder), 'w')
  76. def set_input_for_each_challenge(self, input, challenge):
  77. format = self.get_challenge_format()
  78. def aux(sizes, data):
  79. if len(sizes) == 0:
  80. write(input, data)
  81. else:
  82. assert len(data) == sizes[0], 'Incorrect format for challenge. Get {} instead of {}'.format(len(data), sizes[0])
  83. for i in range(sizes[0]):
  84. aux(sizes[1:], data[i])
  85. for num_part in range(len(format)):
  86. aux(format[num_part], challenge[num_part])
  87. def set_input(self, input):
  88. assert len(self.challenges) < 2**16, 'The number of challenges must be strictly lower than 65536. Currently, there are {} challenges.'.format(len(self.challenges))
  89. write(input, len(self.challenges), nb_bits=self._nb_bits_for_nb_challenges)
  90. for challenge in self.challenges:
  91. self.set_input_for_each_challenge(input, challenge)
  92. def run(self):
  93. with open('{}/input.txt'.format(self.elmo_folder), 'w') as _input:
  94. self.set_input(_input)
  95. launch_simulation(project=self.get_project_label(), quiet=False)
  96. self.is_executed = True
  97. def get_asmtrace_filename(self):
  98. return '{}/output/asmoutput/asmtrace00001.txt'.format(self.elmo_folder)
  99. def get_indexes_of(self, condition):
  100. with open(self.get_asmtrace_filename(), 'r') as _file:
  101. asmtrace = _file.readlines()
  102. return [i for i, instr in enumerate(asmtrace) if condition(instr)]
  103. def get_number_of_traces(self):
  104. return len(self.challenges)
  105. def get_results(self, only_filenames=False, reorganise=None, indexes=None):
  106. assert self.is_executed
  107. nb_traces = self.get_number_of_traces()
  108. trace_filenames = []
  109. for filename in os.listdir('{}/output/traces/'.format(self.elmo_folder)):
  110. if re.search(r'^trace\d+\.trc$', filename):
  111. trace_filenames.append('{}/output/traces/{}'.format(self.elmo_folder, filename))
  112. if len(trace_filenames) >= nb_traces:
  113. break
  114. assert len(trace_filenames) == nb_traces
  115. results = trace_filenames
  116. if not only_filenames:
  117. for i in range(len(results)):
  118. with open(results[i], 'r') as _file:
  119. if indexes is not None:
  120. results[i] = list(map(float, _file.readlines()[indexes]))
  121. else:
  122. results[i] = list(map(float, _file.readlines()))
  123. if reorganise is not None:
  124. results = reorganise(results)
  125. return results
  126. def get_traces(self, reorganise=None, indexes=None):
  127. results = self.get_results(only_filenames=False, reorganise=reorganise,indexes=indexes)
  128. nb_traces = self.get_number_of_traces()
  129. trace_length = len(results[0])
  130. traces = np.zeros((nb_traces, trace_length))
  131. for i in range(nb_traces):
  132. traces[i,:] = results[i]
  133. if reorganise is not None:
  134. traces = reorganise(traces)
  135. return traces
  136. def get_printed_data(self):
  137. with open('{}/output/printdata.txt'.format(self.elmo_folder), 'r') as _file:
  138. data = list(map(lambda x: int(x, 16), _file.readlines()))
  139. nb_traces = self.get_number_of_traces()
  140. nb_data_per_trace = len(data) // nb_traces
  141. return [data[nb_data_per_trace*i:nb_data_per_trace*(i+1)] for i in range(nb_traces)]
  142. def analyse_operands(self, num_line, num_trace=1):
  143. num_str = str(num_trace)
  144. num_str = '0'*(5-len(num_str)) + num_str
  145. operands_filename = self.elmo_folder + '/output/operands/operands{}.txt'.format(num_str)
  146. trace_filename = self.elmo_folder + '/output/traces/trace0000{}.trc'.format(num_trace)
  147. is_multiple = (type(num_line) is list)
  148. if not is_multiple:
  149. num_line = [num_line]
  150. output = [{}]*len(num_line)
  151. with open(operands_filename, 'r') as _file:
  152. lines = _file.readlines()
  153. for i, num in enumerate(num_line):
  154. line = lines[num].split()
  155. data = list(map(int, line[0:7]))
  156. output[i]['previous'] = data[0:2]
  157. output[i]['current'] = data[2:4]
  158. output[i]['triplet'] = data[4:7]
  159. output[i]['other'] = list(map(float, line[7:]))
  160. with open(trace_filename, 'r') as _file:
  161. lines = _file.readlines()
  162. for i, num in enumerate(num_line):
  163. line = lines[num]
  164. output[i]['power'] = float(line)
  165. return output if is_multiple else output[0]