diff options
| author | Andrej Bátora | 2023-09-27 21:31:06 +0200 |
|---|---|---|
| committer | Andrej Bátora | 2023-09-27 21:31:06 +0200 |
| commit | 570ec60fc4e365d8dc5c7eef9ff2dc784ec7318b (patch) | |
| tree | c53bba33bdd8a6fe389879262f35166975dfc2b1 /pyecsca/sca/attack | |
| parent | 2e97eae75817d6a002e2a8797102cfd149436736 (diff) | |
| download | pyecsca-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.py | 77 |
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 |
