aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJ08nY2023-07-28 17:41:24 +0200
committerJ08nY2023-07-28 17:41:24 +0200
commit739bb13e775d568c9b0d9708c965e36f2b7a4f68 (patch)
treebf9edf2fd2d45eb8b70cffdb589d1255b910e14c
parentdc9e1cf991dc0b5bc89668e494f4a881398d5853 (diff)
downloadpyecsca-739bb13e775d568c9b0d9708c965e36f2b7a4f68.tar.gz
pyecsca-739bb13e775d568c9b0d9708c965e36f2b7a4f68.tar.zst
pyecsca-739bb13e775d568c9b0d9708c965e36f2b7a4f68.zip
Add tests for RPA-RE.
-rw-r--r--pyecsca/sca/re/rpa.py8
-rw-r--r--test/sca/test_rpa.py82
-rw-r--r--test/sca/test_target.py11
3 files changed, 88 insertions, 13 deletions
diff --git a/pyecsca/sca/re/rpa.py b/pyecsca/sca/re/rpa.py
index 5fd07c6..3f1aee5 100644
--- a/pyecsca/sca/re/rpa.py
+++ b/pyecsca/sca/re/rpa.py
@@ -5,7 +5,7 @@ Provides functionality inspired by the Refined-Power Analysis attack by Goubin.
`<https://dl.acm.org/doi/10.5555/648120.747060>`_
"""
from public import public
-from typing import MutableMapping, Optional, Callable
+from typing import MutableMapping, Optional, Callable, List
from collections import Counter
from sympy import FF, sympify, Poly, symbols
@@ -117,7 +117,7 @@ def rpa_point_x0(params: DomainParameters) -> Optional[Point]:
# TODO: There may be more roots.
if not roots:
return None
- x = Mod(int(roots[0]), params.curve.prime)
+ x = Mod(int(next(iter(roots.keys()))), params.curve.prime)
return Point(AffineCoordinateModel(params.curve.model), x=x, y=Mod(0, params.curve.prime))
elif isinstance(params.curve.model, MontgomeryModel):
return Point(AffineCoordinateModel(params.curve.model), x=Mod(0, params.curve.prime),
@@ -126,7 +126,7 @@ def rpa_point_x0(params: DomainParameters) -> Optional[Point]:
raise NotImplementedError
-def rpa_distinguish(params: DomainParameters, mults: list[ScalarMultiplier], oracle: Callable[[int, Point], bool]) -> list[ScalarMultiplier]:
+def rpa_distinguish(params: DomainParameters, mults: List[ScalarMultiplier], oracle: Callable[[int, Point], bool]) -> List[ScalarMultiplier]:
"""
Distinguish the scalar multiplier used (from the possible :paramref:`~.rpa_distinguish.mults`) using
an RPA :paramref:`~.rpa_distinguish.oracle`.
@@ -136,7 +136,7 @@ def rpa_distinguish(params: DomainParameters, mults: list[ScalarMultiplier], ora
:param oracle: An oracle that returns `True` when an RPA point is encountered during scalar multiplication of the input by the scalar.
:returns: The list of possible multipliers after distinguishing (ideally just one).
"""
- P0 = rpa_point_x0(params) or rpa_point_0y(params)
+ P0 = rpa_point_0y(params) or rpa_point_x0(params)
if not P0:
raise ValueError("There are no RPA-points on the provided curve.")
print(f"Got RPA point {P0}")
diff --git a/test/sca/test_rpa.py b/test/sca/test_rpa.py
index 995099d..e563452 100644
--- a/test/sca/test_rpa.py
+++ b/test/sca/test_rpa.py
@@ -1,17 +1,26 @@
+import io
+from contextlib import redirect_stdout
from unittest import TestCase
from parameterized import parameterized
from pyecsca.ec.context import local
+from pyecsca.ec.coordinates import AffineCoordinateModel
+from pyecsca.ec.model import ShortWeierstrassModel
+from pyecsca.ec.curve import EllipticCurve
+from pyecsca.ec.mod import Mod
from pyecsca.ec.mult import (
LTRMultiplier,
+ RTLMultiplier,
BinaryNAFMultiplier,
WindowNAFMultiplier,
LadderMultiplier,
- DifferentialLadderMultiplier,
+ SimpleLadderMultiplier,
+ DifferentialLadderMultiplier
)
-from pyecsca.ec.params import get_params
-from pyecsca.sca.re.rpa import MultipleContext
+from pyecsca.ec.params import get_params, DomainParameters
+from pyecsca.ec.point import Point
+from pyecsca.sca.re.rpa import MultipleContext, rpa_point_0y, rpa_point_x0, rpa_distinguish
class MultipleContextTests(TestCase):
@@ -30,8 +39,8 @@ class MultipleContextTests(TestCase):
("10", 10),
("2355498743", 2355498743),
(
- "325385790209017329644351321912443757746",
- 325385790209017329644351321912443757746,
+ "325385790209017329644351321912443757746",
+ 325385790209017329644351321912443757746,
),
("13613624287328732", 13613624287328732),
]
@@ -92,3 +101,66 @@ class MultipleContextTests(TestCase):
dadd_mult.multiply(1339278426732672313)
muls = list(ctx.points.values())
self.assertEqual(muls[-2], 1339278426732672313)
+
+
+class RPATests(TestCase):
+
+ def setUp(self):
+ self.model = ShortWeierstrassModel()
+ self.coords = self.model.coordinates["projective"]
+ self.add = self.coords.formulas["add-2007-bl"]
+ self.dbl = self.coords.formulas["dbl-2007-bl"]
+ self.neg = self.coords.formulas["neg"]
+
+ def test_x0_point(self):
+ p = 0x85d265945a4f5681
+ a = Mod(0x7fc57b4110698bc0, p)
+ b = Mod(0x37113ea591b04527, p)
+ gx = Mod(0x80d2d78fddb97597, p)
+ gy = Mod(0x5586d818b7910930, p)
+ # (0x4880bcf620852a54, 0) RPA point
+
+ infty = Point(self.coords, X=Mod(0, p), Y=Mod(1, p), Z=Mod(0, p))
+ g = Point(self.coords, X=gx, Y=gy, Z=Mod(1, p))
+ curve = EllipticCurve(self.model, self.coords, p, infty, dict(a=a, b=b))
+ params_full = DomainParameters(curve, g, 0x85d265932d90785c, 1)
+
+ self.assertIsNotNone(rpa_point_x0(params_full))
+
+ def test_0y_point(self):
+ p = 0x85d265945a4f5681
+ a = Mod(0x7fc57b4110698bc0, p)
+ b = Mod(0x37113ea591b04527, p)
+ gx = Mod(0x80d2d78fddb97597, p)
+ gy = Mod(0x5586d818b7910930, p)
+ # (0, 0x6bed3155c9ada064) RPA point
+
+ infty = Point(self.coords, X=Mod(0, p), Y=Mod(1, p), Z=Mod(0, p))
+ g = Point(self.coords, X=gx, Y=gy, Z=Mod(1, p))
+ curve = EllipticCurve(self.model, self.coords, p, infty, dict(a=a, b=b))
+ params_full = DomainParameters(curve, g, 0x85d265932d90785c, 1)
+
+ self.assertIsNotNone(rpa_point_0y(params_full))
+
+ def test_distinguish(self):
+ secp128r1 = get_params("secg", "secp128r1", "projective")
+ multipliers = [LTRMultiplier(self.add, self.dbl, None, False, True, True),
+ LTRMultiplier(self.add, self.dbl, None, True, True, True),
+ RTLMultiplier(self.add, self.dbl, None, False, True),
+ RTLMultiplier(self.add, self.dbl, None, True, True),
+ SimpleLadderMultiplier(self.add, self.dbl, None, True, True),
+ BinaryNAFMultiplier(self.add, self.dbl, self.neg, None, True),
+ WindowNAFMultiplier(self.add, self.dbl, self.neg, 3, None, True),
+ WindowNAFMultiplier(self.add, self.dbl, self.neg, 4, None, True)]
+ for real_mult in multipliers:
+ def simulated_oracle(scalar, affine_point):
+ point = affine_point.to_model(secp128r1.curve.coordinate_model, secp128r1.curve)
+ with local(MultipleContext()) as ctx:
+ real_mult.init(secp128r1, point)
+ real_mult.multiply(scalar)
+ return any(map(lambda P: P.X == 0 or P.Y == 0, ctx.points.keys()))
+
+ with redirect_stdout(io.StringIO()):
+ result = rpa_distinguish(secp128r1, multipliers, simulated_oracle)
+ self.assertEqual(1, len(result))
+ self.assertEqual(real_mult, result[0])
diff --git a/test/sca/test_target.py b/test/sca/test_target.py
index 299e127..9da3473 100644
--- a/test/sca/test_target.py
+++ b/test/sca/test_target.py
@@ -1,3 +1,5 @@
+import io
+from contextlib import redirect_stdout
from copy import copy
from os.path import realpath, dirname, join
from typing import Optional
@@ -31,7 +33,7 @@ from pyecsca.sca.target.ectester import (
)
if has_pyscard:
- from pyecsca.sca.target.ectester import ECTesterTarget
+ from pyecsca.sca.target.ectester import ECTesterTargetPCSC as ECTesterTarget
else:
ECTesterTarget = None
@@ -54,9 +56,10 @@ class BinaryTargetTests(TestCase):
def test_debug(self):
target_path = join(dirname(realpath(__file__)), "..", "data", "target.py")
target = TestTarget(["python", target_path], debug_output=True)
- target.connect()
- target.send_cmd(SimpleSerialMessage("d", ""), 500)
- target.disconnect()
+ with redirect_stdout(io.StringIO()):
+ target.connect()
+ target.send_cmd(SimpleSerialMessage("d", ""), 500)
+ target.disconnect()
def test_no_connection(self):
target_path = join(dirname(realpath(__file__)), "..", "data", "target.py")