Source code for pyecsca.sca.attack.CPA
from public import public
from scipy.stats import pearsonr
import numpy as np
from numpy.typing import NDArray
from ...ec.mult import ScalarMultiplier
from ...ec.point import Point
from ...ec.context import DefaultContext, local
from ...ec.params import DomainParameters
from ...ec.mod import Mod
from ..trace import Trace
from ..trace.plot import plot_trace
from ..attack.leakage_model import LeakageModel
[docs]
@public
class CPA:
traces: NDArray
points: list[Point]
mult: ScalarMultiplier
params: DomainParameters
leakage_model: LeakageModel
correlations: dict[str, list[list[float]]]
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
self.correlations = {"guess_one": [], "guess_zero": []}
[docs]
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
[docs]
def plot_correlations(self, ct):
return plot_trace(Trace(np.array(ct))).opts(width=950, height=600)
[docs]
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
)
self.correlations["guess_zero"].append(correlation_trace_0)
self.correlations["guess_one"].append(correlation_trace_1)
if np.nanmax(np.abs(correlation_trace_0)) > np.nanmax(
np.abs(correlation_trace_1)
):
return guessed_scalar_0
return guessed_scalar_1