aboutsummaryrefslogtreecommitdiffhomepage
path: root/pyecsca/sca/attack
diff options
context:
space:
mode:
authorAndrej Bátora2023-09-27 21:31:06 +0200
committerAndrej Bátora2023-09-27 21:31:06 +0200
commit570ec60fc4e365d8dc5c7eef9ff2dc784ec7318b (patch)
treec53bba33bdd8a6fe389879262f35166975dfc2b1 /pyecsca/sca/attack
parent2e97eae75817d6a002e2a8797102cfd149436736 (diff)
downloadpyecsca-570ec60fc4e365d8dc5c7eef9ff2dc784ec7318b.tar.gz
pyecsca-570ec60fc4e365d8dc5c7eef9ff2dc784ec7318b.tar.zst
pyecsca-570ec60fc4e365d8dc5c7eef9ff2dc784ec7318b.zip
implemented emulator target and DPA
Diffstat (limited to 'pyecsca/sca/attack')
-rw-r--r--pyecsca/sca/attack/DPA.py77
1 files changed, 77 insertions, 0 deletions
diff --git a/pyecsca/sca/attack/DPA.py b/pyecsca/sca/attack/DPA.py
new file mode 100644
index 0000000..3930f5e
--- /dev/null
+++ b/pyecsca/sca/attack/DPA.py
@@ -0,0 +1,77 @@
+from pyecsca.ec.mult import ScalarMultiplier
+from pyecsca.sca.trace import Trace
+from pyecsca.ec.point import Point
+from pyecsca.ec.context import DefaultContext, local
+from pyecsca.ec.params import DomainParameters
+from pyecsca.sca.trace import Trace, average, subtract
+from pyecsca.sca.trace.plot import plot_trace
+from typing import Tuple
+import holoviews as hv
+
+class DPA():
+
+ traces: list[Trace]
+ points: list[Point]
+ mult: ScalarMultiplier
+ params: DomainParameters
+
+ def __init__(self, points: list[Point], traces: list[Trace], mult: ScalarMultiplier, params: DomainParameters):
+ self.points = points
+ self.traces = traces
+ self.mult = mult
+ self.params = params
+
+ def compute_split_point(self, guessed_scalar: int, target_bit: int, point: Point) -> Point:
+ with(local(DefaultContext())) as ctx:
+ self.mult.init(self.params, point)
+ self.mult.multiply(guessed_scalar)
+ action_index = -1
+ for bit in bin(guessed_scalar)[2:target_bit + 2]:
+ if bit == '1':
+ action_index += 2
+ elif bit == '0':
+ action_index += 1
+ result = ctx.actions.get_by_index([0, action_index])[0]
+ return result.output_points[0]
+
+ def split_traces(self, guessed_scalar: int, target_bit: int) -> Tuple[list[Trace], list[Trace]]:
+ one_traces = []
+ zero_traces = []
+ for i in range(len(self.points)):
+ split_value = self.compute_split_point(guessed_scalar, target_bit, self.points[i]).coords.get('X')
+ if int(split_value) & 1 == 1:
+ one_traces.append(self.traces[i])
+ elif int(split_value) & 1 == 0:
+ zero_traces.append(self.traces[i])
+ return one_traces, zero_traces
+
+ def calculate_difference_of_means(self, one_traces: list[Trace], zero_traces: list[Trace]) -> Trace:
+ avg_ones = average(*one_traces)
+ avg_zeros = average(*zero_traces)
+ return subtract(avg_ones, avg_zeros)
+
+ def plot_difference_of_means(self, dom):
+ return plot_trace(dom).opts(width=950, height=600)
+
+ def recover_bit(self, recovered_scalar: int, target_bit: int, scalar_bit_length: int, real_pub_key: Point) -> int:
+ if target_bit == scalar_bit_length - 1:
+ if real_pub_key == self.mult.multiply(recovered_scalar):
+ return recovered_scalar
+ return recovered_scalar | 1
+ mask = 1 << (scalar_bit_length - target_bit - 1)
+ guessed_scalar_0 = recovered_scalar
+ guessed_scalar_1 = recovered_scalar | mask
+ ones_0, zeros_0 = self.split_traces(guessed_scalar_0, target_bit)
+ ones_1, zeros_1 = self.split_traces(guessed_scalar_1, target_bit)
+ dom_0 = self.calculate_difference_of_means(ones_0, zeros_0)
+ dom_1 = self.calculate_difference_of_means(ones_1, zeros_1)
+ if abs(max(dom_0)) > abs(max(dom_1)):
+ return guessed_scalar_0
+ return guessed_scalar_1
+
+ def perform(self, scalar_bit_length: int, real_pub_key: Point) -> int:
+ recovered_scalar = 1 << (scalar_bit_length - 1)
+ for target_bit in range(1, scalar_bit_length):
+ recovered_scalar = self.recover_bit(recovered_scalar, target_bit, scalar_bit_length, real_pub_key)
+ self.mult.init(self.params, self.params.generator)
+ return recovered_scalar \ No newline at end of file