aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/sca
diff options
context:
space:
mode:
authorJ08nY2018-12-11 21:24:35 +0100
committerJ08nY2019-03-21 11:00:14 +0100
commit0c740f412626f33f08d6bb9857f0c5619b9ea79c (patch)
treec2313faaf8bc878d3d72acf2fd7c830b9512a529 /test/sca
parentcbeca585d5787e8cab35fb5207339e7b22eab382 (diff)
downloadpyecsca-0c740f412626f33f08d6bb9857f0c5619b9ea79c.tar.gz
pyecsca-0c740f412626f33f08d6bb9857f0c5619b9ea79c.tar.zst
pyecsca-0c740f412626f33f08d6bb9857f0c5619b9ea79c.zip
Move SCA stuff to sca package.
Diffstat (limited to 'test/sca')
-rw-r--r--test/sca/__init__.py0
-rw-r--r--test/sca/test_align.py76
-rw-r--r--test/sca/test_combine.py35
-rw-r--r--test/sca/test_edit.py28
-rw-r--r--test/sca/test_filter.py35
-rw-r--r--test/sca/test_process.py50
-rw-r--r--test/sca/test_sampling.py37
-rw-r--r--test/sca/test_trace.py12
-rw-r--r--test/sca/test_traceset.py58
-rw-r--r--test/sca/test_ttest.py25
-rw-r--r--test/sca/utils.py24
11 files changed, 380 insertions, 0 deletions
diff --git a/test/sca/__init__.py b/test/sca/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/sca/__init__.py
diff --git a/test/sca/test_align.py b/test/sca/test_align.py
new file mode 100644
index 0000000..3e64334
--- /dev/null
+++ b/test/sca/test_align.py
@@ -0,0 +1,76 @@
+from unittest import TestCase
+
+import numpy as np
+from pyecsca.sca import align_correlation, align_peaks, align_sad, align_dtw_scale,\
+ align_dtw, Trace, InspectorTraceSet
+from .utils import slow, plot
+
+
+class AlignTests(TestCase):
+
+ 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, 10], dtype=np.dtype("i1"))
+ third_arr = np.array([70, 30, 42, 35, 28, 21, 15, 10, 5], dtype=np.dtype("i1"))
+ a = Trace(None, None, first_arr)
+ b = Trace(None, None, second_arr)
+ c = Trace(None, None, third_arr)
+ result = 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, 10, 0, 0, 0], dtype=np.dtype("i1")))
+
+ @slow
+ def test_large_align(self):
+ example = InspectorTraceSet("test/data/example.trs")
+ result = align_correlation(*example, reference_offset=100000, reference_length=20000, max_offset=15000)
+ self.assertIsNotNone(result)
+
+ @slow
+ def test_large_dtw_align(self):
+ example = InspectorTraceSet("test/data/example.trs")
+ result = align_dtw(*example[:5])
+ self.assertIsNotNone(result)
+
+ 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, 10], dtype=np.dtype("i1"))
+ a = Trace(None, None, first_arr)
+ b = Trace(None, None, 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, 10, 10, 90, 40, 50, 20, 10, 17, 16, 10, 10], dtype=np.dtype("i1"))
+ a = Trace(None, None, first_arr)
+ b = Trace(None, None, second_arr)
+ result = align_sad(a, b, reference_offset=2, reference_length=5, max_offset=3)
+ self.assertEqual(len(result), 2)
+
+ 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("i1"))
+ second_arr = np.array([10, 10, 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, 37, 21, 77, 20, 28, 25, 10, 9, 10, 15, 9, 10], dtype=np.dtype("i1"))
+ a = Trace(None, None, first_arr)
+ b = Trace(None, None, second_arr)
+ c = Trace(None, None, 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))
+ plot(self, *result)
+
+ 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, 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(None, None, first_arr)
+ b = Trace(None, None, second_arr)
+ c = Trace(None, None, third_arr)
+ result = align_dtw(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))
+ plot(self, *result)
diff --git a/test/sca/test_combine.py b/test/sca/test_combine.py
new file mode 100644
index 0000000..113eb69
--- /dev/null
+++ b/test/sca/test_combine.py
@@ -0,0 +1,35 @@
+from unittest import TestCase
+
+import numpy as np
+from pyecsca.sca import Trace, CombinedTrace, average, conditional_average, standard_deviation
+
+
+class CombineTests(TestCase):
+
+ def setUp(self):
+ self.a = Trace(None, b"\xff", np.array([20, 80], dtype=np.dtype("i1")))
+ self.b = Trace(None, b"\xff", np.array([30, 42], dtype=np.dtype("i1")))
+ self.c = Trace(None, b"\x00", np.array([78, 56], dtype=np.dtype("i1")))
+
+ 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_conditional_average(self):
+ result = conditional_average(self.a, self.b, self.c,
+ condition=lambda trace: trace.data[0] == 0xff)
+ 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)
diff --git a/test/sca/test_edit.py b/test/sca/test_edit.py
new file mode 100644
index 0000000..88376aa
--- /dev/null
+++ b/test/sca/test_edit.py
@@ -0,0 +1,28 @@
+from unittest import TestCase
+
+import numpy as np
+
+from pyecsca.sca import Trace, trim, reverse, pad
+
+
+class EditTests(TestCase):
+
+ def setUp(self):
+ self._trace = Trace(None, None, np.array([10, 20, 30, 40, 50], 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")))
+
+ 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")))
diff --git a/test/sca/test_filter.py b/test/sca/test_filter.py
new file mode 100644
index 0000000..c95d5b5
--- /dev/null
+++ b/test/sca/test_filter.py
@@ -0,0 +1,35 @@
+from unittest import TestCase
+
+import numpy as np
+from pyecsca.sca import Trace, filter_lowpass, filter_highpass, filter_bandpass, filter_bandstop
+from .utils import plot
+
+
+class FilterTests(TestCase):
+
+ def setUp(self):
+ self._trace = Trace(None, None, np.array([5, 12, 15, 13, 15, 11, 7, 2, -4, -8, -10, -8, -13, -9, -11, -8, -5], dtype=np.dtype("i1")))
+
+ def test_lowpass(self):
+ result = filter_lowpass(self._trace, 100, 20)
+ self.assertIsNotNone(result)
+ self.assertEqual(len(self._trace.samples), len(result.samples))
+ plot(self, 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))
+ plot(self, self._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))
+ plot(self, 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))
+ plot(self, self._trace, result)
diff --git a/test/sca/test_process.py b/test/sca/test_process.py
new file mode 100644
index 0000000..5b80d1f
--- /dev/null
+++ b/test/sca/test_process.py
@@ -0,0 +1,50 @@
+from unittest import TestCase
+
+import numpy as np
+from pyecsca.sca import Trace, absolute, invert, threshold, rolling_mean, offset, recenter, normalize, normalize_wl
+
+
+class ProcessTests(TestCase):
+
+ def setUp(self):
+ self._trace = Trace(None, None, np.array([30, -60, 145, 247], dtype=np.dtype("i2")))
+
+ 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_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_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(self):
+ result = normalize(self._trace)
+ self.assertIsNotNone(result)
+
+ def test_normalize_wl(self):
+ result = normalize_wl(self._trace)
+ self.assertIsNotNone(result) \ No newline at end of file
diff --git a/test/sca/test_sampling.py b/test/sca/test_sampling.py
new file mode 100644
index 0000000..75a227d
--- /dev/null
+++ b/test/sca/test_sampling.py
@@ -0,0 +1,37 @@
+from unittest import TestCase
+
+import numpy as np
+from pyecsca.sca import Trace, downsample_average, downsample_pick, downsample_decimate
+from .utils import plot
+
+
+class SamplingTests(TestCase):
+
+ def setUp(self):
+ self._trace = Trace(None, None, np.array([20, 40, 50, 50, 10], dtype=np.dtype("i1")))
+
+ 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_decimate(self):
+ trace = Trace(None, None, 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)
+ plot(self, trace, result)
diff --git a/test/sca/test_trace.py b/test/sca/test_trace.py
new file mode 100644
index 0000000..91b7161
--- /dev/null
+++ b/test/sca/test_trace.py
@@ -0,0 +1,12 @@
+from unittest import TestCase
+import numpy as np
+from pyecsca.sca import Trace
+
+
+class TraceTests(TestCase):
+
+ def test_basic(self):
+ trace = Trace("Name", b"\xff\xaa", np.array([10, 15, 24], dtype=np.dtype("i1")))
+ self.assertIsNotNone(trace)
+ self.assertIn("Trace", str(trace))
+ self.assertIsNone(trace.trace_set)
diff --git a/test/sca/test_traceset.py b/test/sca/test_traceset.py
new file mode 100644
index 0000000..90768c2
--- /dev/null
+++ b/test/sca/test_traceset.py
@@ -0,0 +1,58 @@
+from unittest import TestCase
+import os.path
+import tempfile
+
+from pyecsca.sca import TraceSet, InspectorTraceSet, ChipWhispererTraceSet
+
+
+class TraceSetTests(TestCase):
+
+ def test_create(self):
+ self.assertIsNotNone(TraceSet())
+ self.assertIsNotNone(InspectorTraceSet())
+ self.assertIsNotNone(ChipWhispererTraceSet())
+
+
+class InspectorTraceSetTests(TestCase):
+
+ def test_load_fname(self):
+ result = InspectorTraceSet("test/data/example.trs")
+ self.assertIsNotNone(result)
+ self.assertEqual(result.global_title, "Example trace set")
+ self.assertEqual(len(result), 10)
+ self.assertIn("InspectorTraceSet", str(result))
+ self.assertIs(result[0].trace_set, result)
+ self.assertEqual(result.sampling_frequency, 12500000)
+
+ def test_load_file(self):
+ with open("test/data/example.trs", "rb") as f:
+ self.assertIsNotNone(InspectorTraceSet(f))
+
+ def test_load_bytes(self):
+ with open("test/data/example.trs", "rb") as f:
+ self.assertIsNotNone(InspectorTraceSet(f.read()))
+
+ def test_get_bytes(self):
+ self.assertIsNotNone(bytes(InspectorTraceSet("test/data/example.trs")))
+
+ def test_keep_traces(self):
+ trace_set = InspectorTraceSet("test/data/example.trs")
+ self.assertIsNotNone(trace_set.raw)
+ trace_set = InspectorTraceSet("test/data/example.trs", keep_raw_traces=False)
+ self.assertIsNone(trace_set.raw)
+
+ def test_save(self):
+ trace_set = InspectorTraceSet("test/data/example.trs")
+ with tempfile.TemporaryDirectory() as dirname:
+ path = os.path.join(dirname, "out.trs")
+ trace_set.save(path)
+ self.assertTrue(os.path.exists(path))
+ self.assertIsNotNone(InspectorTraceSet(path))
+
+
+class ChipWhispererTraceSetTest(TestCase):
+
+ def test_load_fname(self):
+ result = ChipWhispererTraceSet("test/data/", "chipwhisperer")
+ self.assertIsNotNone(result)
+ self.assertEqual(len(result), 2)
diff --git a/test/sca/test_ttest.py b/test/sca/test_ttest.py
new file mode 100644
index 0000000..02f78c5
--- /dev/null
+++ b/test/sca/test_ttest.py
@@ -0,0 +1,25 @@
+from unittest import TestCase
+
+import numpy as np
+from pyecsca.sca import Trace, welch_ttest, student_ttest
+
+
+class TTestTests(TestCase):
+
+ def setUp(self):
+ self.a = Trace(None, b"\xff", np.array([20, 80], dtype=np.dtype("i1")))
+ self.b = Trace(None, b"\xff", np.array([30, 42], dtype=np.dtype("i1")))
+ self.c = Trace(None, b"\x00", np.array([78, 56], dtype=np.dtype("i1")))
+ self.d = Trace(None, b"\x00", np.array([98, 36], dtype=np.dtype("i1")))
+
+ def test_welch_ttest(self):
+ self.assertIsNotNone(welch_ttest([self.a, self.b], [self.c, self.d]))
+ a = Trace(None, None, np.array([19.8, 20.4, 19.6, 17.8, 18.5, 18.9, 18.3, 18.9, 19.5, 22.0]))
+ b = Trace(None, None, np.array([28.2, 26.6, 20.1, 23.3, 25.2, 22.1, 17.7, 27.6, 20.6, 13.7]))
+ c = Trace(None, None, 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])
+ self.assertIsNotNone(result)
+
+ def test_students_ttest(self):
+ self.assertIsNotNone(student_ttest([self.a, self.b], [self.c, self.d]))
diff --git a/test/sca/utils.py b/test/sca/utils.py
new file mode 100644
index 0000000..1083b87
--- /dev/null
+++ b/test/sca/utils.py
@@ -0,0 +1,24 @@
+import matplotlib.pyplot as plt
+from unittest import TestCase
+from pyecsca.sca import Trace
+from os.path import join, exists
+from os import mkdir, getenv
+
+
+def slow(func):
+ func.slow = 1
+ return func
+
+
+def plot(case: TestCase, *traces: Trace):
+ if 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))
+ ax.legend(loc="best")
+ directory = join("test", "plots")
+ if not exists(directory):
+ mkdir(directory)
+ plt.savefig(join(directory, case.id() + ".png"))