From 28d3448cec3599559a04e3f0ebe8d175bf6385d1 Mon Sep 17 00:00:00 2001 From: Andrej Bátora Date: Thu, 5 Oct 2023 14:44:02 +0200 Subject: implemented CPA --- pyecsca/sca/attack/CPA.py | 77 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 pyecsca/sca/attack/CPA.py diff --git a/pyecsca/sca/attack/CPA.py b/pyecsca/sca/attack/CPA.py new file mode 100644 index 0000000..ad65804 --- /dev/null +++ b/pyecsca/sca/attack/CPA.py @@ -0,0 +1,77 @@ +from pyecsca.ec.mult import ScalarMultiplier +from pyecsca.ec.point import Point +from pyecsca.ec.context import DefaultContext, local +from pyecsca.ec.params import DomainParameters +from pyecsca.ec.mod import Mod +from pyecsca.sca.trace import Trace +from public import public +from scipy.stats import pearsonr +from pyecsca.sca.attack.leakage_model import LeakageModel +import numpy as np +from numpy.typing import NDArray + +@public +class CPA(): + + traces: list[Trace] + points: list[Point] + mult: ScalarMultiplier + params: DomainParameters + leakage_model: LeakageModel + + def __init__(self, points: list[Point], traces: list[Trace], leakage_model: LeakageModel, mult: ScalarMultiplier, params: DomainParameters): + ''' + :param points: Points on which scalar multiplication with secret scalar was performed + :param traces: Power traces corresponding to the scalar multiplication for each of the points + :param mult: Scalar multiplier used + :param params: Domain parameters used + ''' + self.points = points + self.traces = np.array([trace.samples for trace in traces]).transpose() + self.mult = mult + self.params = params + self.leakage_model = leakage_model + + def compute_intermediate_value(self, guessed_scalar: int, target_bit: int, point: Point) -> Mod: + 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].X + + def compute_correlation_trace(self, guessed_scalar: int, target_bit: int) -> NDArray: + correlation_trace = [] + intermediate_values = [] + for i in range(len(self.points)): + intermediate_value = self.compute_intermediate_value(guessed_scalar, target_bit, self.points[i]) + intermediate_values.append(self.leakage_model(intermediate_value)) + for trace in self.traces: + correlation_trace.append(pearsonr(intermediate_values, trace)[0]) + return correlation_trace + + 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: + self.mult.init(self.params, self.params.generator) + 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 + correlation_trace_0 = self.compute_correlation_trace(guessed_scalar_0, target_bit) + correlation_trace_1 = self.compute_correlation_trace(guessed_scalar_1, target_bit) + if np.nanmax(np.abs(correlation_trace_0)) > np.nanmax(np.abs(correlation_trace_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) + return recovered_scalar \ No newline at end of file -- cgit v1.3.1 From 71bac00f26e745c929d318b607d1794568fc6514 Mon Sep 17 00:00:00 2001 From: Andrej Bátora Date: Thu, 5 Oct 2023 18:48:19 +0200 Subject: fixed CPA --- pyecsca/sca/attack/CPA.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyecsca/sca/attack/CPA.py b/pyecsca/sca/attack/CPA.py index ad65804..3ef57b0 100644 --- a/pyecsca/sca/attack/CPA.py +++ b/pyecsca/sca/attack/CPA.py @@ -13,7 +13,7 @@ from numpy.typing import NDArray @public class CPA(): - traces: list[Trace] + traces: NDArray points: list[Point] mult: ScalarMultiplier params: DomainParameters @@ -45,7 +45,7 @@ class CPA(): result = ctx.actions.get_by_index([0, action_index])[0] return result.output_points[0].X - def compute_correlation_trace(self, guessed_scalar: int, target_bit: int) -> NDArray: + def compute_correlation_trace(self, guessed_scalar: int, target_bit: int) -> list[any]: correlation_trace = [] intermediate_values = [] for i in range(len(self.points)): -- cgit v1.3.1 From 509ffef3df7a98cc8cceccbb7d1ca3e8440ea4f5 Mon Sep 17 00:00:00 2001 From: Andrej Bátora Date: Thu, 5 Oct 2023 20:18:51 +0200 Subject: typing fixes --- pyecsca/sca/attack/CPA.py | 3 ++- pyecsca/sca/target/emulator.py | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/pyecsca/sca/attack/CPA.py b/pyecsca/sca/attack/CPA.py index 3ef57b0..e46181e 100644 --- a/pyecsca/sca/attack/CPA.py +++ b/pyecsca/sca/attack/CPA.py @@ -7,6 +7,7 @@ from pyecsca.sca.trace import Trace from public import public from scipy.stats import pearsonr from pyecsca.sca.attack.leakage_model import LeakageModel +from typing import Any import numpy as np from numpy.typing import NDArray @@ -45,7 +46,7 @@ class CPA(): result = ctx.actions.get_by_index([0, action_index])[0] return result.output_points[0].X - def compute_correlation_trace(self, guessed_scalar: int, target_bit: int) -> list[any]: + def compute_correlation_trace(self, guessed_scalar: int, target_bit: int) -> list[Any]: correlation_trace = [] intermediate_values = [] for i in range(len(self.points)): diff --git a/pyecsca/sca/target/emulator.py b/pyecsca/sca/target/emulator.py index 0f097e5..8d74bf6 100644 --- a/pyecsca/sca/target/emulator.py +++ b/pyecsca/sca/target/emulator.py @@ -2,16 +2,16 @@ from pyecsca.ec.coordinates import CoordinateModel from pyecsca.ec.mod import Mod from pyecsca.ec.model import CurveModel from pyecsca.ec.params import DomainParameters -from pyecsca.ec.point import Point, InfinityPoint +from pyecsca.ec.point import Point from pyecsca.ec.mult import ScalarMultiplier from pyecsca.ec.key_generation import KeyGeneration from pyecsca.ec.key_agreement import KeyAgreement from pyecsca.ec.signature import Signature, SignatureResult from pyecsca.ec.formula import FormulaAction -from pyecsca.ec.context import Context, DefaultContext, local +from pyecsca.ec.context import DefaultContext, local from pyecsca.sca.attack import LeakageModel -from pyecsca.sca.trace import Trace, average, subtract -from typing import Mapping, Union, Optional, Tuple +from pyecsca.sca.trace import Trace +from typing import Optional, Tuple from public import public from .base import Target import numpy as np @@ -23,7 +23,7 @@ class EmulatorTarget(Target): coords: CoordinateModel mult: ScalarMultiplier params: Optional[DomainParameters] - leakage_model: LeakageModel + leakage_model: Optional[LeakageModel] privkey: Optional[Mod] pubkey: Optional[Point] @@ -55,7 +55,7 @@ class EmulatorTarget(Target): traces.append(trace) return points, traces - def emulate_ecdh_traces(self, num_of_traces: int) -> Tuple[list[Trace], list[Trace]]: + def emulate_ecdh_traces(self, num_of_traces: int) -> Tuple[list[Point], list[Trace]]: other_pubs = [self.params.curve.affine_random().to_model(self.coords, self.params.curve) for _ in range(num_of_traces)] traces = [] for pub in other_pubs: -- cgit v1.3.1 From 738aa9ac769e8fc9e43e0e2434def03f9021d5a9 Mon Sep 17 00:00:00 2001 From: Andrej Bátora Date: Fri, 6 Oct 2023 15:51:08 +0200 Subject: fixed codestyle CPA --- pyecsca/sca/attack/CPA.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pyecsca/sca/attack/CPA.py b/pyecsca/sca/attack/CPA.py index e46181e..d245b7a 100644 --- a/pyecsca/sca/attack/CPA.py +++ b/pyecsca/sca/attack/CPA.py @@ -7,10 +7,10 @@ from pyecsca.sca.trace import Trace from public import public from scipy.stats import pearsonr from pyecsca.sca.attack.leakage_model import LeakageModel -from typing import Any import numpy as np from numpy.typing import NDArray + @public class CPA(): @@ -34,7 +34,7 @@ class CPA(): self.leakage_model = leakage_model def compute_intermediate_value(self, guessed_scalar: int, target_bit: int, point: Point) -> Mod: - with(local(DefaultContext())) as ctx: + with (local(DefaultContext())) as ctx: self.mult.init(self.params, point) self.mult.multiply(guessed_scalar) action_index = -1 @@ -46,14 +46,14 @@ class CPA(): result = ctx.actions.get_by_index([0, action_index])[0] return result.output_points[0].X - def compute_correlation_trace(self, guessed_scalar: int, target_bit: int) -> list[Any]: + def compute_correlation_trace(self, guessed_scalar: int, target_bit: int) -> list[float]: correlation_trace = [] intermediate_values = [] for i in range(len(self.points)): intermediate_value = self.compute_intermediate_value(guessed_scalar, target_bit, self.points[i]) intermediate_values.append(self.leakage_model(intermediate_value)) for trace in self.traces: - correlation_trace.append(pearsonr(intermediate_values, trace)[0]) + correlation_trace.append(pearsonr(intermediate_values, trace)[0]) return correlation_trace def recover_bit(self, recovered_scalar: int, target_bit: int, scalar_bit_length: int, real_pub_key: Point) -> int: @@ -68,11 +68,12 @@ class CPA(): correlation_trace_0 = self.compute_correlation_trace(guessed_scalar_0, target_bit) correlation_trace_1 = self.compute_correlation_trace(guessed_scalar_1, target_bit) if np.nanmax(np.abs(correlation_trace_0)) > np.nanmax(np.abs(correlation_trace_1)): - return guessed_scalar_0 + 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) - return recovered_scalar \ No newline at end of file + return recovered_scalar + \ No newline at end of file -- cgit v1.3.1 From 6cd42203f314650199ef1ef8764e8bfdd1aeb3ae Mon Sep 17 00:00:00 2001 From: Andrej Bátora Date: Fri, 6 Oct 2023 16:06:23 +0200 Subject: fix_2 codestyle CPA --- pyecsca/sca/attack/CPA.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pyecsca/sca/attack/CPA.py b/pyecsca/sca/attack/CPA.py index d245b7a..667078c 100644 --- a/pyecsca/sca/attack/CPA.py +++ b/pyecsca/sca/attack/CPA.py @@ -76,4 +76,3 @@ class CPA(): for target_bit in range(1, scalar_bit_length): recovered_scalar = self.recover_bit(recovered_scalar, target_bit, scalar_bit_length, real_pub_key) return recovered_scalar - \ No newline at end of file -- cgit v1.3.1