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 kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

engine.py 9.2KB

  1. import numpy as np
  2. import os
  3. from enum import IntEnum, unique
  4. from .utils import binary_writing
  5. from .config import ELMO_TOOL_REPOSITORY
  6. @unique
  7. class Instruction(IntEnum):
  8. EOR = 0
  9. LSL = 1
  10. STR = 2
  11. LDR = 3
  12. MUL = 4
  13. OTHER = 5
  14. # Short name for 'Instruction' class
  15. Instr = Instruction
  16. PREVIOUS = 0
  17. CURRENT = 1
  18. SUBSEQUENT = 2
  19. class ELMOEngine:
  20. ### Initialization
  21. def __init__(self):
  22. self.load_coefficients()
  23. self.reset_points()
  24. def _extract_data(self, nb):
  25. coeffs = self.coefficients[self.pos:self.pos+nb]
  26. self.pos += nb
  27. return coeffs
  28. def load_coefficients(self):
  29. """ Load the coefficients for the ELMO model about power leakage """
  30. filename = os.path.join(
  31. os.path.dirname(os.path.abspath(__file__)),
  32. ELMO_TOOL_REPOSITORY,
  33. 'coeffs.txt',
  34. )
  35. self.coefficients = None
  36. with open(filename, 'r') as _file:
  37. self.coefficients = np.array([list(map(float, line.split())) for line in _file.readlines()[:2153]])
  38. if self.coefficients is None:
  39. raise IOError('Problem to read the coefficients.')
  40. self.pos = 0
  41. self.constant = np.squeeze(self._extract_data(1))
  42. self.PrvInstr = self._extract_data(4)
  43. self.SubInstr = self._extract_data(4)
  44. self.Operand1 = self._extract_data(32)
  45. self.Operand2 = self._extract_data(32)
  46. self.BitFlip1 = self._extract_data(32)
  47. self.BitFlip2 = self._extract_data(32)
  48. self.HWOp1PrvInstr = self._extract_data(4)
  49. self.HWOp2PrvInstr = self._extract_data(4)
  50. self.HDOp1PrvInstr = self._extract_data(4)
  51. self.HDOp2PrvInstr = self._extract_data(4)
  52. self.HWOp1SubInstr = self._extract_data(4)
  53. self.HWOp2SubInstr = self._extract_data(4)
  54. self.HDOp1SubInstr = self._extract_data(4)
  55. self.HDOp2SubInstr = self._extract_data(4)
  56. self.Operand1_bitinteractions = self._extract_data(496)
  57. self.Operand2_bitinteractions = self._extract_data(496)
  58. self.BitFlip1_bitinteractions = self._extract_data(496)
  59. self.BitFlip2_bitinteractions = self._extract_data(496)
  60. ### Computation core
  61. def _dot(self, a, b):
  62. return np.sum(a * b, axis=0)
  63. def calculate_point(self, triplet, previous_ops, current_ops, debug=False):
  64. nb_points = triplet.shape[1]
  65. instructiontype = triplet[CURRENT]
  66. instructiontype = instructiontype % 5 # Type 5 = Instruction was not profiled
  67. # Previous
  68. previous_instruction_typedec = triplet[PREVIOUS]
  69. previous_instruction_type = np.zeros((5, nb_points))
  70. for i in range(nb_points):
  71. if previous_instruction_typedec[i] < 5:
  72. previous_instruction_type[previous_instruction_typedec[i],i] = 1
  73. # Current
  74. (current_op1_binary, hw_op1) = binary_writing(current_ops[0], with_hamming=True)
  75. (current_op2_binary, hw_op2) = binary_writing(current_ops[1], with_hamming=True)
  76. (current_op1_bitflip, hd_op1) = binary_writing(previous_ops[0] ^ current_ops[0], with_hamming=True)
  77. (current_op2_bitflip, hd_op2) = binary_writing(previous_ops[1] ^ current_ops[1], with_hamming=True)
  78. current_instruction_typedec = instructiontype
  79. current_instruction_type = np.zeros((5, nb_points))
  80. for i in range(nb_points):
  81. if triplet[CURRENT,i] < 5:
  82. current_instruction_type[current_instruction_typedec[i],i] = 1
  83. # Subsequent
  84. subsequent_instruction_typedec = triplet[SUBSEQUENT]
  85. subsequent_instruction_type = np.zeros((5, nb_points))
  86. for i in range(nb_points):
  87. if subsequent_instruction_typedec[i] < 5:
  88. subsequent_instruction_type[subsequent_instruction_typedec[i],i] = 1
  89. # Component variables
  90. PrvInstr_data = self._dot( previous_instruction_type[1:], self.PrvInstr[:,instructiontype] )
  91. SubInstr_data = self._dot( subsequent_instruction_type[1:], self.SubInstr[:,instructiontype] )
  92. Operand1_data = self._dot( current_op1_binary, self.Operand1[:,instructiontype] )
  93. Operand2_data = self._dot( current_op2_binary, self.Operand2[:,instructiontype] )
  94. BitFlip1_data = self._dot( current_op1_bitflip, self.BitFlip1[:,instructiontype] )
  95. BitFlip2_data = self._dot( current_op2_bitflip, self.BitFlip2[:,instructiontype] )
  96. HWOp1PrvInstr_data = hw_op1 * self._dot(previous_instruction_type[1:], self.HWOp1PrvInstr[:,instructiontype])
  97. HWOp2PrvInstr_data = hw_op2 * self._dot(previous_instruction_type[1:], self.HWOp2PrvInstr[:,instructiontype])
  98. HDOp1PrvInstr_data = hd_op1 * self._dot(previous_instruction_type[1:], self.HDOp1PrvInstr[:,instructiontype])
  99. HDOp2PrvInstr_data = hd_op2 * self._dot(previous_instruction_type[1:], self.HDOp2PrvInstr[:,instructiontype])
  100. HWOp1SubInstr_data = hw_op1 * self._dot(subsequent_instruction_type[1:], self.HWOp1SubInstr[:,instructiontype])
  101. HWOp2SubInstr_data = hw_op2 * self._dot(subsequent_instruction_type[1:], self.HWOp2SubInstr[:,instructiontype])
  102. HDOp1SubInstr_data = hd_op1 * self._dot(subsequent_instruction_type[1:], self.HDOp1SubInstr[:,instructiontype])
  103. HDOp2SubInstr_data = hd_op2 * self._dot(subsequent_instruction_type[1:], self.HDOp2SubInstr[:,instructiontype])
  104. Operand1_bitinteractions_data = np.zeros((nb_points))
  105. Operand2_bitinteractions_data = np.zeros((nb_points))
  106. BitFlip1_bitinteractions_data = np.zeros((nb_points))
  107. BitFlip2_bitinteractions_data = np.zeros((nb_points))
  108. count = 0
  109. for i in range(32):
  110. for j in range(i+1,32):
  111. Operand1_bitinteractions_data += self.Operand1_bitinteractions[count,instructiontype] * current_op1_binary[i] * current_op1_binary[j]
  112. Operand2_bitinteractions_data += self.Operand2_bitinteractions[count,instructiontype] * current_op2_binary[i] * current_op2_binary[j]
  113. BitFlip1_bitinteractions_data += self.BitFlip1_bitinteractions[count,instructiontype] * current_op1_bitflip[i] * current_op1_bitflip[j]
  114. BitFlip2_bitinteractions_data += self.BitFlip2_bitinteractions[count,instructiontype] * current_op2_bitflip[i] * current_op2_bitflip[j]
  115. count += 1
  116. power = self.constant[instructiontype] \
  117. + PrvInstr_data + SubInstr_data \
  118. + Operand1_data + Operand2_data \
  119. + BitFlip1_data + BitFlip2_data \
  120. + HWOp1PrvInstr_data + HWOp2PrvInstr_data \
  121. + HDOp1PrvInstr_data + HDOp2PrvInstr_data \
  122. + HWOp1SubInstr_data + HWOp2SubInstr_data \
  123. + HDOp1SubInstr_data + HDOp2SubInstr_data \
  124. + Operand1_bitinteractions_data + Operand2_bitinteractions_data \
  125. + BitFlip1_bitinteractions_data + BitFlip2_bitinteractions_data
  126. for i in range(nb_points):
  127. if triplet[CURRENT,i] == 5:
  128. power[i] = self.constant[triplet[CURRENT,i]]
  129. if debug:
  130. print([self.constant[instructiontype], \
  131. PrvInstr_data, SubInstr_data, \
  132. Operand1_data, Operand2_data, \
  133. BitFlip1_data, BitFlip2_data, \
  134. HWOp1PrvInstr_data, HWOp2PrvInstr_data, \
  135. HDOp1PrvInstr_data, HDOp2PrvInstr_data, \
  136. HWOp1SubInstr_data, HWOp2SubInstr_data, \
  137. HDOp1SubInstr_data, HDOp2SubInstr_data, \
  138. Operand1_bitinteractions_data, Operand2_bitinteractions_data, \
  139. BitFlip1_bitinteractions_data, BitFlip2_bitinteractions_data])
  140. return power
  141. ### To manage studied points
  142. def reset_points(self):
  143. """ Reset all the points previously added """
  144. self.points = []
  145. self.power = None
  146. def add_point(self, triplet, previous_ops, current_ops):
  147. """ Add a new point to analyse """
  148. self.points.append((triplet, previous_ops, current_ops))
  149. def run(self):
  150. """ Compute the power leakage of all the points previously added
  151. Store the results in 'self.power'
  152. """
  153. nb_points = len(self.points)
  154. triplet = np.array([p[0] for p in self.points]).T # shape = (3, nb_points)
  155. previous_ops = np.array([p[1] for p in self.points]).T # shape = (2, nb_points)
  156. current_ops = np.array([p[2] for p in self.points]).T # shape = (2, nb_points)
  157. self.power = self.calculate_point(triplet, previous_ops, current_ops)
  158. def oneshot_point(self, triplet, previous_ops, current_ops):
  159. """ Compute the power of a single point
  160. defined by 'triplet', 'previous_ops', and 'current_ops'
  161. """
  162. self.reset_points()
  163. self.add_point(triplet, previous_ops, current_ops)
  164. self.run()
  165. return self.power