diff options
| author | J08nY | 2023-07-28 17:41:24 +0200 |
|---|---|---|
| committer | J08nY | 2023-07-28 17:41:24 +0200 |
| commit | 739bb13e775d568c9b0d9708c965e36f2b7a4f68 (patch) | |
| tree | bf9edf2fd2d45eb8b70cffdb589d1255b910e14c | |
| parent | dc9e1cf991dc0b5bc89668e494f4a881398d5853 (diff) | |
| download | pyecsca-739bb13e775d568c9b0d9708c965e36f2b7a4f68.tar.gz pyecsca-739bb13e775d568c9b0d9708c965e36f2b7a4f68.tar.zst pyecsca-739bb13e775d568c9b0d9708c965e36f2b7a4f68.zip | |
Add tests for RPA-RE.
| -rw-r--r-- | pyecsca/sca/re/rpa.py | 8 | ||||
| -rw-r--r-- | test/sca/test_rpa.py | 82 | ||||
| -rw-r--r-- | test/sca/test_target.py | 11 |
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") |
