aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ08nY2020-06-14 13:55:49 +0200
committerJ08nY2020-06-14 14:05:28 +0200
commit925b7824f4c79d795d81b111cc531233651f18b6 (patch)
tree762e76aeb5b2dcd95da1e61abdcd27f385116500
parent7e51c6546d369ec46a6ae8978147e79f2f0195a3 (diff)
downloadpyecsca-925b7824f4c79d795d81b111cc531233651f18b6.tar.gz
pyecsca-925b7824f4c79d795d81b111cc531233651f18b6.tar.zst
pyecsca-925b7824f4c79d795d81b111cc531233651f18b6.zip
-rw-r--r--.coveragerc1
-rw-r--r--.travis.yml2
-rw-r--r--Makefile2
-rw-r--r--README.md2
-rw-r--r--docs/index.rst7
-rw-r--r--pyecsca/ec/curve.py2
-rw-r--r--pyecsca/ec/mult.py4
-rw-r--r--pyecsca/ec/op.py8
-rw-r--r--pyecsca/ec/params.py5
-rw-r--r--pyecsca/ec/signature.py4
-rw-r--r--pyecsca/sca/target/binary.py16
-rw-r--r--pyecsca/sca/trace/combine.py17
-rw-r--r--pyecsca/sca/trace_set/base.py8
-rw-r--r--pyecsca/sca/trace_set/chipwhisperer.py8
-rw-r--r--pyecsca/sca/trace_set/hdf5.py22
-rw-r--r--pyecsca/sca/trace_set/inspector.py16
-rw-r--r--pyecsca/sca/trace_set/pickle.py16
-rwxr-xr-x[-rw-r--r--]test/data/target.py1
-rw-r--r--test/ec/test_curve.py20
-rw-r--r--test/ec/test_formula.py5
-rw-r--r--test/ec/test_mod.py11
-rw-r--r--test/ec/test_point.py4
-rw-r--r--test/ec/test_signature.py22
-rw-r--r--test/sca/test_align.py12
-rw-r--r--test/sca/test_combine.py17
-rw-r--r--test/sca/test_plot.py2
-rw-r--r--test/sca/test_target.py16
27 files changed, 179 insertions, 71 deletions
diff --git a/.coveragerc b/.coveragerc
index 92627e6..75b19fd 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -8,6 +8,7 @@ omit =
[report]
exclude_lines =
__repr__
+ __str__
pragma: no cover
raise AssertionError
raise NotImplementedError
diff --git a/.travis.yml b/.travis.yml
index 9c61f48..5ef16fc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -33,7 +33,7 @@ install:
script:
- make -i typecheck
- make -i codestyle
- - make test
+ - make test-plots
after_success:
- codecov
diff --git a/Makefile b/Makefile
index 5aeb2ed..125f807 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@ test-all:
nose2 -s test -C -v ${TESTS}
typecheck:
- mypy pyecsca --ignore-missing-imports
+ mypy pyecsca --ignore-missing-imports --show-error-codes
codestyle:
flake8 --ignore=E501,F405,F403,F401,E126 pyecsca
diff --git a/README.md b/README.md
index 64dffa5..46c1e7e 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# ![](docs/_static/logo_black_small.png) pyecsca [pɪɛtska]
-[![Build Status](https://travis-ci.com/J08nY/pyecsca.svg?branch=master)](https://travis-ci.com/J08nY/pyecsca) [![docs](https://img.shields.io/badge/docs-neuromancer.sk-brightgreen.svg)](https://neuromancer.sk/pyecsca/) ![License: MIT](https://img.shields.io/github/license/J08nY/pyecsca.svg) [![codecov](https://codecov.io/gh/J08nY/pyecsca/branch/master/graph/badge.svg)](https://codecov.io/gh/J08nY/pyecsca)
+[![docs](https://img.shields.io/badge/docs-neuromancer.sk-brightgreen.svg)](https://neuromancer.sk/pyecsca/) [![License MIT ](https://img.shields.io/github/license/J08nY/pyecsca?color=brightgreen)](https://github.com/J08nY/pyecsca/blob/master/LICENSE) [![Build Status](https://travis-ci.com/J08nY/pyecsca.svg?branch=master)](https://travis-ci.com/J08nY/pyecsca) [![Codecov](https://img.shields.io/codecov/c/gh/J08nY/pyecsca?color=brightgreen&logo=codecov)](https://codecov.io/gh/J08nY/pyecsca) ![](https://img.shields.io/static/v1?label=mypy&message=No%20issues&color=brightgreen)
**Py**thon **E**lliptic **C**urve cryptography **S**ide-**C**hannel **A**nalysis toolkit.
diff --git a/docs/index.rst b/docs/index.rst
index 4067296..af26547 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -4,12 +4,13 @@ pyecsca [pɪɛtska]
.. image:: https://img.shields.io/badge/-Github-brightgreen?style=flat&logo=github
:target: https://github.com/J08nY/pyecsca
+.. image:: https://img.shields.io/github/license/J08nY/pyecsca?color=brightgreen
+ :target: https://github.com/J08nY/pyecsca/blob/master/LICENSE
.. image:: https://img.shields.io/travis/J08nY/pyecsca
:target: https://travis-ci.com/J08nY/pyecsca
-.. image:: https://img.shields.io/github/license/J08nY/pyecsca.svg
- :target: https://github.com/J08nY/pyecsca/blob/master/LICENSE
-.. image:: https://codecov.io/gh/J08nY/pyecsca/branch/master/graph/badge.svg
+.. image:: https://img.shields.io/codecov/c/gh/J08nY/pyecsca?color=brightgreen&logo=codecov
:target: https://codecov.io/gh/J08nY/pyecsca
+.. image:: https://img.shields.io/static/v1?label=mypy&message=No%20issues&color=brightgreen
**Py**\ thon **E**\ lliptic **C**\ urve cryptography **S**\ ide-**C**\ hannel **A**\ nalysis toolkit.
diff --git a/pyecsca/ec/curve.py b/pyecsca/ec/curve.py
index a05ff3f..8cbd48e 100644
--- a/pyecsca/ec/curve.py
+++ b/pyecsca/ec/curve.py
@@ -112,7 +112,7 @@ class EllipticCurve(object):
def to_affine(self) -> "EllipticCurve":
"""Convert this curve into the affine coordinate model, if possible."""
coord_model = AffineCoordinateModel(self.model)
- return EllipticCurve(self.model, coord_model, self.prime, self.neutral.to_affine(), self.parameters)
+ return EllipticCurve(self.model, coord_model, self.prime, self.neutral.to_affine(), self.parameters) # type: ignore[arg-type]
def decode_point(self, encoded: bytes) -> Point:
"""Decode a point encoded as a sequence of bytes (ANSI X9.62)."""
diff --git a/pyecsca/ec/mult.py b/pyecsca/ec/mult.py
index 6dfd5cd..a3622f5 100644
--- a/pyecsca/ec/mult.py
+++ b/pyecsca/ec/mult.py
@@ -35,8 +35,8 @@ class ScalarMultiplier(ABC):
of the point at infinity.
:param formulas: Formulas this instance will use.
"""
- requires: ClassVar[Set[Type[Formula]]]
- optionals: ClassVar[Set[Type[Formula]]]
+ requires: ClassVar[Set[Type]] #Type[Formula] but mypy has a false positive
+ optionals: ClassVar[Set[Type]] #Type[Formula] but mypy has a false positive
short_circuit: bool
formulas: Mapping[str, Formula]
_params: DomainParameters
diff --git a/pyecsca/ec/op.py b/pyecsca/ec/op.py
index ea0c1ad..d0cec58 100644
--- a/pyecsca/ec/op.py
+++ b/pyecsca/ec/op.py
@@ -1,8 +1,8 @@
from ast import (Module, walk, Name, BinOp, UnaryOp, Constant, Mult, Div, Add, Sub, Pow, Assign,
- operator as ast_operator, USub)
+ operator as ast_operator, unaryop as ast_unaryop, USub)
from enum import Enum
from types import CodeType
-from typing import FrozenSet, cast, Any, Optional
+from typing import FrozenSet, cast, Any, Optional, Union
from public import public
@@ -43,7 +43,7 @@ class CodeOp(object):
params = set()
variables = set()
constants = set()
- op = None
+ op: Optional[Union[ast_operator, ast_unaryop]] = None
self.left = None
self.right = None
for node in walk(assign.value):
@@ -80,7 +80,7 @@ class CodeOp(object):
else:
return None
- def __to_op(self, op: Optional[ast_operator], left: Any, right: Any) -> OpType:
+ def __to_op(self, op: Optional[Union[ast_operator, ast_unaryop]], left: Any, right: Any) -> OpType:
if isinstance(op, Mult):
return OpType.Mult
elif isinstance(op, Div):
diff --git a/pyecsca/ec/params.py b/pyecsca/ec/params.py
index 29d431d..8f5afd6 100644
--- a/pyecsca/ec/params.py
+++ b/pyecsca/ec/params.py
@@ -5,7 +5,7 @@ from typing import Optional, Dict, Union
from pkg_resources import resource_listdir, resource_isdir, resource_stream
from public import public
-from .coordinates import AffineCoordinateModel
+from .coordinates import AffineCoordinateModel, CoordinateModel
from .curve import EllipticCurve
from .mod import Mod
from .model import (CurveModel, ShortWeierstrassModel, MontgomeryModel, EdwardsModel,
@@ -106,6 +106,7 @@ def get_params(category: str, name: str, coords: str, infty: bool = True) -> Dom
params = {name: Mod(int(curve["params"][name], 16), field) for name in param_names}
# Check coordinate model name and assumptions
+ coord_model: CoordinateModel
if coords == "affine":
coord_model = AffineCoordinateModel(model)
else:
@@ -138,7 +139,7 @@ def get_params(category: str, name: str, coords: str, infty: bool = True) -> Dom
value = Mod(value, field)
infinity_coords[coordinate] = value
infinity = Point(coord_model, **infinity_coords)
- elliptic_curve = EllipticCurve(model, coord_model, field, infinity, params)
+ elliptic_curve = EllipticCurve(model, coord_model, field, infinity, params) # type: ignore[arg-type]
affine = Point(AffineCoordinateModel(model), x=Mod(int(curve["generator"]["x"], 16), field),
y=Mod(int(curve["generator"]["y"], 16), field))
if not isinstance(coord_model, AffineCoordinateModel):
diff --git a/pyecsca/ec/signature.py b/pyecsca/ec/signature.py
index 569367e..e61dc1b 100644
--- a/pyecsca/ec/signature.py
+++ b/pyecsca/ec/signature.py
@@ -163,7 +163,7 @@ class Signature(object):
def sign_data(self, data: bytes, nonce: Optional[int] = None) -> SignatureResult:
"""Sign data."""
- if not self.can_sign:
+ if not self.can_sign or self.privkey is None:
raise RuntimeError("This instance cannot sign.")
with ECDSASignAction(self.params, self.hash_algo, data, self.privkey):
k = self._get_nonce(nonce)
@@ -199,7 +199,7 @@ class Signature(object):
def verify_data(self, signature: SignatureResult, data: bytes) -> bool:
"""Verify data."""
- if not self.can_verify:
+ if not self.can_verify or self.pubkey is None:
raise RuntimeError("This instance cannot verify.")
with ECDSAVerifyAction(self.params, self.hash_algo, data, signature, self.pubkey):
if self.hash_algo is None:
diff --git a/pyecsca/sca/target/binary.py b/pyecsca/sca/target/binary.py
index cb4c918..f21c2e7 100644
--- a/pyecsca/sca/target/binary.py
+++ b/pyecsca/sca/target/binary.py
@@ -10,7 +10,7 @@ from .serial import SerialTarget
@public
class BinaryTarget(SerialTarget):
binary: List[str]
- process: Optional[Popen]
+ process: Optional[Popen] = None
debug_output: bool
def __init__(self, binary: Union[str, List[str]], debug_output: bool = False, **kwargs):
@@ -31,16 +31,20 @@ class BinaryTarget(SerialTarget):
raise ValueError
if self.debug_output:
print(">>", data.decode())
- self.process.stdin.write(data.decode())
- self.process.stdin.flush()
+ if self.process.stdin:
+ self.process.stdin.write(data.decode())
+ self.process.stdin.flush()
def read(self, num: int = 0, timeout: int = 0) -> bytes:
if self.process is None:
raise ValueError
- if num != 0:
- read = self.process.stdout.readline(num)
+ if self.process.stdout:
+ if num != 0:
+ read = self.process.stdout.readline(num)
+ else:
+ read = self.process.stdout.readline()
else:
- read = self.process.stdout.readline()
+ read = bytes() # pragma: no cover
if self.debug_output:
print("<<", read, end="")
return read.encode()
diff --git a/pyecsca/sca/trace/combine.py b/pyecsca/sca/trace/combine.py
index 5eeaaec..26a3e98 100644
--- a/pyecsca/sca/trace/combine.py
+++ b/pyecsca/sca/trace/combine.py
@@ -52,6 +52,23 @@ def standard_deviation(*traces: Trace) -> Optional[CombinedTrace]:
@public
+def add(*traces: Trace) -> Optional[CombinedTrace]:
+ """
+ Add `traces`, sample-wise.
+
+ :param traces:
+ :return:
+ """
+ if not traces:
+ return None
+ if len(traces) == 1:
+ return CombinedTrace(traces[0].samples.copy())
+ dtype = traces[0].samples.dtype
+ result_samples = np.sum(np.array([trace.samples for trace in traces]), axis=0).astype(dtype)
+ return CombinedTrace(result_samples)
+
+
+@public
def subtract(one: Trace, other: Trace) -> CombinedTrace:
"""
Subtract `other` from `one`, sample-wise.
diff --git a/pyecsca/sca/trace_set/base.py b/pyecsca/sca/trace_set/base.py
index 1826a98..7cd80b6 100644
--- a/pyecsca/sca/trace_set/base.py
+++ b/pyecsca/sca/trace_set/base.py
@@ -1,6 +1,6 @@
from io import RawIOBase, BufferedIOBase
from pathlib import Path
-from typing import List, Union
+from typing import List, Union, BinaryIO
from public import public
@@ -32,14 +32,14 @@ class TraceSet(object):
yield from self._traces
@classmethod
- def read(cls, input: Union[str, Path, bytes, RawIOBase, BufferedIOBase]) -> "TraceSet":
+ def read(cls, input: Union[str, Path, bytes, BinaryIO]) -> "TraceSet":
raise NotImplementedError
@classmethod
- def inplace(cls, input: Union[str, Path, bytes, RawIOBase, BufferedIOBase]) -> "TraceSet":
+ def inplace(cls, input: Union[str, Path, bytes, BinaryIO]) -> "TraceSet":
raise NotImplementedError
- def write(self, output: Union[str, Path, RawIOBase, BufferedIOBase]):
+ def write(self, output: Union[str, Path, BinaryIO]):
raise NotImplementedError
def __repr__(self):
diff --git a/pyecsca/sca/trace_set/chipwhisperer.py b/pyecsca/sca/trace_set/chipwhisperer.py
index ea1fc99..05606ee 100644
--- a/pyecsca/sca/trace_set/chipwhisperer.py
+++ b/pyecsca/sca/trace_set/chipwhisperer.py
@@ -3,7 +3,7 @@ from io import RawIOBase, BufferedIOBase
from itertools import zip_longest
from os.path import exists, isfile, join, basename, dirname
from pathlib import Path
-from typing import Union
+from typing import Union, BinaryIO
import numpy as np
from public import public
@@ -18,7 +18,7 @@ class ChipWhispererTraceSet(TraceSet):
@classmethod
def read(cls,
- input: Union[str, Path, bytes, RawIOBase, BufferedIOBase]) -> "ChipWhispererTraceSet":
+ input: Union[str, Path, bytes, BinaryIO]) -> "ChipWhispererTraceSet":
if isinstance(input, (str, Path)):
traces, kwargs = ChipWhispererTraceSet.__read(input)
return ChipWhispererTraceSet(*traces, **kwargs)
@@ -26,10 +26,10 @@ class ChipWhispererTraceSet(TraceSet):
raise ValueError
@classmethod
- def inplace(cls, input: Union[str, Path, bytes, RawIOBase, BufferedIOBase]) -> "ChipWhispererTraceSet":
+ def inplace(cls, input: Union[str, Path, bytes, BinaryIO]) -> "ChipWhispererTraceSet":
raise NotImplementedError
- def write(self, output: Union[str, Path, RawIOBase, BufferedIOBase]):
+ def write(self, output: Union[str, Path, BinaryIO]):
raise NotImplementedError
@classmethod
diff --git a/pyecsca/sca/trace_set/hdf5.py b/pyecsca/sca/trace_set/hdf5.py
index b610735..7446bed 100644
--- a/pyecsca/sca/trace_set/hdf5.py
+++ b/pyecsca/sca/trace_set/hdf5.py
@@ -3,7 +3,7 @@ import uuid
from collections import MutableMapping
from io import RawIOBase, BufferedIOBase, IOBase
from pathlib import Path
-from typing import Union, Optional, Dict, Any, List
+from typing import Union, Optional, Dict, Any, List, BinaryIO
import h5py
import numpy as np
@@ -49,7 +49,7 @@ class HDF5Meta(MutableMapping):
@public
class HDF5TraceSet(TraceSet):
_file: Optional[h5py.File]
- _ordering: Optional[List[str]]
+ _ordering: List[str]
#_meta: Optional[HDF5Meta]
def __init__(self, *traces: Trace, _file: Optional[h5py.File] = None,
@@ -62,13 +62,13 @@ class HDF5TraceSet(TraceSet):
@classmethod
- def read(cls, input: Union[str, Path, bytes, RawIOBase, BufferedIOBase]) -> "HDF5TraceSet":
+ def read(cls, input: Union[str, Path, bytes, BinaryIO]) -> "HDF5TraceSet":
if isinstance(input, (str, Path)):
hdf5 = h5py.File(str(input), mode="r")
- elif isinstance(input, IOBase):
+ elif isinstance(input, (RawIOBase, BufferedIOBase, BinaryIO)):
hdf5 = h5py.File(input, mode="r")
else:
- raise ValueError
+ raise TypeError
kwargs = dict(hdf5.attrs)
kwargs["_ordering"] = list(kwargs["_ordering"]) if "_ordering" in kwargs else list(hdf5.keys())
traces = []
@@ -80,13 +80,13 @@ class HDF5TraceSet(TraceSet):
return HDF5TraceSet(*traces, **kwargs)
@classmethod
- def inplace(cls, input: Union[str, Path, bytes, RawIOBase, BufferedIOBase]) -> "HDF5TraceSet":
+ def inplace(cls, input: Union[str, Path, bytes, BinaryIO]) -> "HDF5TraceSet":
if isinstance(input, (str, Path)):
hdf5 = h5py.File(str(input), mode="a")
- elif isinstance(input, IOBase):
+ elif isinstance(input, (RawIOBase, BufferedIOBase, BinaryIO)):
hdf5 = h5py.File(input, mode="a")
else:
- raise ValueError
+ raise TypeError
kwargs = dict(hdf5.attrs)
kwargs["_ordering"] = list(kwargs["_ordering"]) if "_ordering" in kwargs else list(hdf5.keys())
traces = []
@@ -94,7 +94,7 @@ class HDF5TraceSet(TraceSet):
meta = HDF5Meta(hdf5[k].attrs)
samples = hdf5[k]
traces.append(Trace(samples, meta))
- return HDF5TraceSet(*traces, **kwargs, _file=hdf5)
+ return HDF5TraceSet(*traces, **kwargs, _file=hdf5) # type: ignore[misc]
def insert(self, index: int, value: Trace) -> Trace:
key = str(uuid.uuid4())
@@ -147,10 +147,10 @@ class HDF5TraceSet(TraceSet):
# else:
# super().__setattr__(key, value)
- def write(self, output: Union[str, Path, RawIOBase, BufferedIOBase]):
+ def write(self, output: Union[str, Path, BinaryIO]):
if isinstance(output, (str, Path)):
hdf5 = h5py.File(str(output), "w")
- elif isinstance(output, IOBase):
+ elif isinstance(output, BinaryIO):
hdf5 = h5py.File(output, "w")
else:
raise ValueError
diff --git a/pyecsca/sca/trace_set/inspector.py b/pyecsca/sca/trace_set/inspector.py
index d95e5b7..4fabb9c 100644
--- a/pyecsca/sca/trace_set/inspector.py
+++ b/pyecsca/sca/trace_set/inspector.py
@@ -2,7 +2,7 @@ import struct
from enum import IntEnum
from io import BytesIO, RawIOBase, BufferedIOBase, UnsupportedOperation
from pathlib import Path
-from typing import Union, Optional
+from typing import Union, Optional, BinaryIO
import numpy as np
from public import public
@@ -138,7 +138,7 @@ class InspectorTraceSet(TraceSet):
}
@classmethod
- def read(cls, input: Union[str, Path, bytes, RawIOBase, BufferedIOBase]) -> "TraceSet":
+ def read(cls, input: Union[str, Path, bytes, BinaryIO]) -> "TraceSet":
"""
Read Inspector trace set from file path, bytes or file-like object.
@@ -151,10 +151,10 @@ class InspectorTraceSet(TraceSet):
elif isinstance(input, (str, Path)):
with open(input, "rb") as f:
traces, tags = InspectorTraceSet.__read(f)
- elif isinstance(input, (RawIOBase, BufferedIOBase)):
+ elif isinstance(input, (RawIOBase, BufferedIOBase, BinaryIO)):
traces, tags = InspectorTraceSet.__read(input)
else:
- raise ValueError
+ raise TypeError
for trace in traces:
new = InspectorTraceSet.__scale(trace.samples, tags["y_scale"])
del trace.samples
@@ -194,10 +194,10 @@ class InspectorTraceSet(TraceSet):
return result, tags
@classmethod
- def inplace(cls, input: Union[str, Path, bytes, RawIOBase, BufferedIOBase]) -> "TraceSet":
+ def inplace(cls, input: Union[str, Path, bytes, BinaryIO]) -> "TraceSet":
raise NotImplementedError
- def write(self, output: Union[str, Path, RawIOBase, BufferedIOBase]):
+ def write(self, output: Union[str, Path, BinaryIO]):
"""
Save this trace set into a file.
@@ -206,10 +206,10 @@ class InspectorTraceSet(TraceSet):
if isinstance(output, (str, Path)):
with open(output, "wb") as f:
self.__write(f)
- elif isinstance(output, (RawIOBase, BufferedIOBase)):
+ elif isinstance(output, (RawIOBase, BufferedIOBase, BinaryIO)):
self.__write(output)
else:
- raise ValueError
+ raise TypeError
def __write(self, file):
for tag, tag_tuple in self._tag_parsers.items():
diff --git a/pyecsca/sca/trace_set/pickle.py b/pyecsca/sca/trace_set/pickle.py
index 42bc3bb..f754bbf 100644
--- a/pyecsca/sca/trace_set/pickle.py
+++ b/pyecsca/sca/trace_set/pickle.py
@@ -1,7 +1,7 @@
import pickle
from io import BufferedIOBase, RawIOBase, IOBase
from pathlib import Path
-from typing import Union
+from typing import Union, BinaryIO
from public import public
@@ -11,25 +11,25 @@ from .base import TraceSet
@public
class PickleTraceSet(TraceSet):
@classmethod
- def read(cls, input: Union[str, Path, bytes, RawIOBase, BufferedIOBase]) -> "PickleTraceSet":
+ def read(cls, input: Union[str, Path, bytes, BinaryIO]) -> "PickleTraceSet":
if isinstance(input, bytes):
return pickle.loads(input)
elif isinstance(input, (str, Path)):
with open(input, "rb") as f:
return pickle.load(f)
- elif isinstance(input, IOBase):
+ elif isinstance(input, (RawIOBase, BufferedIOBase, BinaryIO)):
return pickle.load(input)
- raise ValueError
+ raise TypeError
@classmethod
- def inplace(cls, input: Union[str, Path, bytes, RawIOBase, BufferedIOBase]) -> "PickleTraceSet":
+ def inplace(cls, input: Union[str, Path, bytes, BinaryIO]) -> "PickleTraceSet":
raise NotImplementedError
- def write(self, output: Union[str, Path, RawIOBase, BufferedIOBase]):
+ def write(self, output: Union[str, Path, BinaryIO]):
if isinstance(output, (str, Path)):
with open(output, "wb") as f:
pickle.dump(self, f)
- elif isinstance(output, IOBase):
+ elif isinstance(output, (RawIOBase, BufferedIOBase, BinaryIO)):
pickle.dump(self, output)
else:
- raise ValueError
+ raise TypeError
diff --git a/test/data/target.py b/test/data/target.py
index 1583597..9e6e0e0 100644..100755
--- a/test/data/target.py
+++ b/test/data/target.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python3
from sys import stdout
if __name__ == "__main__":
diff --git a/test/ec/test_curve.py b/test/ec/test_curve.py
index 1b22279..f9e3387 100644
--- a/test/ec/test_curve.py
+++ b/test/ec/test_curve.py
@@ -1,7 +1,6 @@
from binascii import unhexlify
from unittest import TestCase
-from pyecsca.ec.coordinates import AffineCoordinateModel
from pyecsca.ec.curve import EllipticCurve
from pyecsca.ec.params import get_params
from pyecsca.ec.mod import Mod
@@ -35,6 +34,7 @@ class CurveTests(TestCase):
self.assertTrue(self.secp128r1.curve.is_neutral(InfinityPoint(self.secp128r1.curve.coordinate_model)))
def test_is_on_curve(self):
+ self.assertTrue(self.secp128r1.curve.is_on_curve(self.secp128r1.curve.neutral))
pt = Point(self.secp128r1.curve.coordinate_model,
X=Mod(0x161ff7528b899b2d0c28607ca52c5b86, self.secp128r1.curve.prime),
Y=Mod(0xcf5ac8395bafeb13c02da292dded7a83, self.secp128r1.curve.prime),
@@ -46,6 +46,7 @@ class CurveTests(TestCase):
Y=Mod(0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, self.secp128r1.curve.prime),
Z=Mod(1, self.secp128r1.curve.prime))
self.assertFalse(self.secp128r1.curve.is_on_curve(other))
+ self.assertFalse(self.secp128r1.curve.is_on_curve(self.curve25519.generator))
def test_affine_add(self):
self.assertIsNotNone(self.secp128r1.curve.affine_add(self.affine_base, self.affine_base))
@@ -88,4 +89,21 @@ class CurveTests(TestCase):
affine_compressed_bytes = unhexlify("03161ff7528b899b2d0c28607ca52c5b86")
decoded_compressed = affine_curve.decode_point(affine_compressed_bytes)
self.assertEqual(decoded_compressed, affine_point)
+ affine_compressed_bytes = unhexlify("02161ff7528b899b2d0c28607ca52c5b86")
+ decoded_compressed = affine_curve.decode_point(affine_compressed_bytes)
+ decoded_compressed = self.secp128r1.curve.affine_negate(decoded_compressed)
+ self.assertEqual(decoded_compressed, affine_point)
+
+ infinity_bytes = unhexlify("00")
+ decoded_infinity = affine_curve.decode_point(infinity_bytes)
+ self.assertEqual(affine_curve.neutral, decoded_infinity)
+
+ with self.assertRaises(ValueError):
+ affine_curve.decode_point(unhexlify("03161ff7528b899b2d0c28607ca52c5b"))
+ with self.assertRaises(ValueError):
+ affine_curve.decode_point(unhexlify("04161ff7528b899b2d0c28607ca52c5b2c5b2c5b2c5b"))
+ with self.assertRaises(ValueError):
+ affine_curve.decode_point(unhexlify("7a161ff7528b899b2d0c28607ca52c5b86"))
+ with self.assertRaises(ValueError):
+ affine_curve.decode_point(unhexlify("03161ff7528b899b2d0c28607ca52c5b88"))
diff --git a/test/ec/test_formula.py b/test/ec/test_formula.py
index c0eed28..d5f8392 100644
--- a/test/ec/test_formula.py
+++ b/test/ec/test_formula.py
@@ -8,6 +8,7 @@ class FormulaTests(TestCase):
def setUp(self):
self.secp128r1 = get_params("secg", "secp128r1", "projective")
self.add = self.secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
+ self.dbl = self.secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
def test_wrong_call(self):
with self.assertRaises(ValueError):
@@ -23,6 +24,10 @@ class FormulaTests(TestCase):
self.assertEqual(self.add.inputs, {"X1", "Y1", "Z1", "X2", "Y2", "Z2"})
self.assertEqual(self.add.outputs, {"X3", "Y3", "Z3"})
+ def test_eq(self):
+ self.assertEqual(self.add, self.add)
+ self.assertNotEqual(self.add, self.dbl)
+
def test_num_ops(self):
self.assertEqual(self.add.num_operations, 33)
self.assertEqual(self.add.num_multiplications, 17)
diff --git a/test/ec/test_mod.py b/test/ec/test_mod.py
index 59c8e24..db54456 100644
--- a/test/ec/test_mod.py
+++ b/test/ec/test_mod.py
@@ -21,10 +21,21 @@ class ModTests(TestCase):
def test_is_residue(self):
self.assertTrue(Mod(4, 11).is_residue())
self.assertFalse(Mod(11, 31).is_residue())
+ self.assertTrue(Mod(0, 7).is_residue())
+ self.assertTrue(Mod(1, 2).is_residue())
def test_sqrt(self):
p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff
self.assertIn(Mod(0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc, p).sqrt(), (0x9add512515b70d9ec471151c1dec46625cd18b37bde7ca7fb2c8b31d7033599d, 0x6522aed9ea48f2623b8eeae3e213b99da32e74c9421835804d374ce28fcca662))
+ q = 0x75d44fee9a71841ae8403c0c251fbad
+ self.assertIn(Mod(0x591e0db18cf1bd81a11b2985a821eb3, q).sqrt(), (0x113b41a1a2b73f636e73be3f9a3716e, 0x64990e4cf7ba44b779cc7dcc8ae8a3f))
+
+ def test_eq(self):
+ self.assertEqual(Mod(1, 7), 1)
+ self.assertNotEqual(Mod(1, 7), "1")
+ self.assertEqual(Mod(1, 7), Mod(1, 7))
+ self.assertNotEqual(Mod(1, 7), Mod(5, 7))
+ self.assertNotEqual(Mod(1, 7), Mod(1, 5))
def test_wrong_mod(self):
a = Mod(5, 7)
diff --git a/test/ec/test_point.py b/test/ec/test_point.py
index b0ed051..936d4e9 100644
--- a/test/ec/test_point.py
+++ b/test/ec/test_point.py
@@ -14,6 +14,10 @@ class PointTests(TestCase):
self.coords = self.secp128r1.curve.coordinate_model
self.affine = AffineCoordinateModel(ShortWeierstrassModel())
+ def test_construction(self):
+ with self.assertRaises(ValueError):
+ Point(self.coords)
+
def test_to_affine(self):
pt = Point(self.coords,
X=Mod(0x161ff7528b899b2d0c28607ca52c5b86, self.secp128r1.curve.prime),
diff --git a/test/ec/test_signature.py b/test/ec/test_signature.py
index 0d3c5a9..8d4a439 100644
--- a/test/ec/test_signature.py
+++ b/test/ec/test_signature.py
@@ -30,17 +30,16 @@ class SignatureTests(TestCase):
])
def test_all(self, name, algo):
signer = algo(self.mult, self.secp128r1, privkey=self.priv)
- assert signer.can_sign
+ self.assertTrue(signer.can_sign)
sig = signer.sign_data(self.msg)
verifier = algo(self.mult, self.secp128r1, add=self.add, pubkey=self.pub)
- assert verifier.can_verify
- assert verifier.verify_data(sig, self.msg)
- # none = ECDSA_NONE(self.mult, add=self.add, pubkey=self.pub, privkey=self.priv)
- # digest = sha1(self.msg).digest()
- # sig = none.sign_hash(digest)
- # assert none.verify_hash(sig, digest)
- # sig = none.sign_data(digest)
- # assert none.verify_data(sig, digest)
+ self.assertTrue(verifier.can_verify)
+ self.assertTrue(verifier.verify_data(sig, self.msg))
+
+ none = ECDSA_NONE(self.mult, self.secp128r1, add=self.add, pubkey=self.pub, privkey=self.priv)
+ digest = signer.hash_algo(self.msg).digest()
+ sig = none.sign_hash(digest)
+ self.assertTrue(none.verify_hash(sig, digest))
def test_cannot(self):
ok = ECDSA_NONE(self.mult, self.secp128r1, add=self.add, pubkey=self.pub, privkey=self.priv)
@@ -73,10 +72,11 @@ class SignatureTests(TestCase):
sig_one = signer.sign_data(self.msg, nonce=0xabcdef)
sig_other = signer.sign_data(self.msg, nonce=0xabcdef)
verifier = algo(self.mult, self.secp128r1, add=self.add, pubkey=self.pub)
- assert verifier.verify_data(sig_one, self.msg)
- assert verifier.verify_data(sig_other, self.msg)
+ self.assertTrue(verifier.verify_data(sig_one, self.msg))
+ self.assertTrue(verifier.verify_data(sig_other, self.msg))
self.assertEqual(sig_one, sig_other)
def test_der(self):
sig = SignatureResult(0xaaaaa, 0xbbbbb)
self.assertEqual(sig, SignatureResult.from_DER(sig.to_DER()))
+ self.assertNotEqual(sig, "abc")
diff --git a/test/sca/test_align.py b/test/sca/test_align.py
index c36cff0..15d452a 100644
--- a/test/sca/test_align.py
+++ b/test/sca/test_align.py
@@ -60,6 +60,12 @@ class AlignTests(Plottable):
self.assertEqual(np.argmax(result[1].samples), np.argmax(result[2].samples))
self.plot(*result)
+ 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(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"))
@@ -72,3 +78,9 @@ class AlignTests(Plottable):
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)
+
+ 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)
diff --git a/test/sca/test_combine.py b/test/sca/test_combine.py
index a35772b..c48c7f8 100644
--- a/test/sca/test_combine.py
+++ b/test/sca/test_combine.py
@@ -1,7 +1,7 @@
from unittest import TestCase
import numpy as np
-from pyecsca.sca import Trace, CombinedTrace, average, conditional_average, standard_deviation
+from pyecsca.sca import Trace, CombinedTrace, average, conditional_average, standard_deviation, add, subtract
class CombineTests(TestCase):
@@ -33,3 +33,18 @@ class CombineTests(TestCase):
result = standard_deviation(self.a, self.b)
self.assertIsInstance(result, CombinedTrace)
self.assertEqual(len(result.samples), 2)
+
+ 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)
+
diff --git a/test/sca/test_plot.py b/test/sca/test_plot.py
index 5b65c87..2cd6b11 100644
--- a/test/sca/test_plot.py
+++ b/test/sca/test_plot.py
@@ -2,6 +2,7 @@ from os import getenv
import numpy as np
import holoviews as hv
+import matplotlib as mpl
from pyecsca.sca.trace import Trace
from pyecsca.sca.trace.plot import (plot_trace, save_figure, save_figure_png, save_figure_svg,
plot_traces)
@@ -27,6 +28,7 @@ class PlotTests(Plottable):
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())
diff --git a/test/sca/test_target.py b/test/sca/test_target.py
index 6c56d97..3652309 100644
--- a/test/sca/test_target.py
+++ b/test/sca/test_target.py
@@ -39,6 +39,22 @@ class BinaryTargetTests(TestCase):
self.assertEqual(resp["r"].data, "01020304")
target.disconnect()
+ def test_debug(self):
+ target_path = join(dirname(realpath(__file__)), "..", "data", "target.py")
+ target = TestTarget(["python", target_path], debug_output=True)
+ target.connect()
+ target.send_cmd(SimpleSerialMessage("d", ""), 500)
+ target.disconnect()
+
+ def test_no_connection(self):
+ target_path = join(dirname(realpath(__file__)), "..", "data", "target.py")
+ target = TestTarget(target_path)
+ with self.assertRaises(ValueError):
+ target.write(bytes([1,2,3,4]))
+ with self.assertRaises(ValueError):
+ target.read(5)
+ target.disconnect()
+
class ECTesterTargetTests(TestCase):
reader: Optional[str] = None