aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ08nY2023-08-08 16:21:07 +0200
committerJ08nY2023-08-08 16:21:07 +0200
commit077bf996ef042244c9259d3b32e13f07c2f3f3ae (patch)
tree506f27332fa172eff52b920449a3c6ddd7a10021
parent109fec027766630166083c497ea0f0e8052965a4 (diff)
downloadpyecsca-077bf996ef042244c9259d3b32e13f07c2f3f3ae.tar.gz
pyecsca-077bf996ef042244c9259d3b32e13f07c2f3f3ae.tar.zst
pyecsca-077bf996ef042244c9259d3b32e13f07c2f3f3ae.zip
-rw-r--r--pyproject.toml3
-rw-r--r--test/ec/conftest.py18
-rw-r--r--test/ec/test_configuration.py118
-rw-r--r--test/ec/test_context.py153
-rw-r--r--test/ec/test_curve.py319
-rw-r--r--test/ec/test_divpoly.py266
-rw-r--r--test/ec/test_formula.py189
-rw-r--r--test/ec/test_key_agreement.py60
-rw-r--r--test/ec/test_key_generation.py37
-rw-r--r--test/ec/test_mod.py357
-rw-r--r--test/ec/test_model.py13
-rw-r--r--test/ec/test_mult.py567
-rw-r--r--test/ec/test_naf.py9
-rw-r--r--test/ec/test_op.py61
-rw-r--r--test/ec/test_params.py212
-rw-r--r--test/ec/test_point.py246
-rw-r--r--test/ec/test_regress.py191
-rw-r--r--test/ec/test_signature.py159
-rw-r--r--test/ec/test_transformations.py57
-rw-r--r--test/ec/utils.py1
20 files changed, 1481 insertions, 1555 deletions
diff --git a/pyproject.toml b/pyproject.toml
index bfffb07..12b681c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -72,3 +72,6 @@ testpaths = ["test"]
markers = [
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
]
+filterwarnings = [
+ "ignore:Deprecated call to `pkg_resources.declare_namespace"
+]
diff --git a/test/ec/conftest.py b/test/ec/conftest.py
new file mode 100644
index 0000000..5c3f855
--- /dev/null
+++ b/test/ec/conftest.py
@@ -0,0 +1,18 @@
+import pytest
+
+from pyecsca.ec.params import get_params, DomainParameters
+
+
+@pytest.fixture(scope="session")
+def secp128r1() -> DomainParameters:
+ return get_params("secg", "secp128r1", "projective")
+
+
+@pytest.fixture(scope="session")
+def curve25519() -> DomainParameters:
+ return get_params("other", "Curve25519", "xz")
+
+
+@pytest.fixture(scope="session")
+def ed25519() -> DomainParameters:
+ return get_params("other", "Ed25519", "projective")
diff --git a/test/ec/test_configuration.py b/test/ec/test_configuration.py
index a90f3ce..17fb6f7 100644
--- a/test/ec/test_configuration.py
+++ b/test/ec/test_configuration.py
@@ -1,5 +1,3 @@
-from unittest import TestCase
-
import pytest
from pyecsca.ec.configuration import (
@@ -15,86 +13,44 @@ from pyecsca.ec.model import ShortWeierstrassModel
from pyecsca.ec.mult import LTRMultiplier
-class ConfigurationTests(TestCase):
- def base_independents(self):
- return {
- "hash_type": HashType.SHA1,
- "mod_rand": RandomMod.SAMPLE,
- "mult": Multiplication.BASE,
- "sqr": Squaring.BASE,
- "red": Reduction.BASE,
- "inv": Inversion.GCD,
- }
+@pytest.fixture(scope="module")
+def base_independents():
+ return {"hash_type": HashType.SHA1, "mod_rand": RandomMod.SAMPLE, "mult": Multiplication.BASE, "sqr": Squaring.BASE,
+ "red": Reduction.BASE, "inv": Inversion.GCD, }
+
+
+@pytest.mark.slow
+def test_all():
+ j = 0
+ for _ in all_configurations(model=ShortWeierstrassModel()):
+ j += 1
+
+
+def test_weierstrass_projective(base_independents):
+ model = ShortWeierstrassModel()
+ coords = model.coordinates["projective"]
+ configs = list(all_configurations(model=model, coords=coords, **base_independents))
+ assert len(configs) == 1960
- @pytest.mark.slow
- def test_all(self):
- j = 0
- for _ in all_configurations(model=ShortWeierstrassModel()):
- j += 1
- def test_weierstrass_projective(self):
- model = ShortWeierstrassModel()
- coords = model.coordinates["projective"]
- configs = list(
- all_configurations(model=model, coords=coords, **self.base_independents())
- )
- self.assertEqual(len(configs), 1960)
+def test_mult_class(base_independents):
+ model = ShortWeierstrassModel()
+ coords = model.coordinates["projective"]
+ scalarmult = LTRMultiplier
+ configs = list(all_configurations(model=model, coords=coords, scalarmult=scalarmult, **base_independents))
+ assert len(configs) == 560
- def test_mult_class(self):
- model = ShortWeierstrassModel()
- coords = model.coordinates["projective"]
- scalarmult = LTRMultiplier
- configs = list(
- all_configurations(
- model=model,
- coords=coords,
- scalarmult=scalarmult,
- **self.base_independents()
- )
- )
- self.assertEqual(len(configs), 560)
- def test_one(self):
- model = ShortWeierstrassModel()
- coords = model.coordinates["projective"]
- scalarmult = {
- "cls": LTRMultiplier,
- "add": coords.formulas["add-1998-cmo"],
- "dbl": coords.formulas["dbl-1998-cmo"],
- "scl": None,
- "always": True,
- "complete": False,
- "short_circuit": True,
- }
- configs = list(
- all_configurations(
- model=model,
- coords=coords,
- scalarmult=scalarmult,
- **self.base_independents()
- )
- )
- self.assertEqual(len(configs), 1)
- scalarmult = LTRMultiplier(
- coords.formulas["add-1998-cmo"],
- coords.formulas["dbl-1998-cmo"],
- None,
- True,
- False,
- True,
- )
- configs = list(
- all_configurations(
- model=model,
- coords=coords,
- scalarmult=scalarmult,
- **self.base_independents()
- )
- )
- self.assertEqual(len(configs), 1)
- configs = list(
- all_configurations(
- model=model, scalarmult=scalarmult, **self.base_independents()
- )
- )
- self.assertEqual(len(configs), 1)
+def test_one(base_independents):
+ model = ShortWeierstrassModel()
+ coords = model.coordinates["projective"]
+ scalarmult = {"cls": LTRMultiplier, "add": coords.formulas["add-1998-cmo"], "dbl": coords.formulas["dbl-1998-cmo"],
+ "scl": None, "always": True, "complete": False, "short_circuit": True, }
+ configs = list(all_configurations(model=model, coords=coords, scalarmult=scalarmult, **base_independents))
+ assert len(configs) == 1
+ scalarmult = LTRMultiplier(coords.formulas["add-1998-cmo"], coords.formulas["dbl-1998-cmo"], None, True, False,
+ True, )
+ configs = list(all_configurations(model=model, coords=coords, scalarmult=scalarmult, **base_independents))
+ assert len(configs) == 1
+ configs = list(all_configurations(model=model, scalarmult=scalarmult, **base_independents))
+ assert len(configs) == 1
diff --git a/test/ec/test_context.py b/test/ec/test_context.py
index 9cd74a3..9ec7962 100644
--- a/test/ec/test_context.py
+++ b/test/ec/test_context.py
@@ -1,4 +1,4 @@
-from unittest import TestCase
+import pytest
from pyecsca.ec.context import (
local,
@@ -7,90 +7,95 @@ from pyecsca.ec.context import (
PathContext
)
from pyecsca.ec.key_generation import KeyGeneration
-from pyecsca.ec.params import get_params
from pyecsca.ec.mod import RandomModAction
from pyecsca.ec.mult import LTRMultiplier, ScalarMultiplicationAction
-class TreeTests(TestCase):
- def test_walk_by_key(self):
- tree = Tree()
- tree["a"] = Tree()
- tree["a"]["1"] = Tree()
- tree["a"]["2"] = Tree()
- self.assertIn("a", tree)
- self.assertIsInstance(tree.get_by_key([]), Tree)
- self.assertIsInstance(tree.get_by_key(["a"]), Tree)
- self.assertIsInstance(tree.get_by_key(["a", "1"]), Tree)
+def test_walk_by_key():
+ tree = Tree()
+ tree["a"] = Tree()
+ tree["a"]["1"] = Tree()
+ tree["a"]["2"] = Tree()
+ assert "a" in tree
+ assert isinstance(tree.get_by_key([]), Tree)
+ assert isinstance(tree.get_by_key(["a"]), Tree)
+ assert isinstance(tree.get_by_key(["a", "1"]), Tree)
- def test_walk_by_index(self):
- tree = Tree()
- a = Tree()
- tree["a"] = a
- d = Tree()
- b = Tree()
- tree["a"]["d"] = d
- tree["a"]["b"] = b
- self.assertIn("a", tree)
- with self.assertRaises(ValueError):
- tree.get_by_index([])
- self.assertEqual(tree.get_by_index([0]), ("a", a))
- self.assertEqual(tree.get_by_index([0, 0]), ("d", d))
+def test_walk_by_index():
+ tree = Tree()
+ a = Tree()
+ tree["a"] = a
+ d = Tree()
+ b = Tree()
+ tree["a"]["d"] = d
+ tree["a"]["b"] = b
+ assert "a" in tree
+ with pytest.raises(ValueError):
+ tree.get_by_index([])
- def test_repr(self):
- tree = Tree()
- tree["a"] = Tree()
- tree["a"]["1"] = Tree()
- tree["a"]["2"] = Tree()
- txt = tree.repr()
- self.assertEqual(txt.count("\t"), 2)
- self.assertEqual(txt.count("\n"), 3)
+ assert tree.get_by_index([0]) == ("a", a)
+ assert tree.get_by_index([0, 0]) == ("d", d)
-class ContextTests(TestCase):
- def setUp(self):
- self.secp128r1 = get_params("secg", "secp128r1", "projective")
- self.base = self.secp128r1.generator
- self.coords = self.secp128r1.curve.coordinate_model
- self.mult = LTRMultiplier(
- self.coords.formulas["add-1998-cmo"],
- self.coords.formulas["dbl-1998-cmo"],
- self.coords.formulas["z"],
- always=True,
- )
- self.mult.init(self.secp128r1, self.base)
+def test_repr():
+ tree = Tree()
+ tree["a"] = Tree()
+ tree["a"]["1"] = Tree()
+ tree["a"]["2"] = Tree()
+ txt = tree.repr()
+ assert txt.count("\t") == 2
+ assert txt.count("\n") == 3
- def test_null(self):
- with local() as ctx:
- self.mult.multiply(59)
- self.assertIs(ctx, None)
- def test_default(self):
- with local(DefaultContext()) as ctx:
- result = self.mult.multiply(59)
- self.assertEqual(len(ctx.actions), 1)
- action = next(iter(ctx.actions.keys()))
- self.assertIsInstance(action, ScalarMultiplicationAction)
- self.assertEqual(result, action.result)
+@pytest.fixture()
+def mult(secp128r1):
+ base = secp128r1.generator
+ coords = secp128r1.curve.coordinate_model
+ mult = LTRMultiplier(
+ coords.formulas["add-1998-cmo"],
+ coords.formulas["dbl-1998-cmo"],
+ coords.formulas["z"],
+ always=True,
+ )
+ mult.init(secp128r1, base)
+ return mult
- def test_default_no_enter(self):
- with local(DefaultContext()) as default, self.assertRaises(ValueError):
- default.exit_action(RandomModAction(7))
- def test_path(self):
- with local(PathContext([0, 1])) as ctx:
- key_generator = KeyGeneration(self.mult, self.secp128r1, True)
- key_generator.generate()
- self.assertIsInstance(ctx.value, ScalarMultiplicationAction)
- with local(PathContext([0, 1, 7])) as ctx:
- key_generator = KeyGeneration(self.mult, self.secp128r1, True)
- key_generator.generate()
+def test_null(mult):
+ with local() as ctx:
+ mult.multiply(59)
+ assert ctx is None
- def test_str(self):
- with local(DefaultContext()) as default:
- self.mult.multiply(59)
- str(default)
- str(default.actions)
- with local(None):
- self.mult.multiply(59)
+
+def test_default(mult):
+ with local(DefaultContext()) as ctx:
+ result = mult.multiply(59)
+ assert len(ctx.actions) == 1
+ action = next(iter(ctx.actions.keys()))
+ assert isinstance(action, ScalarMultiplicationAction)
+ assert result == action.result
+
+
+def test_default_no_enter():
+ with local(DefaultContext()) as default, pytest.raises(ValueError):
+ default.exit_action(RandomModAction(7))
+
+
+def test_path(mult, secp128r1):
+ with local(PathContext([0, 1])) as ctx:
+ key_generator = KeyGeneration(mult, secp128r1, True)
+ key_generator.generate()
+ assert isinstance(ctx.value, ScalarMultiplicationAction)
+ with local(PathContext([0, 1, 7])):
+ key_generator = KeyGeneration(mult, secp128r1, True)
+ key_generator.generate()
+
+
+def test_str(mult):
+ with local(DefaultContext()) as default:
+ mult.multiply(59)
+ assert str(default) is not None
+ assert str(default.actions) is not None
+ with local(None):
+ mult.multiply(59)
diff --git a/test/ec/test_curve.py b/test/ec/test_curve.py
index bc0cdaf..cd0639a 100644
--- a/test/ec/test_curve.py
+++ b/test/ec/test_curve.py
@@ -1,192 +1,187 @@
from binascii import unhexlify
-from unittest import TestCase
+import pytest
from pyecsca.ec.coordinates import AffineCoordinateModel
from pyecsca.ec.curve import EllipticCurve
from pyecsca.ec.error import UnsatisfiedAssumptionError
-from pyecsca.ec.params import get_params
from pyecsca.ec.mod import Mod
from pyecsca.ec.model import MontgomeryModel
from pyecsca.ec.point import Point, InfinityPoint
-class CurveTests(TestCase):
- def setUp(self):
- self.secp128r1 = get_params("secg", "secp128r1", "projective")
- self.base = self.secp128r1.generator
- self.affine_base = self.base.to_affine()
- self.curve25519 = get_params("other", "Curve25519", "xz")
- self.ed25519 = get_params("other", "Ed25519", "projective")
+def test_init(secp128r1):
+ with pytest.raises(ValueError):
+ EllipticCurve(
+ MontgomeryModel(),
+ secp128r1.curve.coordinate_model,
+ 1,
+ InfinityPoint(secp128r1.curve.coordinate_model),
+ parameters={},
+ )
- def test_init(self):
- with self.assertRaises(ValueError):
- EllipticCurve(
- MontgomeryModel(),
- self.secp128r1.curve.coordinate_model,
- 1,
- InfinityPoint(self.secp128r1.curve.coordinate_model),
- parameters={},
- )
+ with pytest.raises(ValueError):
+ EllipticCurve(
+ secp128r1.curve.model,
+ secp128r1.curve.coordinate_model,
+ 15,
+ InfinityPoint(secp128r1.curve.coordinate_model),
+ parameters={"c": 0},
+ )
- with self.assertRaises(ValueError):
- EllipticCurve(
- self.secp128r1.curve.model,
- self.secp128r1.curve.coordinate_model,
- 15,
- InfinityPoint(self.secp128r1.curve.coordinate_model),
- parameters={"c": 0},
- )
+ with pytest.raises(ValueError):
+ EllipticCurve(
+ secp128r1.curve.model,
+ secp128r1.curve.coordinate_model,
+ 15,
+ InfinityPoint(secp128r1.curve.coordinate_model),
+ parameters={"a": Mod(1, 5), "b": Mod(2, 5)},
+ )
- with self.assertRaises(ValueError):
- EllipticCurve(
- self.secp128r1.curve.model,
- self.secp128r1.curve.coordinate_model,
- 15,
- InfinityPoint(self.secp128r1.curve.coordinate_model),
- parameters={"a": Mod(1, 5), "b": Mod(2, 5)},
- )
- def test_to_coords(self):
- affine = self.secp128r1.to_affine()
- m1_coords = affine.curve.model.coordinates["projective-1"]
- m3_coords = affine.curve.model.coordinates["projective-3"]
- with self.assertRaises(UnsatisfiedAssumptionError):
- affine.to_coords(m1_coords)
- affine.to_coords(m3_coords)
+def test_to_coords(secp128r1):
+ affine = secp128r1.to_affine()
+ m1_coords = affine.curve.model.coordinates["projective-1"]
+ m3_coords = affine.curve.model.coordinates["projective-3"]
+ with pytest.raises(UnsatisfiedAssumptionError):
+ affine.to_coords(m1_coords)
+ affine.to_coords(m3_coords)
- def test_to_affine(self):
- affine = self.secp128r1.to_affine()
- model = AffineCoordinateModel(affine.curve.model)
- self.assertEqual(affine.curve.coordinate_model, model)
- self.assertEqual(affine.generator.coordinate_model, model)
- def test_is_neutral(self):
- self.assertTrue(
- self.secp128r1.curve.is_neutral(
- InfinityPoint(self.secp128r1.curve.coordinate_model)
- )
- )
+def test_to_affine(secp128r1):
+ affine = secp128r1.to_affine()
+ model = AffineCoordinateModel(affine.curve.model)
+ assert affine.curve.coordinate_model == model
+ assert affine.generator.coordinate_model == model
- def test_is_on_curve(self):
- self.assertTrue(self.secp128r1.curve.is_on_curve(self.secp128r1.curve.neutral))
- pt = Point(
- self.secp128r1.curve.coordinate_model,
- X=Mod(0x161FF7528B899B2D0C28607CA52C5B86, self.secp128r1.curve.prime),
- Y=Mod(0xCF5AC8395BAFEB13C02DA292DDED7A83, self.secp128r1.curve.prime),
- Z=Mod(1, self.secp128r1.curve.prime),
- )
- self.assertTrue(self.secp128r1.curve.is_on_curve(pt))
- self.assertTrue(self.secp128r1.curve.is_on_curve(pt.to_affine()))
- other = Point(
- self.secp128r1.curve.coordinate_model,
- X=Mod(0x161FF7528B899B2D0C28607CA52C5B86, self.secp128r1.curve.prime),
- Y=Mod(0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA, self.secp128r1.curve.prime),
- Z=Mod(1, self.secp128r1.curve.prime),
- )
- self.assertFalse(self.secp128r1.curve.is_on_curve(other))
- self.assertFalse(self.secp128r1.curve.is_on_curve(self.curve25519.generator))
- def test_affine_add(self):
- pt = Point(
- AffineCoordinateModel(self.secp128r1.curve.model),
- x=Mod(0xEB916224EDA4FB356421773573297C15, self.secp128r1.curve.prime),
- y=Mod(0xBCDAF32A2C08FD4271228FEF35070848, self.secp128r1.curve.prime),
- )
- self.assertIsNotNone(self.secp128r1.curve.affine_add(self.affine_base, pt))
+def test_is_neutral(secp128r1):
+ assert secp128r1.curve.is_neutral(
+ InfinityPoint(secp128r1.curve.coordinate_model)
+ )
- added = self.secp128r1.curve.affine_add(self.affine_base, self.affine_base)
- doubled = self.secp128r1.curve.affine_double(self.affine_base)
- self.assertEqual(added, doubled)
- self.assertEqual(
- self.secp128r1.curve.affine_add(self.secp128r1.curve.neutral, pt), pt
- )
- self.assertEqual(
- self.secp128r1.curve.affine_add(pt, self.secp128r1.curve.neutral), pt
- )
- def test_affine_double(self):
- self.assertIsNotNone(self.secp128r1.curve.affine_double(self.affine_base))
- self.assertEqual(
- self.secp128r1.curve.affine_double(self.secp128r1.curve.neutral),
- self.secp128r1.curve.neutral,
- )
+def test_is_on_curve(secp128r1, curve25519):
+ assert secp128r1.curve.is_on_curve(secp128r1.curve.neutral)
+ pt = Point(
+ secp128r1.curve.coordinate_model,
+ X=Mod(0x161FF7528B899B2D0C28607CA52C5B86, secp128r1.curve.prime),
+ Y=Mod(0xCF5AC8395BAFEB13C02DA292DDED7A83, secp128r1.curve.prime),
+ Z=Mod(1, secp128r1.curve.prime),
+ )
+ assert secp128r1.curve.is_on_curve(pt)
+ assert secp128r1.curve.is_on_curve(pt.to_affine())
+ other = Point(
+ secp128r1.curve.coordinate_model,
+ X=Mod(0x161FF7528B899B2D0C28607CA52C5B86, secp128r1.curve.prime),
+ Y=Mod(0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA, secp128r1.curve.prime),
+ Z=Mod(1, secp128r1.curve.prime),
+ )
+ assert not secp128r1.curve.is_on_curve(other)
+ assert not secp128r1.curve.is_on_curve(curve25519.generator)
- def test_affine_negate(self):
- self.assertIsNotNone(self.secp128r1.curve.affine_negate(self.affine_base))
- self.assertEqual(
- self.secp128r1.curve.affine_negate(self.secp128r1.curve.neutral),
- self.secp128r1.curve.neutral,
- )
- with self.assertRaises(ValueError):
- self.secp128r1.curve.affine_negate(self.base)
- with self.assertRaises(ValueError):
- self.secp128r1.curve.affine_negate(self.curve25519.generator)
- def test_affine_multiply(self):
- expected = self.affine_base
- expected = self.secp128r1.curve.affine_double(expected)
- expected = self.secp128r1.curve.affine_double(expected)
- expected = self.secp128r1.curve.affine_add(expected, self.affine_base)
- expected = self.secp128r1.curve.affine_double(expected)
- self.assertEqual(
- self.secp128r1.curve.affine_multiply(self.affine_base, 10), expected
- )
- self.assertEqual(
- self.secp128r1.curve.affine_multiply(self.secp128r1.curve.neutral, 10),
- self.secp128r1.curve.neutral,
- )
- with self.assertRaises(ValueError):
- self.secp128r1.curve.affine_multiply(self.base, 10)
- with self.assertRaises(ValueError):
- self.secp128r1.curve.affine_multiply(self.curve25519.generator, 10)
+def test_affine_add(secp128r1):
+ pt = Point(
+ AffineCoordinateModel(secp128r1.curve.model),
+ x=Mod(0xEB916224EDA4FB356421773573297C15, secp128r1.curve.prime),
+ y=Mod(0xBCDAF32A2C08FD4271228FEF35070848, secp128r1.curve.prime),
+ )
+ affine_base = secp128r1.generator.to_affine()
+ assert secp128r1.curve.affine_add(affine_base, pt) is not None
- def test_affine_neutral(self):
- self.assertIsNone(self.secp128r1.curve.affine_neutral)
- self.assertIsNone(self.curve25519.curve.affine_neutral)
- self.assertIsNotNone(self.ed25519.curve.affine_neutral)
+ added = secp128r1.curve.affine_add(affine_base, affine_base)
+ doubled = secp128r1.curve.affine_double(affine_base)
+ assert added == doubled
+ assert secp128r1.curve.affine_add(secp128r1.curve.neutral, pt) == pt
+ assert secp128r1.curve.affine_add(pt, secp128r1.curve.neutral) == pt
- def test_affine_random(self):
- for params in [self.secp128r1, self.curve25519, self.ed25519]:
- for _ in range(20):
- pt = params.curve.affine_random()
- self.assertIsNotNone(pt)
- self.assertTrue(params.curve.is_on_curve(pt))
- def test_neutral_is_affine(self):
- self.assertFalse(self.secp128r1.curve.neutral_is_affine)
- self.assertFalse(self.curve25519.curve.neutral_is_affine)
- self.assertTrue(self.ed25519.curve.neutral_is_affine)
+def test_affine_double(secp128r1):
+ affine_base = secp128r1.generator.to_affine()
+ assert secp128r1.curve.affine_double(affine_base) is not None
+ assert secp128r1.curve.affine_double(secp128r1.curve.neutral) == \
+ secp128r1.curve.neutral
- def test_eq(self):
- self.assertEqual(self.secp128r1.curve, self.secp128r1.curve)
- self.assertNotEqual(self.secp128r1.curve, self.curve25519.curve)
- self.assertNotEqual(self.secp128r1.curve, None)
- def test_decode(self):
- affine_curve = self.secp128r1.curve.to_affine()
- affine_point = self.secp128r1.generator.to_affine()
- decoded = affine_curve.decode_point(bytes(affine_point))
- self.assertEqual(decoded, affine_point)
+def test_affine_negate(secp128r1, curve25519):
+ affine_base = secp128r1.generator.to_affine()
+ assert secp128r1.curve.affine_negate(affine_base) is not None
+ assert secp128r1.curve.affine_negate(secp128r1.curve.neutral) == \
+ secp128r1.curve.neutral
+ with pytest.raises(ValueError):
+ secp128r1.curve.affine_negate(secp128r1.generator)
+ with pytest.raises(ValueError):
+ secp128r1.curve.affine_negate(curve25519.generator)
- affine_compressed_bytes = unhexlify("03161ff7528b899b2d0c28607ca52c5b86")
- decoded_compressed = affine_curve.decode_point(affine_compressed_bytes)
- self.assertEqual(decoded_compressed, affine_point)
- affine_compressed_bytes = unhexlify("02161ff7528b899b2d0c28607ca52c5b86")
- decoded_compressed = affine_curve.decode_point(affine_compressed_bytes)
- decoded_compressed = self.secp128r1.curve.affine_negate(decoded_compressed)
- self.assertEqual(decoded_compressed, affine_point)
- infinity_bytes = unhexlify("00")
- decoded_infinity = affine_curve.decode_point(infinity_bytes)
- self.assertEqual(affine_curve.neutral, decoded_infinity)
+def test_affine_multiply(secp128r1, curve25519):
+ affine_base = secp128r1.generator.to_affine()
+ expected = affine_base
+ expected = secp128r1.curve.affine_double(expected)
+ expected = secp128r1.curve.affine_double(expected)
+ expected = secp128r1.curve.affine_add(expected, affine_base)
+ expected = secp128r1.curve.affine_double(expected)
+ assert secp128r1.curve.affine_multiply(affine_base, 10) == expected
+ assert secp128r1.curve.affine_multiply(secp128r1.curve.neutral, 10) == \
+ secp128r1.curve.neutral
+ with pytest.raises(ValueError):
+ secp128r1.curve.affine_multiply(secp128r1.generator, 10)
+ with pytest.raises(ValueError):
+ secp128r1.curve.affine_multiply(curve25519.generator, 10)
- with self.assertRaises(ValueError):
- affine_curve.decode_point(unhexlify("03161ff7528b899b2d0c28607ca52c5b"))
- with self.assertRaises(ValueError):
- affine_curve.decode_point(
- unhexlify("04161ff7528b899b2d0c28607ca52c5b2c5b2c5b2c5b")
- )
- with self.assertRaises(ValueError):
- affine_curve.decode_point(unhexlify("7a161ff7528b899b2d0c28607ca52c5b86"))
- with self.assertRaises(ValueError):
- affine_curve.decode_point(unhexlify("03161ff7528b899b2d0c28607ca52c5b88"))
+
+def test_affine_neutral(secp128r1, curve25519, ed25519):
+ assert secp128r1.curve.affine_neutral is None
+ assert curve25519.curve.affine_neutral is None
+ assert ed25519.curve.affine_neutral is not None
+
+
+def test_neutral_is_affine(secp128r1, curve25519, ed25519):
+ assert not secp128r1.curve.neutral_is_affine
+ assert not curve25519.curve.neutral_is_affine
+ assert ed25519.curve.neutral_is_affine
+
+
+@pytest.mark.parametrize("curve_name", ["secp128r1", "curve25519", "ed25519"])
+def test_affine_random(curve_name, request):
+ params = request.getfixturevalue(curve_name)
+ for _ in range(20):
+ pt = params.curve.affine_random()
+ assert pt is not None
+ assert params.curve.is_on_curve(pt)
+
+
+def test_eq(secp128r1, curve25519):
+ assert secp128r1.curve == secp128r1.curve
+ assert secp128r1.curve != curve25519.curve
+ assert secp128r1.curve is not None
+
+
+def test_decode(secp128r1):
+ affine_curve = secp128r1.curve.to_affine()
+ affine_point = secp128r1.generator.to_affine()
+ decoded = affine_curve.decode_point(bytes(affine_point))
+ assert decoded == affine_point
+
+ affine_compressed_bytes = unhexlify("03161ff7528b899b2d0c28607ca52c5b86")
+ decoded_compressed = affine_curve.decode_point(affine_compressed_bytes)
+ assert decoded_compressed == affine_point
+ affine_compressed_bytes = unhexlify("02161ff7528b899b2d0c28607ca52c5b86")
+ decoded_compressed = affine_curve.decode_point(affine_compressed_bytes)
+ decoded_compressed = secp128r1.curve.affine_negate(decoded_compressed)
+ assert decoded_compressed == affine_point
+
+ infinity_bytes = unhexlify("00")
+ decoded_infinity = affine_curve.decode_point(infinity_bytes)
+ assert affine_curve.neutral == decoded_infinity
+
+ with pytest.raises(ValueError):
+ affine_curve.decode_point(unhexlify("03161ff7528b899b2d0c28607ca52c5b"))
+ with pytest.raises(ValueError):
+ affine_curve.decode_point(
+ unhexlify("04161ff7528b899b2d0c28607ca52c5b2c5b2c5b2c5b")
+ )
+ with pytest.raises(ValueError):
+ affine_curve.decode_point(unhexlify("7a161ff7528b899b2d0c28607ca52c5b86"))
+ with pytest.raises(ValueError):
+ affine_curve.decode_point(unhexlify("03161ff7528b899b2d0c28607ca52c5b88"))
diff --git a/test/ec/test_divpoly.py b/test/ec/test_divpoly.py
index f09fdf0..aace00b 100644
--- a/test/ec/test_divpoly.py
+++ b/test/ec/test_divpoly.py
@@ -1,188 +1,112 @@
-from unittest import TestCase
import json
from importlib.resources import files
import test.data.divpoly
from sympy import FF
from pyecsca.ec.divpoly import a_invariants, b_invariants, divpoly0, divpoly, mult_by_n
-from pyecsca.ec.model import ShortWeierstrassModel
-from pyecsca.ec.params import get_params
-class DivpolyTests(TestCase):
- def setUp(self):
- self.secp128r1 = get_params("secg", "secp128r1", "projective")
- 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_ainvs(secp128r1):
+ ainvs = a_invariants(secp128r1.curve)
+ assert ainvs == (0, 0, 0, 340282366762482138434845932244680310780, 308990863222245658030922601041482374867)
- def test_ainvs(self):
- ainvs = a_invariants(self.secp128r1.curve)
- self.assertSequenceEqual(ainvs, (0,
- 0,
- 0,
- 340282366762482138434845932244680310780,
- 308990863222245658030922601041482374867))
- def test_binvs(self):
- binvs = b_invariants(self.secp128r1.curve)
- self.assertSequenceEqual(binvs, (0,
- 340282366762482138434845932244680310777,
- 215116352601536216819152607431888567119,
- 340282366762482138434845932244680310774))
+def test_binvs(secp128r1):
+ binvs = b_invariants(secp128r1.curve)
+ assert binvs == (0, 340282366762482138434845932244680310777, 215116352601536216819152607431888567119,
+ 340282366762482138434845932244680310774)
- def test_divpoly0(self):
- # Data from sagemath
- coeffs = [11,
- 0,
- 340282366762482138434845932244680302401,
- 211962053797180672439257756222135086642,
- 340282366762482138434845932244678441564,
- 115415922367823003571854983213102698477,
- 152803211743444076787231275062278784385,
- 68540219804769369063918923691867278088,
- 43207172520353703997069627419519708522,
- 83208285732019037267730920881743782729,
- 93286967763556583502947234289842152563,
- 324950611928652823046744874201355360259,
- 244242343224213805514200367379671854852,
- 307096814154284337284845014037169929735,
- 180946781765592277412990188457219828893,
- 301253861469456022084288029442105687698,
- 58053323975526190296189278379252064657,
- 224437885189054146208302696540070489578,
- 281987318191429654256483850017931541622,
- 21449216018131966691124843738286677726,
- 10958264881628724646042625283328121348,
- 104868338562600481545003572552335444641,
- 127205813185570107009206143413997395181,
- 116865717360861207318274706645935808417,
- 281460458922812844939222119784601506753,
- 336607098463310980140968249747513775735,
- 304486486784143285234063826161805094682,
- 194935097339732797131694429642153881938,
- 193523171473792085604518744912658246509,
- 204844449336357293979832621297234119270,
- 244481753281744913785581086721299830802,
- 46816299473081369405217767361380254657,
- 303070923752707405164354702252828590781,
- 222516549119176621389776816552836322766,
- 292006660232236762950883960515487362063,
- 53617127992846936725441702182362940200,
- 242498306026562585655027965022211017540,
- 25039963304689451659955607939868533124,
- 328580435950647191774558154445103295305,
- 24226614081978788956695324769468902511,
- 147945052666123617872720080832548744564,
- 287190187011075399698210761813202261601,
- 117131681517270554750959286838283723521,
- 35018410385280384289320020556813474742,
- 83939964512240352730304831725346032711,
- 147219996946006689656600631222993527180,
- 280430477096741745234510250577626566690,
- 32753113267385981127807026368593329576,
- 105134319561523011785486683031223863934,
- 206456116679151691099661865534540095270,
- 116180470443213022739312068090342951131,
- 245850120846480965440408943459023315919,
- 45805943896736805301879725516256422457,
- 226777421435695229777151315574975350291,
- 283680841707610526659029980964566557627,
- 53168487339451866167506032177471934158,
- 69212302225932892622760219621519562036,
- 183916411340675637978873336955593385541,
- 119478537598919956688656337369481692789,
- 234767298887335988751880131162396819780,
- 218412162101425422347176804186940045781]
- K = FF(self.secp128r1.curve.prime)
- poly = divpoly0(self.secp128r1.curve, 11)[11]
- computed = list(map(K, poly.all_coeffs()))
- self.assertListEqual(coeffs, computed)
+def test_divpoly0(secp128r1):
+ # Data from sagemath
+ coeffs = [11, 0, 340282366762482138434845932244680302401, 211962053797180672439257756222135086642,
+ 340282366762482138434845932244678441564, 115415922367823003571854983213102698477,
+ 152803211743444076787231275062278784385, 68540219804769369063918923691867278088,
+ 43207172520353703997069627419519708522, 83208285732019037267730920881743782729,
+ 93286967763556583502947234289842152563, 324950611928652823046744874201355360259,
+ 244242343224213805514200367379671854852, 307096814154284337284845014037169929735,
+ 180946781765592277412990188457219828893, 301253861469456022084288029442105687698,
+ 58053323975526190296189278379252064657, 224437885189054146208302696540070489578,
+ 281987318191429654256483850017931541622, 21449216018131966691124843738286677726,
+ 10958264881628724646042625283328121348, 104868338562600481545003572552335444641,
+ 127205813185570107009206143413997395181, 116865717360861207318274706645935808417,
+ 281460458922812844939222119784601506753, 336607098463310980140968249747513775735,
+ 304486486784143285234063826161805094682, 194935097339732797131694429642153881938,
+ 193523171473792085604518744912658246509, 204844449336357293979832621297234119270,
+ 244481753281744913785581086721299830802, 46816299473081369405217767361380254657,
+ 303070923752707405164354702252828590781, 222516549119176621389776816552836322766,
+ 292006660232236762950883960515487362063, 53617127992846936725441702182362940200,
+ 242498306026562585655027965022211017540, 25039963304689451659955607939868533124,
+ 328580435950647191774558154445103295305, 24226614081978788956695324769468902511,
+ 147945052666123617872720080832548744564, 287190187011075399698210761813202261601,
+ 117131681517270554750959286838283723521, 35018410385280384289320020556813474742,
+ 83939964512240352730304831725346032711, 147219996946006689656600631222993527180,
+ 280430477096741745234510250577626566690, 32753113267385981127807026368593329576,
+ 105134319561523011785486683031223863934, 206456116679151691099661865534540095270,
+ 116180470443213022739312068090342951131, 245850120846480965440408943459023315919,
+ 45805943896736805301879725516256422457, 226777421435695229777151315574975350291,
+ 283680841707610526659029980964566557627, 53168487339451866167506032177471934158,
+ 69212302225932892622760219621519562036, 183916411340675637978873336955593385541,
+ 119478537598919956688656337369481692789, 234767298887335988751880131162396819780,
+ 218412162101425422347176804186940045781]
+ K = FF(secp128r1.curve.prime)
+ poly = divpoly0(secp128r1.curve, 11)[11]
+ computed = list(map(K, poly.all_coeffs()))
+ assert coeffs == computed
- def test_divpoly(self):
- # Data from sagemath
- K = FF(self.secp128r1.curve.prime)
- coeffs_0 = {
- (0,): K(16020440675387382717114730680672549016),
- (1,): K(269851015321770885610377847857290470365),
- (2,): K(340282366762482138434845932244680310693),
- (3,): K(109469325440469337582450480850803806492),
- (4,): K(340282366762482138434845932244680310753),
- (6,): K(2)
- }
- self.assertDictEqual(divpoly(self.secp128r1.curve, 4, 0).as_dict(), coeffs_0)
- coeffs_1 = {
- (6, 1): K(4),
- (4, 1): K(340282366762482138434845932244680310723),
- (3, 1): K(218938650880938675164900961701607612984),
- (2, 1): K(340282366762482138434845932244680310603),
- (1, 1): K(199419663881059632785909763469900629947),
- (0, 1): K(32040881350774765434229461361345098032)
- }
- self.assertDictEqual(divpoly(self.secp128r1.curve, 4, 1).as_dict(), coeffs_1)
- coeffs_2 = {
- (9,): K(8),
- (7,): K(340282366762482138434845932244680310639),
- (6,): K(187545273439985507098415273777631738640),
- (4,): K(117928913205007755574446043156465405646),
- (3,): K(244159722710157842132157548160645018307),
- (2,): K(200234655086793134086408617236124137371),
- (1,): K(51914434605509249526780779992574428819),
- (0,): K(60581150995923875019702403440670701629)
- }
- self.assertDictEqual(divpoly(self.secp128r1.curve, 4, 2).as_dict(), coeffs_2)
- def test_mult_by_n(self):
- # Data from sagemath
- K = FF(self.secp128r1.curve.prime)
- coeffs_mx_num = [1,
- 0,
- 6,
- 250332028321891843231386649625583487328,
- 9]
- coeffs_mx_denom = [4,
- 0,
- 340282366762482138434845932244680310771,
- 215116352601536216819152607431888567119]
- coeffs_my_num = {
- (6, 1): K(8),
- (4, 1): K(340282366762482138434845932244680310663),
- (3, 1): K(97594934999395211894955991158534915185),
- (2, 1): K(340282366762482138434845932244680310423),
- (1, 1): K(58556960999637127136973594695120949111),
- (0, 1): K(64081762701549530868458922722690196064)
- }
- coeffs_my_denom = {
- (6, 0): K(64),
- (4, 0): K(340282366762482138434845932244680310399),
- (3, 0): K(78075947999516169515964792926827932148),
- (2, 0): K(576),
- (1, 0): K(106054522763933629886951553464196514339),
- (0, 0): K(276200604060932607566387009521990114935)
- }
- mx, my = mult_by_n(self.secp128r1.curve, 2)
- mx_num, mx_denom = mx
- self.assertListEqual(coeffs_mx_num, list(map(K, mx_num.all_coeffs())))
- self.assertListEqual(coeffs_mx_denom, list(map(K, mx_denom.all_coeffs())))
- my_num, my_denom = my
- self.assertDictEqual(my_num.as_dict(), coeffs_my_num)
- self.assertDictEqual(my_denom.as_dict(), coeffs_my_denom)
+def test_divpoly(secp128r1):
+ # Data from sagemath
+ K = FF(secp128r1.curve.prime)
+ coeffs_0 = {(0,): K(16020440675387382717114730680672549016), (1,): K(269851015321770885610377847857290470365),
+ (2,): K(340282366762482138434845932244680310693), (3,): K(109469325440469337582450480850803806492),
+ (4,): K(340282366762482138434845932244680310753), (6,): K(2)}
+ assert divpoly(secp128r1.curve, 4, 0).as_dict() == coeffs_0
+ coeffs_1 = {(6, 1): K(4), (4, 1): K(340282366762482138434845932244680310723),
+ (3, 1): K(218938650880938675164900961701607612984), (2, 1): K(340282366762482138434845932244680310603),
+ (1, 1): K(199419663881059632785909763469900629947), (0, 1): K(32040881350774765434229461361345098032)}
+ assert divpoly(secp128r1.curve, 4, 1).as_dict() == coeffs_1
+ coeffs_2 = {(9,): K(8), (7,): K(340282366762482138434845932244680310639),
+ (6,): K(187545273439985507098415273777631738640), (4,): K(117928913205007755574446043156465405646),
+ (3,): K(244159722710157842132157548160645018307), (2,): K(200234655086793134086408617236124137371),
+ (1,): K(51914434605509249526780779992574428819), (0,): K(60581150995923875019702403440670701629)}
+ assert divpoly(secp128r1.curve, 4, 2).as_dict() == coeffs_2
- def test_mult_by_n_large(self):
- K = FF(self.secp128r1.curve.prime)
- mx, my = mult_by_n(self.secp128r1.curve, 21)
- with files(test.data.divpoly).joinpath("mult_21.json").open("r") as f:
- sage_data = json.load(f)
- sage_data["mx"][0] = {eval(key): K(val) for key, val in sage_data["mx"][0].items()}
- sage_data["mx"][1] = {eval(key): K(val) for key, val in sage_data["mx"][1].items()}
- sage_data["my"][0] = {eval(key): K(val) for key, val in sage_data["my"][0].items()}
- sage_data["my"][1] = {eval(key): K(val) for key, val in sage_data["my"][1].items()}
- self.assertDictEqual(mx[0].as_dict(), sage_data["mx"][0])
- self.assertDictEqual(mx[1].as_dict(), sage_data["mx"][1])
+def test_mult_by_n(secp128r1):
+ # Data from sagemath
+ K = FF(secp128r1.curve.prime)
+ coeffs_mx_num = [1, 0, 6, 250332028321891843231386649625583487328, 9]
+ coeffs_mx_denom = [4, 0, 340282366762482138434845932244680310771, 215116352601536216819152607431888567119]
+ coeffs_my_num = {(6, 1): K(8), (4, 1): K(340282366762482138434845932244680310663),
+ (3, 1): K(97594934999395211894955991158534915185),
+ (2, 1): K(340282366762482138434845932244680310423),
+ (1, 1): K(58556960999637127136973594695120949111),
+ (0, 1): K(64081762701549530868458922722690196064)}
+ coeffs_my_denom = {(6, 0): K(64), (4, 0): K(340282366762482138434845932244680310399),
+ (3, 0): K(78075947999516169515964792926827932148), (2, 0): K(576),
+ (1, 0): K(106054522763933629886951553464196514339),
+ (0, 0): K(276200604060932607566387009521990114935)}
+ mx, my = mult_by_n(secp128r1.curve, 2)
+ mx_num, mx_denom = mx
+ assert coeffs_mx_num == list(map(K, mx_num.all_coeffs()))
+ assert coeffs_mx_denom == list(map(K, mx_denom.all_coeffs()))
+ my_num, my_denom = my
+ assert my_num.as_dict() == coeffs_my_num
+ assert my_denom.as_dict() == coeffs_my_denom
- self.assertDictEqual(my[0].as_dict(), sage_data["my"][0])
- self.assertDictEqual(my[1].as_dict(), sage_data["my"][1])
+
+def test_mult_by_n_large(secp128r1):
+ K = FF(secp128r1.curve.prime)
+ mx, my = mult_by_n(secp128r1.curve, 21)
+ with files(test.data.divpoly).joinpath("mult_21.json").open("r") as f:
+ sage_data = json.load(f)
+ sage_data["mx"][0] = {eval(key): K(val) for key, val in sage_data["mx"][0].items()}
+ sage_data["mx"][1] = {eval(key): K(val) for key, val in sage_data["mx"][1].items()}
+ sage_data["my"][0] = {eval(key): K(val) for key, val in sage_data["my"][0].items()}
+ sage_data["my"][1] = {eval(key): K(val) for key, val in sage_data["my"][1].items()}
+
+ assert mx[0].as_dict() == sage_data["mx"][0]
+ assert mx[1].as_dict() == sage_data["mx"][1]
+ assert my[0].as_dict() == sage_data["my"][0]
+ assert my[1].as_dict() == sage_data["my"][1]
diff --git a/test/ec/test_formula.py b/test/ec/test_formula.py
index ffae4c4..420e0b3 100644
--- a/test/ec/test_formula.py
+++ b/test/ec/test_formula.py
@@ -1,5 +1,4 @@
-from unittest import TestCase
-
+import pytest
from sympy import FF, symbols
from pyecsca.ec.mod import SymbolicMod, Mod
@@ -9,99 +8,115 @@ from pyecsca.ec.params import get_params
from pyecsca.ec.point import Point
-class FormulaTests(TestCase):
- def setUp(self):
- self.secp128r1 = get_params("secg", "secp128r1", "projective")
- self.add = self.secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
- self.dbl = self.secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
- self.mdbl = self.secp128r1.curve.coordinate_model.formulas["mdbl-2007-bl"]
- self.jac_secp128r1 = get_params("secg", "secp128r1", "jacobian")
- self.jac_dbl = self.jac_secp128r1.curve.coordinate_model.formulas[
- "dbl-1998-hnm"
- ]
+@pytest.fixture()
+def add(secp128r1):
+ return secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
- def test_wrong_call(self):
- with self.assertRaises(ValueError):
- self.add(self.secp128r1.curve.prime)
- with self.assertRaises(ValueError):
- self.add(
- self.secp128r1.curve.prime,
- self.secp128r1.generator.to_affine(),
- self.secp128r1.generator.to_affine(),
- )
- def test_indices(self):
- self.assertEqual(self.add.input_index, 1)
- self.assertEqual(self.add.output_index, 3)
+@pytest.fixture()
+def dbl(secp128r1):
+ return secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
- def test_inputs_outputs(self):
- self.assertEqual(self.add.inputs, {"X1", "Y1", "Z1", "X2", "Y2", "Z2"})
- self.assertEqual(self.add.outputs, {"X3", "Y3", "Z3"})
- def test_eq(self):
- self.assertEqual(self.add, self.add)
- self.assertNotEqual(self.add, self.dbl)
+@pytest.fixture()
+def mdbl(secp128r1):
+ return secp128r1.curve.coordinate_model.formulas["mdbl-2007-bl"]
- def test_num_ops(self):
- self.assertEqual(self.add.num_operations, 33)
- self.assertEqual(self.add.num_multiplications, 17)
- self.assertEqual(self.add.num_divisions, 0)
- self.assertEqual(self.add.num_inversions, 0)
- self.assertEqual(self.add.num_powers, 0)
- self.assertEqual(self.add.num_squarings, 6)
- self.assertEqual(self.add.num_addsubs, 10)
- def test_assumptions(self):
- res = self.mdbl(
- self.secp128r1.curve.prime,
- self.secp128r1.generator,
- **self.secp128r1.curve.parameters
+def test_wrong_call(secp128r1, add):
+ with pytest.raises(ValueError):
+ add(secp128r1.curve.prime)
+ with pytest.raises(ValueError):
+ add(
+ secp128r1.curve.prime,
+ secp128r1.generator.to_affine(),
+ secp128r1.generator.to_affine(),
)
- self.assertIsNotNone(res)
- coords = {
- name: value * 5 for name, value in self.secp128r1.generator.coords.items()
- }
- other = Point(self.secp128r1.generator.coordinate_model, **coords)
- with self.assertRaises(UnsatisfiedAssumptionError):
- self.mdbl(
- self.secp128r1.curve.prime, other, **self.secp128r1.curve.parameters
- )
- with TemporaryConfig() as cfg:
- cfg.ec.unsatisfied_formula_assumption_action = "ignore"
- pt = self.mdbl(
- self.secp128r1.curve.prime, other, **self.secp128r1.curve.parameters
- )
- self.assertIsNotNone(pt)
- def test_parameters(self):
- res = self.jac_dbl(
- self.secp128r1.curve.prime,
- self.jac_secp128r1.generator,
- **self.jac_secp128r1.curve.parameters
- )
- self.assertIsNotNone(res)
+def test_indices(add):
+ assert add.input_index == 1
+ assert add.output_index == 3
+
+
+def test_inputs_outputs(add):
+ assert add.inputs == {"X1", "Y1", "Z1", "X2", "Y2", "Z2"}
+ assert add.outputs == {"X3", "Y3", "Z3"}
+
+
+def test_eq(add, dbl):
+ assert add == add
+ assert add != dbl
+
- def test_symbolic(self):
- p = self.secp128r1.curve.prime
- k = FF(p)
- coords = self.secp128r1.curve.coordinate_model
- sympy_params = {
- key: SymbolicMod(k(int(value)), p)
- for key, value in self.secp128r1.curve.parameters.items()
- }
- symbolic_point = Point(
- coords, **{key: SymbolicMod(symbols(key), p) for key in coords.variables}
+def test_num_ops(add):
+ assert add.num_operations == 33
+ assert add.num_multiplications == 17
+ assert add.num_divisions == 0
+ assert add.num_inversions == 0
+ assert add.num_powers == 0
+ assert add.num_squarings == 6
+ assert add.num_addsubs == 10
+
+
+def test_assumptions(secp128r1, mdbl):
+ res = mdbl(
+ secp128r1.curve.prime,
+ secp128r1.generator,
+ **secp128r1.curve.parameters
+ )
+ assert res is not None
+
+ coords = {
+ name: value * 5 for name, value in secp128r1.generator.coords.items()
+ }
+ other = Point(secp128r1.generator.coordinate_model, **coords)
+ with pytest.raises(UnsatisfiedAssumptionError):
+ mdbl(
+ secp128r1.curve.prime, other, **secp128r1.curve.parameters
)
- symbolic_double = self.dbl(p, symbolic_point, **sympy_params)[0]
- generator_double = self.dbl(
- p, self.secp128r1.generator, **self.secp128r1.curve.parameters
- )[0]
- for outer_var in coords.variables:
- symbolic_val = getattr(symbolic_double, outer_var).x
- generator_val = getattr(generator_double, outer_var).x
- for inner_var in coords.variables:
- symbolic_val = symbolic_val.subs(
- inner_var, k(getattr(self.secp128r1.generator, inner_var).x)
- )
- self.assertEqual(Mod(int(symbolic_val), p), Mod(generator_val, p))
+ with TemporaryConfig() as cfg:
+ cfg.ec.unsatisfied_formula_assumption_action = "ignore"
+ pt = mdbl(
+ secp128r1.curve.prime, other, **secp128r1.curve.parameters
+ )
+ assert pt is not None
+
+
+def test_parameters():
+ jac_secp128r1 = get_params("secg", "secp128r1", "jacobian")
+ jac_dbl = jac_secp128r1.curve.coordinate_model.formulas[
+ "dbl-1998-hnm"
+ ]
+
+ res = jac_dbl(
+ jac_secp128r1.curve.prime,
+ jac_secp128r1.generator,
+ **jac_secp128r1.curve.parameters
+ )
+ assert res is not None
+
+
+def test_symbolic(secp128r1, dbl):
+ p = secp128r1.curve.prime
+ k = FF(p)
+ coords = secp128r1.curve.coordinate_model
+ sympy_params = {
+ key: SymbolicMod(k(int(value)), p)
+ for key, value in secp128r1.curve.parameters.items()
+ }
+ symbolic_point = Point(
+ coords, **{key: SymbolicMod(symbols(key), p) for key in coords.variables}
+ )
+ symbolic_double = dbl(p, symbolic_point, **sympy_params)[0]
+ generator_double = dbl(
+ p, secp128r1.generator, **secp128r1.curve.parameters
+ )[0]
+ for outer_var in coords.variables:
+ symbolic_val = getattr(symbolic_double, outer_var).x
+ generator_val = getattr(generator_double, outer_var).x
+ for inner_var in coords.variables:
+ symbolic_val = symbolic_val.subs(
+ inner_var, k(getattr(secp128r1.generator, inner_var).x)
+ )
+ assert Mod(int(symbolic_val), p) == Mod(generator_val, p)
diff --git a/test/ec/test_key_agreement.py b/test/ec/test_key_agreement.py
index 240c174..14bd138 100644
--- a/test/ec/test_key_agreement.py
+++ b/test/ec/test_key_agreement.py
@@ -1,8 +1,4 @@
-from unittest import TestCase
-
-from parameterized import parameterized
-
-from pyecsca.ec.params import get_params
+import pytest
from pyecsca.ec.key_agreement import (
ECDH_NONE,
ECDH_SHA1,
@@ -15,31 +11,33 @@ from pyecsca.ec.mod import Mod
from pyecsca.ec.mult import LTRMultiplier
-class KeyAgreementTests(TestCase):
- def setUp(self):
- self.secp128r1 = get_params("secg", "secp128r1", "projective")
- self.add = self.secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
- self.dbl = self.secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
- self.mult = LTRMultiplier(self.add, self.dbl)
- self.priv_a = Mod(0xDEADBEEF, self.secp128r1.order)
- self.mult.init(self.secp128r1, self.secp128r1.generator)
- self.pub_a = self.mult.multiply(int(self.priv_a))
- self.priv_b = Mod(0xCAFEBABE, self.secp128r1.order)
- self.pub_b = self.mult.multiply(int(self.priv_b))
+@pytest.fixture()
+def mult(secp128r1):
+ add = secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
+ dbl = secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
+ return LTRMultiplier(add, dbl)
+
+
+@pytest.fixture()
+def keypair_a(secp128r1, mult):
+ priv_a = Mod(0xDEADBEEF, secp128r1.order)
+ mult.init(secp128r1, secp128r1.generator)
+ pub_a = mult.multiply(int(priv_a))
+ return priv_a, pub_a
+
+
+@pytest.fixture()
+def keypair_b(secp128r1, mult):
+ priv_b = Mod(0xCAFEBABE, secp128r1.order)
+ mult.init(secp128r1, secp128r1.generator)
+ pub_b = mult.multiply(int(priv_b))
+ return priv_b, pub_b
+
- @parameterized.expand(
- [
- ("NONE", ECDH_NONE),
- ("SHA1", ECDH_SHA1),
- ("SHA224", ECDH_SHA224),
- ("SHA256", ECDH_SHA256),
- ("SHA384", ECDH_SHA384),
- ("SHA512", ECDH_SHA512),
- ]
- )
- def test_all(self, name, algo):
- result_ab = algo(self.mult, self.secp128r1, self.pub_a, self.priv_b).perform()
- result_ba = algo(self.mult, self.secp128r1, self.pub_b, self.priv_a).perform()
- self.assertEqual(result_ab, result_ba)
+@pytest.mark.parametrize("algo", [ECDH_NONE, ECDH_SHA1, ECDH_SHA224, ECDH_SHA256, ECDH_SHA384, ECDH_SHA512])
+def test_ka(algo, mult, secp128r1, keypair_a, keypair_b):
+ result_ab = algo(mult, secp128r1, keypair_a[1], keypair_b[0]).perform()
+ result_ba = algo(mult, secp128r1, keypair_b[1], keypair_a[0]).perform()
+ assert result_ab == result_ba
- # TODO: Add KAT-based tests here.
+# TODO: Add KAT-based tests here.
diff --git a/test/ec/test_key_generation.py b/test/ec/test_key_generation.py
index 7eb26f0..512aaac 100644
--- a/test/ec/test_key_generation.py
+++ b/test/ec/test_key_generation.py
@@ -1,25 +1,24 @@
-from unittest import TestCase
+import pytest
-from pyecsca.ec.params import get_params
from pyecsca.ec.key_generation import KeyGeneration
from pyecsca.ec.mult import LTRMultiplier
-class KeyGenerationTests(TestCase):
- def setUp(self):
- self.secp128r1 = get_params("secg", "secp128r1", "projective")
- self.add = self.secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
- self.dbl = self.secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
- self.mult = LTRMultiplier(self.add, self.dbl)
+@pytest.fixture()
+def mult(secp128r1):
+ add = secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
+ dbl = secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
+ return LTRMultiplier(add, dbl)
- def test_basic(self):
- generator = KeyGeneration(self.mult, self.secp128r1)
- priv, pub = generator.generate()
- self.assertIsNotNone(priv)
- self.assertIsNotNone(pub)
- self.assertTrue(self.secp128r1.curve.is_on_curve(pub))
- generator = KeyGeneration(self.mult, self.secp128r1, True)
- priv, pub = generator.generate()
- self.assertIsNotNone(priv)
- self.assertIsNotNone(pub)
- self.assertTrue(self.secp128r1.curve.is_on_curve(pub))
+
+def test_basic(secp128r1, mult):
+ generator = KeyGeneration(mult, secp128r1)
+ priv, pub = generator.generate()
+ assert priv is not None
+ assert pub is not None
+ assert secp128r1.curve.is_on_curve(pub)
+ generator = KeyGeneration(mult, secp128r1, True)
+ priv, pub = generator.generate()
+ assert priv is not None
+ assert pub is not None
+ assert secp128r1.curve.is_on_curve(pub)
diff --git a/test/ec/test_mod.py b/test/ec/test_mod.py
index 62022b0..29b818e 100644
--- a/test/ec/test_mod.py
+++ b/test/ec/test_mod.py
@@ -1,6 +1,7 @@
import warnings
+
+import pytest
from sympy import FF, symbols
-from unittest import TestCase
from pyecsca.ec.mod import (
Mod,
@@ -22,153 +23,149 @@ from pyecsca.ec.error import (
from pyecsca.misc.cfg import getconfig, TemporaryConfig
-class ModTests(TestCase):
- def test_gcd(self):
- self.assertEqual(gcd(15, 20), 5)
- self.assertEqual(extgcd(15, 0), (1, 0, 15))
- self.assertEqual(extgcd(15, 20), (-1, 1, 5))
+def test_gcd():
+ assert gcd(15, 20) == 5
+ assert extgcd(15, 0) == (1, 0, 15)
+ assert extgcd(15, 20) == (-1, 1, 5)
- def test_jacobi(self):
- self.assertEqual(jacobi(5, 1153486465415345646578465454655646543248656451), 1)
- self.assertEqual(
- jacobi(564786456646845, 46874698564153465453246546545456849797895547657), -1
- )
- self.assertEqual(
- jacobi(564786456646845, 46874698564153465453246546545456849797895), 0
- )
- def test_miller_rabin(self):
- self.assertTrue(miller_rabin(2))
- self.assertTrue(miller_rabin(3))
- self.assertTrue(miller_rabin(5))
- self.assertFalse(miller_rabin(8))
- self.assertTrue(
- miller_rabin(0xE807561107CCF8FA82AF74FD492543A918CA2E9C13750233A9)
- )
- self.assertFalse(
- miller_rabin(0x6F6889DEB08DA211927370810F026EB4C17B17755F72EA005)
- )
+def test_jacobi():
+ assert jacobi(5, 1153486465415345646578465454655646543248656451) == 1
+ assert jacobi(564786456646845, 46874698564153465453246546545456849797895547657) == -1
+ assert jacobi(564786456646845, 46874698564153465453246546545456849797895) == 0
- def test_inverse(self):
- p = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
- self.assertEqual(
- Mod(
- 0x702BDAFD3C1C837B23A1CB196ED7F9FADB333C5CFE4A462BE32ADCD67BFB6AC1, p
- ).inverse(),
- Mod(0x1CB2E5274BBA085C4CA88EEDE75AE77949E7A410C80368376E97AB22EB590F9D, p),
- )
- with self.assertRaises(NonInvertibleError):
- Mod(0, p).inverse()
- with self.assertRaises(NonInvertibleError):
- Mod(5, 10).inverse()
- getconfig().ec.no_inverse_action = "warning"
- with warnings.catch_warnings(record=True) as w:
- Mod(0, p).inverse()
- self.assertTrue(issubclass(w[0].category, NonInvertibleWarning))
- with warnings.catch_warnings(record=True) as w:
- Mod(5, 10).inverse()
- self.assertTrue(issubclass(w[0].category, NonInvertibleWarning))
- getconfig().ec.no_inverse_action = "ignore"
+
+def test_miller_rabin():
+ assert miller_rabin(2)
+ assert miller_rabin(3)
+ assert miller_rabin(5)
+ assert not miller_rabin(8)
+ assert miller_rabin(0xE807561107CCF8FA82AF74FD492543A918CA2E9C13750233A9)
+ assert not miller_rabin(0x6F6889DEB08DA211927370810F026EB4C17B17755F72EA005)
+
+
+def test_inverse():
+ p = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
+ assert Mod(
+ 0x702BDAFD3C1C837B23A1CB196ED7F9FADB333C5CFE4A462BE32ADCD67BFB6AC1, p
+ ).inverse() == \
+ Mod(0x1CB2E5274BBA085C4CA88EEDE75AE77949E7A410C80368376E97AB22EB590F9D, p)
+ with pytest.raises(NonInvertibleError):
+ Mod(0, p).inverse()
+ with pytest.raises(NonInvertibleError):
+ Mod(5, 10).inverse()
+ getconfig().ec.no_inverse_action = "warning"
+ with warnings.catch_warnings(record=True) as w:
Mod(0, p).inverse()
+ assert issubclass(w[0].category, NonInvertibleWarning)
+ with warnings.catch_warnings(record=True) as w:
Mod(5, 10).inverse()
- getconfig().ec.no_inverse_action = "error"
+ assert issubclass(w[0].category, NonInvertibleWarning)
+ getconfig().ec.no_inverse_action = "ignore"
+ Mod(0, p).inverse()
+ Mod(5, 10).inverse()
+ getconfig().ec.no_inverse_action = "error"
- def test_is_residue(self):
- self.assertTrue(Mod(4, 11).is_residue())
- self.assertFalse(Mod(11, 31).is_residue())
- self.assertTrue(Mod(0, 7).is_residue())
- self.assertTrue(Mod(1, 2).is_residue())
- def test_sqrt(self):
- p = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
- self.assertIn(
- Mod(
- 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC, p
- ).sqrt(),
- (
- 0x9ADD512515B70D9EC471151C1DEC46625CD18B37BDE7CA7FB2C8B31D7033599D,
- 0x6522AED9EA48F2623B8EEAE3E213B99DA32E74C9421835804D374CE28FCCA662,
- ),
- )
- with self.assertRaises(NonResidueError):
- Mod(
- 0x702BDAFD3C1C837B23A1CB196ED7F9FADB333C5CFE4A462BE32ADCD67BFB6AC1, p
- ).sqrt()
- getconfig().ec.non_residue_action = "warning"
- with warnings.catch_warnings(record=True) as w:
- Mod(
- 0x702BDAFD3C1C837B23A1CB196ED7F9FADB333C5CFE4A462BE32ADCD67BFB6AC1, p
- ).sqrt()
- self.assertTrue(issubclass(w[0].category, NonResidueWarning))
- getconfig().ec.non_residue_action = "ignore"
+def test_is_residue():
+ assert Mod(4, 11).is_residue()
+ assert not Mod(11, 31).is_residue()
+ assert Mod(0, 7).is_residue()
+ assert Mod(1, 2).is_residue()
+
+
+def test_sqrt():
+ p = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
+ assert Mod(
+ 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC, p
+ ).sqrt() in \
+ (
+ 0x9ADD512515B70D9EC471151C1DEC46625CD18B37BDE7CA7FB2C8B31D7033599D,
+ 0x6522AED9EA48F2623B8EEAE3E213B99DA32E74C9421835804D374CE28FCCA662,
+ )
+ with pytest.raises(NonResidueError):
+ Mod(
+ 0x702BDAFD3C1C837B23A1CB196ED7F9FADB333C5CFE4A462BE32ADCD67BFB6AC1, p
+ ).sqrt()
+ getconfig().ec.non_residue_action = "warning"
+ with warnings.catch_warnings(record=True) as w:
Mod(
0x702BDAFD3C1C837B23A1CB196ED7F9FADB333C5CFE4A462BE32ADCD67BFB6AC1, p
).sqrt()
- with TemporaryConfig() as cfg:
- cfg.ec.non_residue_action = "warning"
- with warnings.catch_warnings(record=True) as w:
- Mod(
- 0x702BDAFD3C1C837B23A1CB196ED7F9FADB333C5CFE4A462BE32ADCD67BFB6AC1,
- p,
- ).sqrt()
- self.assertTrue(issubclass(w[0].category, NonResidueWarning))
- self.assertEqual(Mod(0, p).sqrt(), Mod(0, p))
- q = 0x75D44FEE9A71841AE8403C0C251FBAD
- self.assertIn(
- Mod(0x591E0DB18CF1BD81A11B2985A821EB3, q).sqrt(),
- (0x113B41A1A2B73F636E73BE3F9A3716E, 0x64990E4CF7BA44B779CC7DCC8AE8A3F),
- )
- getconfig().ec.non_residue_action = "error"
+ assert issubclass(w[0].category, NonResidueWarning)
+ getconfig().ec.non_residue_action = "ignore"
+ Mod(
+ 0x702BDAFD3C1C837B23A1CB196ED7F9FADB333C5CFE4A462BE32ADCD67BFB6AC1, p
+ ).sqrt()
+ with TemporaryConfig() as cfg:
+ cfg.ec.non_residue_action = "warning"
+ with warnings.catch_warnings(record=True) as w:
+ Mod(
+ 0x702BDAFD3C1C837B23A1CB196ED7F9FADB333C5CFE4A462BE32ADCD67BFB6AC1,
+ p,
+ ).sqrt()
+ assert issubclass(w[0].category, NonResidueWarning)
+ assert Mod(0, p).sqrt() == Mod(0, p)
+ q = 0x75D44FEE9A71841AE8403C0C251FBAD
+ assert Mod(0x591E0DB18CF1BD81A11B2985A821EB3, q).sqrt() in \
+ (0x113B41A1A2B73F636E73BE3F9A3716E, 0x64990E4CF7BA44B779CC7DCC8AE8A3F)
+ getconfig().ec.non_residue_action = "error"
+
- def test_eq(self):
- self.assertEqual(Mod(1, 7), 1)
- self.assertNotEqual(Mod(1, 7), "1")
- self.assertEqual(Mod(1, 7), Mod(1, 7))
- self.assertNotEqual(Mod(1, 7), Mod(5, 7))
- self.assertNotEqual(Mod(1, 7), Mod(1, 5))
+def test_eq():
+ assert Mod(1, 7) == 1
+ assert Mod(1, 7) != "1"
+ assert Mod(1, 7) == Mod(1, 7)
+ assert Mod(1, 7) != Mod(5, 7)
+ assert Mod(1, 7) != Mod(1, 5)
- def test_pow(self):
- a = Mod(5, 7)
- self.assertEqual(a ** (-1), a.inverse())
- self.assertEqual(a ** 0, Mod(1, 7))
- self.assertEqual(a ** (-2), a.inverse() ** 2)
- def test_wrong_mod(self):
- a = Mod(5, 7)
- b = Mod(4, 11)
- with self.assertRaises(ValueError):
- a + b
+def test_pow():
+ a = Mod(5, 7)
+ assert a ** (-1) == a.inverse()
+ assert a ** 0 == Mod(1, 7)
+ assert a ** (-2) == a.inverse() ** 2
- def test_wrong_pow(self):
- a = Mod(5, 7)
- c = Mod(4, 11)
- with self.assertRaises(TypeError):
- a ** c
- def test_other(self):
- a = Mod(5, 7)
- b = Mod(3, 7)
- self.assertEqual(int(-a), 2)
- self.assertEqual(str(a), "5")
- self.assertEqual(6 - a, Mod(1, 7))
- self.assertNotEqual(a, b)
- self.assertEqual(a / b, Mod(4, 7))
- self.assertEqual(a // b, Mod(4, 7))
- self.assertEqual(5 / b, Mod(4, 7))
- self.assertEqual(5 // b, Mod(4, 7))
- self.assertEqual(a / 3, Mod(4, 7))
- self.assertEqual(a // 3, Mod(4, 7))
- self.assertEqual(divmod(a, b), (Mod(1, 7), Mod(2, 7)))
- self.assertEqual(a + b, Mod(1, 7))
- self.assertEqual(5 + b, Mod(1, 7))
- self.assertEqual(a + 3, Mod(1, 7))
- self.assertNotEqual(a, 6)
- self.assertIsNotNone(hash(a))
+def test_wrong_mod():
+ a = Mod(5, 7)
+ b = Mod(4, 11)
+ with pytest.raises(ValueError):
+ a + b
- def test_undefined(self):
- u = Undefined()
- for k, meth in u.__class__.__dict__.items():
- if k in (
+
+def test_wrong_pow():
+ a = Mod(5, 7)
+ c = Mod(4, 11)
+ with pytest.raises(TypeError):
+ a ** c
+
+
+def test_other():
+ a = Mod(5, 7)
+ b = Mod(3, 7)
+ assert int(-a) == 2
+ assert str(a) == "5"
+ assert 6 - a == Mod(1, 7)
+ assert a != b
+ assert a / b == Mod(4, 7)
+ assert a // b == Mod(4, 7)
+ assert 5 / b == Mod(4, 7)
+ assert 5 // b == Mod(4, 7)
+ assert a / 3 == Mod(4, 7)
+ assert a // 3 == Mod(4, 7)
+ assert divmod(a, b) == (Mod(1, 7), Mod(2, 7))
+ assert a + b == Mod(1, 7)
+ assert 5 + b == Mod(1, 7)
+ assert a + 3 == Mod(1, 7)
+ assert a != 6
+ assert hash(a) is not None
+
+
+def test_undefined():
+ u = Undefined()
+ for k, meth in u.__class__.__dict__.items():
+ if k in (
"__module__",
"__new__",
"__init__",
@@ -179,52 +176,54 @@ class ModTests(TestCase):
"__slots__",
"x",
"n"
- ):
- continue
- args = [5 for _ in range(meth.__code__.co_argcount - 1)]
- if k == "__repr__":
- self.assertEqual(meth(u), "Undefined")
- elif k in ("__eq__", "__ne__"):
- assert not meth(u, *args)
- else:
- try:
- res = meth(u, *args)
- self.assertEqual(res, NotImplemented)
- except NotImplementedError:
- pass
+ ):
+ continue
+ args = [5 for _ in range(meth.__code__.co_argcount - 1)]
+ if k == "__repr__":
+ assert meth(u) == "Undefined"
+ elif k in ("__eq__", "__ne__"):
+ assert not meth(u, *args)
+ else:
+ try:
+ res = meth(u, *args)
+ assert res == NotImplemented
+ except NotImplementedError:
+ pass
+
+
+def test_implementation():
+ if not has_gmp:
+ pytest.skip("Only makes sense if more Mod implementations are available.")
+ with TemporaryConfig() as cfg:
+ cfg.ec.mod_implementation = "python"
+ assert isinstance(Mod(5, 7), RawMod)
- def test_implementation(self):
- if not has_gmp:
- self.skipTest("Only makes sense if more Mod implementations are available.")
- with TemporaryConfig() as cfg:
- cfg.ec.mod_implementation = "python"
- self.assertIsInstance(Mod(5, 7), RawMod)
- def test_symbolic(self):
- x = symbols("x")
- p = 13
- k = FF(p)
- sx = SymbolicMod(x, p)
- a = k(3)
- b = k(5)
- r = sx * a + b
- self.assertIsInstance(r, SymbolicMod)
- self.assertEqual(r.n, p)
- sa = SymbolicMod(a, p)
- sb = SymbolicMod(b, p)
- self.assertEqual(sa, 3)
- self.assertEqual(sa.inverse(), SymbolicMod(k(9), p))
- self.assertEqual(1 / sa, SymbolicMod(k(9), p))
- self.assertEqual(sa + sb, 8)
- self.assertEqual(1 + sa, 4)
- self.assertEqual(sa - 1, 2)
- self.assertEqual(1 - sa, 11)
- self.assertEqual(sa + 1, 4)
- self.assertEqual(-sa, 10)
- self.assertEqual(sa / 2, 8)
- self.assertEqual(2 / sa, 5)
- self.assertEqual(sa // 2, 8)
- self.assertEqual(2 // sa, 5)
- self.assertEqual(int(sa), 3)
- self.assertNotEqual(sa, sb)
- self.assertIsNotNone(hash(sa))
+def test_symbolic():
+ x = symbols("x")
+ p = 13
+ k = FF(p)
+ sx = SymbolicMod(x, p)
+ a = k(3)
+ b = k(5)
+ r = sx * a + b
+ assert isinstance(r, SymbolicMod)
+ assert r.n == p
+ sa = SymbolicMod(a, p)
+ sb = SymbolicMod(b, p)
+ assert sa == 3
+ assert sa.inverse() == SymbolicMod(k(9), p)
+ assert 1 / sa == SymbolicMod(k(9), p)
+ assert sa + sb == 8
+ assert 1 + sa == 4
+ assert sa - 1 == 2
+ assert 1 - sa == 11
+ assert sa + 1 == 4
+ assert -sa == 10
+ assert sa / 2 == 8
+ assert 2 / sa == 5
+ assert sa // 2 == 8
+ assert 2 // sa == 5
+ assert int(sa) == 3
+ assert sa != sb
+ assert hash(sa) is not None
diff --git a/test/ec/test_model.py b/test/ec/test_model.py
index d1c03c3..d5c5afe 100644
--- a/test/ec/test_model.py
+++ b/test/ec/test_model.py
@@ -1,5 +1,3 @@
-from unittest import TestCase
-
from pyecsca.ec.model import (
ShortWeierstrassModel,
MontgomeryModel,
@@ -8,9 +6,8 @@ from pyecsca.ec.model import (
)
-class CurveModelTests(TestCase):
- def test_load(self):
- self.assertGreater(len(ShortWeierstrassModel().coordinates), 0)
- self.assertGreater(len(MontgomeryModel().coordinates), 0)
- self.assertGreater(len(EdwardsModel().coordinates), 0)
- self.assertGreater(len(TwistedEdwardsModel().coordinates), 0)
+def test_load():
+ assert len(ShortWeierstrassModel().coordinates) > 0
+ assert len(MontgomeryModel().coordinates) > 0
+ assert len(EdwardsModel().coordinates) > 0
+ assert len(TwistedEdwardsModel().coordinates) > 0
diff --git a/test/ec/test_mult.py b/test/ec/test_mult.py
index 5200520..91ef6dd 100644
--- a/test/ec/test_mult.py
+++ b/test/ec/test_mult.py
@@ -1,5 +1,6 @@
from unittest import TestCase
+import pytest
from parameterized import parameterized
from pyecsca.ec.params import get_params
@@ -13,320 +14,316 @@ from pyecsca.ec.mult import (
DifferentialLadderMultiplier,
CoronMultiplier,
)
-from pyecsca.ec.point import InfinityPoint
+from pyecsca.ec.point import InfinityPoint, Point
from .utils import cartesian
-class ScalarMultiplierTests(TestCase):
- def setUp(self):
- self.secp128r1 = get_params("secg", "secp128r1", "projective")
- self.base = self.secp128r1.generator
- self.coords = self.secp128r1.curve.coordinate_model
+def get_formulas(coords, *names):
+ return [coords.formulas[name] for name in names if name is not None]
- self.curve25519 = get_params("other", "Curve25519", "xz")
- self.base25519 = self.curve25519.generator
- self.coords25519 = self.curve25519.curve.coordinate_model
- def get_formulas(self, coords, *names):
- return [coords.formulas[name] for name in names if name is not None]
+def assert_pt_equality(one: Point, other: Point, scale):
+ if scale:
+ assert one == other
+ else:
+ assert one.equals(other)
- def assertPointEquality(self, one, other, scale):
- if scale:
- self.assertEqual(one, other)
- else:
- assert one.equals(other)
- def do_basic_test(
- self, mult_class, params, base, add, dbl, scale, neg=None, **kwargs
- ):
- mult = mult_class(
- *self.get_formulas(params.curve.coordinate_model, add, dbl, neg, scale),
- **kwargs
- )
- mult.init(params, base)
- res = mult.multiply(314)
- other = mult.multiply(157)
- mult.init(params, other)
- other = mult.multiply(2)
- self.assertPointEquality(res, other, scale)
- mult.init(params, base)
- self.assertEqual(InfinityPoint(params.curve.coordinate_model), mult.multiply(0))
- return res
+def do_basic_test(
+ mult_class, params, base, add, dbl, scale, neg=None, **kwargs
+):
+ mult = mult_class(
+ *get_formulas(params.curve.coordinate_model, add, dbl, neg, scale),
+ **kwargs
+ )
+ mult.init(params, base)
+ res = mult.multiply(314)
+ other = mult.multiply(157)
+ mult.init(params, other)
+ other = mult.multiply(2)
+ assert_pt_equality(res, other, scale)
+ mult.init(params, base)
+ assert InfinityPoint(params.curve.coordinate_model) == mult.multiply(0)
+ return res
+
+
+@pytest.mark.parametrize("name,add,dbl,scale",
+ [
+ ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"),
+ ("complete", "add-2016-rcb", "dbl-2016-rcb", None),
+ ("none", "add-1998-cmo", "dbl-1998-cmo", None),
+ ])
+def test_rtl(secp128r1, name, add, dbl, scale):
+ do_basic_test(RTLMultiplier, secp128r1, secp128r1.generator, add, dbl, scale)
- @parameterized.expand(
- [
- ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"),
- ("complete", "add-2016-rcb", "dbl-2016-rcb", None),
- ("none", "add-1998-cmo", "dbl-1998-cmo", None),
- ]
+
+@pytest.mark.parametrize("name,add,dbl,scale",
+ [
+ ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"),
+ ("complete", "add-2016-rcb", "dbl-2016-rcb", None),
+ ("none", "add-1998-cmo", "dbl-1998-cmo", None),
+ ])
+def test_ltr(secp128r1, name, add, dbl, scale):
+ a = do_basic_test(
+ LTRMultiplier, secp128r1, secp128r1.generator, add, dbl, scale
+ )
+ b = do_basic_test(
+ LTRMultiplier, secp128r1, secp128r1.generator, add, dbl, scale, always=True
+ )
+ c = do_basic_test(
+ LTRMultiplier, secp128r1, secp128r1.generator, add, dbl, scale, complete=False
)
- def test_rtl(self, name, add, dbl, scale):
- self.do_basic_test(RTLMultiplier, self.secp128r1, self.base, add, dbl, scale)
+ d = do_basic_test(
+ LTRMultiplier,
+ secp128r1,
+ secp128r1.generator,
+ add,
+ dbl,
+ scale,
+ always=True,
+ complete=False,
+ )
+ assert_pt_equality(a, b, scale)
+ assert_pt_equality(b, c, scale)
+ assert_pt_equality(c, d, scale)
+
+
+@pytest.mark.parametrize("name,add,dbl,scale",
+ [
+ ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"),
+ ("complete", "add-2016-rcb", "dbl-2016-rcb", None),
+ ("none", "add-1998-cmo", "dbl-1998-cmo", None),
+ ]
+ )
+def test_coron(secp128r1, name, add, dbl, scale):
+ do_basic_test(CoronMultiplier, secp128r1, secp128r1.generator, add, dbl, scale)
- @parameterized.expand(
- [
- ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"),
- ("complete", "add-2016-rcb", "dbl-2016-rcb", None),
- ("none", "add-1998-cmo", "dbl-1998-cmo", None),
- ]
+
+def test_ladder(curve25519):
+ a = do_basic_test(
+ LadderMultiplier,
+ curve25519,
+ curve25519.generator,
+ "ladd-1987-m",
+ "dbl-1987-m",
+ "scale",
)
- def test_ltr(self, name, add, dbl, scale):
- a = self.do_basic_test(
- LTRMultiplier, self.secp128r1, self.base, add, dbl, scale
- )
- b = self.do_basic_test(
- LTRMultiplier, self.secp128r1, self.base, add, dbl, scale, always=True
- )
- c = self.do_basic_test(
- LTRMultiplier, self.secp128r1, self.base, add, dbl, scale, complete=False
- )
- d = self.do_basic_test(
- LTRMultiplier,
- self.secp128r1,
- self.base,
- add,
- dbl,
- scale,
- always=True,
- complete=False,
- )
- self.assertPointEquality(a, b, scale)
- self.assertPointEquality(b, c, scale)
- self.assertPointEquality(c, d, scale)
+ b = do_basic_test(
+ LadderMultiplier,
+ curve25519,
+ curve25519.generator,
+ "ladd-1987-m",
+ "dbl-1987-m",
+ "scale",
+ complete=False,
+ )
+ assert_pt_equality(a, b, True)
+
- @parameterized.expand(
- [
- ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"),
- ("complete", "add-2016-rcb", "dbl-2016-rcb", None),
- ("none", "add-1998-cmo", "dbl-1998-cmo", None),
- ]
+@pytest.mark.parametrize("name,add,dbl,scale",
+ [
+ ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"),
+ ("complete", "add-2016-rcb", "dbl-2016-rcb", None),
+ ("none", "add-1998-cmo", "dbl-1998-cmo", None),
+ ])
+def test_simple_ladder(secp128r1, name, add, dbl, scale):
+ do_basic_test(
+ SimpleLadderMultiplier, secp128r1, secp128r1.generator, add, dbl, scale
)
- def test_coron(self, name, add, dbl, scale):
- self.do_basic_test(CoronMultiplier, self.secp128r1, self.base, add, dbl, scale)
- def test_ladder(self):
- a = self.do_basic_test(
- LadderMultiplier,
- self.curve25519,
- self.base25519,
- "ladd-1987-m",
- "dbl-1987-m",
- "scale",
- )
- b = self.do_basic_test(
- LadderMultiplier,
- self.curve25519,
- self.base25519,
- "ladd-1987-m",
- "dbl-1987-m",
- "scale",
- complete=False,
- )
- self.assertPointEquality(a, b, True)
- @parameterized.expand(
- [
- ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"),
- ("complete", "add-2016-rcb", "dbl-2016-rcb", None),
- ("none", "add-1998-cmo", "dbl-1998-cmo", None),
- ]
+@pytest.mark.parametrize("name,num,complete",
+ [
+ ("15", 15, True),
+ ("15", 15, False),
+ ("2355498743", 2355498743, True),
+ ("2355498743", 2355498743, False),
+ (
+ "325385790209017329644351321912443757746",
+ 325385790209017329644351321912443757746,
+ True,
+ ),
+ (
+ "325385790209017329644351321912443757746",
+ 325385790209017329644351321912443757746,
+ False,
+ ),
+ ])
+def test_ladder_differential(curve25519, name, num, complete):
+ ladder = LadderMultiplier(
+ curve25519.curve.coordinate_model.formulas["ladd-1987-m"],
+ curve25519.curve.coordinate_model.formulas["dbl-1987-m"],
+ curve25519.curve.coordinate_model.formulas["scale"],
+ complete=complete,
)
- def test_simple_ladder(self, name, add, dbl, scale):
- self.do_basic_test(
- SimpleLadderMultiplier, self.secp128r1, self.base, add, dbl, scale
- )
+ differential = DifferentialLadderMultiplier(
+ curve25519.curve.coordinate_model.formulas["dadd-1987-m"],
+ curve25519.curve.coordinate_model.formulas["dbl-1987-m"],
+ curve25519.curve.coordinate_model.formulas["scale"],
+ complete=complete,
+ )
+ ladder.init(curve25519, curve25519.generator)
+ res_ladder = ladder.multiply(num)
+ differential.init(curve25519, curve25519.generator)
+ res_differential = differential.multiply(num)
+ assert res_ladder == res_differential
+ assert InfinityPoint(curve25519.curve.coordinate_model) == differential.multiply(0)
+
- @parameterized.expand(
- [
- ("15", 15, True),
- ("15", 15, False),
- ("2355498743", 2355498743, True),
- ("2355498743", 2355498743, False),
- (
- "325385790209017329644351321912443757746",
- 325385790209017329644351321912443757746,
- True,
- ),
- (
- "325385790209017329644351321912443757746",
- 325385790209017329644351321912443757746,
- False,
- ),
- ]
+@pytest.mark.parametrize("name,add,dbl,neg,scale",
+ [
+ ("scaled", "add-1998-cmo", "dbl-1998-cmo", "neg", "z"),
+ ("complete", "add-2016-rcb", "dbl-2016-rcb", "neg", None),
+ ("none", "add-1998-cmo", "dbl-1998-cmo", "neg", None),
+ ])
+def test_binary_naf(secp128r1, name, add, dbl, neg, scale):
+ do_basic_test(
+ BinaryNAFMultiplier, secp128r1, secp128r1.generator, add, dbl, scale, neg
)
- def test_ladder_differential(self, name, num, complete):
- ladder = LadderMultiplier(
- self.coords25519.formulas["ladd-1987-m"],
- self.coords25519.formulas["dbl-1987-m"],
- self.coords25519.formulas["scale"],
- complete=complete,
- )
- differential = DifferentialLadderMultiplier(
- self.coords25519.formulas["dadd-1987-m"],
- self.coords25519.formulas["dbl-1987-m"],
- self.coords25519.formulas["scale"],
- complete=complete,
- )
- ladder.init(self.curve25519, self.base25519)
- res_ladder = ladder.multiply(num)
- differential.init(self.curve25519, self.base25519)
- res_differential = differential.multiply(num)
- self.assertEqual(res_ladder, res_differential)
- self.assertEqual(InfinityPoint(self.coords25519), differential.multiply(0))
- @parameterized.expand(
- [
- ("scaled", "add-1998-cmo", "dbl-1998-cmo", "neg", "z"),
- ("complete", "add-2016-rcb", "dbl-2016-rcb", "neg", None),
- ("none", "add-1998-cmo", "dbl-1998-cmo", "neg", None),
- ]
+
+@pytest.mark.parametrize("name,add,dbl,neg,width,scale",
+ [
+ ("scaled3", "add-1998-cmo", "dbl-1998-cmo", "neg", 3, "z"),
+ ("none3", "add-1998-cmo", "dbl-1998-cmo", "neg", 3, None),
+ ("complete3", "add-2016-rcb", "dbl-2016-rcb", "neg", 3, None),
+ ("scaled5", "add-1998-cmo", "dbl-1998-cmo", "neg", 5, "z"),
+ ("none5", "add-1998-cmo", "dbl-1998-cmo", "neg", 5, None),
+ ("complete5", "add-2016-rcb", "dbl-2016-rcb", "neg", 5, None),
+ ])
+def test_window_naf(secp128r1, name, add, dbl, neg, width, scale):
+ formulas = get_formulas(secp128r1.curve.coordinate_model, add, dbl, neg, scale)
+ mult = WindowNAFMultiplier(*formulas[:3], width, *formulas[3:])
+ mult.init(secp128r1, secp128r1.generator)
+ res = mult.multiply(157 * 789)
+ other = mult.multiply(157)
+ mult.init(secp128r1, other)
+ other = mult.multiply(789)
+ assert_pt_equality(res, other, scale)
+ mult.init(secp128r1, secp128r1.generator)
+ assert InfinityPoint(secp128r1.curve.coordinate_model) == mult.multiply(0)
+
+ mult = WindowNAFMultiplier(
+ *formulas[:3], width, *formulas[3:], precompute_negation=True
)
- def test_binary_naf(self, name, add, dbl, neg, scale):
- self.do_basic_test(
- BinaryNAFMultiplier, self.secp128r1, self.base, add, dbl, scale, neg
- )
+ mult.init(secp128r1, secp128r1.generator)
+ res_precompute = mult.multiply(157 * 789)
+ assert_pt_equality(res_precompute, res, scale)
+
- @parameterized.expand(
- [
- ("scaled3", "add-1998-cmo", "dbl-1998-cmo", "neg", 3, "z"),
- ("none3", "add-1998-cmo", "dbl-1998-cmo", "neg", 3, None),
- ("complete3", "add-2016-rcb", "dbl-2016-rcb", "neg", 3, None),
- ("scaled5", "add-1998-cmo", "dbl-1998-cmo", "neg", 5, "z"),
- ("none5", "add-1998-cmo", "dbl-1998-cmo", "neg", 5, None),
- ("complete5", "add-2016-rcb", "dbl-2016-rcb", "neg", 5, None),
- ]
+@pytest.mark.parametrize("name,num,add,dbl",
+ cartesian(
+ [
+ ("10", 10),
+ ("2355498743", 2355498743),
+ (
+ "325385790209017329644351321912443757746",
+ 325385790209017329644351321912443757746,
+ ),
+ ],
+ [("add-1998-cmo", "dbl-1998-cmo"), ("add-2016-rcb", "dbl-2016-rcb")],
+ )
+ )
+def test_basic_multipliers(secp128r1, name, num, add, dbl):
+ ltr = LTRMultiplier(
+ secp128r1.curve.coordinate_model.formulas[add],
+ secp128r1.curve.coordinate_model.formulas[dbl],
+ secp128r1.curve.coordinate_model.formulas["z"],
+ )
+ with pytest.raises(ValueError):
+ ltr.multiply(1)
+ ltr.init(secp128r1, secp128r1.generator)
+ res_ltr = ltr.multiply(num)
+ rtl = RTLMultiplier(
+ secp128r1.curve.coordinate_model.formulas[add],
+ secp128r1.curve.coordinate_model.formulas["dbl-1998-cmo"],
+ secp128r1.curve.coordinate_model.formulas["z"],
)
- def test_window_naf(self, name, add, dbl, neg, width, scale):
- formulas = self.get_formulas(self.coords, add, dbl, neg, scale)
- mult = WindowNAFMultiplier(*formulas[:3], width, *formulas[3:])
- mult.init(self.secp128r1, self.base)
- res = mult.multiply(157 * 789)
- other = mult.multiply(157)
- mult.init(self.secp128r1, other)
- other = mult.multiply(789)
- self.assertPointEquality(res, other, scale)
- mult.init(self.secp128r1, self.base)
- self.assertEqual(InfinityPoint(self.coords), mult.multiply(0))
+ with pytest.raises(ValueError):
+ rtl.multiply(1)
+ rtl.init(secp128r1, secp128r1.generator)
+ res_rtl = rtl.multiply(num)
+ assert res_ltr == res_rtl
- mult = WindowNAFMultiplier(
- *formulas[:3], width, *formulas[3:], precompute_negation=True
- )
- mult.init(self.secp128r1, self.base)
- res_precompute = mult.multiply(157 * 789)
- self.assertPointEquality(res_precompute, res, scale)
+ ltr_always = LTRMultiplier(
+ secp128r1.curve.coordinate_model.formulas[add],
+ secp128r1.curve.coordinate_model.formulas[dbl],
+ secp128r1.curve.coordinate_model.formulas["z"],
+ always=True,
+ )
+ rtl_always = RTLMultiplier(
+ secp128r1.curve.coordinate_model.formulas[add],
+ secp128r1.curve.coordinate_model.formulas[dbl],
+ secp128r1.curve.coordinate_model.formulas["z"],
+ always=True,
+ )
+ ltr_always.init(secp128r1, secp128r1.generator)
+ rtl_always.init(secp128r1, secp128r1.generator)
+ res_ltr_always = ltr_always.multiply(num)
+ res_rtl_always = rtl_always.multiply(num)
+ assert res_ltr == res_ltr_always
+ assert res_rtl == res_rtl_always
- @parameterized.expand(
- cartesian(
- [
- ("10", 10),
- ("2355498743", 2355498743),
- (
- "325385790209017329644351321912443757746",
- 325385790209017329644351321912443757746,
- ),
- ],
- [("add-1998-cmo", "dbl-1998-cmo"), ("add-2016-rcb", "dbl-2016-rcb")],
- )
+ bnaf = BinaryNAFMultiplier(
+ secp128r1.curve.coordinate_model.formulas[add],
+ secp128r1.curve.coordinate_model.formulas[dbl],
+ secp128r1.curve.coordinate_model.formulas["neg"],
+ secp128r1.curve.coordinate_model.formulas["z"],
)
- def test_basic_multipliers(self, name, num, add, dbl):
- ltr = LTRMultiplier(
- self.coords.formulas[add],
- self.coords.formulas[dbl],
- self.coords.formulas["z"],
- )
- with self.assertRaises(ValueError):
- ltr.multiply(1)
- ltr.init(self.secp128r1, self.base)
- res_ltr = ltr.multiply(num)
- rtl = RTLMultiplier(
- self.coords.formulas[add],
- self.coords.formulas["dbl-1998-cmo"],
- self.coords.formulas["z"],
- )
- with self.assertRaises(ValueError):
- rtl.multiply(1)
- rtl.init(self.secp128r1, self.base)
- res_rtl = rtl.multiply(num)
- self.assertEqual(res_ltr, res_rtl)
+ with pytest.raises(ValueError):
+ bnaf.multiply(1)
+ bnaf.init(secp128r1, secp128r1.generator)
+ res_bnaf = bnaf.multiply(num)
+ assert res_bnaf == res_ltr
- ltr_always = LTRMultiplier(
- self.coords.formulas[add],
- self.coords.formulas[dbl],
- self.coords.formulas["z"],
- always=True,
- )
- rtl_always = RTLMultiplier(
- self.coords.formulas[add],
- self.coords.formulas[dbl],
- self.coords.formulas["z"],
- always=True,
- )
- ltr_always.init(self.secp128r1, self.base)
- rtl_always.init(self.secp128r1, self.base)
- res_ltr_always = ltr_always.multiply(num)
- res_rtl_always = rtl_always.multiply(num)
- self.assertEqual(res_ltr, res_ltr_always)
- self.assertEqual(res_rtl, res_rtl_always)
+ wnaf = WindowNAFMultiplier(
+ secp128r1.curve.coordinate_model.formulas[add],
+ secp128r1.curve.coordinate_model.formulas[dbl],
+ secp128r1.curve.coordinate_model.formulas["neg"],
+ 3,
+ secp128r1.curve.coordinate_model.formulas["z"],
+ )
+ with pytest.raises(ValueError):
+ wnaf.multiply(1)
+ wnaf.init(secp128r1, secp128r1.generator)
+ res_wnaf = wnaf.multiply(num)
+ assert res_wnaf == res_ltr
- bnaf = BinaryNAFMultiplier(
- self.coords.formulas[add],
- self.coords.formulas[dbl],
- self.coords.formulas["neg"],
- self.coords.formulas["z"],
- )
- with self.assertRaises(ValueError):
- bnaf.multiply(1)
- bnaf.init(self.secp128r1, self.base)
- res_bnaf = bnaf.multiply(num)
- self.assertEqual(res_bnaf, res_ltr)
+ ladder = SimpleLadderMultiplier(
+ secp128r1.curve.coordinate_model.formulas[add],
+ secp128r1.curve.coordinate_model.formulas[dbl],
+ secp128r1.curve.coordinate_model.formulas["z"],
+ )
+ with pytest.raises(ValueError):
+ ladder.multiply(1)
+ ladder.init(secp128r1, secp128r1.generator)
+ res_ladder = ladder.multiply(num)
+ assert res_ladder == res_ltr
- wnaf = WindowNAFMultiplier(
- self.coords.formulas[add],
- self.coords.formulas[dbl],
- self.coords.formulas["neg"],
- 3,
- self.coords.formulas["z"],
- )
- with self.assertRaises(ValueError):
- wnaf.multiply(1)
- wnaf.init(self.secp128r1, self.base)
- res_wnaf = wnaf.multiply(num)
- self.assertEqual(res_wnaf, res_ltr)
+ coron = CoronMultiplier(
+ secp128r1.curve.coordinate_model.formulas[add],
+ secp128r1.curve.coordinate_model.formulas[dbl],
+ secp128r1.curve.coordinate_model.formulas["z"],
+ )
+ with pytest.raises(ValueError):
+ coron.multiply(1)
+ coron.init(secp128r1, secp128r1.generator)
+ res_coron = coron.multiply(num)
+ assert res_coron == res_ltr
- ladder = SimpleLadderMultiplier(
- self.coords.formulas[add],
- self.coords.formulas[dbl],
- self.coords.formulas["z"],
- )
- with self.assertRaises(ValueError):
- ladder.multiply(1)
- ladder.init(self.secp128r1, self.base)
- res_ladder = ladder.multiply(num)
- self.assertEqual(res_ladder, res_ltr)
- coron = CoronMultiplier(
- self.coords.formulas[add],
- self.coords.formulas[dbl],
- self.coords.formulas["z"],
- )
- with self.assertRaises(ValueError):
- coron.multiply(1)
- coron.init(self.secp128r1, self.base)
- res_coron = coron.multiply(num)
- self.assertEqual(res_coron, res_ltr)
+def test_init_fail(curve25519, secp128r1):
+ mult = DifferentialLadderMultiplier(
+ curve25519.curve.coordinate_model.formulas["dadd-1987-m"],
+ curve25519.curve.coordinate_model.formulas["dbl-1987-m"],
+ curve25519.curve.coordinate_model.formulas["scale"],
+ )
+ with pytest.raises(ValueError):
+ mult.init(secp128r1, secp128r1.generator)
- def test_init_fail(self):
- mult = DifferentialLadderMultiplier(
- self.coords25519.formulas["dadd-1987-m"],
- self.coords25519.formulas["dbl-1987-m"],
- self.coords25519.formulas["scale"],
+ with pytest.raises(ValueError):
+ LadderMultiplier(
+ curve25519.curve.coordinate_model.formulas["ladd-1987-m"],
+ scl=curve25519.curve.coordinate_model.formulas["scale"],
+ complete=False,
)
- with self.assertRaises(ValueError):
- mult.init(self.secp128r1, self.base)
-
- with self.assertRaises(ValueError):
- LadderMultiplier(
- self.coords25519.formulas["ladd-1987-m"],
- scl=self.coords25519.formulas["scale"],
- complete=False,
- )
diff --git a/test/ec/test_naf.py b/test/ec/test_naf.py
index bdc176a..3e7c444 100644
--- a/test/ec/test_naf.py
+++ b/test/ec/test_naf.py
@@ -1,9 +1,6 @@
-from unittest import TestCase
-
from pyecsca.ec.naf import naf, wnaf
-class NafTests(TestCase):
- def test_nafs(self):
- i = 0b1100110101001101011011
- self.assertListEqual(naf(i), wnaf(i, 2))
+def test_nafs():
+ i = 0b1100110101001101011011
+ assert naf(i) == wnaf(i, 2)
diff --git a/test/ec/test_op.py b/test/ec/test_op.py
index e418350..94edcc3 100644
--- a/test/ec/test_op.py
+++ b/test/ec/test_op.py
@@ -1,49 +1,30 @@
from ast import parse
-from unittest import TestCase
-from parameterized import parameterized
-
-from pyecsca.ec.formula import OpResult
+import pytest
from pyecsca.ec.mod import Mod
from pyecsca.ec.op import CodeOp, OpType
-class OpTests(TestCase):
- @parameterized.expand(
- [
- ("add", "x = a+b", "x = a+b", OpType.Add),
- ("sub", "x = a-b", "x = a-b", OpType.Sub),
- ("mul", "y = a*b", "y = a*b", OpType.Mult),
- ("div", "z = a/b", "z = a/b", OpType.Div),
- ("inv", "z = 1/b", "z = 1/b", OpType.Inv),
- ("pow", "b = a**d", "b = a^d", OpType.Pow),
- ("sqr", "b = a**2", "b = a^2", OpType.Sqr),
- ("id1", "b = 7", "b = 7", OpType.Id),
- ("id2", "b = a", "b = a", OpType.Id),
- ]
- )
- def test_str(self, name, module, result, op_type):
- code = parse(module, mode="exec")
- op = CodeOp(code)
- self.assertEqual(str(op), result)
- self.assertEqual(op.operator, op_type)
+@pytest.mark.parametrize("name,module,result,op_type",
+ [("add", "x = a+b", "x = a+b", OpType.Add), ("sub", "x = a-b", "x = a-b", OpType.Sub),
+ ("mul", "y = a*b", "y = a*b", OpType.Mult), ("div", "z = a/b", "z = a/b", OpType.Div),
+ ("inv", "z = 1/b", "z = 1/b", OpType.Inv), ("pow", "b = a**d", "b = a^d", OpType.Pow),
+ ("sqr", "b = a**2", "b = a^2", OpType.Sqr), ("id1", "b = 7", "b = 7", OpType.Id),
+ ("id2", "b = a", "b = a", OpType.Id), ])
+def test_str(name, module, result, op_type):
+ code = parse(module, mode="exec")
+ op = CodeOp(code)
+ assert str(op) == result
+ assert op.operator == op_type
- @parameterized.expand(
- [
- ("add", "x = a+b", {"a": Mod(5, 21), "b": Mod(7, 21)}, Mod(12, 21)),
- ("sub", "x = a-b", {"a": Mod(7, 21), "b": Mod(5, 21)}, Mod(2, 21)),
- ]
- )
- def test_call(self, name, module, locals, result):
- code = parse(module, mode="exec")
- op = CodeOp(code)
- res = op(**locals)
- self.assertEqual(res, result)
+@pytest.mark.parametrize("name,module,locals,result",
+ [("add", "x = a+b", {"a": Mod(5, 21), "b": Mod(7, 21)}, Mod(12, 21)),
+ ("sub", "x = a-b", {"a": Mod(7, 21), "b": Mod(5, 21)}, Mod(2, 21)), ])
+def test_call(name, module, locals, result):
+ code = parse(module, mode="exec")
+ op = CodeOp(code)
+ res = op(**locals)
+ assert res == result
-class OpResultTests(TestCase):
- def test_str(self):
- for op in (OpType.Add, OpType.Sub, OpType.Mult, OpType.Div):
- res = OpResult("X1", Mod(0, 5), op, Mod(2, 5), Mod(3, 5))
- self.assertEqual(str(res), "X1")
- self.assertEqual(repr(res), f"X1 = 2{op.op_str}3")
+# TODO: Add op_type tests
diff --git a/test/ec/test_params.py b/test/ec/test_params.py
index 9f18ded..5441ed0 100644
--- a/test/ec/test_params.py
+++ b/test/ec/test_params.py
@@ -3,6 +3,8 @@ from unittest import TestCase
from parameterized import parameterized
from importlib.resources import files, as_file
+import pytest
+
import test.data.ec
from pyecsca.ec.mod import Mod
from pyecsca.ec.point import Point, InfinityPoint
@@ -15,125 +17,131 @@ from pyecsca.ec.model import ShortWeierstrassModel
from pyecsca.ec.curve import EllipticCurve
-class DomainParameterTests(TestCase):
- def setUp(self):
- self.secp128r1 = get_params("secg", "secp128r1", "projective")
- self.curve25519 = get_params("other", "Curve25519", "xz")
+def test_eq(secp128r1, curve25519):
+ assert secp128r1 == secp128r1
+ assert secp128r1 != curve25519
+ assert secp128r1 is not None
+
+
+def test_str(secp128r1):
+ assert str(secp128r1) == "DomainParameters(secg/secp128r1)"
+
- def test_eq(self):
- self.assertEqual(self.secp128r1, self.secp128r1)
- self.assertNotEqual(self.secp128r1, self.curve25519)
- self.assertNotEqual(self.secp128r1, None)
+@pytest.mark.parametrize("name,coords",
+ [
+ ("secg/secp128r1", "projective"),
+ ("secg/secp256r1", "projective"),
+ ("secg/secp521r1", "projective"),
+ ("other/Curve25519", "xz"),
+ ("other/Ed25519", "projective"),
+ ("other/Ed448", "projective"),
+ ("other/E-222", "projective"),
+ ])
+def test_get_params(name, coords):
+ params = get_params(*name.split("/"), coords)
+ try:
+ assert params.curve.is_on_curve(params.generator)
+ except NotImplementedError:
+ pass
- def test_str(self):
- self.assertEqual(str(self.secp128r1), "DomainParameters(secg/secp128r1)")
- @parameterized.expand(
- [
- ("secg/secp128r1", "projective"),
- ("secg/secp256r1", "projective"),
- ("secg/secp521r1", "projective"),
- ("other/Curve25519", "xz"),
- ("other/Ed25519", "projective"),
- ("other/Ed448", "projective"),
- ("other/E-222", "projective"),
- ]
- )
- def test_get_params(self, name, coords):
- params = get_params(*name.split("/"), coords)
+@pytest.mark.parametrize("name,coords",
+ [
+ ("anssi", "projective"),
+ (
+ "brainpool",
+ lambda name: "projective" if name.endswith("r1") else "jacobian",
+ ),
+ ])
+def test_get_category(name, coords):
+ get_category(name, coords)
+
+
+def test_load_params():
+ with as_file(files(test.data.ec).joinpath("curve.json")) as path:
+ params = load_params(path, "projective")
try:
assert params.curve.is_on_curve(params.generator)
except NotImplementedError:
pass
- @parameterized.expand(
- [
- ("anssi", "projective"),
- (
- "brainpool",
- lambda name: "projective" if name.endswith("r1") else "jacobian",
- ),
- ]
- )
- def test_get_category(self, name, coords):
- get_category(name, coords)
- def test_load_params(self):
- with as_file(files(test.data.ec).joinpath("curve.json")) as path:
- params = load_params(path, "projective")
- try:
- assert params.curve.is_on_curve(params.generator)
- except NotImplementedError:
- pass
+def test_load_params_ectester(secp128r1):
+ with as_file(files(test.data.ec).joinpath("ectester_secp128r1.csv")) as path:
+ params = load_params_ectester(path, "projective")
+ assert params.curve.is_on_curve(params.generator)
+ assert params == secp128r1
- def test_load_params_ectester(self):
- with as_file(files(test.data.ec).joinpath("ectester_secp128r1.csv")) as path:
- params = load_params_ectester(path, "projective")
- assert params.curve.is_on_curve(params.generator)
- self.assertEqual(params, self.secp128r1)
- def test_load_params_ecgen(self):
- with as_file(files(test.data.ec).joinpath("ecgen_secp128r1.json")) as path:
- params = load_params_ecgen(path, "projective")
- assert params.curve.is_on_curve(params.generator)
- self.assertEqual(params, self.secp128r1)
+def test_load_params_ecgen(secp128r1):
+ with as_file(files(test.data.ec).joinpath("ecgen_secp128r1.json")) as path:
+ params = load_params_ecgen(path, "projective")
+ assert params.curve.is_on_curve(params.generator)
+ assert params == secp128r1
+
+
+def test_load_category():
+ with as_file(files(test.data.ec).joinpath("curves.json")) as path:
+ category = load_category(path, "yz")
+ assert len(category) == 1
+
+
+@pytest.mark.parametrize("name,coords",
+ [
+ ("no_category/some", "else"),
+ ("secg/no_curve", "else"),
+ ("secg/secp128r1", "some"),
+ ])
+def test_unknown(name, coords):
+ with pytest.raises(ValueError):
+ get_params(*name.split("/"), coords)
+
+
+def test_assumption():
+ with pytest.raises(UnsatisfiedAssumptionError):
+ get_params("secg", "secp128r1", "projective-1")
+ with TemporaryConfig() as cfg:
+ cfg.ec.unsatisfied_coordinate_assumption_action = "ignore"
+ params = get_params("secg", "secp128r1", "projective-1")
+ assert params is not None
+ assert get_params("secg", "secp128r1", "projective-3") is not None
+
+
+def test_infty():
+ with pytest.raises(ValueError):
+ get_params("other", "Ed25519", "modified", False)
+ assert get_params("secg", "secp128r1", "projective", False) is not None
- def test_load_category(self):
- with as_file(files(test.data.ec).joinpath("curves.json")) as path:
- category = load_category(path, "yz")
- self.assertEqual(len(category), 1)
- @parameterized.expand(
- [
- ("no_category/some", "else"),
- ("secg/no_curve", "else"),
- ("secg/secp128r1", "some"),
- ]
- )
- def test_unknown(self, name, coords):
- with self.assertRaises(ValueError):
- get_params(*name.split("/"), coords)
+def test_no_binary():
+ with pytest.raises(ValueError):
+ get_params("secg", "sect163r1", "something")
- def test_assumption(self):
- with self.assertRaises(UnsatisfiedAssumptionError):
- get_params("secg", "secp128r1", "projective-1")
- with TemporaryConfig() as cfg:
- cfg.ec.unsatisfied_coordinate_assumption_action = "ignore"
- params = get_params("secg", "secp128r1", "projective-1")
- self.assertIsNotNone(params)
- self.assertIsNotNone(get_params("secg", "secp128r1", "projective-3"))
- def test_infty(self):
- with self.assertRaises(ValueError):
- get_params("other", "Ed25519", "modified", False)
- self.assertIsNotNone(get_params("secg", "secp128r1", "projective", False))
+def test_no_extension():
+ with pytest.raises(ValueError):
+ get_params("other", "Fp254n2BNa", "something")
- def test_no_binary(self):
- with self.assertRaises(ValueError):
- get_params("secg", "sect163r1", "something")
- def test_no_extension(self):
- with self.assertRaises(ValueError):
- get_params("other", "Fp254n2BNa", "something")
+def test_affine():
+ aff = get_params("secg", "secp128r1", "affine")
+ assert isinstance(aff.curve.coordinate_model, AffineCoordinateModel)
- def test_affine(self):
- aff = get_params("secg", "secp128r1", "affine")
- self.assertIsInstance(aff.curve.coordinate_model, AffineCoordinateModel)
- def test_custom_params(self):
- model = ShortWeierstrassModel()
- coords = model.coordinates["projective"]
- p = 0xd7d1247f
- a = Mod(0xa4a44016, p)
- b = Mod(0x73f76716, p)
- n = 0xd7d2a475
- h = 1
- gx, gy, gz = Mod(0x54eed6d7, p), Mod(0x6f1e55ac, p), Mod(1, p)
- generator = Point(coords, X=gx, Y=gy, Z=gz)
- neutral = InfinityPoint(coords)
+def test_custom_params():
+ model = ShortWeierstrassModel()
+ coords = model.coordinates["projective"]
+ p = 0xd7d1247f
+ a = Mod(0xa4a44016, p)
+ b = Mod(0x73f76716, p)
+ n = 0xd7d2a475
+ h = 1
+ gx, gy, gz = Mod(0x54eed6d7, p), Mod(0x6f1e55ac, p), Mod(1, p)
+ generator = Point(coords, X=gx, Y=gy, Z=gz)
+ neutral = InfinityPoint(coords)
- curve = EllipticCurve(model, coords, p, neutral, {"a": a, "b": b})
- params = DomainParameters(curve, generator, n, h)
- self.assertIsNotNone(params)
- res = params.curve.affine_double(generator.to_affine())
- self.assertIsNotNone(res)
+ curve = EllipticCurve(model, coords, p, neutral, {"a": a, "b": b})
+ params = DomainParameters(curve, generator, n, h)
+ assert params is not None
+ res = params.curve.affine_double(generator.to_affine())
+ assert res is not None
diff --git a/test/ec/test_point.py b/test/ec/test_point.py
index b2096be..b09ca30 100644
--- a/test/ec/test_point.py
+++ b/test/ec/test_point.py
@@ -5,6 +5,7 @@ from pyecsca.ec.params import get_params
from pyecsca.ec.mod import Mod
from pyecsca.ec.model import ShortWeierstrassModel, MontgomeryModel
from pyecsca.ec.point import Point, InfinityPoint
+import pytest
class PointTests(TestCase):
@@ -14,131 +15,146 @@ class PointTests(TestCase):
self.coords = self.secp128r1.curve.coordinate_model
self.affine = AffineCoordinateModel(ShortWeierstrassModel())
- def test_construction(self):
- with self.assertRaises(ValueError):
- Point(self.coords)
- def test_to_affine(self):
- pt = Point(
- self.coords,
- X=Mod(0x161FF7528B899B2D0C28607CA52C5B86, self.secp128r1.curve.prime),
- Y=Mod(0xCF5AC8395BAFEB13C02DA292DDED7A83, self.secp128r1.curve.prime),
- Z=Mod(1, self.secp128r1.curve.prime),
- )
- affine = pt.to_affine()
+@pytest.fixture()
+def coords(secp128r1):
+ return secp128r1.curve.coordinate_model
- self.assertIsInstance(affine.coordinate_model, AffineCoordinateModel)
- self.assertSetEqual(set(affine.coords.keys()), set(self.affine.variables))
- self.assertEqual(affine.coords["x"], pt.coords["X"])
- self.assertEqual(affine.coords["y"], pt.coords["Y"])
- self.assertEqual(affine.to_affine(), affine)
- affine = InfinityPoint(self.coords).to_affine()
- self.assertIsInstance(affine, InfinityPoint)
+@pytest.fixture()
+def affine_model():
+ return AffineCoordinateModel(ShortWeierstrassModel())
- def test_to_model(self):
- affine = Point(
- self.affine,
- x=Mod(0xABCD, self.secp128r1.curve.prime),
- y=Mod(0xEF, self.secp128r1.curve.prime),
- )
- projective_model = self.coords
- other = affine.to_model(projective_model, self.secp128r1.curve)
- self.assertEqual(other.coordinate_model, projective_model)
- self.assertSetEqual(set(other.coords.keys()), set(projective_model.variables))
- self.assertEqual(other.coords["X"], affine.coords["x"])
- self.assertEqual(other.coords["Y"], affine.coords["y"])
- self.assertEqual(other.coords["Z"], Mod(1, self.secp128r1.curve.prime))
+def test_construction(coords):
+ with pytest.raises(ValueError):
+ Point(coords)
- infty = InfinityPoint(AffineCoordinateModel(self.secp128r1.curve.model))
- other_infty = infty.to_model(self.coords, self.secp128r1.curve)
- self.assertIsInstance(other_infty, InfinityPoint)
- with self.assertRaises(ValueError):
- self.base.to_model(self.coords, self.secp128r1.curve)
+def test_to_affine(secp128r1, coords, affine_model):
+ pt = Point(
+ coords,
+ X=Mod(0x161FF7528B899B2D0C28607CA52C5B86, secp128r1.curve.prime),
+ Y=Mod(0xCF5AC8395BAFEB13C02DA292DDED7A83, secp128r1.curve.prime),
+ Z=Mod(1, secp128r1.curve.prime),
+ )
+ affine = pt.to_affine()
- def test_to_from_affine(self):
- pt = Point(
- self.coords,
- X=Mod(0x161FF7528B899B2D0C28607CA52C5B86, self.secp128r1.curve.prime),
- Y=Mod(0xCF5AC8395BAFEB13C02DA292DDED7A83, self.secp128r1.curve.prime),
- Z=Mod(1, self.secp128r1.curve.prime),
- )
- other = pt.to_affine().to_model(self.coords, self.secp128r1.curve)
- self.assertEqual(pt, other)
+ assert isinstance(affine.coordinate_model, AffineCoordinateModel)
+ assert set(affine.coords.keys()) == set(affine_model.variables)
+ assert affine.coords["x"] == pt.coords["X"]
+ assert affine.coords["y"] == pt.coords["Y"]
+ assert affine.to_affine() == affine
- def test_equals(self):
- pt = Point(
- self.coords,
- X=Mod(0x4, self.secp128r1.curve.prime),
- Y=Mod(0x6, self.secp128r1.curve.prime),
- Z=Mod(2, self.secp128r1.curve.prime),
- )
- other = Point(
- self.coords,
- X=Mod(0x2, self.secp128r1.curve.prime),
- Y=Mod(0x3, self.secp128r1.curve.prime),
- Z=Mod(1, self.secp128r1.curve.prime),
- )
- third = Point(
- self.coords,
- X=Mod(0x5, self.secp128r1.curve.prime),
- Y=Mod(0x3, self.secp128r1.curve.prime),
- Z=Mod(1, self.secp128r1.curve.prime),
- )
- self.assertTrue(pt.equals(other))
- self.assertNotEqual(pt, other)
- self.assertFalse(pt.equals(2))
- self.assertNotEqual(pt, 2)
- self.assertFalse(pt.equals(third))
- self.assertNotEqual(pt, third)
- self.assertTrue(pt.equals_scaled(other))
- self.assertTrue(pt.equals_affine(other))
- self.assertFalse(pt.equals_scaled(third))
+ affine = InfinityPoint(coords).to_affine()
+ assert isinstance(affine, InfinityPoint)
- infty_one = InfinityPoint(self.coords)
- infty_other = InfinityPoint(self.coords)
- self.assertTrue(infty_one.equals(infty_other))
- self.assertTrue(infty_one.equals_affine(infty_other))
- self.assertTrue(infty_one.equals_scaled(infty_other))
- self.assertEqual(infty_one, infty_other)
- self.assertFalse(pt.equals(infty_one))
- self.assertFalse(pt.equals_affine(infty_one))
- self.assertFalse(pt.equals_scaled(infty_one))
- mont = MontgomeryModel()
- different = Point(
- mont.coordinates["xz"],
- X=Mod(
- 0x64DACCD2656420216545E5F65221EB,
- 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,
- ),
- Z=Mod(1, 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA),
- )
- self.assertFalse(pt.equals(different))
- self.assertNotEqual(pt, different)
+def test_to_model(secp128r1, coords, affine_model):
+ affine = Point(
+ affine_model,
+ x=Mod(0xABCD, secp128r1.curve.prime),
+ y=Mod(0xEF, secp128r1.curve.prime),
+ )
+ projective_model = coords
+ other = affine.to_model(projective_model, secp128r1.curve)
- def test_bytes(self):
- pt = Point(
- self.coords,
- X=Mod(0x4, self.secp128r1.curve.prime),
- Y=Mod(0x6, self.secp128r1.curve.prime),
- Z=Mod(2, self.secp128r1.curve.prime),
- )
- self.assertEqual(
- bytes(pt),
- b"\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02",
- )
- self.assertEqual(bytes(InfinityPoint(self.coords)), b"\x00")
+ assert other.coordinate_model == projective_model
+ assert set(other.coords.keys()) == set(projective_model.variables)
+ assert other.coords["X"] == affine.coords["x"]
+ assert other.coords["Y"] == affine.coords["y"]
+ assert other.coords["Z"] == Mod(1, secp128r1.curve.prime)
- def test_iter(self):
- pt = Point(
- self.coords,
- X=Mod(0x4, self.secp128r1.curve.prime),
- Y=Mod(0x6, self.secp128r1.curve.prime),
- Z=Mod(2, self.secp128r1.curve.prime),
- )
- t = tuple(pt)
- self.assertEqual(len(t), 3)
- self.assertEqual(len(pt), 3)
+ infty = InfinityPoint(AffineCoordinateModel(secp128r1.curve.model))
+ other_infty = infty.to_model(coords, secp128r1.curve)
+ assert isinstance(other_infty, InfinityPoint)
+
+ with pytest.raises(ValueError):
+ secp128r1.generator.to_model(coords, secp128r1.curve)
+
+
+def test_to_from_affine(secp128r1, coords):
+ pt = Point(
+ coords,
+ X=Mod(0x161FF7528B899B2D0C28607CA52C5B86, secp128r1.curve.prime),
+ Y=Mod(0xCF5AC8395BAFEB13C02DA292DDED7A83, secp128r1.curve.prime),
+ Z=Mod(1, secp128r1.curve.prime),
+ )
+ other = pt.to_affine().to_model(coords, secp128r1.curve)
+ assert pt == other
+
+
+def test_equals(secp128r1, coords):
+ pt = Point(
+ coords,
+ X=Mod(0x4, secp128r1.curve.prime),
+ Y=Mod(0x6, secp128r1.curve.prime),
+ Z=Mod(2, secp128r1.curve.prime),
+ )
+ other = Point(
+ coords,
+ X=Mod(0x2, secp128r1.curve.prime),
+ Y=Mod(0x3, secp128r1.curve.prime),
+ Z=Mod(1, secp128r1.curve.prime),
+ )
+ third = Point(
+ coords,
+ X=Mod(0x5, secp128r1.curve.prime),
+ Y=Mod(0x3, secp128r1.curve.prime),
+ Z=Mod(1, secp128r1.curve.prime),
+ )
+ assert pt.equals(other)
+ assert pt != other
+ assert not pt.equals(2)
+ assert pt != 2
+ assert not pt.equals(third)
+ assert pt != third
+ assert pt.equals_scaled(other)
+ assert pt.equals_affine(other)
+ assert not pt.equals_scaled(third)
+
+ infty_one = InfinityPoint(coords)
+ infty_other = InfinityPoint(coords)
+ assert infty_one.equals(infty_other)
+ assert infty_one.equals_affine(infty_other)
+ assert infty_one.equals_scaled(infty_other)
+ assert infty_one == infty_other
+ assert not pt.equals(infty_one)
+ assert not pt.equals_affine(infty_one)
+ assert not pt.equals_scaled(infty_one)
+
+ mont = MontgomeryModel()
+ different = Point(
+ mont.coordinates["xz"],
+ X=Mod(
+ 0x64DACCD2656420216545E5F65221EB,
+ 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,
+ ),
+ Z=Mod(1, 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA),
+ )
+ assert not pt.equals(different)
+ assert pt != different
+
+
+def test_bytes(secp128r1, coords):
+ pt = Point(
+ coords,
+ X=Mod(0x4, secp128r1.curve.prime),
+ Y=Mod(0x6, secp128r1.curve.prime),
+ Z=Mod(2, secp128r1.curve.prime),
+ )
+ assert bytes(pt) == \
+ b"\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"
+ assert bytes(InfinityPoint(coords)) == b"\x00"
+
+
+def test_iter(secp128r1, coords):
+ pt = Point(
+ coords,
+ X=Mod(0x4, secp128r1.curve.prime),
+ Y=Mod(0x6, secp128r1.curve.prime),
+ Z=Mod(2, secp128r1.curve.prime),
+ )
+ t = tuple(pt)
+ assert len(t) == 3
+ assert len(pt) == 3
diff --git a/test/ec/test_regress.py b/test/ec/test_regress.py
index 13e6655..f032de2 100644
--- a/test/ec/test_regress.py
+++ b/test/ec/test_regress.py
@@ -1,10 +1,11 @@
from typing import cast
-from unittest import TestCase, skip
+from unittest import TestCase
+
+import pytest
from sympy import symbols
from pyecsca.ec.coordinates import AffineCoordinateModel
from pyecsca.ec.curve import EllipticCurve
-from pyecsca.ec.error import UnsatisfiedAssumptionError
from pyecsca.ec.formula import AdditionFormula, DoublingFormula, ScalingFormula
from pyecsca.ec.mod import Mod, SymbolicMod
from pyecsca.ec.model import MontgomeryModel, EdwardsModel
@@ -13,101 +14,101 @@ from pyecsca.ec.mult import LTRMultiplier
from pyecsca.ec.point import Point, InfinityPoint
-class RegressionTests(TestCase):
- def test_issue_7(self):
- secp128r1 = get_params("secg", "secp128r1", "projective")
- base = secp128r1.generator
- coords = secp128r1.curve.coordinate_model
- add = cast(AdditionFormula, coords.formulas["add-1998-cmo"])
- dbl = cast(DoublingFormula, coords.formulas["dbl-1998-cmo"])
- scl = cast(ScalingFormula, coords.formulas["z"])
- mult = LTRMultiplier(
- add, dbl, scl, always=False, complete=False, short_circuit=True
- )
- mult.init(secp128r1, base)
- pt = mult.multiply(13613624287328732)
- self.assertIsInstance(pt.coords["X"], Mod)
- self.assertIsInstance(pt.coords["Y"], Mod)
- self.assertIsInstance(pt.coords["Z"], Mod)
- mult.init(secp128r1, pt)
- a = mult.multiply(1)
- self.assertNotIsInstance(a.coords["X"].x, float)
- self.assertNotIsInstance(a.coords["Y"].x, float)
- self.assertNotIsInstance(a.coords["Z"].x, float)
+def test_issue_7():
+ secp128r1 = get_params("secg", "secp128r1", "projective")
+ base = secp128r1.generator
+ coords = secp128r1.curve.coordinate_model
+ add = cast(AdditionFormula, coords.formulas["add-1998-cmo"])
+ dbl = cast(DoublingFormula, coords.formulas["dbl-1998-cmo"])
+ scl = cast(ScalingFormula, coords.formulas["z"])
+ mult = LTRMultiplier(add, dbl, scl, always=False, complete=False, short_circuit=True)
+ mult.init(secp128r1, base)
+ pt = mult.multiply(13613624287328732)
+ assert isinstance(pt.coords["X"], Mod)
+ assert isinstance(pt.coords["Y"], Mod)
+ assert isinstance(pt.coords["Z"], Mod)
+ mult.init(secp128r1, pt)
+ a = mult.multiply(1)
+ assert not isinstance(a.coords["X"].x, float)
+ assert not isinstance(a.coords["Y"].x, float)
+ assert not isinstance(a.coords["Z"].x, float)
+
+
+def test_issue_8():
+ e222 = get_params("other", "E-222", "projective")
+ base = e222.generator
+ affine_base = base.to_affine()
+ affine_double = e222.curve.affine_double(affine_base)
+ affine_triple = e222.curve.affine_add(affine_base, affine_double)
+ assert affine_double is not None
+ assert affine_triple is not None
+
+
+def test_issue_9():
+ model = MontgomeryModel()
+ coords = model.coordinates["xz"]
+ p = 19
+ neutral = Point(coords, X=Mod(1, p), Z=Mod(0, p))
+ curve = EllipticCurve(model, coords, p, neutral, {"a": Mod(8, p), "b": Mod(1, p)})
+ base = Point(coords, X=Mod(12, p), Z=Mod(1, p))
+ formula = coords.formulas["dbl-1987-m-2"]
+ res = formula(p, base, **curve.parameters)[0]
+ assert res is not None
+ affine_base = Point(AffineCoordinateModel(model), x=Mod(12, p), y=Mod(2, p))
+ dbase = curve.affine_double(affine_base).to_model(coords, curve)
+ ladder = coords.formulas["ladd-1987-m-3"]
+ one, other = ladder(p, base, dbase, base, **curve.parameters)
+ assert one is not None
+ assert other is not None
+
- def test_issue_8(self):
- e222 = get_params("other", "E-222", "projective")
- base = e222.generator
- affine_base = base.to_affine()
- affine_double = e222.curve.affine_double(affine_base)
- affine_triple = e222.curve.affine_add(affine_base, affine_double)
- self.assertIsNotNone(affine_double)
- self.assertIsNotNone(affine_triple)
+def test_issue_10():
+ model = EdwardsModel()
+ coords = model.coordinates["yz"]
+ coords_sqr = model.coordinates["yzsquared"]
+ p = 0x1D
+ c = Mod(1, p)
+ d = Mod(0x1C, p)
+ r = d.sqrt()
+ neutral = Point(coords, Y=c * r, Z=Mod(1, p))
+ curve = EllipticCurve(model, coords, p, neutral, {"c": c, "d": d, "r": r})
+ neutral_affine = Point(AffineCoordinateModel(model), x=Mod(0, p), y=c)
+ assert neutral == neutral_affine.to_model(coords, curve)
+ neutral_sqr = Point(coords_sqr, Y=c ** 2 * r, Z=Mod(1, p))
+ assert neutral_sqr == neutral_affine.to_model(coords_sqr, curve)
- def test_issue_9(self):
- model = MontgomeryModel()
- coords = model.coordinates["xz"]
- p = 19
- neutral = Point(coords, X=Mod(1, p), Z=Mod(0, p))
- curve = EllipticCurve(
- model, coords, p, neutral, {"a": Mod(8, p), "b": Mod(1, p)}
- )
- base = Point(coords, X=Mod(12, p), Z=Mod(1, p))
- formula = coords.formulas["dbl-1987-m-2"]
- res = formula(p, base, **curve.parameters)[0]
- self.assertIsNotNone(res)
- affine_base = Point(AffineCoordinateModel(model), x=Mod(12, p), y=Mod(2, p))
- dbase = curve.affine_double(affine_base).to_model(coords, curve)
- ladder = coords.formulas["ladd-1987-m-3"]
- one, other = ladder(p, base, dbase, base, **curve.parameters)
- self.assertIsNotNone(one)
- self.assertIsNotNone(other)
- def test_issue_10(self):
- model = EdwardsModel()
- coords = model.coordinates["yz"]
- coords_sqr = model.coordinates["yzsquared"]
- p = 0x1D
- c = Mod(1, p)
- d = Mod(0x1C, p)
- r = d.sqrt()
- neutral = Point(coords, Y=c * r, Z=Mod(1, p))
- curve = EllipticCurve(model, coords, p, neutral, {"c": c, "d": d, "r": r})
- neutral_affine = Point(AffineCoordinateModel(model), x=Mod(0, p), y=c)
- self.assertEqual(neutral, neutral_affine.to_model(coords, curve))
- neutral_sqr = Point(coords_sqr, Y=c ** 2 * r, Z=Mod(1, p))
- self.assertEqual(neutral_sqr, neutral_affine.to_model(coords_sqr, curve))
+def test_issue_13():
+ model = EdwardsModel()
+ coords = model.coordinates["yz"]
+ c, r, d = symbols("c r d")
+ p = 53
+ c = SymbolicMod(c, p)
+ r = SymbolicMod(r, p)
+ d = SymbolicMod(d, p)
+ yd, zd, yp, zp, yq, zq = symbols("yd zd yp zp yq zq")
+ PmQ = Point(coords, Y=SymbolicMod(yd, p), Z=SymbolicMod(zd, p))
+ P = Point(coords, Y=SymbolicMod(yp, p), Z=SymbolicMod(zp, p))
+ Q = Point(coords, Y=SymbolicMod(yq, p), Z=SymbolicMod(zq, p))
+ formula = coords.formulas["dadd-2006-g-2"]
+ formula(p, PmQ, P, Q, c=c, r=r, d=d)
- def test_issue_13(self):
- model = EdwardsModel()
- coords = model.coordinates["yz"]
- c, r, d = symbols("c r d")
- p = 53
- c = SymbolicMod(c, p)
- r = SymbolicMod(r, p)
- d = SymbolicMod(d, p)
- yd, zd, yp, zp, yq, zq = symbols("yd zd yp zp yq zq")
- PmQ = Point(coords, Y=SymbolicMod(yd, p), Z=SymbolicMod(zd, p))
- P = Point(coords, Y=SymbolicMod(yp, p), Z=SymbolicMod(zp, p))
- Q = Point(coords, Y=SymbolicMod(yq, p), Z=SymbolicMod(zq, p))
- formula = coords.formulas["dadd-2006-g-2"]
- formula(p, PmQ, P, Q, c=c, r=r, d=d)
- @skip("Unresolved issue currently.")
- def test_issue_14(self):
- model = EdwardsModel()
- coords = model.coordinates["projective"]
- affine = AffineCoordinateModel(model)
- formula = coords.formulas["add-2007-bl-4"]
- p = 19
- c = Mod(2, p)
- d = Mod(10, p)
- curve = EllipticCurve(model, coords, p, InfinityPoint(coords), {"c": c, "d": d})
- Paff = Point(affine, x=Mod(0xD, p), y=Mod(0x9, p))
- P = Paff.to_model(coords, curve)
- Qaff = Point(affine, x=Mod(0x4, p), y=Mod(0x12, p))
- Q = Qaff.to_model(coords, curve)
- PQaff = curve.affine_add(Paff, Qaff)
- R = formula(p, P, Q, **curve.parameters)[0]
- Raff = R.to_affine()
- self.assertEqual(PQaff, Raff)
+@pytest.mark.xfail(reason="Unresolved issue currently.")
+def test_issue_14():
+ model = EdwardsModel()
+ coords = model.coordinates["projective"]
+ affine = AffineCoordinateModel(model)
+ formula = coords.formulas["add-2007-bl-4"]
+ p = 19
+ c = Mod(2, p)
+ d = Mod(10, p)
+ curve = EllipticCurve(model, coords, p, InfinityPoint(coords), {"c": c, "d": d})
+ Paff = Point(affine, x=Mod(0xD, p), y=Mod(0x9, p))
+ P = Paff.to_model(coords, curve)
+ Qaff = Point(affine, x=Mod(0x4, p), y=Mod(0x12, p))
+ Q = Qaff.to_model(coords, curve)
+ PQaff = curve.affine_add(Paff, Qaff)
+ R = formula(p, P, Q, **curve.parameters)[0]
+ Raff = R.to_affine()
+ assert PQaff == Raff
diff --git a/test/ec/test_signature.py b/test/ec/test_signature.py
index f6ab302..73e4611 100644
--- a/test/ec/test_signature.py
+++ b/test/ec/test_signature.py
@@ -1,7 +1,7 @@
from unittest import TestCase
from parameterized import parameterized
-
+import pytest
from pyecsca.ec.params import get_params
from pyecsca.ec.mod import Mod
from pyecsca.ec.mult import LTRMultiplier
@@ -17,81 +17,98 @@ from pyecsca.ec.signature import (
)
-class SignatureTests(TestCase):
- def setUp(self):
- self.secp128r1 = get_params("secg", "secp128r1", "projective")
- self.add = self.secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
- self.dbl = self.secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
- self.mult = LTRMultiplier(self.add, self.dbl)
- self.msg = 0xCAFEBABE .to_bytes(4, byteorder="big")
- self.priv = Mod(0xDEADBEEF, self.secp128r1.order)
- self.mult.init(self.secp128r1, self.secp128r1.generator)
- self.pub = self.mult.multiply(self.priv.x)
+@pytest.fixture()
+def add(secp128r1):
+ return secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
+
+
+@pytest.fixture()
+def mult(secp128r1, add):
+ dbl = secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
+ return LTRMultiplier(add, dbl)
- @parameterized.expand(
- [
- ("SHA1", ECDSA_SHA1),
- ("SHA224", ECDSA_SHA224),
- ("SHA256", ECDSA_SHA256),
- ("SHA384", ECDSA_SHA384),
- ("SHA512", ECDSA_SHA512),
- ]
- )
- def test_all(self, name, algo):
- signer = algo(self.mult, self.secp128r1, privkey=self.priv)
- self.assertTrue(signer.can_sign)
- sig = signer.sign_data(self.msg)
- verifier = algo(self.mult, self.secp128r1, add=self.add, pubkey=self.pub)
- self.assertTrue(verifier.can_verify)
- self.assertTrue(verifier.verify_data(sig, self.msg))
- none = ECDSA_NONE(
- self.mult, self.secp128r1, add=self.add, pubkey=self.pub, privkey=self.priv
- )
- digest = signer.hash_algo(self.msg).digest()
- sig = none.sign_hash(digest)
- self.assertTrue(none.verify_hash(sig, digest))
+@pytest.fixture()
+def keypair(secp128r1, mult):
+ priv = Mod(0xDEADBEEF, secp128r1.order)
+ mult.init(secp128r1, secp128r1.generator)
+ pub = mult.multiply(int(priv))
+ return priv, pub
- def test_cannot(self):
- ok = ECDSA_NONE(
- self.mult, self.secp128r1, add=self.add, pubkey=self.pub, privkey=self.priv
- )
- data = b"aaaa"
- sig = ok.sign_data(data)
- no_priv = ECDSA_NONE(self.mult, self.secp128r1, pubkey=self.pub)
- with self.assertRaises(RuntimeError):
- no_priv.sign_data(data)
- with self.assertRaises(RuntimeError):
- no_priv.sign_hash(data)
- no_pubadd = ECDSA_NONE(self.mult, self.secp128r1, privkey=self.priv)
- with self.assertRaises(RuntimeError):
- no_pubadd.verify_data(sig, data)
- with self.assertRaises(RuntimeError):
- no_pubadd.verify_hash(sig, data)
+@pytest.fixture()
+def msg():
+ return 0xCAFEBABE.to_bytes(4, byteorder="big")
- with self.assertRaises(ValueError):
- Signature(self.mult, self.secp128r1)
- @parameterized.expand(
- [
- ("SHA1", ECDSA_SHA1),
- ("SHA224", ECDSA_SHA224),
- ("SHA256", ECDSA_SHA256),
- ("SHA384", ECDSA_SHA384),
- ("SHA512", ECDSA_SHA512),
- ]
+@pytest.mark.parametrize("name,algo",
+ [
+ ("SHA1", ECDSA_SHA1),
+ ("SHA224", ECDSA_SHA224),
+ ("SHA256", ECDSA_SHA256),
+ ("SHA384", ECDSA_SHA384),
+ ("SHA512", ECDSA_SHA512),
+ ])
+def test_all(secp128r1, mult, keypair, msg, add, name, algo):
+ priv, pub = keypair
+ signer = algo(mult, secp128r1, privkey=keypair[0])
+ assert signer.can_sign
+ sig = signer.sign_data(msg)
+ verifier = algo(mult, secp128r1, add=add, pubkey=pub)
+ assert verifier.can_verify
+ assert verifier.verify_data(sig, msg)
+
+ none = ECDSA_NONE(
+ mult, secp128r1, add=add, pubkey=pub, privkey=priv
)
- def test_fixed_nonce(self, name, algo):
- signer = algo(self.mult, self.secp128r1, privkey=self.priv)
- sig_one = signer.sign_data(self.msg, nonce=0xABCDEF)
- sig_other = signer.sign_data(self.msg, nonce=0xABCDEF)
- verifier = algo(self.mult, self.secp128r1, add=self.add, pubkey=self.pub)
- self.assertTrue(verifier.verify_data(sig_one, self.msg))
- self.assertTrue(verifier.verify_data(sig_other, self.msg))
- self.assertEqual(sig_one, sig_other)
+ digest = signer.hash_algo(msg).digest()
+ sig = none.sign_hash(digest)
+ assert none.verify_hash(sig, digest)
+
+
+def test_cannot(secp128r1, add, mult, keypair):
+ priv, pub = keypair
+ ok = ECDSA_NONE(
+ mult, secp128r1, add=add, pubkey=pub, privkey=priv
+ )
+ data = b"aaaa"
+ sig = ok.sign_data(data)
+
+ no_priv = ECDSA_NONE(mult, secp128r1, pubkey=pub)
+ with pytest.raises(RuntimeError):
+ no_priv.sign_data(data)
+ with pytest.raises(RuntimeError):
+ no_priv.sign_hash(data)
+ no_pubadd = ECDSA_NONE(mult, secp128r1, privkey=priv)
+ with pytest.raises(RuntimeError):
+ no_pubadd.verify_data(sig, data)
+ with pytest.raises(RuntimeError):
+ no_pubadd.verify_hash(sig, data)
+
+ with pytest.raises(ValueError):
+ Signature(mult, secp128r1)
+
+
+@pytest.mark.parametrize("name,algo",
+ [
+ ("SHA1", ECDSA_SHA1),
+ ("SHA224", ECDSA_SHA224),
+ ("SHA256", ECDSA_SHA256),
+ ("SHA384", ECDSA_SHA384),
+ ("SHA512", ECDSA_SHA512),
+ ])
+def test_fixed_nonce(secp128r1, mult, keypair, msg, add, name, algo):
+ priv, pub = keypair
+ signer = algo(mult, secp128r1, privkey=priv)
+ sig_one = signer.sign_data(msg, nonce=0xABCDEF)
+ sig_other = signer.sign_data(msg, nonce=0xABCDEF)
+ verifier = algo(mult, secp128r1, add=add, pubkey=pub)
+ assert verifier.verify_data(sig_one, msg)
+ assert verifier.verify_data(sig_other, msg)
+ assert sig_one == sig_other
+
- def test_der(self):
- sig = SignatureResult(0xAAAAA, 0xBBBBB)
- self.assertEqual(sig, SignatureResult.from_DER(sig.to_DER()))
- self.assertNotEqual(sig, "abc")
+def test_der():
+ sig = SignatureResult(0xAAAAA, 0xBBBBB)
+ assert sig == SignatureResult.from_DER(sig.to_DER())
+ assert sig != "abc"
diff --git a/test/ec/test_transformations.py b/test/ec/test_transformations.py
index b15f868..f33c8f1 100644
--- a/test/ec/test_transformations.py
+++ b/test/ec/test_transformations.py
@@ -1,35 +1,34 @@
-from unittest import TestCase
-
from pyecsca.ec.params import get_params
from pyecsca.ec.transformations import M2SW, M2TE, TE2M, SW2M, SW2TE
-class TransformationTests(TestCase):
- def test_montgomery(self):
- curve25519 = get_params("other", "Curve25519", "affine")
- sw = M2SW(curve25519)
- self.assertIsNotNone(sw)
- self.assertTrue(sw.curve.is_on_curve(sw.generator))
- self.assertTrue(sw.curve.is_neutral(sw.curve.neutral))
- te = M2TE(curve25519)
- self.assertIsNotNone(te)
- self.assertTrue(te.curve.is_on_curve(te.generator))
- self.assertTrue(te.curve.is_neutral(te.curve.neutral))
+def test_montgomery():
+ curve25519 = get_params("other", "Curve25519", "affine")
+ sw = M2SW(curve25519)
+ assert sw is not None
+ assert sw.curve.is_on_curve(sw.generator)
+ assert sw.curve.is_neutral(sw.curve.neutral)
+ te = M2TE(curve25519)
+ assert te is not None
+ assert te.curve.is_on_curve(te.generator)
+ assert te.curve.is_neutral(te.curve.neutral)
+
+
+def test_twistededwards():
+ ed25519 = get_params("other", "Ed25519", "affine")
+ m = TE2M(ed25519)
+ assert m is not None
+ assert m.curve.is_on_curve(m.generator)
+ assert m.curve.is_neutral(m.curve.neutral)
- def test_twistededwards(self):
- ed25519 = get_params("other", "Ed25519", "affine")
- m = TE2M(ed25519)
- self.assertIsNotNone(m)
- self.assertTrue(m.curve.is_on_curve(m.generator))
- self.assertTrue(m.curve.is_neutral(m.curve.neutral))
- def test_shortweierstrass(self):
- secp128r2 = get_params("secg", "secp128r2", "affine")
- m = SW2M(secp128r2)
- self.assertIsNotNone(m)
- self.assertTrue(m.curve.is_on_curve(m.generator))
- self.assertTrue(m.curve.is_neutral(m.curve.neutral))
- te = SW2TE(secp128r2)
- self.assertIsNotNone(te)
- self.assertTrue(te.curve.is_on_curve(te.generator))
- self.assertTrue(te.curve.is_neutral(te.curve.neutral))
+def test_shortweierstrass():
+ secp128r2 = get_params("secg", "secp128r2", "affine")
+ m = SW2M(secp128r2)
+ assert m is not None
+ assert m.curve.is_on_curve(m.generator)
+ assert m.curve.is_neutral(m.curve.neutral)
+ te = SW2TE(secp128r2)
+ assert te is not None
+ assert te.curve.is_on_curve(te.generator)
+ assert te.curve.is_neutral(te.curve.neutral)
diff --git a/test/ec/utils.py b/test/ec/utils.py
index 0d0a875..1f32033 100644
--- a/test/ec/utils.py
+++ b/test/ec/utils.py
@@ -1,6 +1,7 @@
from itertools import product
from functools import reduce
+
def cartesian(*items):
for cart in product(*items):
yield reduce(lambda x, y: x + y, cart)