aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJ08nY2023-08-09 17:19:55 +0200
committerJ08nY2023-08-09 17:19:55 +0200
commit21fa65c287fc3e830f169f610f643975a4d93966 (patch)
treecf1f4146390bc8b40eed5aa1025caaae23f3a3d4
parent5309bf2ace118a507aa17c0a7b9a7b7bb109b682 (diff)
downloadpyecsca-21fa65c287fc3e830f169f610f643975a4d93966.tar.gz
pyecsca-21fa65c287fc3e830f169f610f643975a4d93966.tar.zst
pyecsca-21fa65c287fc3e830f169f610f643975a4d93966.zip
Move sca tests to pytest.
-rw-r--r--pyecsca/misc/__init__.py2
-rw-r--r--pyecsca/sca/trace_set/inspector.py4
-rw-r--r--test/conftest.py18
-rw-r--r--test/ec/conftest.py18
-rwxr-xr-xtest/ec/perf_mult.py7
-rw-r--r--test/ec/test_mod.py6
-rw-r--r--test/ec/test_point.py2
-rw-r--r--test/sca/conftest.py43
-rw-r--r--test/sca/test_align.py246
-rw-r--r--test/sca/test_combine.py118
-rw-r--r--test/sca/test_edit.py76
-rw-r--r--test/sca/test_filter.py65
-rw-r--r--test/sca/test_leakage_models.py170
-rw-r--r--test/sca/test_match.py131
-rw-r--r--test/sca/test_plot.py57
-rw-r--r--test/sca/test_process.py86
-rw-r--r--test/sca/test_rpa.py190
-rw-r--r--test/sca/test_rpa_context.py106
-rw-r--r--test/sca/test_sampling.py295
-rw-r--r--test/sca/test_stacked_combine.py164
-rw-r--r--test/sca/test_target.py854
-rw-r--r--test/sca/test_test.py62
-rw-r--r--test/sca/test_trace.py12
-rw-r--r--test/sca/test_traceset.py200
-rw-r--r--test/sca/test_zvp.py30
-rw-r--r--test/sca/utils.py42
26 files changed, 1518 insertions, 1486 deletions
diff --git a/pyecsca/misc/__init__.py b/pyecsca/misc/__init__.py
index f093677..243fc08 100644
--- a/pyecsca/misc/__init__.py
+++ b/pyecsca/misc/__init__.py
@@ -1 +1 @@
-"""package for miscellaneous things."""
+"""Package for miscellaneous things."""
diff --git a/pyecsca/sca/trace_set/inspector.py b/pyecsca/sca/trace_set/inspector.py
index 2c9d581..9e18b04 100644
--- a/pyecsca/sca/trace_set/inspector.py
+++ b/pyecsca/sca/trace_set/inspector.py
@@ -146,7 +146,7 @@ class InspectorTraceSet(TraceSet):
}
@classmethod
- def read(cls, input: Union[str, Path, bytes, BinaryIO]) -> "TraceSet":
+ def read(cls, input: Union[str, Path, bytes, BinaryIO]) -> "InspectorTraceSet":
"""
Read Inspector trace set from file path, bytes or file-like object.
@@ -207,7 +207,7 @@ class InspectorTraceSet(TraceSet):
return result, tags
@classmethod
- def inplace(cls, input: Union[str, Path, bytes, BinaryIO]) -> "TraceSet":
+ def inplace(cls, input: Union[str, Path, bytes, BinaryIO]) -> "InspectorTraceSet":
raise NotImplementedError
def write(self, output: Union[str, Path, BinaryIO]):
diff --git a/test/conftest.py b/test/conftest.py
new file mode 100644
index 0000000..5c3f855
--- /dev/null
+++ b/test/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/conftest.py b/test/ec/conftest.py
index 5c3f855..e69de29 100644
--- a/test/ec/conftest.py
+++ b/test/ec/conftest.py
@@ -1,18 +0,0 @@
-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/perf_mult.py b/test/ec/perf_mult.py
index 51fb5a9..521f5e7 100755
--- a/test/ec/perf_mult.py
+++ b/test/ec/perf_mult.py
@@ -1,6 +1,9 @@
#!/usr/bin/env python
+from typing import cast
+
import click
+from pyecsca.ec.formula import AdditionFormula, DoublingFormula
from pyecsca.ec.mod import has_gmp
from pyecsca.ec.mult import LTRMultiplier
from pyecsca.ec.params import get_params
@@ -29,8 +32,8 @@ def main(profiler, mod, operations, directory):
cfg.ec.mod_implementation = mod
p256 = get_params("secg", "secp256r1", "projective")
coords = p256.curve.coordinate_model
- add = coords.formulas["add-2016-rcb"]
- dbl = coords.formulas["dbl-2016-rcb"]
+ add = cast(AdditionFormula, coords.formulas["add-2016-rcb"])
+ dbl = cast(DoublingFormula, coords.formulas["dbl-2016-rcb"])
mult = LTRMultiplier(add, dbl)
click.echo(
f"Profiling {operations} {p256.curve.prime.bit_length()}-bit scalar multiplication executions..."
diff --git a/test/ec/test_mod.py b/test/ec/test_mod.py
index 29b818e..55522b0 100644
--- a/test/ec/test_mod.py
+++ b/test/ec/test_mod.py
@@ -48,8 +48,7 @@ def test_inverse():
p = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
assert Mod(
0x702BDAFD3C1C837B23A1CB196ED7F9FADB333C5CFE4A462BE32ADCD67BFB6AC1, p
- ).inverse() == \
- Mod(0x1CB2E5274BBA085C4CA88EEDE75AE77949E7A410C80368376E97AB22EB590F9D, p)
+ ).inverse() == Mod(0x1CB2E5274BBA085C4CA88EEDE75AE77949E7A410C80368376E97AB22EB590F9D, p)
with pytest.raises(NonInvertibleError):
Mod(0, p).inverse()
with pytest.raises(NonInvertibleError):
@@ -78,8 +77,7 @@ def test_sqrt():
p = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
assert Mod(
0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC, p
- ).sqrt() in \
- (
+ ).sqrt() in (
0x9ADD512515B70D9EC471151C1DEC46625CD18B37BDE7CA7FB2C8B31D7033599D,
0x6522AED9EA48F2623B8EEAE3E213B99DA32E74C9421835804D374CE28FCCA662,
)
diff --git a/test/ec/test_point.py b/test/ec/test_point.py
index b09ca30..4a5a6f6 100644
--- a/test/ec/test_point.py
+++ b/test/ec/test_point.py
@@ -105,7 +105,7 @@ def test_equals(secp128r1, coords):
)
assert pt.equals(other)
assert pt != other
- assert not pt.equals(2)
+ assert not pt.equals(2) # type: ignore
assert pt != 2
assert not pt.equals(third)
assert pt != third
diff --git a/test/sca/conftest.py b/test/sca/conftest.py
new file mode 100644
index 0000000..a7a21d6
--- /dev/null
+++ b/test/sca/conftest.py
@@ -0,0 +1,43 @@
+from typing import Dict
+
+import pytest
+from importlib_resources import files, as_file
+
+import matplotlib.pyplot as plt
+
+from pyecsca.sca import Trace
+
+cases: Dict[str, int] = {}
+
+
+@pytest.fixture()
+def plot_name(request):
+ def namer():
+ test_name = f"{request.module.__name__}.{request.node.name}"
+ case_id = cases.setdefault(test_name, 0) + 1
+ cases[test_name] = case_id
+ return test_name + str(case_id)
+ return namer
+
+
+@pytest.fixture()
+def plot_path(plot_name):
+ def namer():
+ with as_file(files("test").joinpath("plots", plot_name())) as fname:
+ return fname
+ return namer
+
+
+@pytest.fixture()
+def plot(plot_path):
+ def plotter(*traces: Trace, **kwtraces: Trace):
+ fig = plt.figure()
+ ax = fig.add_subplot(111)
+ for i, trace in enumerate(traces):
+ ax.plot(trace.samples, label=str(i))
+ for name, trace in kwtraces.items():
+ ax.plot(trace.samples, label=name)
+ ax.legend(loc="best")
+ fname = plot_path()
+ plt.savefig(fname.parent / (fname.name + ".png"))
+ return plotter
diff --git a/test/sca/test_align.py b/test/sca/test_align.py
index db3874e..ad45d86 100644
--- a/test/sca/test_align.py
+++ b/test/sca/test_align.py
@@ -11,143 +11,139 @@ from pyecsca.sca import (
InspectorTraceSet,
)
import test.data.sca
-from .utils import Plottable
-class AlignTests(Plottable):
- def test_align(self):
- first_arr = np.array(
- [10, 64, 120, 64, 10, 10, 10, 10, 10], dtype=np.dtype("i1")
- )
- second_arr = np.array([10, 10, 10, 10, 50, 80, 50, 20], dtype=np.dtype("i1"))
- third_arr = np.array([70, 30, 42, 35, 28, 21, 15, 10, 5], dtype=np.dtype("i1"))
- a = Trace(first_arr)
- b = Trace(second_arr)
- c = Trace(third_arr)
- result, offsets = align_correlation(
- a,
- b,
- c,
- reference_offset=1,
- reference_length=3,
- max_offset=4,
- min_correlation=0.65,
- )
- self.assertIsNotNone(result)
- self.assertEqual(len(result), 2)
- np.testing.assert_equal(result[0].samples, first_arr)
- np.testing.assert_equal(
- result[1].samples,
- np.array([10, 50, 80, 50, 20, 0, 0, 0], dtype=np.dtype("i1")),
+def test_align():
+ first_arr = np.array(
+ [10, 64, 120, 64, 10, 10, 10, 10, 10], dtype=np.dtype("i1")
+ )
+ second_arr = np.array([10, 10, 10, 10, 50, 80, 50, 20], dtype=np.dtype("i1"))
+ third_arr = np.array([70, 30, 42, 35, 28, 21, 15, 10, 5], dtype=np.dtype("i1"))
+ a = Trace(first_arr)
+ b = Trace(second_arr)
+ c = Trace(third_arr)
+ result, offsets = align_correlation(
+ a,
+ b,
+ c,
+ reference_offset=1,
+ reference_length=3,
+ max_offset=4,
+ min_correlation=0.65,
+ )
+ assert result is not None
+ assert len(result) == 2
+ np.testing.assert_equal(result[0].samples, first_arr)
+ np.testing.assert_equal(
+ result[1].samples,
+ np.array([10, 50, 80, 50, 20, 0, 0, 0], dtype=np.dtype("i1")),
+ )
+ assert len(offsets) == 2
+ assert offsets[0] == 0
+ assert offsets[1] == 3
+
+
+@pytest.mark.slow
+def test_large_align():
+ with as_file(files(test.data.sca).joinpath("example.trs")) as path:
+ example = InspectorTraceSet.read(path)
+ result, _ = align_correlation(
+ *example, reference_offset=100000, reference_length=20000, max_offset=15000
)
- self.assertEqual(len(offsets), 2)
- self.assertEqual(offsets[0], 0)
- self.assertEqual(offsets[1], 3)
+ assert result is not None
- @pytest.mark.slow
- def test_large_align(self):
- with as_file(files(test.data.sca).joinpath("example.trs")) as path:
- example = InspectorTraceSet.read(path)
- result, _ = align_correlation(
- *example, reference_offset=100000, reference_length=20000, max_offset=15000
- )
- self.assertIsNotNone(result)
- @pytest.mark.slow
- def test_large_dtw_align(self):
- with as_file(files(test.data.sca).joinpath("example.trs")) as path:
- example = InspectorTraceSet.read(path)
- result = align_dtw(*example[:5])
- self.assertIsNotNone(result)
+@pytest.mark.slow
+def test_large_dtw_align():
+ with as_file(files(test.data.sca).joinpath("example.trs")) as path:
+ example = InspectorTraceSet.read(path)
+ result = align_dtw(*example[:5])
+ assert result is not None
- def test_peak_align(self):
- first_arr = np.array(
- [10, 64, 14, 120, 15, 30, 10, 15, 20, 15, 15, 10, 10], dtype=np.dtype("i1")
- )
- second_arr = np.array(
- [10, 10, 10, 10, 90, 40, 50, 20, 10, 17, 16, 10], dtype=np.dtype("i1")
- )
- a = Trace(first_arr)
- b = Trace(second_arr)
- result, _ = align_peaks(
- a, b, reference_offset=2, reference_length=5, max_offset=3
- )
- self.assertEqual(np.argmax(result[0].samples), np.argmax(result[1].samples))
- def test_sad_align(self):
- first_arr = np.array(
- [10, 64, 14, 120, 15, 30, 10, 15, 20, 15, 15, 10, 10], dtype=np.dtype("i1")
- )
- second_arr = np.array(
- [10, 10, 90, 40, 50, 20, 10, 17, 16, 10, 10], dtype=np.dtype("i1")
- )
- a = Trace(first_arr)
- b = Trace(second_arr)
- result, _ = align_sad(
- a, b, reference_offset=2, reference_length=5, max_offset=3
- )
- self.assertEqual(len(result), 2)
+def test_peak_align():
+ first_arr = np.array(
+ [10, 64, 14, 120, 15, 30, 10, 15, 20, 15, 15, 10, 10], dtype=np.dtype("i1")
+ )
+ second_arr = np.array(
+ [10, 10, 10, 10, 90, 40, 50, 20, 10, 17, 16, 10], dtype=np.dtype("i1")
+ )
+ a = Trace(first_arr)
+ b = Trace(second_arr)
+ result, _ = align_peaks(
+ a, b, reference_offset=2, reference_length=5, max_offset=3
+ )
+ assert np.argmax(result[0].samples) == np.argmax(result[1].samples)
- def test_dtw_align_scale(self):
- first_arr = np.array(
- [10, 64, 14, 120, 15, 30, 10, 15, 20, 15, 15, 10, 10, 8, 10, 12, 10, 13, 9],
- dtype=np.dtype("f2"),
- )
- second_arr = np.array(
- [10, 10, 60, 40, 90, 20, 10, 17, 16, 10, 10, 10, 10, 10, 17, 12, 10],
- dtype=np.dtype("f2"),
- )
- third_arr = np.array(
- [10, 30, 20, 21, 15, 8, 10, 37, 21, 77, 20, 28, 25, 10, 9, 10, 15, 9, 10],
- dtype=np.dtype("f2"),
- )
- a = Trace(first_arr)
- b = Trace(second_arr)
- c = Trace(third_arr)
- result = align_dtw_scale(a, b, c)
- self.assertEqual(np.argmax(result[0].samples), np.argmax(result[1].samples))
- self.assertEqual(np.argmax(result[1].samples), np.argmax(result[2].samples))
- self.plot(*result)
+def test_sad_align():
+ first_arr = np.array(
+ [10, 64, 14, 120, 15, 30, 10, 15, 20, 15, 15, 10, 10], dtype=np.dtype("i1")
+ )
+ second_arr = np.array(
+ [10, 10, 90, 40, 50, 20, 10, 17, 16, 10, 10], dtype=np.dtype("i1")
+ )
+ a = Trace(first_arr)
+ b = Trace(second_arr)
+ result, _ = align_sad(
+ a, b, reference_offset=2, reference_length=5, max_offset=3
+ )
+ assert len(result) == 2
- result_other = align_dtw_scale(a, b, c, fast=False)
- self.assertEqual(
- np.argmax(result_other[0].samples), np.argmax(result_other[1].samples)
- )
- self.assertEqual(
- np.argmax(result_other[1].samples), np.argmax(result_other[2].samples)
- )
- self.plot(*result_other)
+def test_dtw_align(plot):
+ first_arr = np.array(
+ [10, 64, 14, 120, 15, 30, 10, 15, 20, 15, 15, 10, 10, 8, 10, 12, 10, 13, 9],
+ dtype=np.dtype("i1"),
+ )
+ second_arr = np.array(
+ [10, 10, 60, 40, 90, 20, 10, 17, 16, 10, 10, 10, 10, 10, 17, 12, 10],
+ dtype=np.dtype("i1"),
+ )
+ third_arr = np.array(
+ [10, 30, 20, 21, 15, 8, 10, 47, 21, 77, 20, 28, 25, 10, 9, 10, 15, 9, 10],
+ dtype=np.dtype("i1"),
+ )
+ a = Trace(first_arr)
+ b = Trace(second_arr)
+ c = Trace(third_arr)
+ result = align_dtw(a, b, c)
- def test_dtw_align(self):
- first_arr = np.array(
- [10, 64, 14, 120, 15, 30, 10, 15, 20, 15, 15, 10, 10, 8, 10, 12, 10, 13, 9],
- dtype=np.dtype("i1"),
- )
- second_arr = np.array(
- [10, 10, 60, 40, 90, 20, 10, 17, 16, 10, 10, 10, 10, 10, 17, 12, 10],
- dtype=np.dtype("i1"),
- )
- third_arr = np.array(
- [10, 30, 20, 21, 15, 8, 10, 47, 21, 77, 20, 28, 25, 10, 9, 10, 15, 9, 10],
- dtype=np.dtype("i1"),
- )
- a = Trace(first_arr)
- b = Trace(second_arr)
- c = Trace(third_arr)
- result = align_dtw(a, b, c)
+ assert np.argmax(result[0].samples) == np.argmax(result[1].samples)
+ assert np.argmax(result[1].samples) == np.argmax(result[2].samples)
+ plot(*result)
- self.assertEqual(np.argmax(result[0].samples), np.argmax(result[1].samples))
- self.assertEqual(np.argmax(result[1].samples), np.argmax(result[2].samples))
- self.plot(*result)
+ result_other = align_dtw(a, b, c, fast=False)
- result_other = align_dtw(a, b, c, fast=False)
+ assert np.argmax(result_other[0].samples) == np.argmax(result_other[1].samples)
+ assert np.argmax(result_other[1].samples) == np.argmax(result_other[2].samples)
+ plot(*result_other)
- self.assertEqual(
- np.argmax(result_other[0].samples), np.argmax(result_other[1].samples)
- )
- self.assertEqual(
- np.argmax(result_other[1].samples), np.argmax(result_other[2].samples)
- )
- self.plot(*result_other)
+
+def test_dtw_align_scale(plot):
+ first_arr = np.array(
+ [10, 64, 14, 120, 15, 30, 10, 15, 20, 15, 15, 10, 10, 8, 10, 12, 10, 13, 9],
+ dtype=np.dtype("f2"),
+ )
+ second_arr = np.array(
+ [10, 10, 60, 40, 90, 20, 10, 17, 16, 10, 10, 10, 10, 10, 17, 12, 10],
+ dtype=np.dtype("f2"),
+ )
+ third_arr = np.array(
+ [10, 30, 20, 21, 15, 8, 10, 37, 21, 77, 20, 28, 25, 10, 9, 10, 15, 9, 10],
+ dtype=np.dtype("f2"),
+ )
+ a = Trace(first_arr)
+ b = Trace(second_arr)
+ c = Trace(third_arr)
+ result = align_dtw_scale(a, b, c)
+
+ assert np.argmax(result[0].samples) == np.argmax(result[1].samples)
+ assert np.argmax(result[1].samples) == np.argmax(result[2].samples)
+ plot(*result)
+
+ result_other = align_dtw_scale(a, b, c, fast=False)
+
+ assert np.argmax(result_other[0].samples) == np.argmax(result_other[1].samples)
+ assert np.argmax(result_other[1].samples) == np.argmax(result_other[2].samples)
+ plot(*result_other)
diff --git a/test/sca/test_combine.py b/test/sca/test_combine.py
index 953b4bf..7e62780 100644
--- a/test/sca/test_combine.py
+++ b/test/sca/test_combine.py
@@ -1,6 +1,7 @@
-from unittest import TestCase
-
+from collections import namedtuple
import numpy as np
+import pytest
+
from pyecsca.sca import (
Trace,
CombinedTrace,
@@ -14,65 +15,68 @@ from pyecsca.sca import (
)
-class CombineTests(TestCase):
- def setUp(self):
- self.a = Trace(np.array([20, 80], dtype=np.dtype("i1")), {"data": b"\xff"})
- self.b = Trace(np.array([30, 42], dtype=np.dtype("i1")), {"data": b"\xff"})
- self.c = Trace(np.array([78, 56], dtype=np.dtype("i1")), {"data": b"\x00"})
+@pytest.fixture()
+def data():
+ Data = namedtuple("Data", ["a", "b", "c"])
+ return Data(a=Trace(np.array([20, 80], dtype=np.dtype("i1")), {"data": b"\xff"}),
+ b=Trace(np.array([30, 42], dtype=np.dtype("i1")), {"data": b"\xff"}),
+ c=Trace(np.array([78, 56], dtype=np.dtype("i1")), {"data": b"\x00"}))
+
+
+def test_average(data):
+ assert average() is None
+ result = average(data.a, data.b)
+ assert result is not None
+ assert isinstance(result, CombinedTrace)
+ assert len(result.samples) == 2
+ assert result.samples[0] == 25
+ assert result.samples[1] == 61
+
+
+def test_conditional_average(data):
+ result = conditional_average(data.a, data.b, data.c, condition=lambda trace: trace.meta["data"] == b"\xff", )
+ assert isinstance(result, CombinedTrace)
+ assert len(result.samples) == 2
+ assert result.samples[0] == 25
+ assert result.samples[1] == 61
+
+
+def test_standard_deviation(data):
+ assert standard_deviation() is None
+ result = standard_deviation(data.a, data.b)
+ assert isinstance(result, CombinedTrace)
+ assert len(result.samples) == 2
+
- def test_average(self):
- self.assertIsNone(average())
- result = average(self.a, self.b)
- self.assertIsNotNone(result)
- self.assertIsInstance(result, CombinedTrace)
- self.assertEqual(len(result.samples), 2)
- self.assertEqual(result.samples[0], 25)
- self.assertEqual(result.samples[1], 61)
+def test_variance(data):
+ assert variance() is None
+ result = variance(data.a, data.b)
+ assert isinstance(result, CombinedTrace)
+ assert len(result.samples) == 2
- def test_conditional_average(self):
- result = conditional_average(
- self.a,
- self.b,
- self.c,
- condition=lambda trace: trace.meta["data"] == b"\xff",
- )
- self.assertIsInstance(result, CombinedTrace)
- self.assertEqual(len(result.samples), 2)
- self.assertEqual(result.samples[0], 25)
- self.assertEqual(result.samples[1], 61)
- def test_standard_deviation(self):
- self.assertIsNone(standard_deviation())
- result = standard_deviation(self.a, self.b)
- self.assertIsInstance(result, CombinedTrace)
- self.assertEqual(len(result.samples), 2)
+def test_average_and_variance(data):
+ assert average_and_variance() is None
+ mean, var = average_and_variance(data.a, data.b)
+ assert isinstance(mean, CombinedTrace)
+ assert isinstance(var, CombinedTrace)
+ assert len(mean.samples) == 2
+ assert len(var.samples) == 2
+ assert mean == average(data.a, data.b)
+ assert var == variance(data.a, data.b)
- def test_variance(self):
- self.assertIsNone(variance())
- result = variance(self.a, self.b)
- self.assertIsInstance(result, CombinedTrace)
- self.assertEqual(len(result.samples), 2)
- def test_average_and_variance(self):
- self.assertIsNone(average_and_variance())
- mean, var = average_and_variance(self.a, self.b)
- self.assertIsInstance(mean, CombinedTrace)
- self.assertIsInstance(var, CombinedTrace)
- self.assertEqual(len(mean.samples), 2)
- self.assertEqual(len(var.samples), 2)
- self.assertEqual(mean, average(self.a, self.b))
- self.assertEqual(var, variance(self.a, self.b))
+def test_add(data):
+ assert add() is None
+ result = add(data.a, data.b)
+ assert isinstance(result, CombinedTrace)
+ assert result.samples[0] == 50
+ assert result.samples[1] == 122
+ np.testing.assert_equal(data.a.samples, add(data.a).samples)
- def test_add(self):
- self.assertIsNone(add())
- result = add(self.a, self.b)
- self.assertIsInstance(result, CombinedTrace)
- self.assertEqual(result.samples[0], 50)
- self.assertEqual(result.samples[1], 122)
- np.testing.assert_equal(self.a.samples, add(self.a).samples)
- def test_subtract(self):
- result = subtract(self.a, self.b)
- self.assertIsInstance(result, CombinedTrace)
- self.assertEqual(result.samples[0], -10)
- self.assertEqual(result.samples[1], 38)
+def test_subtract(data):
+ result = subtract(data.a, data.b)
+ assert isinstance(result, CombinedTrace)
+ assert result.samples[0] == -10
+ assert result.samples[1] == 38
diff --git a/test/sca/test_edit.py b/test/sca/test_edit.py
index 282e62e..db80393 100644
--- a/test/sca/test_edit.py
+++ b/test/sca/test_edit.py
@@ -1,48 +1,50 @@
-from unittest import TestCase
-
import numpy as np
+import pytest
from pyecsca.sca import Trace, trim, reverse, pad
-class EditTests(TestCase):
- def setUp(self):
- self._trace = Trace(np.array([10, 20, 30, 40, 50], dtype=np.dtype("i1")))
+@pytest.fixture()
+def trace():
+ return Trace(np.array([10, 20, 30, 40, 50], dtype=np.dtype("i1")))
+
+
+def test_trim(trace):
+ result = trim(trace, 2)
+ assert result is not None
+ np.testing.assert_equal(
+ result.samples, np.array([30, 40, 50], dtype=np.dtype("i1"))
+ )
+
+ result = trim(trace, end=3)
+ assert result is not None
+ np.testing.assert_equal(
+ result.samples, np.array([10, 20, 30], dtype=np.dtype("i1"))
+ )
- def test_trim(self):
- result = trim(self._trace, 2)
- self.assertIsNotNone(result)
- np.testing.assert_equal(
- result.samples, np.array([30, 40, 50], dtype=np.dtype("i1"))
- )
+ with pytest.raises(ValueError):
+ trim(trace, 5, 1)
- result = trim(self._trace, end=3)
- self.assertIsNotNone(result)
- np.testing.assert_equal(
- result.samples, np.array([10, 20, 30], dtype=np.dtype("i1"))
- )
- with self.assertRaises(ValueError):
- trim(self._trace, 5, 1)
+def test_reverse(trace):
+ result = reverse(trace)
+ assert result is not None
+ np.testing.assert_equal(
+ result.samples, np.array([50, 40, 30, 20, 10], dtype=np.dtype("i1"))
+ )
- def test_reverse(self):
- result = reverse(self._trace)
- self.assertIsNotNone(result)
- np.testing.assert_equal(
- result.samples, np.array([50, 40, 30, 20, 10], dtype=np.dtype("i1"))
- )
- def test_pad(self):
- result = pad(self._trace, 2)
- self.assertIsNotNone(result)
- np.testing.assert_equal(
- result.samples,
- np.array([0, 0, 10, 20, 30, 40, 50, 0, 0], dtype=np.dtype("i1")),
- )
+def test_pad(trace):
+ result = pad(trace, 2)
+ assert result is not None
+ np.testing.assert_equal(
+ result.samples,
+ np.array([0, 0, 10, 20, 30, 40, 50, 0, 0], dtype=np.dtype("i1")),
+ )
- result = pad(self._trace, (1, 3))
- self.assertIsNotNone(result)
- np.testing.assert_equal(
- result.samples,
- np.array([0, 10, 20, 30, 40, 50, 0, 0, 0], dtype=np.dtype("i1")),
- )
+ result = pad(trace, (1, 3))
+ assert result is not None
+ np.testing.assert_equal(
+ result.samples,
+ np.array([0, 10, 20, 30, 40, 50, 0, 0, 0], dtype=np.dtype("i1")),
+ )
diff --git a/test/sca/test_filter.py b/test/sca/test_filter.py
index 91f037c..d937f3a 100644
--- a/test/sca/test_filter.py
+++ b/test/sca/test_filter.py
@@ -1,4 +1,6 @@
import numpy as np
+import pytest
+
from pyecsca.sca import (
Trace,
filter_lowpass,
@@ -6,39 +8,42 @@ from pyecsca.sca import (
filter_bandpass,
filter_bandstop,
)
-from .utils import Plottable
-class FilterTests(Plottable):
- def setUp(self):
- self._trace = Trace(
- np.array(
- [5, 12, 15, 13, 15, 11, 7, 2, -4, -8, -10, -8, -13, -9, -11, -8, -5],
- dtype=np.dtype("i1"),
- ),
- None,
- )
+@pytest.fixture()
+def trace():
+ return Trace(
+ np.array(
+ [5, 12, 15, 13, 15, 11, 7, 2, -4, -8, -10, -8, -13, -9, -11, -8, -5],
+ dtype=np.dtype("i1"),
+ ),
+ None,
+ )
+
+
+def test_lowpass(trace, plot):
+ result = filter_lowpass(trace, 100, 20)
+ assert result is not None
+ assert len(trace.samples) == len(result.samples)
+ plot(trace, result)
+
+
+def test_highpass(trace, plot):
+ result = filter_highpass(trace, 128, 20)
+ assert result is not None
+ assert len(trace.samples) == len(result.samples)
+ plot(trace, result)
- def test_lowpass(self):
- result = filter_lowpass(self._trace, 100, 20)
- self.assertIsNotNone(result)
- self.assertEqual(len(self._trace.samples), len(result.samples))
- self.plot(self._trace, result)
- def test_highpass(self):
- result = filter_highpass(self._trace, 128, 20)
- self.assertIsNotNone(result)
- self.assertEqual(len(self._trace.samples), len(result.samples))
- self.plot(self._trace, result)
+def test_bandpass(trace, plot):
+ result = filter_bandpass(trace, 128, 20, 60)
+ assert result is not None
+ assert len(trace.samples) == len(result.samples)
+ plot(trace, result)
- def test_bandpass(self):
- result = filter_bandpass(self._trace, 128, 20, 60)
- self.assertIsNotNone(result)
- self.assertEqual(len(self._trace.samples), len(result.samples))
- self.plot(self._trace, result)
- def test_bandstop(self):
- result = filter_bandstop(self._trace, 128, 20, 60)
- self.assertIsNotNone(result)
- self.assertEqual(len(self._trace.samples), len(result.samples))
- self.plot(self._trace, result)
+def test_bandstop(trace, plot):
+ result = filter_bandstop(trace, 128, 20, 60)
+ assert result is not None
+ assert len(trace.samples) == len(result.samples)
+ plot(trace, result)
diff --git a/test/sca/test_leakage_models.py b/test/sca/test_leakage_models.py
index e9da42c..8be5704 100644
--- a/test/sca/test_leakage_models.py
+++ b/test/sca/test_leakage_models.py
@@ -1,119 +1,101 @@
-from unittest import TestCase
-
from pyecsca.ec.context import local, DefaultContext
from pyecsca.ec.formula import FormulaAction, OpResult
from pyecsca.ec.mod import Mod
from pyecsca.ec.mult import LTRMultiplier
from pyecsca.ec.op import OpType
-from pyecsca.ec.params import get_params
from pyecsca.sca.attack.leakage_model import Identity, Bit, Slice, HammingWeight, HammingDistance, BitLength
+import pytest
-class LeakageModelTests(TestCase):
+def test_identity():
+ val = Mod(3, 7)
+ lm = Identity()
+ assert lm(val) == 3
- def test_identity(self):
- val = Mod(3, 7)
- lm = Identity()
- self.assertEqual(lm(val), 3)
- def test_bit(self):
- val = Mod(3, 7)
- lm = Bit(0)
- self.assertEqual(lm(val), 1)
- lm = Bit(4)
- self.assertEqual(lm(val), 0)
- with self.assertRaises(ValueError):
- Bit(-3)
+def test_bit():
+ val = Mod(3, 7)
+ lm = Bit(0)
+ assert lm(val) == 1
+ lm = Bit(4)
+ assert lm(val) == 0
+ with pytest.raises(ValueError):
+ Bit(-3)
- def test_slice(self):
- val = Mod(0b11110000, 0xf00)
- lm = Slice(0, 4)
- self.assertEqual(lm(val), 0)
- lm = Slice(1, 5)
- self.assertEqual(lm(val), 0b1000)
- lm = Slice(4, 8)
- self.assertEqual(lm(val), 0b1111)
- with self.assertRaises(ValueError):
- Slice(7, 1)
- def test_hamming_weight(self):
- val = Mod(0b11110000, 0xf00)
- lm = HammingWeight()
- self.assertEqual(lm(val), 4)
+def test_slice():
+ val = Mod(0b11110000, 0xf00)
+ lm = Slice(0, 4)
+ assert lm(val) == 0
+ lm = Slice(1, 5)
+ assert lm(val) == 0b1000
+ lm = Slice(4, 8)
+ assert lm(val) == 0b1111
+ with pytest.raises(ValueError):
+ Slice(7, 1)
- def test_hamming_distance(self):
- a = Mod(0b11110000, 0xf00)
- b = Mod(0b00010000, 0xf00)
- lm = HammingDistance()
- self.assertEqual(lm(a, b), 3)
- def test_bit_length(self):
- a = Mod(0b11110000, 0xf00)
- lm = BitLength()
- self.assertEqual(lm(a), 8)
+def test_hamming_weight():
+ val = Mod(0b11110000, 0xf00)
+ lm = HammingWeight()
+ assert lm(val) == 4
-class ModelTraceTests(TestCase):
+def test_hamming_distance():
+ a = Mod(0b11110000, 0xf00)
+ b = Mod(0b00010000, 0xf00)
+ lm = HammingDistance()
+ assert lm(a, b) == 3
- def setUp(self):
- self.secp128r1 = get_params("secg", "secp128r1", "projective")
- self.base = self.secp128r1.generator
- self.coords = self.secp128r1.curve.coordinate_model
- self.add = self.coords.formulas["add-1998-cmo"]
- self.dbl = self.coords.formulas["dbl-1998-cmo"]
- self.neg = self.coords.formulas["neg"]
- self.scale = self.coords.formulas["z"]
- def test_mult_hw(self):
- scalar = 0x123456789
- mult = LTRMultiplier(
- self.add,
- self.dbl,
- self.scale,
- always=True,
- complete=False,
- short_circuit=True,
- )
- with local(DefaultContext()) as ctx:
- mult.init(self.secp128r1, self.base)
- mult.multiply(scalar)
+def test_bit_length():
+ a = Mod(0b11110000, 0xf00)
+ lm = BitLength()
+ assert lm(a) == 8
- lm = HammingWeight()
- trace = []
- def callback(action):
- if isinstance(action, FormulaAction):
- for intermediate in action.op_results:
- leak = lm(intermediate.value)
- trace.append(leak)
+@pytest.fixture()
+def context(secp128r1):
+ scalar = 0x123456789
+ mult = LTRMultiplier(
+ secp128r1.curve.coordinate_model.formulas["add-1998-cmo"],
+ secp128r1.curve.coordinate_model.formulas["dbl-1998-cmo"],
+ secp128r1.curve.coordinate_model.formulas["z"],
+ always=True,
+ complete=False,
+ short_circuit=True,
+ )
+ with local(DefaultContext()) as ctx:
+ mult.init(secp128r1, secp128r1.generator)
+ mult.multiply(scalar)
+ return ctx
+
- ctx.actions.walk(callback)
- self.assertGreater(len(trace), 0)
+def test_mult_hw(context):
+ lm = HammingWeight()
+ trace = []
- def test_mult_hd(self):
- scalar = 0x123456789
- mult = LTRMultiplier(
- self.add,
- self.dbl,
- self.scale,
- always=True,
- complete=False,
- short_circuit=True,
- )
- with local(DefaultContext()) as ctx:
- mult.init(self.secp128r1, self.base)
- mult.multiply(scalar)
+ def callback(action):
+ if isinstance(action, FormulaAction):
+ for intermediate in action.op_results:
+ leak = lm(intermediate.value)
+ trace.append(leak)
- lm = HammingDistance()
- trace = []
+ context.actions.walk(callback)
+ assert len(trace) > 0
- def callback(action):
- if isinstance(action, FormulaAction):
- for intermediate in action.op_results:
- if intermediate.op == OpType.Mult:
- values = list(map(lambda v: v.value if isinstance(v, OpResult) else v, intermediate.parents))
- leak = lm(*values)
- trace.append(leak)
- ctx.actions.walk(callback)
- self.assertGreater(len(trace), 0)
+def test_mult_hd(context):
+ lm = HammingDistance()
+ trace = []
+
+ def callback(action):
+ if isinstance(action, FormulaAction):
+ for intermediate in action.op_results:
+ if intermediate.op == OpType.Mult:
+ values = list(map(lambda v: v.value if isinstance(v, OpResult) else v, intermediate.parents))
+ leak = lm(*values)
+ trace.append(leak)
+
+ context.actions.walk(callback)
+ assert len(trace) > 0
diff --git a/test/sca/test_match.py b/test/sca/test_match.py
index d39e8c3..03d11c4 100644
--- a/test/sca/test_match.py
+++ b/test/sca/test_match.py
@@ -1,72 +1,71 @@
import numpy as np
from pyecsca.sca import Trace, match_pattern, match_part, pad
-from .utils import Plottable
-class MatchingTests(Plottable):
- def test_simple_match(self):
- pattern = Trace(
- np.array([1, 15, 12, -10, 0, 13, 17, -1, 0], dtype=np.dtype("i1")), None
- )
- base = Trace(
- np.array(
- [0, 1, 3, 1, 2, -2, -3, 1, 15, 12, -10, 0, 13, 17, -1, 0, 3, 1],
- dtype=np.dtype("i1"),
- ),
- None,
- )
- filtered = match_part(base, 7, 9)
- self.assertListEqual(filtered, [7])
- self.plot(base=base, pattern=pad(pattern, (filtered[0], 0)))
+def test_simple_match(plot):
+ pattern = Trace(
+ np.array([1, 15, 12, -10, 0, 13, 17, -1, 0], dtype=np.dtype("i1")), None
+ )
+ base = Trace(
+ np.array(
+ [0, 1, 3, 1, 2, -2, -3, 1, 15, 12, -10, 0, 13, 17, -1, 0, 3, 1],
+ dtype=np.dtype("i1"),
+ ),
+ None,
+ )
+ filtered = match_part(base, 7, 9)
+ assert filtered == [7]
+ plot(base=base, pattern=pad(pattern, (filtered[0], 0)))
- def test_multiple_match(self):
- pattern = Trace(
- np.array([1, 15, 12, -10, 0, 13, 17, -1, 0], dtype=np.dtype("i1")), None
- )
- base = Trace(
- np.array(
- [
- 0,
- 1,
- 3,
- 1,
- 2,
- -2,
- -3,
- 1,
- 18,
- 10,
- -5,
- 0,
- 13,
- 17,
- -1,
- 0,
- 3,
- 1,
- 2,
- 5,
- 13,
- 8,
- -8,
- 1,
- 11,
- 15,
- 0,
- 1,
- 5,
- 2,
- 4,
- ],
- dtype=np.dtype("i1"),
- ),
- None,
- )
- filtered = match_pattern(base, pattern, 0.9)
- self.assertListEqual(filtered, [7, 19])
- self.plot(
- base=base,
- pattern1=pad(pattern, (filtered[0], 0)),
- pattern2=pad(pattern, (filtered[1], 0)),
- )
+
+def test_multiple_match(plot):
+ pattern = Trace(
+ np.array([1, 15, 12, -10, 0, 13, 17, -1, 0], dtype=np.dtype("i1")), None
+ )
+ base = Trace(
+ np.array(
+ [
+ 0,
+ 1,
+ 3,
+ 1,
+ 2,
+ -2,
+ -3,
+ 1,
+ 18,
+ 10,
+ -5,
+ 0,
+ 13,
+ 17,
+ -1,
+ 0,
+ 3,
+ 1,
+ 2,
+ 5,
+ 13,
+ 8,
+ -8,
+ 1,
+ 11,
+ 15,
+ 0,
+ 1,
+ 5,
+ 2,
+ 4,
+ ],
+ dtype=np.dtype("i1"),
+ ),
+ None,
+ )
+ filtered = match_pattern(base, pattern, 0.9)
+ assert filtered == [7, 19]
+ plot(
+ base=base,
+ pattern1=pad(pattern, (filtered[0], 0)),
+ pattern2=pad(pattern, (filtered[1], 0)),
+ )
diff --git a/test/sca/test_plot.py b/test/sca/test_plot.py
index 7d2cec0..2722ba3 100644
--- a/test/sca/test_plot.py
+++ b/test/sca/test_plot.py
@@ -1,8 +1,8 @@
-from os import getenv
-
import numpy as np
import holoviews as hv
import matplotlib as mpl
+import pytest
+
from pyecsca.sca.trace import Trace
from pyecsca.sca.trace.plot import (
plot_trace,
@@ -11,34 +11,35 @@ from pyecsca.sca.trace.plot import (
save_figure_svg,
plot_traces,
)
-from .utils import Plottable
-class PlotTests(Plottable):
- def setUp(self) -> None:
- self.trace1 = Trace(np.array([6, 7, 3, -2, 5, 1], dtype=np.dtype("i1")))
- self.trace2 = Trace(np.array([2, 3, 7, 0, -1, 0], dtype=np.dtype("i1")))
+@pytest.fixture()
+def trace1():
+ return Trace(np.array([6, 7, 3, -2, 5, 1], dtype=np.dtype("i1")))
+
+
+@pytest.fixture()
+def trace2():
+ return Trace(np.array([2, 3, 7, 0, -1, 0], dtype=np.dtype("i1")))
+
+
+def test_html(trace1, trace2, plot_path):
+ hv.extension("bokeh")
+ fig = plot_trace(trace1)
+ save_figure(fig, str(plot_path()))
+ other = plot_traces(trace1, trace2)
+ save_figure(other, str(plot_path()))
+
- def test_html(self):
- if getenv("PYECSCA_TEST_PLOTS") is None:
- return
- hv.extension("bokeh")
- fig = plot_trace(self.trace1)
- save_figure(fig, self.get_fname())
- other = plot_traces(self.trace1, self.trace2)
- save_figure(other, self.get_fname())
+@pytest.mark.skip("Broken")
+def test_png(trace1, plot_path):
+ hv.extension("matplotlib")
+ mpl.use("agg")
+ fig = plot_trace(trace1)
+ save_figure_png(fig, str(plot_path()))
- def test_png(self):
- if getenv("PYECSCA_TEST_PLOTS") is None:
- return
- hv.extension("matplotlib")
- mpl.use("agg")
- fig = plot_trace(self.trace1)
- save_figure_png(fig, self.get_fname())
- def test_svg(self):
- if getenv("PYECSCA_TEST_PLOTS") is None:
- return
- hv.extension("matplotlib")
- fig = plot_trace(self.trace1)
- save_figure_svg(fig, self.get_fname())
+def test_svg(trace1, plot_path):
+ hv.extension("matplotlib")
+ fig = plot_trace(trace1)
+ save_figure_svg(fig, str(plot_path()))
diff --git a/test/sca/test_process.py b/test/sca/test_process.py
index fda8575..cf9fbbd 100644
--- a/test/sca/test_process.py
+++ b/test/sca/test_process.py
@@ -1,6 +1,6 @@
-from unittest import TestCase
-
import numpy as np
+import pytest
+
from pyecsca.sca import (
Trace,
absolute,
@@ -14,48 +14,56 @@ from pyecsca.sca import (
)
-class ProcessTests(TestCase):
- def setUp(self):
- self._trace = Trace(np.array([30, -60, 145, 247], dtype=np.dtype("i2")), None)
+@pytest.fixture()
+def trace():
+ return Trace(np.array([30, -60, 145, 247], dtype=np.dtype("i2")), None)
+
+
+def test_absolute(trace):
+ result = absolute(trace)
+ assert result is not None
+ assert result.samples[1] == 60
+
+
+def test_invert(trace):
+ result = invert(trace)
+ assert result is not None
+ np.testing.assert_equal(result.samples, [-30, 60, -145, -247])
+
+
+def test_threshold(trace):
+ result = threshold(trace, 128)
+ assert result is not None
+ assert result.samples[0] == 0
+ assert result.samples[2] == 1
+
+
+def test_rolling_mean(trace):
+ result = rolling_mean(trace, 2)
+ assert result is not None
+ assert len(result.samples) == 3
+ assert result.samples[0] == -15
+ assert result.samples[1] == 42
+ assert result.samples[2] == 196
- def test_absolute(self):
- result = absolute(self._trace)
- self.assertIsNotNone(result)
- self.assertEqual(result.samples[1], 60)
- def test_invert(self):
- result = invert(self._trace)
- self.assertIsNotNone(result)
- np.testing.assert_equal(result.samples, [-30, 60, -145, -247])
+def test_offset(trace):
+ result = offset(trace, 5)
+ assert result is not None
+ np.testing.assert_equal(
+ result.samples, np.array([35, -55, 150, 252], dtype=np.dtype("i2"))
+ )
- def test_threshold(self):
- result = threshold(self._trace, 128)
- self.assertIsNotNone(result)
- self.assertEqual(result.samples[0], 0)
- self.assertEqual(result.samples[2], 1)
- def test_rolling_mean(self):
- result = rolling_mean(self._trace, 2)
- self.assertIsNotNone(result)
- self.assertEqual(len(result.samples), 3)
- self.assertEqual(result.samples[0], -15)
- self.assertEqual(result.samples[1], 42)
- self.assertEqual(result.samples[2], 196)
+def test_recenter(trace):
+ assert recenter(trace) is not None
- def test_offset(self):
- result = offset(self._trace, 5)
- self.assertIsNotNone(result)
- np.testing.assert_equal(
- result.samples, np.array([35, -55, 150, 252], dtype=np.dtype("i2"))
- )
- def test_recenter(self):
- self.assertIsNotNone(recenter(self._trace))
+def test_normalize(trace):
+ result = normalize(trace)
+ assert result is not None
- def test_normalize(self):
- result = normalize(self._trace)
- self.assertIsNotNone(result)
- def test_normalize_wl(self):
- result = normalize_wl(self._trace)
- self.assertIsNotNone(result)
+def test_normalize_wl(trace):
+ result = normalize_wl(trace)
+ assert result is not None
diff --git a/test/sca/test_rpa.py b/test/sca/test_rpa.py
index 2ab784a..f5dc7cc 100644
--- a/test/sca/test_rpa.py
+++ b/test/sca/test_rpa.py
@@ -1,8 +1,7 @@
import io
from contextlib import redirect_stdout
-from unittest import TestCase
-from parameterized import parameterized
+import pytest
from pyecsca.ec.context import local
from pyecsca.ec.model import ShortWeierstrassModel
@@ -13,153 +12,84 @@ from pyecsca.ec.mult import (
RTLMultiplier,
BinaryNAFMultiplier,
WindowNAFMultiplier,
- LadderMultiplier,
SimpleLadderMultiplier,
- DifferentialLadderMultiplier
)
-from pyecsca.ec.params import get_params, DomainParameters
+from pyecsca.ec.params import DomainParameters
from pyecsca.ec.point import Point
from pyecsca.sca.re.rpa import MultipleContext, rpa_point_0y, rpa_point_x0, rpa_distinguish
-class MultipleContextTests(TestCase):
- def setUp(self):
- self.secp128r1 = get_params("secg", "secp128r1", "projective")
- self.base = self.secp128r1.generator
- self.coords = self.secp128r1.curve.coordinate_model
- self.add = self.coords.formulas["add-1998-cmo"]
- self.dbl = self.coords.formulas["dbl-1998-cmo"]
- self.neg = self.coords.formulas["neg"]
- self.scale = self.coords.formulas["z"]
+@pytest.fixture()
+def model():
+ return ShortWeierstrassModel()
- @parameterized.expand(
- [
- ("5", 5),
- ("10", 10),
- ("2355498743", 2355498743),
- (
- "325385790209017329644351321912443757746",
- 325385790209017329644351321912443757746,
- ),
- ("13613624287328732", 13613624287328732),
- ]
- )
- def test_basic(self, name, scalar):
- mult = LTRMultiplier(
- self.add,
- self.dbl,
- self.scale,
- always=False,
- complete=False,
- short_circuit=True,
- )
- with local(MultipleContext()) as ctx:
- mult.init(self.secp128r1, self.base)
- mult.multiply(scalar)
- muls = list(ctx.points.values())
- self.assertEqual(muls[-1], scalar)
- def test_precomp(self):
- bnaf = BinaryNAFMultiplier(self.add, self.dbl, self.neg, self.scale)
- with local(MultipleContext()) as ctx:
- bnaf.init(self.secp128r1, self.base)
- muls = list(ctx.points.values())
- self.assertListEqual(muls, [1, -1])
+@pytest.fixture()
+def coords(model):
+ return model.coordinates["projective"]
- wnaf = WindowNAFMultiplier(self.add, self.dbl, self.neg, 3, self.scale)
- with local(MultipleContext()) as ctx:
- wnaf.init(self.secp128r1, self.base)
- muls = list(ctx.points.values())
- self.assertListEqual(muls, [1, 2, 3, 5])
- def test_window(self):
- mult = WindowNAFMultiplier(
- self.add, self.dbl, self.neg, 3, precompute_negation=True
- )
- with local(MultipleContext()):
- mult.init(self.secp128r1, self.base)
- mult.multiply(5)
+@pytest.fixture()
+def add(coords):
+ return coords.formulas["add-2007-bl"]
- def test_ladder(self):
- curve25519 = get_params("other", "Curve25519", "xz")
- base = curve25519.generator
- coords = curve25519.curve.coordinate_model
- ladd = coords.formulas["ladd-1987-m"]
- dadd = coords.formulas["dadd-1987-m"]
- dbl = coords.formulas["dbl-1987-m"]
- scale = coords.formulas["scale"]
- ladd_mult = LadderMultiplier(ladd, dbl, scale)
- with local(MultipleContext()) as ctx:
- ladd_mult.init(curve25519, base)
- ladd_mult.multiply(1339278426732672313)
- muls = list(ctx.points.values())
- self.assertEqual(muls[-2], 1339278426732672313)
- dadd_mult = DifferentialLadderMultiplier(dadd, dbl, scale)
- with local(MultipleContext()) as ctx:
- dadd_mult.init(curve25519, base)
- dadd_mult.multiply(1339278426732672313)
- muls = list(ctx.points.values())
- self.assertEqual(muls[-2], 1339278426732672313)
+@pytest.fixture()
+def dbl(coords):
+ return coords.formulas["dbl-2007-bl"]
-class RPATests(TestCase):
- def setUp(self):
- self.model = ShortWeierstrassModel()
- self.coords = self.model.coordinates["projective"]
- self.add = self.coords.formulas["add-2007-bl"]
- self.dbl = self.coords.formulas["dbl-2007-bl"]
- self.neg = self.coords.formulas["neg"]
+@pytest.fixture()
+def neg(coords):
+ return coords.formulas["neg"]
- def test_x0_point(self):
- p = 0x85d265945a4f5681
- a = Mod(0x7fc57b4110698bc0, p)
- b = Mod(0x37113ea591b04527, p)
- gx = Mod(0x80d2d78fddb97597, p)
- gy = Mod(0x5586d818b7910930, p)
- # (0x4880bcf620852a54, 0) RPA point
- infty = Point(self.coords, X=Mod(0, p), Y=Mod(1, p), Z=Mod(0, p))
- g = Point(self.coords, X=gx, Y=gy, Z=Mod(1, p))
- curve = EllipticCurve(self.model, self.coords, p, infty, dict(a=a, b=b))
- params_full = DomainParameters(curve, g, 0x85d265932d90785c, 1)
+@pytest.fixture()
+def rpa_params(model, coords):
+ p = 0x85d265945a4f5681
+ a = Mod(0x7fc57b4110698bc0, p)
+ b = Mod(0x37113ea591b04527, p)
+ gx = Mod(0x80d2d78fddb97597, p)
+ gy = Mod(0x5586d818b7910930, p)
+ # (0x4880bcf620852a54, 0) RPA point
+ # (0, 0x6bed3155c9ada064) RPA point
- self.assertIsNotNone(rpa_point_x0(params_full))
+ infty = Point(coords, X=Mod(0, p), Y=Mod(1, p), Z=Mod(0, p))
+ g = Point(coords, X=gx, Y=gy, Z=Mod(1, p))
+ curve = EllipticCurve(model, coords, p, infty, dict(a=a, b=b))
+ return DomainParameters(curve, g, 0x85d265932d90785c, 1)
- def test_0y_point(self):
- p = 0x85d265945a4f5681
- a = Mod(0x7fc57b4110698bc0, p)
- b = Mod(0x37113ea591b04527, p)
- gx = Mod(0x80d2d78fddb97597, p)
- gy = Mod(0x5586d818b7910930, p)
- # (0, 0x6bed3155c9ada064) RPA point
- infty = Point(self.coords, X=Mod(0, p), Y=Mod(1, p), Z=Mod(0, p))
- g = Point(self.coords, X=gx, Y=gy, Z=Mod(1, p))
- curve = EllipticCurve(self.model, self.coords, p, infty, dict(a=a, b=b))
- params_full = DomainParameters(curve, g, 0x85d265932d90785c, 1)
+def test_x0_point(rpa_params):
+ res = rpa_point_x0(rpa_params)
+ assert res is not None
+ assert res.y == 0
- self.assertIsNotNone(rpa_point_0y(params_full))
- def test_distinguish(self):
- secp128r1 = get_params("secg", "secp128r1", "projective")
- multipliers = [LTRMultiplier(self.add, self.dbl, None, False, True, True),
- LTRMultiplier(self.add, self.dbl, None, True, True, True),
- RTLMultiplier(self.add, self.dbl, None, False, True),
- RTLMultiplier(self.add, self.dbl, None, True, True),
- SimpleLadderMultiplier(self.add, self.dbl, None, True, True),
- BinaryNAFMultiplier(self.add, self.dbl, self.neg, None, True),
- WindowNAFMultiplier(self.add, self.dbl, self.neg, 3, None, True),
- WindowNAFMultiplier(self.add, self.dbl, self.neg, 4, None, True)]
- for real_mult in multipliers:
- def simulated_oracle(scalar, affine_point):
- point = affine_point.to_model(secp128r1.curve.coordinate_model, secp128r1.curve)
- with local(MultipleContext()) as ctx:
- real_mult.init(secp128r1, point)
- real_mult.multiply(scalar)
- return any(map(lambda P: P.X == 0 or P.Y == 0, ctx.points.keys()))
+def test_0y_point(rpa_params):
+ res = rpa_point_0y(rpa_params)
+ assert res is not None
+ assert res.x == 0
- with redirect_stdout(io.StringIO()):
- result = rpa_distinguish(secp128r1, multipliers, simulated_oracle)
- self.assertEqual(1, len(result))
- self.assertEqual(real_mult, result[0])
+
+def test_distinguish(secp128r1, add, dbl, neg):
+ multipliers = [LTRMultiplier(add, dbl, None, False, True, True),
+ LTRMultiplier(add, dbl, None, True, True, True),
+ RTLMultiplier(add, dbl, None, False, True),
+ RTLMultiplier(add, dbl, None, True, True),
+ SimpleLadderMultiplier(add, dbl, None, True, True),
+ BinaryNAFMultiplier(add, dbl, neg, None, True),
+ WindowNAFMultiplier(add, dbl, neg, 3, None, True),
+ WindowNAFMultiplier(add, dbl, neg, 4, None, True)]
+ for real_mult in multipliers:
+ def simulated_oracle(scalar, affine_point):
+ point = affine_point.to_model(secp128r1.curve.coordinate_model, secp128r1.curve)
+ with local(MultipleContext()) as ctx:
+ real_mult.init(secp128r1, point)
+ real_mult.multiply(scalar)
+ return any(map(lambda P: P.X == 0 or P.Y == 0, ctx.points.keys()))
+
+ with redirect_stdout(io.StringIO()):
+ result = rpa_distinguish(secp128r1, multipliers, simulated_oracle)
+ assert 1 == len(result)
+ assert real_mult == result[0]
diff --git a/test/sca/test_rpa_context.py b/test/sca/test_rpa_context.py
new file mode 100644
index 0000000..78191bc
--- /dev/null
+++ b/test/sca/test_rpa_context.py
@@ -0,0 +1,106 @@
+from typing import cast
+
+import pytest
+
+from pyecsca.ec.context import local
+from pyecsca.ec.formula import LadderFormula, DifferentialAdditionFormula, DoublingFormula, \
+ ScalingFormula
+from pyecsca.ec.mult import (
+ LTRMultiplier,
+ BinaryNAFMultiplier,
+ WindowNAFMultiplier,
+ LadderMultiplier,
+ DifferentialLadderMultiplier
+)
+from pyecsca.sca.re.rpa import MultipleContext
+
+
+@pytest.fixture()
+def add(secp128r1):
+ return secp128r1.curve.coordinate_model.formulas["add-1998-cmo"]
+
+
+@pytest.fixture()
+def dbl(secp128r1):
+ return secp128r1.curve.coordinate_model.formulas["dbl-1998-cmo"]
+
+
+@pytest.fixture()
+def neg(secp128r1):
+ return secp128r1.curve.coordinate_model.formulas["neg"]
+
+
+@pytest.fixture()
+def scale(secp128r1):
+ return secp128r1.curve.coordinate_model.formulas["z"]
+
+
+@pytest.mark.parametrize("name,scalar",
+ [
+ ("5", 5),
+ ("10", 10),
+ ("2355498743", 2355498743),
+ (
+ "325385790209017329644351321912443757746",
+ 325385790209017329644351321912443757746,
+ ),
+ ("13613624287328732", 13613624287328732),
+ ])
+def test_basic(secp128r1, add, dbl, scale, name, scalar):
+ mult = LTRMultiplier(
+ add,
+ dbl,
+ scale,
+ always=False,
+ complete=False,
+ short_circuit=True,
+ )
+ with local(MultipleContext()) as ctx:
+ mult.init(secp128r1, secp128r1.generator)
+ mult.multiply(scalar)
+ muls = list(ctx.points.values())
+ assert muls[-1] == scalar
+
+
+def test_precomp(secp128r1, add, dbl, neg, scale):
+ bnaf = BinaryNAFMultiplier(add, dbl, neg, scale)
+ with local(MultipleContext()) as ctx:
+ bnaf.init(secp128r1, secp128r1.generator)
+ muls = list(ctx.points.values())
+ assert muls == [1, -1]
+
+ wnaf = WindowNAFMultiplier(add, dbl, neg, 3, scale)
+ with local(MultipleContext()) as ctx:
+ wnaf.init(secp128r1, secp128r1.generator)
+ muls = list(ctx.points.values())
+ assert muls == [1, 2, 3, 5]
+
+
+def test_window(secp128r1, add, dbl, neg):
+ mult = WindowNAFMultiplier(
+ add, dbl, neg, 3, precompute_negation=True
+ )
+ with local(MultipleContext()):
+ mult.init(secp128r1, secp128r1.generator)
+ mult.multiply(5)
+
+
+def test_ladder(curve25519):
+ base = curve25519.generator
+ coords = curve25519.curve.coordinate_model
+ ladd = cast(LadderFormula, coords.formulas["ladd-1987-m"])
+ dadd = cast(DifferentialAdditionFormula, coords.formulas["dadd-1987-m"])
+ dbl = cast(DoublingFormula, coords.formulas["dbl-1987-m"])
+ scale = cast(ScalingFormula, coords.formulas["scale"])
+ ladd_mult = LadderMultiplier(ladd, dbl, scale)
+ with local(MultipleContext()) as ctx:
+ ladd_mult.init(curve25519, base)
+ ladd_mult.multiply(1339278426732672313)
+ muls = list(ctx.points.values())
+ assert muls[-2] == 1339278426732672313
+ dadd_mult = DifferentialLadderMultiplier(dadd, dbl, scale)
+ with local(MultipleContext()) as ctx:
+ dadd_mult.init(curve25519, base)
+ dadd_mult.multiply(1339278426732672313)
+ muls = list(ctx.points.values())
+ assert muls[-2] == 1339278426732672313
diff --git a/test/sca/test_sampling.py b/test/sca/test_sampling.py
index fcebf2d..062e726 100644
--- a/test/sca/test_sampling.py
+++ b/test/sca/test_sampling.py
@@ -7,162 +7,159 @@ from pyecsca.sca import (
downsample_max,
downsample_min,
)
-from .utils import Plottable
-class SamplingTests(Plottable):
- def setUp(self):
- self._trace = Trace(np.array([20, 40, 50, 50, 10], dtype=np.dtype("i1")))
+def test_downsample_average():
+ trace = Trace(np.array([20, 40, 50, 50, 10], dtype=np.dtype("i1")))
+ result = downsample_average(trace, 2)
+ assert result is not None
+ assert isinstance(result, Trace)
+ assert len(result.samples) == 2
+ assert result.samples[0] == 30
+ assert result.samples[1] == 50
- def test_downsample_average(self):
- result = downsample_average(self._trace, 2)
- self.assertIsNotNone(result)
- self.assertIsInstance(result, Trace)
- self.assertEqual(len(result.samples), 2)
- self.assertEqual(result.samples[0], 30)
- self.assertEqual(result.samples[1], 50)
- def test_downsample_pick(self):
- result = downsample_pick(self._trace, 2)
- self.assertIsNotNone(result)
- self.assertIsInstance(result, Trace)
- self.assertEqual(len(result.samples), 3)
- self.assertEqual(result.samples[0], 20)
- self.assertEqual(result.samples[1], 50)
+def test_downsample_pick():
+ trace = Trace(np.array([20, 40, 50, 50, 10], dtype=np.dtype("i1")))
+ result = downsample_pick(trace, 2)
+ assert result is not None
+ assert isinstance(result, Trace)
+ assert len(result.samples) == 3
+ assert result.samples[0] == 20
+ assert result.samples[1] == 50
- def test_downsample_max(self):
- trace = Trace(
- np.array(
- [
- 20,
- 30,
- 55,
- 18,
- 15,
- 10,
- 35,
- 24,
- 21,
- 15,
- 10,
- 8,
- -10,
- -5,
- -8,
- -12,
- -15,
- -18,
- -34,
- -21,
- -17,
- -10,
- -5,
- -12,
- -6,
- -2,
- 4,
- 8,
- 21,
- 28,
- ],
- dtype=np.dtype("i1"),
- )
- )
- result = downsample_max(trace, 2)
- self.assertIsNotNone(result)
- self.assertIsInstance(result, Trace)
- self.assertEqual(len(result.samples), 15)
- self.assertEqual(
- list(result), [30, 55, 15, 35, 21, 10, -5, -8, -15, -21, -10, -5, -2, 8, 28]
- )
- def test_downsample_min(self):
- trace = Trace(
- np.array(
- [
- 20,
- 30,
- 55,
- 18,
- 15,
- 10,
- 35,
- 24,
- 21,
- 15,
- 10,
- 8,
- -10,
- -5,
- -8,
- -12,
- -15,
- -18,
- -34,
- -21,
- -17,
- -10,
- -5,
- -12,
- -6,
- -2,
- 4,
- 8,
- 21,
- 28,
- ],
- dtype=np.dtype("i1"),
- )
+def test_downsample_max():
+ trace = Trace(
+ np.array(
+ [
+ 20,
+ 30,
+ 55,
+ 18,
+ 15,
+ 10,
+ 35,
+ 24,
+ 21,
+ 15,
+ 10,
+ 8,
+ -10,
+ -5,
+ -8,
+ -12,
+ -15,
+ -18,
+ -34,
+ -21,
+ -17,
+ -10,
+ -5,
+ -12,
+ -6,
+ -2,
+ 4,
+ 8,
+ 21,
+ 28,
+ ],
+ dtype=np.dtype("i1"),
)
- result = downsample_min(trace, 2)
- self.assertIsNotNone(result)
- self.assertIsInstance(result, Trace)
- self.assertEqual(len(result.samples), 15)
- self.assertEqual(
- list(result),
- [20, 18, 10, 24, 15, 8, -10, -12, -18, -34, -17, -12, -6, 4, 21],
+ )
+ result = downsample_max(trace, 2)
+ assert result is not None
+ assert isinstance(result, Trace)
+ assert len(result.samples) == 15
+ assert list(result) == [30, 55, 15, 35, 21, 10, -5, -8, -15, -21, -10, -5, -2, 8, 28]
+
+
+def test_downsample_min():
+ trace = Trace(
+ np.array(
+ [
+ 20,
+ 30,
+ 55,
+ 18,
+ 15,
+ 10,
+ 35,
+ 24,
+ 21,
+ 15,
+ 10,
+ 8,
+ -10,
+ -5,
+ -8,
+ -12,
+ -15,
+ -18,
+ -34,
+ -21,
+ -17,
+ -10,
+ -5,
+ -12,
+ -6,
+ -2,
+ 4,
+ 8,
+ 21,
+ 28,
+ ],
+ dtype=np.dtype("i1"),
)
+ )
+ result = downsample_min(trace, 2)
+ assert result is not None
+ assert isinstance(result, Trace)
+ assert len(result.samples) == 15
+ assert list(result) == \
+ [20, 18, 10, 24, 15, 8, -10, -12, -18, -34, -17, -12, -6, 4, 21]
+
- def test_downsample_decimate(self):
- trace = Trace(
- np.array(
- [
- 20,
- 30,
- 55,
- 18,
- 15,
- 10,
- 35,
- 24,
- 21,
- 15,
- 10,
- 8,
- -10,
- -5,
- -8,
- -12,
- -15,
- -18,
- -34,
- -21,
- -17,
- -10,
- -5,
- -12,
- -6,
- -2,
- 4,
- 8,
- 21,
- 28,
- ],
- dtype=np.dtype("i1"),
- )
+def test_downsample_decimate(plot):
+ trace = Trace(
+ np.array(
+ [
+ 20,
+ 30,
+ 55,
+ 18,
+ 15,
+ 10,
+ 35,
+ 24,
+ 21,
+ 15,
+ 10,
+ 8,
+ -10,
+ -5,
+ -8,
+ -12,
+ -15,
+ -18,
+ -34,
+ -21,
+ -17,
+ -10,
+ -5,
+ -12,
+ -6,
+ -2,
+ 4,
+ 8,
+ 21,
+ 28,
+ ],
+ dtype=np.dtype("i1"),
)
- result = downsample_decimate(trace, 2)
- self.assertIsNotNone(result)
- self.assertIsInstance(result, Trace)
- self.assertEqual(len(result.samples), 15)
- self.plot(trace, result)
+ )
+ result = downsample_decimate(trace, 2)
+ assert result is not None
+ assert isinstance(result, Trace)
+ assert len(result.samples) == 15
+ plot(original=trace, result=result)
diff --git a/test/sca/test_stacked_combine.py b/test/sca/test_stacked_combine.py
index 6f8fe60..4ed8d35 100644
--- a/test/sca/test_stacked_combine.py
+++ b/test/sca/test_stacked_combine.py
@@ -1,4 +1,4 @@
-from unittest import TestCase
+import pytest
from numba import cuda
import numpy as np
@@ -15,98 +15,94 @@ TRACE_COUNT = 32
TRACE_LEN = 4 * TPB
-class StackedCombineTests(TestCase):
- def setUp(self):
- if not cuda.is_available():
- self.skipTest("CUDA not available")
- self.samples = np.random.rand(TRACE_COUNT, TRACE_LEN)
- self.stacked_ts = StackedTraces(self.samples)
- self.gpu_manager = GPUTraceManager(self.stacked_ts, TPB)
+@pytest.fixture()
+def samples():
+ np.random.seed(0x1234)
+ return np.random.rand(TRACE_COUNT, TRACE_LEN)
- def test_fromarray(self):
- max_len = self.samples.shape[1]
- min_len = max_len // 2
- jagged_samples = [
- t[min_len:np.random.randint(max_len)]
- for t
- in self.samples
- ]
- min_len = min(map(len, jagged_samples))
- stacked = StackedTraces.fromarray(jagged_samples)
- self.assertIsInstance(stacked, StackedTraces)
- self.assertTupleEqual(
- stacked.samples.shape,
- (self.samples.shape[0], min_len)
- )
- self.assertTrue((stacked.samples == self.samples[:, :min_len]).all())
+@pytest.fixture()
+def gpu_manager(samples):
+ if not cuda.is_available():
+ pytest.skip("CUDA not available")
+ return GPUTraceManager(StackedTraces(samples), TPB)
- def test_fromtraceset(self):
- max_len = self.samples.shape[1]
- min_len = max_len // 2
- traces = [
- Trace(t[min_len:np.random.randint(max_len)])
- for t
- in self.samples
- ]
- tset = TraceSet(*traces)
- min_len = min(map(len, traces))
- stacked = StackedTraces.fromtraceset(tset)
- self.assertIsInstance(stacked, StackedTraces)
- self.assertTupleEqual(
- stacked.samples.shape,
- (self.samples.shape[0], min_len)
- )
- self.assertTrue((stacked.samples == self.samples[:, :min_len]).all())
+def test_fromarray(samples):
+ max_len = samples.shape[1]
+ min_len = max_len // 2
+ jagged_samples = [
+ t[min_len:np.random.randint(max_len)]
+ for t
+ in samples
+ ]
+ min_len = min(map(len, jagged_samples))
+ stacked = StackedTraces.fromarray(jagged_samples)
- def test_average(self):
- avg_trace = self.gpu_manager.average()
- avg_cmp: np.ndarray = np.average(self.samples, 0)
+ assert isinstance(stacked, StackedTraces)
+ assert stacked.samples.shape == \
+ (samples.shape[0], min_len)
+ assert (stacked.samples == samples[:, :min_len]).all()
- self.assertIsInstance(avg_trace, CombinedTrace)
- self.assertTupleEqual(
- avg_trace.samples.shape,
- avg_cmp.shape
- )
- self.assertTrue(all(np.isclose(avg_trace.samples, avg_cmp)))
- def test_standard_deviation(self):
- std_trace = self.gpu_manager.standard_deviation()
- std_cmp: np.ndarray = np.std(self.samples, 0)
+def test_fromtraceset(samples):
+ max_len = samples.shape[1]
+ min_len = max_len // 2
+ traces = [
+ Trace(t[min_len:np.random.randint(max_len)])
+ for t
+ in samples
+ ]
+ tset = TraceSet(*traces)
+ min_len = min(map(len, traces))
+ stacked = StackedTraces.fromtraceset(tset)
- self.assertIsInstance(std_trace, CombinedTrace)
- self.assertTupleEqual(
- std_trace.samples.shape,
- std_cmp.shape
- )
- self.assertTrue(all(np.isclose(std_trace.samples, std_cmp)))
+ assert isinstance(stacked, StackedTraces)
+ assert stacked.samples.shape == \
+ (samples.shape[0], min_len)
+ assert (stacked.samples == samples[:, :min_len]).all()
- def test_variance(self):
- var_trace = self.gpu_manager.variance()
- var_cmp: np.ndarray = np.var(self.samples, 0)
- self.assertIsInstance(var_trace, CombinedTrace)
- self.assertTupleEqual(
- var_trace.samples.shape,
- var_cmp.shape
- )
- self.assertTrue(all(np.isclose(var_trace.samples, var_cmp)))
+def test_average(samples, gpu_manager):
+ avg_trace = gpu_manager.average()
+ avg_cmp: np.ndarray = np.average(samples, 0)
- def test_average_and_variance(self):
- avg_trace, var_trace = self.gpu_manager.average_and_variance()
- avg_cmp: np.ndarray = np.average(self.samples, 0)
- var_cmp: np.ndarray = np.var(self.samples, 0)
+ assert isinstance(avg_trace, CombinedTrace)
+ assert avg_trace.samples.shape == \
+ avg_cmp.shape
+ assert all(np.isclose(avg_trace.samples, avg_cmp))
- self.assertIsInstance(avg_trace, CombinedTrace)
- self.assertIsInstance(var_trace, CombinedTrace)
- self.assertTupleEqual(
- avg_trace.samples.shape,
- avg_cmp.shape
- )
- self.assertTupleEqual(
- var_trace.samples.shape,
- var_cmp.shape
- )
- self.assertTrue(all(np.isclose(avg_trace.samples, avg_cmp)))
- self.assertTrue(all(np.isclose(var_trace.samples, var_cmp)))
+
+def test_standard_deviation(samples, gpu_manager):
+ std_trace = gpu_manager.standard_deviation()
+ std_cmp: np.ndarray = np.std(samples, 0)
+
+ assert isinstance(std_trace, CombinedTrace)
+ assert std_trace.samples.shape == \
+ std_cmp.shape
+ assert all(np.isclose(std_trace.samples, std_cmp))
+
+
+def test_variance(samples, gpu_manager):
+ var_trace = gpu_manager.variance()
+ var_cmp: np.ndarray = np.var(samples, 0)
+
+ assert isinstance(var_trace, CombinedTrace)
+ assert var_trace.samples.shape == \
+ var_cmp.shape
+ assert all(np.isclose(var_trace.samples, var_cmp))
+
+
+def test_average_and_variance(samples, gpu_manager):
+ avg_trace, var_trace = gpu_manager.average_and_variance()
+ avg_cmp: np.ndarray = np.average(samples, 0)
+ var_cmp: np.ndarray = np.var(samples, 0)
+
+ assert isinstance(avg_trace, CombinedTrace)
+ assert isinstance(var_trace, CombinedTrace)
+ assert avg_trace.samples.shape == \
+ avg_cmp.shape
+ assert var_trace.samples.shape == \
+ var_cmp.shape
+ assert all(np.isclose(avg_trace.samples, avg_cmp))
+ assert all(np.isclose(var_trace.samples, var_cmp))
diff --git a/test/sca/test_target.py b/test/sca/test_target.py
index 3ca92fb..4155b25 100644
--- a/test/sca/test_target.py
+++ b/test/sca/test_target.py
@@ -1,9 +1,8 @@
import io
from contextlib import redirect_stdout
from copy import copy
-from os.path import realpath, dirname, join
-from typing import Optional
-from unittest import TestCase, SkipTest
+
+import pytest
from importlib_resources import files, as_file
from smartcard.pcsc.PCSCExceptions import BaseSCardException
@@ -36,460 +35,473 @@ from pyecsca.sca.target.ectester import (
if has_pyscard:
from pyecsca.sca.target.ectester import ECTesterTargetPCSC as ECTesterTarget
else:
- ECTesterTarget = None
+ from pyecsca.sca.target.ectester import ECTesterTarget
class TestTarget(SimpleSerialTarget, BinaryTarget):
- pass
+ __test__ = False
+
+def test_basic_target():
+ with as_file(files(test.data.sca).joinpath("target.py")) as target_path:
+ target = TestTarget(["python", target_path])
+ target.connect()
+ resp = target.send_cmd(SimpleSerialMessage("d", ""), 500)
+ assert "r" in resp
+ assert "z" in resp
+ assert resp["r"].data == "01020304"
+ target.disconnect()
-class BinaryTargetTests(TestCase):
- def test_basic_target(self):
- with as_file(files(test.data.sca).joinpath("target.py")) as target_path:
- target = TestTarget(["python", target_path])
+
+def test_debug():
+ with as_file(files(test.data.sca).joinpath("target.py")) as target_path:
+ target = TestTarget(["python", target_path], debug_output=True)
+ with redirect_stdout(io.StringIO()) as out:
target.connect()
- resp = target.send_cmd(SimpleSerialMessage("d", ""), 500)
- self.assertIn("r", resp)
- self.assertIn("z", resp)
- self.assertEqual(resp["r"].data, "01020304")
+ target.send_cmd(SimpleSerialMessage("d", ""), 500)
target.disconnect()
+ assert out.read() is not None
- def test_debug(self):
- with as_file(files(test.data.sca).joinpath("target.py")) as target_path:
- target = TestTarget(["python", target_path], debug_output=True)
- with redirect_stdout(io.StringIO()):
- target.connect()
- target.send_cmd(SimpleSerialMessage("d", ""), 500)
- target.disconnect()
- def test_no_connection(self):
- with as_file(files(test.data.sca).joinpath("target.py")) as target_path:
- target = TestTarget(str(target_path))
- with self.assertRaises(ValueError):
- target.write(bytes([1, 2, 3, 4]))
- with self.assertRaises(ValueError):
- target.read(5)
- target.disconnect()
+def test_no_connection():
+ with as_file(files(test.data.sca).joinpath("target.py")) as target_path:
+ target = TestTarget(str(target_path))
+ with pytest.raises(ValueError):
+ target.write(bytes([1, 2, 3, 4]))
+ with pytest.raises(ValueError):
+ target.read(5)
+ target.disconnect()
-class ECTesterTargetTests(TestCase):
- reader: Optional[str] = None
- target: Optional[ECTesterTarget] = None
- secp256r1: DomainParameters
- secp256r1_projective: DomainParameters
+@pytest.fixture()
+def secp256r1_affine():
+ return get_params("secg", "secp256r1", "affine")
- @classmethod
- def setUpClass(cls):
- if not has_pyscard:
- return
- from smartcard.System import readers
- try:
- rs = readers()
- except BaseSCardException:
- return
- if not rs:
- return
- cls.reader = rs[0]
- cls.secp256r1 = get_params("secg", "secp256r1", "affine")
- cls.secp256r1_projective = get_params("secg", "secp256r1", "projective")
+@pytest.fixture()
+def secp256r1_projective():
+ return get_params("secg", "secp256r1", "projective")
- def setUp(self):
- if not ECTesterTargetTests.reader:
- raise SkipTest("No smartcard readers.")
- self.target = ECTesterTarget(ECTesterTargetTests.reader)
- self.target.connect()
- if not self.target.select_applet():
- self.target.disconnect()
- raise SkipTest("No applet in reader: {}".format(ECTesterTargetTests.reader))
- def tearDown(self):
- self.target.cleanup()
- self.target.disconnect()
+@pytest.fixture()
+def target():
+ if not has_pyscard:
+ pytest.skip("No pyscard.")
+ from smartcard.System import readers
+ rs = None
+ try:
+ rs = readers()
+ except BaseSCardException as e:
+ pytest.skip(f"No reader found: {e}")
+ if not rs:
+ pytest.skip("No reader found")
+ reader = rs[0]
+ target: ECTesterTarget = ECTesterTarget(reader)
+ target.connect()
+ if not target.select_applet():
+ target.disconnect()
+ pytest.skip(f"No applet in reader: {reader}")
+ yield target
+ target.cleanup()
+ target.disconnect()
- def test_allocate(self):
- ka_resp = self.target.allocate_ka(KeyAgreementEnum.ALG_EC_SVDP_DH)
- self.assertTrue(ka_resp.success)
- sig_resp = self.target.allocate_sig(SignatureEnum.ALG_ECDSA_SHA)
- self.assertTrue(sig_resp.success)
- key_resp = self.target.allocate(
- KeypairEnum.KEYPAIR_LOCAL,
- KeyBuildEnum.BUILD_KEYPAIR,
- 256,
- KeyClassEnum.ALG_EC_FP,
- )
- self.assertTrue(key_resp.success)
- def test_set(self):
- self.target.allocate(
- KeypairEnum.KEYPAIR_LOCAL,
- KeyBuildEnum.BUILD_KEYPAIR,
- 256,
- KeyClassEnum.ALG_EC_FP,
- )
- set_resp = self.target.set(
- KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
- )
- self.assertTrue(set_resp.success)
+def test_allocate(target):
+ ka_resp = target.allocate_ka(KeyAgreementEnum.ALG_EC_SVDP_DH)
+ assert ka_resp.success
+ sig_resp = target.allocate_sig(SignatureEnum.ALG_ECDSA_SHA)
+ assert sig_resp.success
+ key_resp = target.allocate(
+ KeypairEnum.KEYPAIR_LOCAL,
+ KeyBuildEnum.BUILD_KEYPAIR,
+ 256,
+ KeyClassEnum.ALG_EC_FP,
+ )
+ assert key_resp.success
- def test_set_explicit(self):
- self.target.allocate(
- KeypairEnum.KEYPAIR_LOCAL,
- KeyBuildEnum.BUILD_KEYPAIR,
- 256,
- KeyClassEnum.ALG_EC_FP,
- )
- values = ECTesterTarget.encode_parameters(
- ParameterEnum.DOMAIN_FP, self.secp256r1
- )
- set_resp = self.target.set(
- KeypairEnum.KEYPAIR_LOCAL,
- CurveEnum.external,
- ParameterEnum.DOMAIN_FP,
- values,
- )
- self.assertTrue(set_resp.success)
- def test_generate(self):
- self.target.allocate(
- KeypairEnum.KEYPAIR_LOCAL,
- KeyBuildEnum.BUILD_KEYPAIR,
- 256,
- KeyClassEnum.ALG_EC_FP,
- )
- self.target.set(
- KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
- )
- generate_resp = self.target.generate(KeypairEnum.KEYPAIR_LOCAL)
- self.assertTrue(generate_resp.success)
+def test_set(target):
+ target.allocate(
+ KeypairEnum.KEYPAIR_LOCAL,
+ KeyBuildEnum.BUILD_KEYPAIR,
+ 256,
+ KeyClassEnum.ALG_EC_FP,
+ )
+ set_resp = target.set(
+ KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
+ )
+ assert set_resp.success
- def test_clear(self):
- self.target.allocate(
- KeypairEnum.KEYPAIR_LOCAL,
- KeyBuildEnum.BUILD_KEYPAIR,
- 256,
- KeyClassEnum.ALG_EC_FP,
- )
- clear_resp = self.target.clear(KeypairEnum.KEYPAIR_LOCAL)
- self.assertTrue(clear_resp.success)
- def test_cleanup(self):
- cleanup_resp = self.target.cleanup()
- self.assertTrue(cleanup_resp.success)
+def test_set_explicit(target, secp256r1_affine):
+ target.allocate(
+ KeypairEnum.KEYPAIR_LOCAL,
+ KeyBuildEnum.BUILD_KEYPAIR,
+ 256,
+ KeyClassEnum.ALG_EC_FP,
+ )
+ values = ECTesterTarget.encode_parameters(
+ ParameterEnum.DOMAIN_FP, secp256r1_affine
+ )
+ set_resp = target.set(
+ KeypairEnum.KEYPAIR_LOCAL,
+ CurveEnum.external,
+ ParameterEnum.DOMAIN_FP,
+ values,
+ )
+ assert set_resp.success
- def test_info(self):
- info_resp = self.target.info()
- self.assertTrue(info_resp.success)
- def test_dry_run(self):
- dry_run_resp = self.target.run_mode(RunModeEnum.MODE_DRY_RUN)
- self.assertTrue(dry_run_resp.success)
- allocate_resp = self.target.allocate(
- KeypairEnum.KEYPAIR_LOCAL,
- KeyBuildEnum.BUILD_KEYPAIR,
- 256,
- KeyClassEnum.ALG_EC_FP,
- )
- self.assertTrue(allocate_resp.success)
- dry_run_resp = self.target.run_mode(RunModeEnum.MODE_NORMAL)
- self.assertTrue(dry_run_resp.success)
+def test_generate(target):
+ target.allocate(
+ KeypairEnum.KEYPAIR_LOCAL,
+ KeyBuildEnum.BUILD_KEYPAIR,
+ 256,
+ KeyClassEnum.ALG_EC_FP,
+ )
+ target.set(
+ KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
+ )
+ generate_resp = target.generate(KeypairEnum.KEYPAIR_LOCAL)
+ assert generate_resp.success
- def test_export(self):
- self.target.allocate(
- KeypairEnum.KEYPAIR_LOCAL,
- KeyBuildEnum.BUILD_KEYPAIR,
- 256,
- KeyClassEnum.ALG_EC_FP,
- )
- self.target.set(
- KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
- )
- self.target.generate(KeypairEnum.KEYPAIR_LOCAL)
- export_public_resp = self.target.export(
- KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PUBLIC, ParameterEnum.W
- )
- self.assertTrue(export_public_resp.success)
- pubkey_bytes = export_public_resp.get_param(
- KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.W
- )
- pubkey = self.secp256r1.curve.decode_point(pubkey_bytes)
- export_privkey_resp = self.target.export(
- KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PRIVATE, ParameterEnum.S
- )
- self.assertTrue(export_privkey_resp.success)
- privkey = int.from_bytes(
- export_privkey_resp.get_param(KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.S),
- "big",
- )
- self.assertEqual(
- pubkey,
- self.secp256r1.curve.affine_multiply(self.secp256r1.generator, privkey),
- )
- def test_export_curve(self):
- self.target.allocate(
- KeypairEnum.KEYPAIR_LOCAL,
- KeyBuildEnum.BUILD_KEYPAIR,
- 256,
- KeyClassEnum.ALG_EC_FP,
- )
- self.target.set(
- KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
- )
- export_resp = self.target.export(
- KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PUBLIC, ParameterEnum.DOMAIN_FP
- )
- self.assertTrue(export_resp.success)
+def test_clear(target):
+ target.allocate(
+ KeypairEnum.KEYPAIR_LOCAL,
+ KeyBuildEnum.BUILD_KEYPAIR,
+ 256,
+ KeyClassEnum.ALG_EC_FP,
+ )
+ clear_resp = target.clear(KeypairEnum.KEYPAIR_LOCAL)
+ assert clear_resp.success
+
+
+def test_cleanup(target):
+ cleanup_resp = target.cleanup()
+ assert cleanup_resp.success
+
+
+def test_info(target):
+ info_resp = target.info()
+ assert info_resp.success
+
+
+def test_dry_run(target):
+ dry_run_resp = target.run_mode(RunModeEnum.MODE_DRY_RUN)
+ assert dry_run_resp.success
+ allocate_resp = target.allocate(
+ KeypairEnum.KEYPAIR_LOCAL,
+ KeyBuildEnum.BUILD_KEYPAIR,
+ 256,
+ KeyClassEnum.ALG_EC_FP,
+ )
+ assert allocate_resp.success
+ dry_run_resp = target.run_mode(RunModeEnum.MODE_NORMAL)
+ assert dry_run_resp.success
- def test_transform(self):
- self.target.allocate(
- KeypairEnum.KEYPAIR_LOCAL,
- KeyBuildEnum.BUILD_KEYPAIR,
- 256,
- KeyClassEnum.ALG_EC_FP,
- )
- self.target.set(
- KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
- )
- self.target.generate(KeypairEnum.KEYPAIR_LOCAL)
- export_privkey_resp1 = self.target.export(
- KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PRIVATE, ParameterEnum.S
- )
- privkey = int.from_bytes(
- export_privkey_resp1.get_param(KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.S),
- "big",
- )
- transform_resp = self.target.transform(
- KeypairEnum.KEYPAIR_LOCAL,
- KeyEnum.PRIVATE,
- ParameterEnum.S,
- TransformationEnum.INCREMENT,
- )
- self.assertTrue(transform_resp.success)
- export_privkey_resp2 = self.target.export(
- KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PRIVATE, ParameterEnum.S
- )
- privkey_new = int.from_bytes(
- export_privkey_resp2.get_param(KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.S),
- "big",
- )
- self.assertEqual(privkey + 1, privkey_new)
- def test_ecdh(self):
- self.target.allocate_ka(KeyAgreementEnum.ALG_EC_SVDP_DH)
- self.target.allocate(
- KeypairEnum.KEYPAIR_BOTH,
- KeyBuildEnum.BUILD_KEYPAIR,
- 256,
- KeyClassEnum.ALG_EC_FP,
- )
- self.target.set(
- KeypairEnum.KEYPAIR_BOTH, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
- )
- self.target.generate(KeypairEnum.KEYPAIR_BOTH)
- ecdh_resp = self.target.ecdh(
- KeypairEnum.KEYPAIR_LOCAL,
- KeypairEnum.KEYPAIR_REMOTE,
- True,
- TransformationEnum.NONE,
- KeyAgreementEnum.ALG_EC_SVDP_DH,
- )
- self.assertTrue(ecdh_resp.success)
- export_public_resp = self.target.export(
- KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PUBLIC, ParameterEnum.W
- )
- pubkey_bytes = export_public_resp.get_param(
- KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.W
- )
- pubkey = self.secp256r1.curve.decode_point(pubkey_bytes)
- export_privkey_resp = self.target.export(
- KeypairEnum.KEYPAIR_REMOTE, KeyEnum.PRIVATE, ParameterEnum.S
- )
- privkey = Mod(
- int.from_bytes(
- export_privkey_resp.get_param(
- KeypairEnum.KEYPAIR_REMOTE, ParameterEnum.S
- ),
- "big",
+def test_export(target, secp256r1_affine):
+ target.allocate(
+ KeypairEnum.KEYPAIR_LOCAL,
+ KeyBuildEnum.BUILD_KEYPAIR,
+ 256,
+ KeyClassEnum.ALG_EC_FP,
+ )
+ target.set(
+ KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
+ )
+ target.generate(KeypairEnum.KEYPAIR_LOCAL)
+ export_public_resp = target.export(
+ KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PUBLIC, ParameterEnum.W
+ )
+ assert export_public_resp.success
+ pubkey_bytes = export_public_resp.get_param(
+ KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.W
+ )
+ pubkey = secp256r1_affine.curve.decode_point(pubkey_bytes)
+ export_privkey_resp = target.export(
+ KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PRIVATE, ParameterEnum.S
+ )
+ assert export_privkey_resp.success
+ privkey = int.from_bytes(
+ export_privkey_resp.get_param(KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.S),
+ "big",
+ )
+ assert pubkey == \
+ secp256r1_affine.curve.affine_multiply(secp256r1_affine.generator, privkey)
+
+
+def test_export_curve(target):
+ target.allocate(
+ KeypairEnum.KEYPAIR_LOCAL,
+ KeyBuildEnum.BUILD_KEYPAIR,
+ 256,
+ KeyClassEnum.ALG_EC_FP,
+ )
+ target.set(
+ KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
+ )
+ export_resp = target.export(
+ KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PUBLIC, ParameterEnum.DOMAIN_FP
+ )
+ assert export_resp.success
+
+
+def test_transform(target):
+ target.allocate(
+ KeypairEnum.KEYPAIR_LOCAL,
+ KeyBuildEnum.BUILD_KEYPAIR,
+ 256,
+ KeyClassEnum.ALG_EC_FP,
+ )
+ target.set(
+ KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
+ )
+ target.generate(KeypairEnum.KEYPAIR_LOCAL)
+ export_privkey_resp1 = target.export(
+ KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PRIVATE, ParameterEnum.S
+ )
+ privkey = int.from_bytes(
+ export_privkey_resp1.get_param(KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.S),
+ "big",
+ )
+ transform_resp = target.transform(
+ KeypairEnum.KEYPAIR_LOCAL,
+ KeyEnum.PRIVATE,
+ ParameterEnum.S,
+ TransformationEnum.INCREMENT,
+ )
+ assert transform_resp.success
+ export_privkey_resp2 = target.export(
+ KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PRIVATE, ParameterEnum.S
+ )
+ privkey_new = int.from_bytes(
+ export_privkey_resp2.get_param(KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.S),
+ "big",
+ )
+ assert privkey + 1 == privkey_new
+
+
+def test_ecdh(target, secp256r1_affine, secp256r1_projective):
+ target.allocate_ka(KeyAgreementEnum.ALG_EC_SVDP_DH)
+ target.allocate(
+ KeypairEnum.KEYPAIR_BOTH,
+ KeyBuildEnum.BUILD_KEYPAIR,
+ 256,
+ KeyClassEnum.ALG_EC_FP,
+ )
+ target.set(
+ KeypairEnum.KEYPAIR_BOTH, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
+ )
+ target.generate(KeypairEnum.KEYPAIR_BOTH)
+ ecdh_resp = target.ecdh(
+ KeypairEnum.KEYPAIR_LOCAL,
+ KeypairEnum.KEYPAIR_REMOTE,
+ True,
+ TransformationEnum.NONE,
+ KeyAgreementEnum.ALG_EC_SVDP_DH,
+ )
+ assert ecdh_resp.success
+ export_public_resp = target.export(
+ KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PUBLIC, ParameterEnum.W
+ )
+ pubkey_bytes = export_public_resp.get_param(
+ KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.W
+ )
+ pubkey = secp256r1_affine.curve.decode_point(pubkey_bytes)
+ export_privkey_resp = target.export(
+ KeypairEnum.KEYPAIR_REMOTE, KeyEnum.PRIVATE, ParameterEnum.S
+ )
+ privkey = Mod(
+ int.from_bytes(
+ export_privkey_resp.get_param(
+ KeypairEnum.KEYPAIR_REMOTE, ParameterEnum.S
),
- self.secp256r1.curve.prime,
- )
- pubkey_projective = pubkey.to_model(
- self.secp256r1_projective.curve.coordinate_model, self.secp256r1.curve
- )
+ "big",
+ ),
+ secp256r1_affine.curve.prime,
+ )
+ pubkey_projective = pubkey.to_model(
+ secp256r1_projective.curve.coordinate_model, secp256r1_affine.curve
+ )
- mult = LTRMultiplier(
- self.secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
- self.secp256r1_projective.curve.coordinate_model.formulas["dbl-2016-rcb"],
- )
- ecdh = ECDH_SHA1(mult, self.secp256r1_projective, pubkey_projective, privkey)
- expected = ecdh.perform()
- self.assertEqual(ecdh_resp.secret, expected)
+ mult = LTRMultiplier(
+ secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
+ secp256r1_projective.curve.coordinate_model.formulas["dbl-2016-rcb"],
+ )
+ ecdh = ECDH_SHA1(mult, secp256r1_projective, pubkey_projective, privkey)
+ expected = ecdh.perform()
+ assert ecdh_resp.secret == expected
- def test_ecdh_raw(self):
- self.target.allocate_ka(KeyAgreementEnum.ALG_EC_SVDP_DH)
- self.target.allocate(
- KeypairEnum.KEYPAIR_LOCAL,
- KeyBuildEnum.BUILD_KEYPAIR,
- 256,
- KeyClassEnum.ALG_EC_FP,
- )
- self.target.set(
- KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
- )
- self.target.generate(KeypairEnum.KEYPAIR_LOCAL)
- mult = LTRMultiplier(
- self.secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
- self.secp256r1_projective.curve.coordinate_model.formulas["dbl-2016-rcb"],
- )
- keygen = KeyGeneration(copy(mult), self.secp256r1_projective)
- _, pubkey_projective = keygen.generate()
- ecdh_resp = self.target.ecdh_direct(
- KeypairEnum.KEYPAIR_LOCAL,
- True,
- TransformationEnum.NONE,
- KeyAgreementEnum.ALG_EC_SVDP_DH,
- bytes(pubkey_projective.to_affine()),
- )
- self.assertTrue(ecdh_resp.success)
- export_privkey_resp = self.target.export(
- KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PRIVATE, ParameterEnum.S
- )
- privkey = Mod(
- int.from_bytes(
- export_privkey_resp.get_param(
- KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.S
- ),
- "big",
+def test_ecdh_raw(target, secp256r1_projective):
+ target.allocate_ka(KeyAgreementEnum.ALG_EC_SVDP_DH)
+ target.allocate(
+ KeypairEnum.KEYPAIR_LOCAL,
+ KeyBuildEnum.BUILD_KEYPAIR,
+ 256,
+ KeyClassEnum.ALG_EC_FP,
+ )
+ target.set(
+ KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
+ )
+ target.generate(KeypairEnum.KEYPAIR_LOCAL)
+ mult = LTRMultiplier(
+ secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
+ secp256r1_projective.curve.coordinate_model.formulas["dbl-2016-rcb"],
+ )
+ keygen = KeyGeneration(copy(mult), secp256r1_projective)
+ _, pubkey_projective = keygen.generate()
+
+ ecdh_resp = target.ecdh_direct(
+ KeypairEnum.KEYPAIR_LOCAL,
+ True,
+ TransformationEnum.NONE,
+ KeyAgreementEnum.ALG_EC_SVDP_DH,
+ bytes(pubkey_projective.to_affine()),
+ )
+ assert ecdh_resp.success
+ export_privkey_resp = target.export(
+ KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PRIVATE, ParameterEnum.S
+ )
+ privkey = Mod(
+ int.from_bytes(
+ export_privkey_resp.get_param(
+ KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.S
),
- self.secp256r1.curve.prime,
- )
+ "big",
+ ),
+ secp256r1_projective.curve.prime,
+ )
- ecdh = ECDH_SHA1(
- copy(mult), self.secp256r1_projective, pubkey_projective, privkey
- )
- expected = ecdh.perform()
- self.assertEqual(ecdh_resp.secret, expected)
+ ecdh = ECDH_SHA1(
+ copy(mult), secp256r1_projective, pubkey_projective, privkey
+ )
+ expected = ecdh.perform()
+ assert ecdh_resp.secret == expected
- def test_ecdsa(self):
- self.target.allocate_sig(SignatureEnum.ALG_ECDSA_SHA)
- self.target.allocate(
- KeypairEnum.KEYPAIR_LOCAL,
- KeyBuildEnum.BUILD_KEYPAIR,
- 256,
- KeyClassEnum.ALG_EC_FP,
- )
- self.target.set(
- KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
- )
- self.target.generate(KeypairEnum.KEYPAIR_LOCAL)
- data = "Some text over here.".encode()
- ecdsa_resp = self.target.ecdsa(
- KeypairEnum.KEYPAIR_LOCAL, True, SignatureEnum.ALG_ECDSA_SHA, data
- )
- self.assertTrue(ecdsa_resp.success)
- export_public_resp = self.target.export(
- KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PUBLIC, ParameterEnum.W
- )
- pubkey_bytes = export_public_resp.get_param(
- KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.W
- )
- pubkey = self.secp256r1.curve.decode_point(pubkey_bytes)
- pubkey_projective = pubkey.to_model(
- self.secp256r1_projective.curve.coordinate_model, self.secp256r1.curve
- )
- sig = SignatureResult.from_DER(ecdsa_resp.signature)
- mult = LTRMultiplier(
- self.secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
- self.secp256r1_projective.curve.coordinate_model.formulas["dbl-2016-rcb"],
- )
- ecdsa = ECDSA_SHA1(
- copy(mult),
- self.secp256r1_projective,
- self.secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
- pubkey_projective,
- )
- self.assertTrue(ecdsa.verify_data(sig, data))
+def test_ecdsa(target, secp256r1_affine, secp256r1_projective):
+ target.allocate_sig(SignatureEnum.ALG_ECDSA_SHA)
+ target.allocate(
+ KeypairEnum.KEYPAIR_LOCAL,
+ KeyBuildEnum.BUILD_KEYPAIR,
+ 256,
+ KeyClassEnum.ALG_EC_FP,
+ )
+ target.set(
+ KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
+ )
+ target.generate(KeypairEnum.KEYPAIR_LOCAL)
+ data = "Some text over here.".encode()
+ ecdsa_resp = target.ecdsa(
+ KeypairEnum.KEYPAIR_LOCAL, True, SignatureEnum.ALG_ECDSA_SHA, data
+ )
+ assert ecdsa_resp.success
+ export_public_resp = target.export(
+ KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PUBLIC, ParameterEnum.W
+ )
+ pubkey_bytes = export_public_resp.get_param(
+ KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.W
+ )
+ pubkey = secp256r1_affine.curve.decode_point(pubkey_bytes)
+ pubkey_projective = pubkey.to_model(
+ secp256r1_projective.curve.coordinate_model, secp256r1_affine.curve
+ )
- def test_ecdsa_sign(self):
- self.target.allocate_sig(SignatureEnum.ALG_ECDSA_SHA)
- self.target.allocate(
- KeypairEnum.KEYPAIR_LOCAL,
- KeyBuildEnum.BUILD_KEYPAIR,
- 256,
- KeyClassEnum.ALG_EC_FP,
- )
- self.target.set(
- KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
- )
- self.target.generate(KeypairEnum.KEYPAIR_LOCAL)
- data = "Some text over here.".encode()
- ecdsa_resp = self.target.ecdsa_sign(
- KeypairEnum.KEYPAIR_LOCAL, True, SignatureEnum.ALG_ECDSA_SHA, data
- )
- self.assertTrue(ecdsa_resp.success)
- export_public_resp = self.target.export(
- KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PUBLIC, ParameterEnum.W
- )
- pubkey_bytes = export_public_resp.get_param(
- KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.W
- )
- pubkey = self.secp256r1.curve.decode_point(pubkey_bytes)
- pubkey_projective = pubkey.to_model(
- self.secp256r1_projective.curve.coordinate_model, self.secp256r1.curve
- )
+ sig = SignatureResult.from_DER(ecdsa_resp.signature)
+ mult = LTRMultiplier(
+ secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
+ secp256r1_projective.curve.coordinate_model.formulas["dbl-2016-rcb"],
+ )
+ ecdsa = ECDSA_SHA1(
+ copy(mult),
+ secp256r1_projective,
+ secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
+ pubkey_projective,
+ )
+ assert ecdsa.verify_data(sig, data)
- sig = SignatureResult.from_DER(ecdsa_resp.signature)
- mult = LTRMultiplier(
- self.secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
- self.secp256r1_projective.curve.coordinate_model.formulas["dbl-2016-rcb"],
- )
- ecdsa = ECDSA_SHA1(
- copy(mult),
- self.secp256r1_projective,
- self.secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
- pubkey_projective,
- )
- self.assertTrue(ecdsa.verify_data(sig, data))
- def test_ecdsa_verify(self):
- self.target.allocate_sig(SignatureEnum.ALG_ECDSA_SHA)
- self.target.allocate(
- KeypairEnum.KEYPAIR_LOCAL,
- KeyBuildEnum.BUILD_KEYPAIR,
- 256,
- KeyClassEnum.ALG_EC_FP,
- )
- self.target.set(
- KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
- )
- mult = LTRMultiplier(
- self.secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
- self.secp256r1_projective.curve.coordinate_model.formulas["dbl-2016-rcb"],
- )
- keygen = KeyGeneration(copy(mult), self.secp256r1_projective)
- priv, pubkey_projective = keygen.generate()
- self.target.set(
- KeypairEnum.KEYPAIR_LOCAL,
- CurveEnum.external,
- ParameterEnum.W,
- ECTesterTarget.encode_parameters(
- ParameterEnum.W, pubkey_projective.to_affine()
- ),
- )
- ecdsa = ECDSA_SHA1(
- copy(mult),
- self.secp256r1_projective,
- self.secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
- pubkey_projective,
- priv,
- )
- data = "Some text over here.".encode()
- sig = ecdsa.sign_data(data)
+def test_ecdsa_sign(target, secp256r1_affine, secp256r1_projective):
+ target.allocate_sig(SignatureEnum.ALG_ECDSA_SHA)
+ target.allocate(
+ KeypairEnum.KEYPAIR_LOCAL,
+ KeyBuildEnum.BUILD_KEYPAIR,
+ 256,
+ KeyClassEnum.ALG_EC_FP,
+ )
+ target.set(
+ KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
+ )
+ target.generate(KeypairEnum.KEYPAIR_LOCAL)
+ data = "Some text over here.".encode()
+ ecdsa_resp = target.ecdsa_sign(
+ KeypairEnum.KEYPAIR_LOCAL, True, SignatureEnum.ALG_ECDSA_SHA, data
+ )
+ assert ecdsa_resp.success
+ export_public_resp = target.export(
+ KeypairEnum.KEYPAIR_LOCAL, KeyEnum.PUBLIC, ParameterEnum.W
+ )
+ pubkey_bytes = export_public_resp.get_param(
+ KeypairEnum.KEYPAIR_LOCAL, ParameterEnum.W
+ )
+ pubkey = secp256r1_affine.curve.decode_point(pubkey_bytes)
+ pubkey_projective = pubkey.to_model(
+ secp256r1_projective.curve.coordinate_model, secp256r1_affine.curve
+ )
+
+ sig = SignatureResult.from_DER(ecdsa_resp.signature)
+ mult = LTRMultiplier(
+ secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
+ secp256r1_projective.curve.coordinate_model.formulas["dbl-2016-rcb"],
+ )
+ ecdsa = ECDSA_SHA1(
+ copy(mult),
+ secp256r1_projective,
+ secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
+ pubkey_projective,
+ )
+ assert ecdsa.verify_data(sig, data)
+
+
+def test_ecdsa_verify(target, secp256r1_projective):
+ target.allocate_sig(SignatureEnum.ALG_ECDSA_SHA)
+ target.allocate(
+ KeypairEnum.KEYPAIR_LOCAL,
+ KeyBuildEnum.BUILD_KEYPAIR,
+ 256,
+ KeyClassEnum.ALG_EC_FP,
+ )
+ target.set(
+ KeypairEnum.KEYPAIR_LOCAL, CurveEnum.secp256r1, ParameterEnum.DOMAIN_FP
+ )
+ mult = LTRMultiplier(
+ secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
+ secp256r1_projective.curve.coordinate_model.formulas["dbl-2016-rcb"],
+ )
+ keygen = KeyGeneration(copy(mult), secp256r1_projective)
+ priv, pubkey_projective = keygen.generate()
+ target.set(
+ KeypairEnum.KEYPAIR_LOCAL,
+ CurveEnum.external,
+ ParameterEnum.W,
+ ECTesterTarget.encode_parameters(
+ ParameterEnum.W, pubkey_projective.to_affine()
+ ),
+ )
+ ecdsa = ECDSA_SHA1(
+ copy(mult),
+ secp256r1_projective,
+ secp256r1_projective.curve.coordinate_model.formulas["add-2016-rcb"],
+ pubkey_projective,
+ priv,
+ )
+ data = "Some text over here.".encode()
+ sig = ecdsa.sign_data(data)
- ecdsa_resp = self.target.ecdsa_verify(
- KeypairEnum.KEYPAIR_LOCAL, SignatureEnum.ALG_ECDSA_SHA, sig.to_DER(), data
- )
- self.assertTrue(ecdsa_resp.success)
+ ecdsa_resp = target.ecdsa_verify(
+ KeypairEnum.KEYPAIR_LOCAL, SignatureEnum.ALG_ECDSA_SHA, sig.to_DER(), data
+ )
+ assert ecdsa_resp.success
diff --git a/test/sca/test_test.py b/test/sca/test_test.py
index 7b4f346..256e77d 100644
--- a/test/sca/test_test.py
+++ b/test/sca/test_test.py
@@ -1,43 +1,41 @@
-from unittest import TestCase
-
+from collections import namedtuple
import numpy as np
+import pytest
from pyecsca.sca import Trace, welch_ttest, student_ttest, ks_test
-class TTestTests(TestCase):
- def setUp(self):
- self.a = Trace(np.array([20, 80], dtype=np.dtype("i1")))
- self.b = Trace(np.array([30, 42], dtype=np.dtype("i1")))
- self.c = Trace(np.array([78, 56], dtype=np.dtype("i1")))
- self.d = Trace(np.array([98, 36], dtype=np.dtype("i1")))
+@pytest.fixture()
+def data():
+ Data = namedtuple("Data", ["a", "b", "c", "d"])
+ return Data(a=Trace(np.array([20, 80], dtype=np.dtype("i1"))),
+ b=Trace(np.array([30, 42], dtype=np.dtype("i1"))),
+ c=Trace(np.array([78, 56], dtype=np.dtype("i1"))),
+ d=Trace(np.array([98, 36], dtype=np.dtype("i1"))))
+
+
+def test_welch_ttest(data):
+ assert welch_ttest([data.a, data.b], [data.c, data.d]) is not None
+ a = Trace(
+ np.array([19.8, 20.4, 19.6, 17.8, 18.5, 18.9, 18.3, 18.9, 19.5, 22.0])
+ )
+ b = Trace(
+ np.array([28.2, 26.6, 20.1, 23.3, 25.2, 22.1, 17.7, 27.6, 20.6, 13.7])
+ )
+ c = Trace(
+ np.array([20.2, 21.6, 27.1, 13.3, 24.2, 20.1, 11.7, 25.6, 26.6, 21.4])
+ )
- def test_welch_ttest(self):
- self.assertIsNotNone(welch_ttest([self.a, self.b], [self.c, self.d]))
- a = Trace(
- np.array([19.8, 20.4, 19.6, 17.8, 18.5, 18.9, 18.3, 18.9, 19.5, 22.0])
- )
- b = Trace(
- np.array([28.2, 26.6, 20.1, 23.3, 25.2, 22.1, 17.7, 27.6, 20.6, 13.7])
- )
- c = Trace(
- np.array([20.2, 21.6, 27.1, 13.3, 24.2, 20.1, 11.7, 25.6, 26.6, 21.4])
- )
+ result = welch_ttest([a, b], [b, c], dof=True, p_value=True)
+ assert result is not None
- result = welch_ttest([a, b], [b, c], dof=True, p_value=True)
- self.assertIsNotNone(result)
- def test_students_ttest(self):
- self.assertIsNone(student_ttest([], []))
- self.assertIsNotNone(student_ttest([self.a, self.b], [self.c, self.d]))
+def test_students_ttest(data):
+ assert student_ttest([], []) is None
+ assert student_ttest([data.a, data.b], [data.c, data.d]) is not None
-class KolmogorovSmirnovTests(TestCase):
- def test_ks_test(self):
- self.assertIsNone(ks_test([], []))
+def test_ks_test(data):
+ assert ks_test([], []) is None
- a = Trace(np.array([20, 80], dtype=np.dtype("i1")))
- b = Trace(np.array([30, 42], dtype=np.dtype("i1")))
- c = Trace(np.array([78, 56], dtype=np.dtype("i1")))
- d = Trace(np.array([98, 36], dtype=np.dtype("i1")))
- self.assertIsNotNone(ks_test([a, b], [c, d]))
+ assert ks_test([data.a, data.b], [data.c, data.d]) is not None
diff --git a/test/sca/test_trace.py b/test/sca/test_trace.py
index 93baa89..98818d3 100644
--- a/test/sca/test_trace.py
+++ b/test/sca/test_trace.py
@@ -1,11 +1,9 @@
-from unittest import TestCase
import numpy as np
from pyecsca.sca import Trace
-class TraceTests(TestCase):
- def test_basic(self):
- trace = Trace(np.array([10, 15, 24], dtype=np.dtype("i1")))
- self.assertIsNotNone(trace)
- self.assertIn("Trace", str(trace))
- self.assertIsNone(trace.trace_set)
+def test_basic():
+ trace = Trace(np.array([10, 15, 24], dtype=np.dtype("i1")))
+ assert trace is not None
+ assert "Trace" in str(trace)
+ assert trace.trace_set is None
diff --git a/test/sca/test_traceset.py b/test/sca/test_traceset.py
index 55b9a0a..a338a9d 100644
--- a/test/sca/test_traceset.py
+++ b/test/sca/test_traceset.py
@@ -1,8 +1,9 @@
import os.path
import shutil
import tempfile
+
+import pytest
from importlib_resources import files, as_file
-from unittest import TestCase
import numpy as np
@@ -16,121 +17,126 @@ from pyecsca.sca import (
Trace,
)
-EXAMPLE_TRACES = [
- Trace(np.array([20, 40, 50, 50, 10], dtype=np.dtype("i1")), {"something": 5}),
- Trace(np.array([1, 2, 3, 4, 5], dtype=np.dtype("i1"))),
- Trace(np.array([6, 7, 8, 9, 10], dtype=np.dtype("i1"))),
-]
-EXAMPLE_KWARGS = {"num_traces": 3, "thingy": "abc"}
+
+@pytest.fixture()
+def example_traces():
+ return [
+ Trace(np.array([20, 40, 50, 50, 10], dtype=np.dtype("i1")), {"something": 5}),
+ Trace(np.array([1, 2, 3, 4, 5], dtype=np.dtype("i1"))),
+ Trace(np.array([6, 7, 8, 9, 10], dtype=np.dtype("i1"))),
+ ]
+
+
+@pytest.fixture()
+def example_kwargs():
+ return {"num_traces": 3, "thingy": "abc"}
-class TraceSetTests(TestCase):
- def test_create(self):
- self.assertIsNotNone(TraceSet())
- self.assertIsNotNone(InspectorTraceSet())
- self.assertIsNotNone(ChipWhispererTraceSet())
- self.assertIsNotNone(PickleTraceSet())
- self.assertIsNotNone(HDF5TraceSet())
+def test_create():
+ assert TraceSet() is not None
+ assert InspectorTraceSet() is not None
+ assert ChipWhispererTraceSet() is not None
+ assert PickleTraceSet() is not None
+ assert HDF5TraceSet() is not None
-class InspectorTraceSetTests(TestCase):
- def test_load_fname(self):
- with as_file(files(test.data.sca).joinpath("example.trs")) as path:
- result = InspectorTraceSet.read(path)
- self.assertIsNotNone(result)
- self.assertEqual(result.global_title, "Example trace set")
- self.assertEqual(len(result), 10)
- self.assertEqual(len(list(result)), 10)
- self.assertIn("InspectorTraceSet", str(result))
- self.assertIs(result[0].trace_set, result)
- self.assertEqual(result.sampling_frequency, 12500000)
+def test_trs_load_fname():
+ with as_file(files(test.data.sca).joinpath("example.trs")) as path:
+ result = InspectorTraceSet.read(path)
+ assert result is not None
+ assert result.global_title == "Example trace set"
+ assert len(result) == 10
+ assert len(list(result)) == 10
+ assert "InspectorTraceSet" in str(result)
+ assert result[0].trace_set is result
+ assert result.sampling_frequency == 12500000
- def test_load_file(self):
- with files(test.data.sca).joinpath("example.trs").open("rb") as f:
- self.assertIsNotNone(InspectorTraceSet.read(f))
- def test_load_bytes(self):
- with files(test.data.sca).joinpath("example.trs").open("rb") as f:
- self.assertIsNotNone(InspectorTraceSet.read(f.read()))
+def test_trs_load_file():
+ with files(test.data.sca).joinpath("example.trs").open("rb") as f:
+ assert InspectorTraceSet.read(f) is not None
- def test_save(self):
- with as_file(files(test.data.sca).joinpath("example.trs")) as path:
- trace_set = InspectorTraceSet.read(path)
+
+def test_trs_load_bytes():
+ with files(test.data.sca).joinpath("example.trs").open("rb") as f:
+ assert InspectorTraceSet.read(f.read()) is not None
+
+
+def test_trs_save():
+ with as_file(files(test.data.sca).joinpath("example.trs")) as path:
+ trace_set = InspectorTraceSet.read(path)
with tempfile.TemporaryDirectory() as dirname:
path = os.path.join(dirname, "out.trs")
trace_set.write(path)
- self.assertTrue(os.path.exists(path))
- self.assertIsNotNone(InspectorTraceSet.read(path))
+ assert os.path.exists(path)
+ assert InspectorTraceSet.read(path) is not None
-class ChipWhispererTraceSetTests(TestCase):
- def test_load_fname(self):
- with as_file(files(test.data.sca).joinpath("config_chipwhisperer_.cfg")) as path:
- # This will not work if the test package is not on the file system directly.
- result = ChipWhispererTraceSet.read(path)
- self.assertIsNotNone(result)
- self.assertEqual(len(result), 2)
+def test_cw_load_fname():
+ with as_file(files(test.data.sca).joinpath("config_chipwhisperer_.cfg")) as path:
+ # This will not work if the test package is not on the file system directly.
+ result = ChipWhispererTraceSet.read(path)
+ assert result is not None
+ assert len(result) == 2
-class PickleTraceSetTests(TestCase):
- def test_load_fname(self):
- with as_file(files(test.data.sca).joinpath("test.pickle")) as path:
- result = PickleTraceSet.read(path)
- self.assertIsNotNone(result)
+def test_pickle_load_fname():
+ with as_file(files(test.data.sca).joinpath("test.pickle")) as path:
+ result = PickleTraceSet.read(path)
+ assert result is not None
- def test_load_file(self):
- with files(test.data.sca).joinpath("test.pickle").open("rb") as f:
- self.assertIsNotNone(PickleTraceSet.read(f))
- def test_save(self):
- trace_set = PickleTraceSet(*EXAMPLE_TRACES, **EXAMPLE_KWARGS)
- with tempfile.TemporaryDirectory() as dirname:
- path = os.path.join(dirname, "out.pickle")
- trace_set.write(path)
- self.assertTrue(os.path.exists(path))
- self.assertIsNotNone(PickleTraceSet.read(path))
+def test_pickle_load_file():
+ with files(test.data.sca).joinpath("test.pickle").open("rb") as f:
+ assert PickleTraceSet.read(f) is not None
-class HDF5TraceSetTests(TestCase):
- def test_load_fname(self):
- with as_file(files(test.data.sca).joinpath("test.h5")) as path:
- result = HDF5TraceSet.read(path)
- self.assertIsNotNone(result)
+def test_pickle_save(example_traces, example_kwargs):
+ trace_set = PickleTraceSet(*example_traces, **example_kwargs)
+ with tempfile.TemporaryDirectory() as dirname:
+ path = os.path.join(dirname, "out.pickle")
+ trace_set.write(path)
+ assert os.path.exists(path)
+ assert PickleTraceSet.read(path) is not None
- def test_load_file(self):
- with files(test.data.sca).joinpath("test.h5").open("rb") as f:
- self.assertIsNotNone(HDF5TraceSet.read(f))
- def test_inplace(self):
- with tempfile.TemporaryDirectory() as dirname, as_file(files(test.data.sca).joinpath("test.h5")) as orig_path:
- path = os.path.join(dirname, "test.h5")
- shutil.copy(orig_path, path)
- trace_set = HDF5TraceSet.inplace(path)
- self.assertIsNotNone(trace_set)
- test_trace = Trace(
- np.array([6, 7], dtype=np.dtype("i1")), meta={"thing": "ring"}
- )
- other_trace = Trace(
- np.array([15, 7], dtype=np.dtype("i1")), meta={"a": "b"}
- )
- trace_set.append(test_trace)
- self.assertEqual(len(trace_set), 4)
- trace_set.append(other_trace)
- trace_set.remove(other_trace)
- self.assertEqual(len(trace_set), 4)
- trace_set.save()
- trace_set.close()
+def test_h5_load_fname():
+ with as_file(files(test.data.sca).joinpath("test.h5")) as path:
+ result = HDF5TraceSet.read(path)
+ assert result is not None
- test_set = HDF5TraceSet.read(path)
- self.assertEqual(test_set.get(3), test_set[3])
- self.assertTrue(np.array_equal(test_set[3].samples, test_trace.samples))
- self.assertEqual(test_set[3].meta["thing"], test_trace.meta["thing"])
- self.assertEqual(test_set[3], test_trace)
- def test_save(self):
- trace_set = HDF5TraceSet(*EXAMPLE_TRACES, **EXAMPLE_KWARGS)
- with tempfile.TemporaryDirectory() as dirname:
- path = os.path.join(dirname, "out.h5")
- trace_set.write(path)
- self.assertTrue(os.path.exists(path))
- self.assertIsNotNone(HDF5TraceSet.read(path))
+def test_h5_load_file():
+ with files(test.data.sca).joinpath("test.h5").open("rb") as f:
+ assert HDF5TraceSet.read(f) is not None
+
+
+def test_h5_inplace():
+ with tempfile.TemporaryDirectory() as dirname, as_file(files(test.data.sca).joinpath("test.h5")) as orig_path:
+ path = os.path.join(dirname, "test.h5")
+ shutil.copy(orig_path, path)
+ trace_set = HDF5TraceSet.inplace(path)
+ assert trace_set is not None
+ test_trace = Trace(np.array([6, 7], dtype=np.dtype("i1")), meta={"thing": "ring"})
+ other_trace = Trace(np.array([15, 7], dtype=np.dtype("i1")), meta={"a": "b"})
+ trace_set.append(test_trace)
+ assert len(trace_set) == 4
+ trace_set.append(other_trace)
+ trace_set.remove(other_trace)
+ assert len(trace_set) == 4
+ trace_set.save()
+ trace_set.close()
+ test_set = HDF5TraceSet.read(path)
+ assert test_set.get(3) == test_set[3]
+ assert np.array_equal(test_set[3].samples, test_trace.samples)
+ assert test_set[3].meta["thing"] == test_trace.meta["thing"]
+ assert test_set[3] == test_trace
+
+
+def test_h5_save(example_traces, example_kwargs):
+ trace_set = HDF5TraceSet(*example_traces, **example_kwargs)
+ with tempfile.TemporaryDirectory() as dirname:
+ path = os.path.join(dirname, "out.h5")
+ trace_set.write(path)
+ assert os.path.exists(path)
+ assert HDF5TraceSet.read(path) is not None
diff --git a/test/sca/test_zvp.py b/test/sca/test_zvp.py
index 837fb08..3b6b046 100644
--- a/test/sca/test_zvp.py
+++ b/test/sca/test_zvp.py
@@ -1,23 +1,13 @@
-from unittest import TestCase
-
-from pyecsca.ec.model import ShortWeierstrassModel
-from pyecsca.ec.params import get_params
from pyecsca.sca.re.zvp import unroll_formula
-class ZVPTests(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_unroll(self):
- results = unroll_formula(self.add, 11)
- self.assertIsNotNone(results)
- results = unroll_formula(self.dbl, 11)
- self.assertIsNotNone(results)
- results = unroll_formula(self.neg, 11)
- self.assertIsNotNone(results)
+def test_unroll(secp128r1):
+ add = secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
+ dbl = secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
+ neg = secp128r1.curve.coordinate_model.formulas["neg"]
+ results = unroll_formula(add, 11)
+ assert results is not None
+ results = unroll_formula(dbl, 11)
+ assert results is not None
+ results = unroll_formula(neg, 11)
+ assert results is not None
diff --git a/test/sca/utils.py b/test/sca/utils.py
deleted file mode 100644
index ad77d21..0000000
--- a/test/sca/utils.py
+++ /dev/null
@@ -1,42 +0,0 @@
-from os import mkdir, getenv, getcwd
-from os.path import join, exists, split
-from typing import Dict
-from unittest import TestCase
-
-import matplotlib.pyplot as plt
-
-from pyecsca.sca import Trace
-
-force_plot = True
-
-
-cases: Dict[str, int] = {}
-
-
-class Plottable(TestCase):
- def get_dir(self):
- if split(getcwd())[1] == "test":
- directory = "plots"
- else:
- directory = join("test", "plots")
- if not exists(directory):
- mkdir(directory)
- return directory
-
- def get_fname(self):
- directory = self.get_dir()
- case_id = cases.setdefault(self.id(), 0) + 1
- cases[self.id()] = case_id
- return join(directory, self.id() + str(case_id))
-
- def plot(self, *traces: Trace, **kwtraces: Trace):
- if not force_plot and getenv("PYECSCA_TEST_PLOTS") is None:
- return
- fig = plt.figure()
- ax = fig.add_subplot(111)
- for i, trace in enumerate(traces):
- ax.plot(trace.samples, label=str(i))
- for name, trace in kwtraces.items():
- ax.plot(trace.samples, label=name)
- ax.legend(loc="best")
- plt.savefig(self.get_fname() + ".png")