diff options
| author | Ján Jančár | 2023-10-10 16:48:30 +0200 |
|---|---|---|
| committer | GitHub | 2023-10-10 16:48:30 +0200 |
| commit | fdab7fb1c85a9d4137312b8fdb252b1fab6aa1bc (patch) | |
| tree | 77750148677c9168146a30a56350df8332ed144b | |
| parent | 0e300b7b532d1796fc2dbea6f09e326b856f866a (diff) | |
| parent | 79ec70d0b1acf681f73d478e775825a6f35ae1e6 (diff) | |
| download | pyecsca-fdab7fb1c85a9d4137312b8fdb252b1fab6aa1bc.tar.gz pyecsca-fdab7fb1c85a9d4137312b8fdb252b1fab6aa1bc.tar.zst pyecsca-fdab7fb1c85a9d4137312b8fdb252b1fab6aa1bc.zip | |
Merge pull request #44 from andrr3j/CPA_pyecsca
Add CPA
| -rw-r--r-- | pyecsca/sca/attack/CPA.py | 78 | ||||
| -rw-r--r-- | pyecsca/sca/target/emulator.py | 8 |
2 files changed, 82 insertions, 4 deletions
diff --git a/pyecsca/sca/attack/CPA.py b/pyecsca/sca/attack/CPA.py new file mode 100644 index 0000000..667078c --- /dev/null +++ b/pyecsca/sca/attack/CPA.py @@ -0,0 +1,78 @@ +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: NDArray + 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) -> 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]) + 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 diff --git a/pyecsca/sca/target/emulator.py b/pyecsca/sca/target/emulator.py index 3bb2085..bca27cf 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 |
