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.
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

  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