aboutsummaryrefslogtreecommitdiffhomepage
path: root/pyecsca
diff options
context:
space:
mode:
authorAndrej Bátora2023-10-05 14:44:02 +0200
committerAndrej Bátora2023-10-05 14:44:02 +0200
commit28d3448cec3599559a04e3f0ebe8d175bf6385d1 (patch)
tree1bbb7cecb85c61f675e0ddf3a7a800812e57ae47 /pyecsca
parent1c25c3fa1b752c170092d0fff34e1a14f363c602 (diff)
downloadpyecsca-28d3448cec3599559a04e3f0ebe8d175bf6385d1.tar.gz
pyecsca-28d3448cec3599559a04e3f0ebe8d175bf6385d1.tar.zst
pyecsca-28d3448cec3599559a04e3f0ebe8d175bf6385d1.zip
implemented CPA
Diffstat (limited to 'pyecsca')
-rw-r--r--pyecsca/sca/attack/CPA.py77
1 files changed, 77 insertions, 0 deletions
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