aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJ08nY2023-08-09 17:40:16 +0200
committerJ08nY2023-08-09 17:40:16 +0200
commitb5801a2acfdd149cdb5b24985992e43afdfb9311 (patch)
treed78605557eb64ae6282e9e309380efd01e3f0d9f
parentf40b69968ad9bbb8300b451640a82e1ac83aa7ba (diff)
parent1cdf2090574074e94a44b0b939d0dff24727ddf7 (diff)
downloadpyecsca-b5801a2acfdd149cdb5b24985992e43afdfb9311.tar.gz
pyecsca-b5801a2acfdd149cdb5b24985992e43afdfb9311.tar.zst
pyecsca-b5801a2acfdd149cdb5b24985992e43afdfb9311.zip
Add RPA/ZVP/EPA stuff.
Merge branch 'zvp-re'
-rw-r--r--.github/workflows/lint.yml2
-rw-r--r--.github/workflows/test.yml4
-rw-r--r--Makefile19
-rw-r--r--pyecsca/ec/context.py4
-rw-r--r--pyecsca/ec/coordinates.py57
-rw-r--r--pyecsca/ec/curve.py82
-rw-r--r--pyecsca/ec/divpoly.py271
m---------pyecsca/ec/efd0
-rw-r--r--pyecsca/ec/formula.py21
-rw-r--r--pyecsca/ec/mod.py14
-rw-r--r--pyecsca/ec/model.py25
-rw-r--r--pyecsca/ec/mult.py202
-rw-r--r--pyecsca/ec/params.py208
-rw-r--r--pyecsca/ec/point.py4
-rw-r--r--pyecsca/ec/signature.py4
m---------pyecsca/ec/std0
-rw-r--r--pyecsca/misc/__init__.py2
-rw-r--r--pyecsca/misc/cfg.py5
-rw-r--r--pyecsca/sca/attack/leakage_model.py22
-rw-r--r--pyecsca/sca/re/rpa.py110
-rw-r--r--pyecsca/sca/re/zvp.py34
-rw-r--r--pyecsca/sca/stacked_traces/combine.py4
-rw-r--r--pyecsca/sca/stacked_traces/stacked_traces.py2
-rw-r--r--pyecsca/sca/trace/trace.py2
-rw-r--r--pyecsca/sca/trace_set/inspector.py4
-rw-r--r--pyproject.toml15
-rw-r--r--test/conftest.py18
-rw-r--r--test/data/__init__.py0
-rw-r--r--test/data/divpoly/__init__.py0
-rw-r--r--test/data/divpoly/mult_21.json2655
-rw-r--r--test/data/ec/__init__.py0
-rw-r--r--test/data/ec/curve.json (renamed from test/data/curve.json)0
-rw-r--r--test/data/ec/curves.json (renamed from test/data/curves.json)0
-rw-r--r--test/data/ec/ecgen_secp128r1.json24
-rw-r--r--test/data/ec/ectester_secp128r1.csv1
-rw-r--r--test/data/sca/__init__.py0
-rw-r--r--test/data/sca/chipwhisperer_keylist.npy (renamed from test/data/chipwhisperer_keylist.npy)bin112 -> 112 bytes
-rw-r--r--test/data/sca/chipwhisperer_knownkey.npy (renamed from test/data/chipwhisperer_knownkey.npy)bin96 -> 96 bytes
-rw-r--r--test/data/sca/chipwhisperer_settings.cwset (renamed from test/data/chipwhisperer_settings.cwset)0
-rw-r--r--test/data/sca/chipwhisperer_textin.npy (renamed from test/data/chipwhisperer_textin.npy)bin112 -> 112 bytes
-rw-r--r--test/data/sca/chipwhisperer_textout.npy (renamed from test/data/chipwhisperer_textout.npy)bin214 -> 214 bytes
-rw-r--r--test/data/sca/chipwhisperer_traces.npy (renamed from test/data/chipwhisperer_traces.npy)bin384080 -> 384080 bytes
-rw-r--r--test/data/sca/config_chipwhisperer_.cfg (renamed from test/data/config_chipwhisperer_.cfg)0
-rw-r--r--test/data/sca/example.trs (renamed from test/data/example.trs)bin26250885 -> 26250885 bytes
-rwxr-xr-xtest/data/sca/target.py (renamed from test/data/target.py)5
-rw-r--r--test/data/sca/test.h5 (renamed from test/data/test.h5)bin6592 -> 6592 bytes
-rw-r--r--test/data/sca/test.pickle (renamed from test/data/test.pickle)bin463 -> 463 bytes
-rw-r--r--test/ec/conftest.py0
-rwxr-xr-xtest/ec/perf_divpoly.py30
-rwxr-xr-xtest/ec/perf_mult.py7
-rw-r--r--test/ec/test_configuration.py119
-rw-r--r--test/ec/test_context.py153
-rw-r--r--test/ec/test_curve.py310
-rw-r--r--test/ec/test_divpoly.py112
-rw-r--r--test/ec/test_formula.py189
-rw-r--r--test/ec/test_key_agreement.py60
-rw-r--r--test/ec/test_key_generation.py37
-rw-r--r--test/ec/test_mod.py355
-rw-r--r--test/ec/test_model.py13
-rw-r--r--test/ec/test_mult.py570
-rw-r--r--test/ec/test_naf.py9
-rw-r--r--test/ec/test_op.py61
-rw-r--r--test/ec/test_params.py208
-rw-r--r--test/ec/test_point.py246
-rw-r--r--test/ec/test_regress.py191
-rw-r--r--test/ec/test_signature.py163
-rw-r--r--test/ec/test_transformations.py57
-rw-r--r--test/ec/utils.py5
-rw-r--r--test/sca/conftest.py43
-rw-r--r--test/sca/perf_combine.py41
-rw-r--r--test/sca/test_align.py241
-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.py159
-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.py848
-rw-r--r--test/sca/test_test.py62
-rw-r--r--test/sca/test_trace.py12
-rw-r--r--test/sca/test_traceset.py196
-rw-r--r--test/sca/test_zvp.py13
-rw-r--r--test/sca/utils.py52
-rw-r--r--unittest.cfg3
89 files changed, 6660 insertions, 2993 deletions
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index a947379..b8c4fc2 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -43,7 +43,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install -U pip setuptools wheel
- pip install -e ".[picoscope_sdk, picoscope_alt, chipwhisperer, smartcard, leia, gmp, test, dev]"
+ pip install -e ".[picoscope_sdk, picoscope_alt, chipwhisperer, smartcard, gmp, test, dev]"
- name: Typecheck
run: |
make typecheck
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index d7aed43..cd0f777 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -53,8 +53,8 @@ jobs:
- name: Install dependencies
run: |
python -m pip install -U pip setuptools wheel
- if [ $USE_GMP == 1 ]; then pip install -e ".[picoscope_sdk, picoscope_alt, chipwhisperer, smartcard, leia, gmp, test, dev]"; fi
- if [ $USE_GMP == 0 ]; then pip install -e ".[picoscope_sdk, picoscope_alt, chipwhisperer, smartcard, leia, test, dev]"; fi
+ if [ $USE_GMP == 1 ]; then pip install -e ".[picoscope_sdk, picoscope_alt, chipwhisperer, smartcard, gmp, test, dev]"; fi
+ if [ $USE_GMP == 0 ]; then pip install -e ".[picoscope_sdk, picoscope_alt, chipwhisperer, smartcard, test, dev]"; fi
- name: Test
run: |
make test
diff --git a/Makefile b/Makefile
index 1ae4371..c6b67f4 100644
--- a/Makefile
+++ b/Makefile
@@ -1,23 +1,24 @@
-EC_TESTS = ec.test_context ec.test_configuration ec.test_curve ec.test_formula \
-ec.test_params ec.test_key_agreement ec.test_key_generation ec.test_mod ec.test_model \
-ec.test_mult ec.test_naf ec.test_op ec.test_point ec.test_signature ec.test_transformations ec.test_regress
+EC_TESTS = test.ec.test_context test.ec.test_configuration test.ec.test_curve test.ec.test_formula \
+test.ec.test_params test.ec.test_key_agreement test.ec.test_key_generation test.ec.test_mod test.ec.test_model \
+test.ec.test_mult test.ec.test_naf test.ec.test_op test.ec.test_point test.ec.test_signature test.ec.test_transformations test.ec.test_regress \
+test.ec.test_divpoly
-SCA_TESTS = sca.test_align sca.test_combine sca.test_edit sca.test_filter sca.test_match sca.test_process \
-sca.test_sampling sca.test_target sca.test_test sca.test_trace sca.test_traceset sca.test_plot sca.test_rpa \
-sca.test_stacked_combine sca.test_leakage_models
+SCA_TESTS = test.sca.test_align test.sca.test_combine test.sca.test_edit test.sca.test_filter test.sca.test_match test.sca.test_process \
+test.sca.test_sampling test.sca.test_target test.sca.test_test test.sca.test_trace test.sca.test_traceset test.sca.test_plot test.sca.test_rpa \
+test.sca.test_zvp test.sca.test_stacked_combine test.sca.test_leakage_models
TESTS = ${EC_TESTS} ${SCA_TESTS}
PERF_SCRIPTS = test.ec.perf_mod test.ec.perf_formula test.ec.perf_mult test.sca.perf_combine
test:
- nose2 -s test -E "not slow and not disabled" -C -v ${TESTS}
+ pytest -m "not slow" --cov=pyecsca
test-plots:
- env PYECSCA_TEST_PLOTS=1 nose2 -s test -E "not slow and not disabled" -C -v ${TESTS}
+ env PYECSCA_TEST_PLOTS=1 pytest -m "not slow"
test-all:
- nose2 -s test -C -v ${TESTS}
+ pytest --cov=pyecsca
typecheck:
mypy --namespace-packages -p pyecsca --ignore-missing-imports --show-error-codes --check-untyped-defs
diff --git a/pyecsca/ec/context.py b/pyecsca/ec/context.py
index dd609f8..5bc9cdf 100644
--- a/pyecsca/ec/context.py
+++ b/pyecsca/ec/context.py
@@ -9,8 +9,6 @@ multiplication actions has as its children an ordered list of the individual for
A :py:class:`PathContext` works like a :py:class:`DefaultContext` that only traces an action on a particular path
in the tree.
-
-A :py:class:`NullContext` does not trace any actions and is the default context.
"""
from abc import abstractmethod, ABC
from collections import OrderedDict
@@ -267,6 +265,4 @@ def local(ctx: Optional[Context] = None) -> ContextManager:
:param ctx: If none, current context is copied.
:return: A context manager.
"""
- if ctx is None:
- ctx = current
return _ContextManager(ctx)
diff --git a/pyecsca/ec/coordinates.py b/pyecsca/ec/coordinates.py
index b258f2d..10ea400 100644
--- a/pyecsca/ec/coordinates.py
+++ b/pyecsca/ec/coordinates.py
@@ -1,9 +1,9 @@
"""Provides a coordinate model class."""
from ast import parse, Module
-from os.path import join
+from importlib_resources.abc import Traversable
+from importlib_resources import as_file
from typing import List, Any, MutableMapping
-from pkg_resources import resource_listdir, resource_isdir, resource_stream
from public import public
from .formula import (
@@ -67,11 +67,11 @@ class AffineCoordinateModel(CoordinateModel):
return self.curve_model == other.curve_model
def __hash__(self):
- return hash(self.curve_model) + hash(self.name)
+ return hash((self.curve_model, self.name))
class EFDCoordinateModel(CoordinateModel):
- def __init__(self, dir_path: str, name: str, curve_model: Any):
+ def __init__(self, dir_path: Traversable, name: str, curve_model: Any):
self.name = name
self.curve_model = curve_model
self.variables = []
@@ -80,31 +80,32 @@ class EFDCoordinateModel(CoordinateModel):
self.assumptions = []
self.neutral = []
self.formulas = {}
- for fname in resource_listdir(__name__, dir_path):
- file_path = join(dir_path, fname)
- if resource_isdir(__name__, file_path):
- self.__read_formula_dir(file_path, fname)
- else:
- self.__read_coordinates_file(file_path)
+ for entry in dir_path.iterdir():
+ with as_file(entry) as file_path:
+ if entry.is_dir():
+ self.__read_formula_dir(file_path, file_path.stem)
+ else:
+ self.__read_coordinates_file(file_path)
- def __read_formula_dir(self, dir_path, formula_type):
- for fname in resource_listdir(__name__, dir_path):
- if fname.endswith(".op3"):
- continue
- formula_types = {
- "addition": AdditionEFDFormula,
- "doubling": DoublingEFDFormula,
- "tripling": TriplingEFDFormula,
- "diffadd": DifferentialAdditionEFDFormula,
- "ladder": LadderEFDFormula,
- "scaling": ScalingEFDFormula,
- "negation": NegationEFDFormula,
- }
- cls = formula_types.get(formula_type, EFDFormula)
- self.formulas[fname] = cls(join(dir_path, fname), fname, self)
+ def __read_formula_dir(self, dir_path: Traversable, formula_type):
+ for entry in dir_path.iterdir():
+ with as_file(entry) as fpath:
+ if fpath.suffix == ".op3":
+ continue
+ formula_types = {
+ "addition": AdditionEFDFormula,
+ "doubling": DoublingEFDFormula,
+ "tripling": TriplingEFDFormula,
+ "diffadd": DifferentialAdditionEFDFormula,
+ "ladder": LadderEFDFormula,
+ "scaling": ScalingEFDFormula,
+ "negation": NegationEFDFormula,
+ }
+ cls = formula_types.get(formula_type, EFDFormula)
+ self.formulas[fpath.stem] = cls(fpath, fpath.with_suffix(".op3"), fpath.stem, self)
- def __read_coordinates_file(self, file_path):
- with resource_stream(__name__, file_path) as f:
+ def __read_coordinates_file(self, file_path: Traversable):
+ with file_path.open("rb") as f:
line = f.readline().decode("ascii").rstrip()
while line:
if line.startswith("name"):
@@ -137,4 +138,4 @@ class EFDCoordinateModel(CoordinateModel):
return self.curve_model == other.curve_model and self.name == other.name
def __hash__(self):
- return hash(self.curve_model) + hash(self.name)
+ return hash((self.curve_model, self.name))
diff --git a/pyecsca/ec/curve.py b/pyecsca/ec/curve.py
index 8fc2793..fb567e8 100644
--- a/pyecsca/ec/curve.py
+++ b/pyecsca/ec/curve.py
@@ -1,14 +1,18 @@
"""Provides an elliptic curve class."""
from ast import Module
+from astunparse import unparse
from copy import copy
-from typing import MutableMapping, Union, List, Optional
+from typing import MutableMapping, Union, List, Optional, Dict
from public import public
+from sympy import FF, sympify
from .coordinates import CoordinateModel, AffineCoordinateModel
+from .error import raise_unsatisified_assumption
from .mod import Mod
from .model import CurveModel
from .point import Point, InfinityPoint
+from ..misc.cfg import getconfig
@public
@@ -27,21 +31,21 @@ class EllipticCurve:
"""The neutral point on the curve."""
def __init__(
- self,
- model: CurveModel,
- coordinate_model: CoordinateModel,
- prime: int,
- neutral: Point,
- parameters: MutableMapping[str, Union[Mod, int]],
+ self,
+ model: CurveModel,
+ coordinate_model: CoordinateModel,
+ prime: int,
+ neutral: Point,
+ parameters: MutableMapping[str, Union[Mod, int]],
):
if coordinate_model not in model.coordinates.values() and not isinstance(
- coordinate_model, AffineCoordinateModel
+ coordinate_model, AffineCoordinateModel
):
raise ValueError
if (
- set(model.parameter_names)
- .union(coordinate_model.parameters)
- .symmetric_difference(parameters.keys())
+ set(model.parameter_names)
+ .union(coordinate_model.parameters)
+ .symmetric_difference(parameters.keys())
):
raise ValueError
self.model = model
@@ -56,6 +60,39 @@ class EllipticCurve:
value = Mod(value, prime)
self.parameters[name] = value
self.neutral = neutral
+ self.__validate_coord_assumptions()
+
+ def __validate_coord_assumptions(self):
+ for assumption in self.coordinate_model.assumptions:
+ # Try to execute assumption, if it works, check with curve parameters
+ # if it doesn't work, move all over to rhs and construct a sympy polynomial of it
+ # then find roots and take first one for new value for new coordinate parameter.
+ try:
+ alocals: Dict[str, Union[Mod, int]] = {}
+ compiled = compile(assumption, "", mode="exec")
+ exec(compiled, None, alocals)
+ for param, value in alocals.items():
+ if self.parameters[param] != value:
+ raise_unsatisified_assumption(
+ getconfig().ec.unsatisfied_coordinate_assumption_action,
+ f"Coordinate model {self.coordinate_model} has an unsatisifed assumption on the {param} parameter (= {value}).",
+ )
+ except NameError:
+ k = FF(self.prime)
+ assumption_string = unparse(assumption)
+ lhs, rhs = assumption_string.split(" = ")
+ expr = sympify(f"{rhs} - {lhs}")
+ for curve_param, value in self.parameters.items():
+ expr = expr.subs(curve_param, k(value))
+ if len(expr.free_symbols) > 0:
+ raise ValueError(
+ f"Missing necessary coordinate model parameter ({assumption_string})."
+ )
+ if k(expr) != 0:
+ raise_unsatisified_assumption(
+ getconfig().ec.unsatisfied_coordinate_assumption_action,
+ f"Coordinate model {self.coordinate_model} has an unsatisifed assumption on the {param} parameter (0 = {expr})."
+ )
def _execute_base_formulas(self, formulas: List[Module], *points: Point) -> Point:
for point in points:
@@ -195,6 +232,18 @@ class EllipticCurve:
loc = {**self.parameters, **point.to_affine().coords}
return eval(compile(self.model.equation, "", mode="eval"), loc)
+ def to_coords(self, coordinate_model: CoordinateModel) -> "EllipticCurve":
+ """
+ Convert this curve into a different coordinate model, only possible if it is currently affine.
+
+ :param coordinate_model: The target coordinate model.
+ :return: The transformed elliptic curve.
+ """
+ if not isinstance(self.coordinate_model, AffineCoordinateModel):
+ raise ValueError
+ return EllipticCurve(self.model, coordinate_model, self.prime, self.neutral.to_model(coordinate_model, self),
+ self.parameters) # type: ignore[arg-type]
+
def to_affine(self) -> "EllipticCurve":
"""
Convert this curve into the affine coordinate model, if possible.
@@ -202,7 +251,8 @@ class EllipticCurve:
:return: The transformed elliptic curve.
"""
coord_model = AffineCoordinateModel(self.model)
- return EllipticCurve(self.model, coord_model, self.prime, self.neutral.to_affine(), self.parameters) # type: ignore[arg-type]
+ 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:
"""
@@ -270,10 +320,10 @@ class EllipticCurve:
if not isinstance(other, EllipticCurve):
return False
return (
- self.model == other.model
- and self.coordinate_model == other.coordinate_model
- and self.prime == other.prime
- and self.parameters == other.parameters
+ self.model == other.model
+ and self.coordinate_model == other.coordinate_model
+ and self.prime == other.prime
+ and self.parameters == other.parameters
)
def __hash__(self):
diff --git a/pyecsca/ec/divpoly.py b/pyecsca/ec/divpoly.py
new file mode 100644
index 0000000..a616801
--- /dev/null
+++ b/pyecsca/ec/divpoly.py
@@ -0,0 +1,271 @@
+"""
+Provides functions for computing division polynomials and the multiplication-by-n map on an elliptic curve.
+"""
+from typing import Tuple, Dict, Set, Mapping
+
+from sympy import symbols, FF, Poly
+import networkx as nx
+
+from .curve import EllipticCurve
+from .mod import Mod
+from .model import ShortWeierstrassModel
+
+
+def values(*ns: int) -> Mapping[int, Tuple[int, ...]]:
+ done: Set[int] = set()
+ vals = {}
+ todo: Set[int] = set()
+ todo.update(ns)
+ while todo:
+ val = todo.pop()
+ if val in done:
+ continue
+ new: Tuple[int, ...] = ()
+ if val == -2:
+ new = (-1,)
+ elif val == -1:
+ pass
+ elif val < 0:
+ raise ValueError(f"bad {val}")
+ elif val in (0, 1, 2, 3):
+ pass
+ elif val == 4:
+ new = (-2, 3)
+ elif val % 2 == 0:
+ m = (val - 2) // 2
+ new = (m + 1, m + 3, m, m - 1, m + 2)
+ else:
+ m = (val - 1) // 2
+ if m % 2 == 0:
+ new = (-2, m + 2, m, m - 1, m + 1)
+ else:
+ new = (m + 2, m, -2, m - 1, m + 1)
+ if new:
+ todo.update(new)
+ vals[val] = new
+ done.add(val)
+ return vals
+
+
+def dep_graph(*ns: int):
+ g = nx.DiGraph()
+ vals = values(*ns)
+ for k, v in vals.items():
+ if v:
+ for e in v:
+ g.add_edge(k, e)
+ else:
+ g.add_node(k)
+ return g, vals
+
+
+def dep_map(*ns: int):
+ g, vals = dep_graph(*ns)
+ current: Set[int] = set()
+ ls = []
+ for vert in nx.lexicographical_topological_sort(g, key=lambda v: -sum(g[v].keys())):
+ if vert in current:
+ current.remove(vert)
+ ls.append((vert, set(current)))
+ current.update(vals[vert])
+ ls.reverse()
+ return ls, vals
+
+
+def a_invariants(curve: EllipticCurve) -> Tuple[Mod, ...]:
+ """
+ Compute the a-invariants of the curve.
+
+ :param curve: The elliptic curve (only ShortWeierstrass model).
+ :return: A tuple of 5 a-invariants (a1, a2, a3, a4, a6).
+ """
+ if isinstance(curve.model, ShortWeierstrassModel):
+ a1 = Mod(0, curve.prime)
+ a2 = Mod(0, curve.prime)
+ a3 = Mod(0, curve.prime)
+ a4 = curve.parameters["a"]
+ a6 = curve.parameters["b"]
+ return a1, a2, a3, a4, a6
+ else:
+ raise NotImplementedError
+
+
+def b_invariants(curve: EllipticCurve) -> Tuple[Mod, ...]:
+ """
+ Compute the b-invariants of the curve.
+
+ :param curve: The elliptic curve (only ShortWeierstrass model).
+ :return: A tuple of 4 b-invariants (b2, b4, b6, b8).
+ """
+ if isinstance(curve.model, ShortWeierstrassModel):
+ a1, a2, a3, a4, a6 = a_invariants(curve)
+ return (a1 * a1 + 4 * a2,
+ a1 * a3 + 2 * a4,
+ a3 ** 2 + 4 * a6,
+ a1 ** 2 * a6 + 4 * a2 * a6 - a1 * a3 * a4 + a2 * a3 ** 2 - a4 ** 2)
+ else:
+ raise NotImplementedError
+
+
+def divpoly0(curve: EllipticCurve, *ns: int) -> Mapping[int, Poly]:
+ """
+ Basically sagemath's division_polynomial_0 but more clever memory management.
+
+ As sagemath says:
+
+ Return the `n^{th}` torsion (division) polynomial, without
+ the 2-torsion factor if `n` is even, as a polynomial in `x`.
+
+ These are the polynomials `g_n` defined in [MT1991]_, but with
+ the sign flipped for even `n`, so that the leading coefficient is
+ always positive.
+
+ :param curve: The elliptic curve.
+ :param ns: The values to compute the polynomial for.
+ :return:
+ """
+ xs = symbols("x")
+
+ K = FF(curve.prime)
+ Kx = lambda r: Poly(r, xs, domain=K) # noqa
+
+ x = Kx(xs)
+
+ b2, b4, b6, b8 = map(lambda b: Kx(int(b)), b_invariants(curve))
+ ls, vals = dep_map(*ns)
+
+ mem: Dict[int, Poly] = {}
+ for i, keep in ls:
+ if i == -2:
+ val = mem[-1] ** 2
+ elif i == -1:
+ val = Kx(4) * x ** 3 + b2 * x ** 2 + Kx(2) * b4 * x + b6
+ elif i == 0:
+ val = Kx(0)
+ elif i < 0:
+ raise ValueError("n must be a positive integer (or -1 or -2)")
+ elif i == 1 or i == 2:
+ val = Kx(1)
+ elif i == 3:
+ val = Kx(3) * x ** 4 + b2 * x ** 3 + Kx(3) * b4 * x ** 2 + Kx(3) * b6 * x + b8
+ elif i == 4:
+ val = -mem[-2] + (Kx(6) * x ** 2 + b2 * x + b4) * mem[3]
+ elif i % 2 == 0:
+ m = (i - 2) // 2
+ val = mem[m + 1] * (mem[m + 3] * mem[m] ** 2 - mem[m - 1] * mem[m + 2] ** 2)
+ else:
+ m = (i - 1) // 2
+ if m % 2 == 0:
+ val = mem[-2] * mem[m + 2] * mem[m] ** 3 - mem[m - 1] * mem[m + 1] ** 3
+ else:
+ val = mem[m + 2] * mem[m] ** 3 - mem[-2] * mem[m - 1] * mem[m + 1] ** 3
+ for dl in set(mem.keys()).difference(keep).difference(ns):
+ del mem[dl]
+ mem[i] = val
+
+ return mem
+
+
+def divpoly(curve: EllipticCurve, n: int, two_torsion_multiplicity: int = 2) -> Poly:
+ """
+ Compute the n-th division polynomial.
+
+ :param curve: Curve to compute on.
+ :param n: Scalar.
+ :param two_torsion_multiplicity: Same as sagemath.
+ :return: The division polynomial.
+ """
+ f: Poly = divpoly0(curve, n)[n]
+ a1, a2, a3, a4, a6 = a_invariants(curve)
+ xs, ys = symbols("x y")
+ x = Poly(xs, xs, domain=f.domain)
+ y = Poly(ys, ys, domain=f.domain)
+
+ if two_torsion_multiplicity == 0:
+ return f
+ elif two_torsion_multiplicity == 1:
+ if n % 2 == 0:
+ Kxy = lambda r: Poly(r, xs, ys, domain=f.domain) # noqa
+ return Kxy(f) * (Kxy(2) * y + Kxy(a1) * x + Kxy(a3))
+ else:
+ return f
+ elif two_torsion_multiplicity == 2:
+ if n % 2 == 0:
+ return f * divpoly0(curve, -1)[-1]
+ else:
+ return f
+ else:
+ raise ValueError
+
+
+def mult_by_n(curve: EllipticCurve, n: int) -> Tuple[Tuple[Poly, Poly], Tuple[Poly, Poly]]:
+ """
+ Compute the multiplication-by-n map on an elliptic curve.
+
+ :param curve: Curve to compute on.
+ :param n: Scalar.
+ :return: A tuple (mx, my) where each is a tuple (numerator, denominator).
+ """
+ xs, ys = symbols("x y")
+ K = FF(curve.prime)
+ x = Poly(xs, xs, domain=K)
+ y = Poly(ys, ys, domain=K)
+ Kxy = lambda r: Poly(r, xs, ys, domain=K) # noqa
+
+ if n == 1:
+ return (x, Kxy(1)), (y, Kxy(1))
+
+ a1, a2, a3, a4, a6 = a_invariants(curve)
+
+ polys = divpoly0(curve, -2, -1, n - 1, n, n + 1, n + 2)
+ # TODO: All of these fractions may benefit from using
+ # sympy.cancel to get rid of common factors in the numerator and denominator.
+ # Though for large polynomials that might be too much.
+ mx_denom = polys[n] ** 2
+ if n % 2 == 0:
+ mx_num = x * polys[-1] * polys[n] ** 2 - polys[n - 1] * polys[n + 1]
+ mx_denom *= polys[-1]
+ else:
+ mx_num = x * polys[n] ** 2 - polys[-1] * polys[n - 1] * polys[n + 1]
+
+ # Alternative that makes the denominator monic by dividing the
+ # numerator by the leading coefficient. Sage does this
+ # simplification when asking for multiplication_by_m with the
+ # x-only=True, as then the poly is an univariate object.
+ # lc = K(mx_denom.LC())
+ # mx = (mx_num.quo(lc), mx_denom.monic())
+ mx = (mx_num, mx_denom)
+
+ # The following lines compute
+ # my = ((2*y+a1*x+a3)*mx.derivative(x)/m - a1*mx-a3)/2
+ # just as sage does, but using sympy and step-by-step
+ # tracking the numerator and denominator of the fraction.
+
+ # mx.derivative()
+ mxd_num = mx[1] * mx[0].diff() - mx[0] * mx[1].diff()
+ mxd_denom = mx[1] ** 2
+
+ # mx.derivative()/m
+ mxd_dn_num = mxd_num
+ mxd_dn_denom = mxd_denom * Kxy(n)
+
+ # (2*y+a1*x+a3)*mx.derivative(x)/m
+ mxd_full_num = mxd_dn_num * (Kxy(2) * y + Kxy(a1) * x + Kxy(a3))
+ mxd_full_denom = mxd_dn_denom
+
+ # a1*mx
+ a1mx_num = (Kxy(a1) * mx[0])
+ a1mx_denom = mx[1] # noqa
+
+ # a3
+ a3_num = (Kxy(a3) * mx[1])
+ a3_denom = mx[1] # noqa
+
+ # The mx.derivative part has a different denominator, basically mx[1]^2 * m
+ # so the rest needs to be multiplied by this factor when subtracitng.
+ mxd_fact = mx[1] * n
+
+ my_num = (mxd_full_num - a1mx_num * mxd_fact - a3_num * mxd_fact)
+ my_denom = mxd_full_denom * Kxy(2)
+ my = (my_num, my_denom)
+ return mx, my
diff --git a/pyecsca/ec/efd b/pyecsca/ec/efd
-Subproject a39cbee81c9a5c0ec720abf3eb97cfd4a3d06af
+Subproject bfecf9e69ae1b20f0fe1b83496407c2ac09cd72
diff --git a/pyecsca/ec/formula.py b/pyecsca/ec/formula.py
index 58978a7..d737c70 100644
--- a/pyecsca/ec/formula.py
+++ b/pyecsca/ec/formula.py
@@ -7,7 +7,7 @@ from astunparse import unparse
from itertools import product
from typing import List, Set, Any, ClassVar, MutableMapping, Tuple, Union, Dict
-from pkg_resources import resource_stream
+from importlib_resources.abc import Traversable
from public import public
from sympy import sympify, FF, symbols, Poly, Rational
@@ -40,6 +40,7 @@ class OpResult:
return self.name
def __repr__(self):
+ # TODO: This repr is broken for square and neg and inv.
char = self.op.op_str
parents = char.join(str(parent) for parent in self.parents)
return f"{self.name} = {parents}"
@@ -338,7 +339,7 @@ class Formula(ABC):
class EFDFormula(Formula):
"""Formula from the `Explicit-Formulas Database <https://www.hyperelliptic.org/EFD/>`_."""
- def __init__(self, path: str, name: str, coordinate_model: Any):
+ def __init__(self, meta_path: Traversable, op3_path: Traversable, name: str, coordinate_model: Any):
self.name = name
self.coordinate_model = coordinate_model
self.meta = {}
@@ -346,11 +347,11 @@ class EFDFormula(Formula):
self.assumptions = []
self.code = []
self.unified = False
- self.__read_meta_file(path)
- self.__read_op3_file(path + ".op3")
+ self.__read_meta_file(meta_path)
+ self.__read_op3_file(op3_path)
- def __read_meta_file(self, path):
- with resource_stream(__name__, path) as f:
+ def __read_meta_file(self, path: Traversable):
+ with path.open("rb") as f:
line = f.readline().decode("ascii").rstrip()
while line:
if line.startswith("source"):
@@ -367,11 +368,11 @@ class EFDFormula(Formula):
self.unified = True
line = f.readline().decode("ascii").rstrip()
- def __read_op3_file(self, path):
- with resource_stream(__name__, path) as f:
+ def __read_op3_file(self, path: Traversable):
+ with path.open("rb") as f:
for line in f.readlines():
code_module = parse(
- line.decode("ascii").replace("^", "**"), path, mode="exec"
+ line.decode("ascii").replace("^", "**"), str(path), mode="exec"
)
self.code.append(CodeOp(code_module))
@@ -410,7 +411,7 @@ class EFDFormula(Formula):
)
def __hash__(self):
- return hash(self.name) + hash(self.coordinate_model)
+ return hash((self.coordinate_model, self.name))
@public
diff --git a/pyecsca/ec/mod.py b/pyecsca/ec/mod.py
index a974462..3dcb609 100644
--- a/pyecsca/ec/mod.py
+++ b/pyecsca/ec/mod.py
@@ -10,7 +10,7 @@ dispatches to the implementation chosen by the runtime configuration of the libr
import random
import secrets
from functools import wraps, lru_cache
-from typing import Type, Dict, Any, Tuple, Union
+from typing import Type, Dict, Any, Tuple, Union, Optional
from public import public
from sympy import Expr, FF
@@ -148,7 +148,7 @@ class Mod:
n: Any
__slots__ = ("x", "n")
- def __new__(cls, *args, **kwargs):
+ def __new__(cls, *args, **kwargs) -> "Mod":
if cls != Mod:
return cls.__new__(cls, *args, **kwargs)
if not _mod_classes:
@@ -561,15 +561,13 @@ class SymbolicMod(Mod):
return str(self.x)
def __hash__(self):
- return hash(("SymbolicMod", self.x, self.n)) + 1
+ return hash(("SymbolicMod", self.x, self.n))
def __pow__(self, n) -> "SymbolicMod":
- try:
- x = pow(self.x, n, self.n)
- except TypeError:
- x = pow(self.x, n) % self.n
- return SymbolicMod(x, self.n)
+ return self.__class__(pow(self.x, n), self.n)
+
+_mod_classes["symbolic"] = SymbolicMod
if has_gmp:
diff --git a/pyecsca/ec/model.py b/pyecsca/ec/model.py
index bea5554..7827a51 100644
--- a/pyecsca/ec/model.py
+++ b/pyecsca/ec/model.py
@@ -1,9 +1,9 @@
"""Provides curve model classes for the supported curve models."""
from ast import parse, Expression, Module
-from os.path import join
from typing import List, MutableMapping
+from importlib_resources import files, as_file
+from importlib_resources.abc import Traversable
-from pkg_resources import resource_listdir, resource_isdir, resource_stream
from public import public
from .coordinates import EFDCoordinateModel, CoordinateModel
@@ -50,19 +50,18 @@ class EFDCurveModel(CurveModel):
self.__class__.to_weierstrass = []
self.__class__.from_weierstrass = []
- files = resource_listdir(__name__, join("efd", efd_name))
- for fname in files:
- file_path = join("efd", efd_name, fname)
- if resource_isdir(__name__, file_path):
- self.__read_coordinate_dir(self.__class__, file_path, fname)
- else:
- self.__read_curve_file(self.__class__, file_path)
+ for entry in files("pyecsca.ec").joinpath("efd", efd_name).iterdir():
+ with as_file(entry) as file_path:
+ if entry.is_dir():
+ self.__read_coordinate_dir(self.__class__, file_path, file_path.stem)
+ else:
+ self.__read_curve_file(self.__class__, file_path)
- def __read_curve_file(self, cls, file_path):
+ def __read_curve_file(self, cls, file_path: Traversable):
def format_eq(line, mode="exec"):
return parse(line.replace("^", "**"), mode=mode)
- with resource_stream(__name__, file_path) as f:
+ with file_path.open("rb") as f:
for raw in f.readlines():
line = raw.decode("ascii").rstrip()
if line.startswith("name"):
@@ -90,7 +89,7 @@ class EFDCurveModel(CurveModel):
else:
cls.full_weierstrass.append(format_eq(line))
- def __read_coordinate_dir(self, cls, dir_path, name):
+ def __read_coordinate_dir(self, cls, dir_path: Traversable, name: str):
cls.coordinates[name] = EFDCoordinateModel(dir_path, name, self)
def __eq__(self, other):
@@ -99,7 +98,7 @@ class EFDCurveModel(CurveModel):
return self._efd_name == other._efd_name
def __hash__(self):
- return hash(self._efd_name) + 1
+ return hash(self._efd_name)
def __str__(self):
return f"{self.__class__.__name__.replace('Model', '')}"
diff --git a/pyecsca/ec/mult.py b/pyecsca/ec/mult.py
index 53e593e..2effb10 100644
--- a/pyecsca/ec/mult.py
+++ b/pyecsca/ec/mult.py
@@ -48,6 +48,9 @@ class PrecomputationAction(Action):
self.params = params
self.point = point
+ def __repr__(self):
+ return f"{self.__class__.__name__}({self.params}, {self.point})"
+
@public
class ScalarMultiplier(ABC):
@@ -73,14 +76,14 @@ class ScalarMultiplier(ABC):
def __init__(self, short_circuit: bool = True, **formulas: Optional[Formula]):
if (
- len(
- {
- formula.coordinate_model
- for formula in formulas.values()
- if formula is not None
- }
- )
- != 1
+ len(
+ {
+ formula.coordinate_model
+ for formula in formulas.values()
+ if formula is not None
+ }
+ )
+ != 1
):
raise ValueError
self.short_circuit = short_circuit
@@ -102,8 +105,8 @@ class ScalarMultiplier(ABC):
if "dbl" not in self.formulas:
raise NotImplementedError
if (
- self.short_circuit
- and point == self._params.curve.neutral
+ self.short_circuit
+ and point == self._params.curve.neutral
):
return copy(point)
return self.formulas["dbl"](
@@ -152,6 +155,17 @@ class ScalarMultiplier(ABC):
self._params.curve.prime, point, **self._params.curve.parameters
)[0]
+ def __hash__(self):
+ return id(self)
+
+ def __eq__(self, other):
+ if not isinstance(other, ScalarMultiplier):
+ return False
+ return self.formulas == other.formulas and self.short_circuit == other.short_circuit
+
+ def __repr__(self):
+ return f"{self.__class__.__name__}({tuple(self.formulas.values())}, short_circuit={self.short_circuit})"
+
def init(self, params: DomainParameters, point: Point):
"""
Initialize the scalar multiplier with :paramref:`~.init.params` and a :paramref:`~.init.point`.
@@ -164,8 +178,8 @@ class ScalarMultiplier(ABC):
"""
coord_model = set(self.formulas.values()).pop().coordinate_model
if (
- params.curve.coordinate_model != coord_model
- or point.coordinate_model != coord_model
+ params.curve.coordinate_model != coord_model
+ or point.coordinate_model != coord_model
):
raise ValueError
self._params = params
@@ -200,18 +214,26 @@ class LTRMultiplier(ScalarMultiplier):
complete: bool
def __init__(
- self,
- add: AdditionFormula,
- dbl: DoublingFormula,
- scl: Optional[ScalingFormula] = None,
- always: bool = False,
- complete: bool = True,
- short_circuit: bool = True,
+ self,
+ add: AdditionFormula,
+ dbl: DoublingFormula,
+ scl: Optional[ScalingFormula] = None,
+ always: bool = False,
+ complete: bool = True,
+ short_circuit: bool = True,
):
super().__init__(short_circuit=short_circuit, add=add, dbl=dbl, scl=scl)
self.always = always
self.complete = complete
+ def __hash__(self):
+ return id(self)
+
+ def __eq__(self, other):
+ if not isinstance(other, LTRMultiplier):
+ return False
+ return self.formulas == other.formulas and self.short_circuit == other.short_circuit and self.always == other.always and self.complete == other.complete
+
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
@@ -251,16 +273,24 @@ class RTLMultiplier(ScalarMultiplier):
always: bool
def __init__(
- self,
- add: AdditionFormula,
- dbl: DoublingFormula,
- scl: Optional[ScalingFormula] = None,
- always: bool = False,
- short_circuit: bool = True,
+ self,
+ add: AdditionFormula,
+ dbl: DoublingFormula,
+ scl: Optional[ScalingFormula] = None,
+ always: bool = False,
+ short_circuit: bool = True,
):
super().__init__(short_circuit=short_circuit, add=add, dbl=dbl, scl=scl)
self.always = always
+ def __hash__(self):
+ return id(self)
+
+ def __eq__(self, other):
+ if not isinstance(other, RTLMultiplier):
+ return False
+ return self.formulas == other.formulas and self.short_circuit == other.short_circuit and self.always == other.always
+
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
@@ -297,14 +327,22 @@ class CoronMultiplier(ScalarMultiplier):
optionals = {ScalingFormula}
def __init__(
- self,
- add: AdditionFormula,
- dbl: DoublingFormula,
- scl: Optional[ScalingFormula] = None,
- short_circuit: bool = True,
+ self,
+ add: AdditionFormula,
+ dbl: DoublingFormula,
+ scl: Optional[ScalingFormula] = None,
+ short_circuit: bool = True,
):
super().__init__(short_circuit=short_circuit, add=add, dbl=dbl, scl=scl)
+ def __hash__(self):
+ return id(self)
+
+ def __eq__(self, other):
+ if not isinstance(other, CoronMultiplier):
+ return False
+ return self.formulas == other.formulas and self.short_circuit == other.short_circuit
+
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
@@ -332,18 +370,26 @@ class LadderMultiplier(ScalarMultiplier):
complete: bool
def __init__(
- self,
- ladd: LadderFormula,
- dbl: Optional[DoublingFormula] = None,
- scl: Optional[ScalingFormula] = None,
- complete: bool = True,
- short_circuit: bool = True,
+ self,
+ ladd: LadderFormula,
+ dbl: Optional[DoublingFormula] = None,
+ scl: Optional[ScalingFormula] = None,
+ complete: bool = True,
+ short_circuit: bool = True,
):
super().__init__(short_circuit=short_circuit, ladd=ladd, dbl=dbl, scl=scl)
self.complete = complete
if (not complete or short_circuit) and dbl is None:
raise ValueError
+ def __hash__(self):
+ return id(self)
+
+ def __eq__(self, other):
+ if not isinstance(other, LadderMultiplier):
+ return False
+ return self.formulas == other.formulas and self.short_circuit == other.short_circuit and self.complete == other.complete
+
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
@@ -378,16 +424,24 @@ class SimpleLadderMultiplier(ScalarMultiplier):
complete: bool
def __init__(
- self,
- add: AdditionFormula,
- dbl: DoublingFormula,
- scl: Optional[ScalingFormula] = None,
- complete: bool = True,
- short_circuit: bool = True,
+ self,
+ add: AdditionFormula,
+ dbl: DoublingFormula,
+ scl: Optional[ScalingFormula] = None,
+ complete: bool = True,
+ short_circuit: bool = True,
):
super().__init__(short_circuit=short_circuit, add=add, dbl=dbl, scl=scl)
self.complete = complete
+ def __hash__(self):
+ return id(self)
+
+ def __eq__(self, other):
+ if not isinstance(other, SimpleLadderMultiplier):
+ return False
+ return self.formulas == other.formulas and self.short_circuit == other.short_circuit and self.complete == other.complete
+
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
@@ -421,16 +475,24 @@ class DifferentialLadderMultiplier(ScalarMultiplier):
complete: bool
def __init__(
- self,
- dadd: DifferentialAdditionFormula,
- dbl: DoublingFormula,
- scl: Optional[ScalingFormula] = None,
- complete: bool = True,
- short_circuit: bool = True,
+ self,
+ dadd: DifferentialAdditionFormula,
+ dbl: DoublingFormula,
+ scl: Optional[ScalingFormula] = None,
+ complete: bool = True,
+ short_circuit: bool = True,
):
super().__init__(short_circuit=short_circuit, dadd=dadd, dbl=dbl, scl=scl)
self.complete = complete
+ def __hash__(self):
+ return id(self)
+
+ def __eq__(self, other):
+ if not isinstance(other, DifferentialLadderMultiplier):
+ return False
+ return self.formulas == other.formulas and self.short_circuit == other.short_circuit and self.complete == other.complete
+
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalarMultiplier not initialized.")
@@ -465,17 +527,25 @@ class BinaryNAFMultiplier(ScalarMultiplier):
_point_neg: Point
def __init__(
- self,
- add: AdditionFormula,
- dbl: DoublingFormula,
- neg: NegationFormula,
- scl: Optional[ScalingFormula] = None,
- short_circuit: bool = True,
+ self,
+ add: AdditionFormula,
+ dbl: DoublingFormula,
+ neg: NegationFormula,
+ scl: Optional[ScalingFormula] = None,
+ short_circuit: bool = True,
):
super().__init__(
short_circuit=short_circuit, add=add, dbl=dbl, neg=neg, scl=scl
)
+ def __hash__(self):
+ return id(self)
+
+ def __eq__(self, other):
+ if not isinstance(other, BinaryNAFMultiplier):
+ return False
+ return self.formulas == other.formulas and self.short_circuit == other.short_circuit
+
def init(self, params: DomainParameters, point: Point):
with PrecomputationAction(params, point):
super().init(params, point)
@@ -512,14 +582,14 @@ class WindowNAFMultiplier(ScalarMultiplier):
width: int
def __init__(
- self,
- add: AdditionFormula,
- dbl: DoublingFormula,
- neg: NegationFormula,
- width: int,
- scl: Optional[ScalingFormula] = None,
- precompute_negation: bool = False,
- short_circuit: bool = True,
+ self,
+ add: AdditionFormula,
+ dbl: DoublingFormula,
+ neg: NegationFormula,
+ width: int,
+ scl: Optional[ScalingFormula] = None,
+ precompute_negation: bool = False,
+ short_circuit: bool = True,
):
super().__init__(
short_circuit=short_circuit, add=add, dbl=dbl, neg=neg, scl=scl
@@ -527,6 +597,14 @@ class WindowNAFMultiplier(ScalarMultiplier):
self.width = width
self.precompute_negation = precompute_negation
+ def __hash__(self):
+ return id(self)
+
+ def __eq__(self, other):
+ if not isinstance(other, WindowNAFMultiplier):
+ return False
+ return self.formulas == other.formulas and self.short_circuit == other.short_circuit and self.width == other.width and self.precompute_negation == other.precompute_negation
+
def init(self, params: DomainParameters, point: Point):
with PrecomputationAction(params, point):
super().init(params, point)
diff --git a/pyecsca/ec/params.py b/pyecsca/ec/params.py
index 8344901..4141dfa 100644
--- a/pyecsca/ec/params.py
+++ b/pyecsca/ec/params.py
@@ -4,19 +4,19 @@ Provides functions for obtaining domain parameters from the `std-curves <https:/
It also provides a domain parameter class and a class for a whole category of domain parameters.
"""
import json
+import csv
from sympy import Poly, FF, symbols, sympify
from astunparse import unparse
from io import RawIOBase, BufferedIOBase
-from os.path import join
from pathlib import Path
from typing import Optional, Dict, Union, BinaryIO, List, Callable, IO
+from importlib_resources import files
-from pkg_resources import resource_listdir, resource_isdir, resource_stream
from public import public
from .coordinates import AffineCoordinateModel, CoordinateModel
from .curve import EllipticCurve
-from .error import UnsatisfiedAssumptionError, raise_unsatisified_assumption
+from .error import raise_unsatisified_assumption
from .mod import Mod
from .model import (
CurveModel,
@@ -41,13 +41,13 @@ class DomainParameters:
category: Optional[str]
def __init__(
- self,
- curve: EllipticCurve,
- generator: Point,
- order: int,
- cofactor: int,
- name: Optional[str] = None,
- category: Optional[str] = None,
+ self,
+ curve: EllipticCurve,
+ generator: Point,
+ order: int,
+ cofactor: int,
+ name: Optional[str] = None,
+ category: Optional[str] = None,
):
self.curve = curve
self.generator = generator
@@ -60,15 +60,38 @@ class DomainParameters:
if not isinstance(other, DomainParameters):
return False
return (
- self.curve == other.curve
- and self.generator == other.generator
- and self.order == other.order
- and self.cofactor == other.cofactor
+ self.curve == other.curve
+ and self.generator == other.generator
+ and self.order == other.order
+ and self.cofactor == other.cofactor
)
def __hash__(self):
return hash((self.curve, self.generator, self.order, self.cofactor))
+ def to_coords(self, coordinate_model: CoordinateModel) -> "DomainParameters":
+ """
+ Convert the domain parameters into a different coordinate model, only possible if they are currently affine.
+
+ :param coordinate_model: The target coordinate model.
+ :return: The transformed domain parameters
+ """
+ if not isinstance(self.curve.coordinate_model, AffineCoordinateModel):
+ raise ValueError
+ curve = self.curve.to_coords(coordinate_model)
+ generator = self.generator.to_model(coordinate_model, curve)
+ return DomainParameters(curve, generator, self.order, self.cofactor, self.name, self.category)
+
+ def to_affine(self) -> "DomainParameters":
+ """
+ Convert the domain parameters into the affine coordinate model, if possible.
+
+ :return: The transformed domain parameters
+ """
+ curve = self.curve.to_affine()
+ generator = self.generator.to_affine()
+ return DomainParameters(curve, generator, self.order, self.cofactor, self.name, self.category)
+
def __get_name(self):
if self.name and self.category:
return f"{self.category}/{self.name}"
@@ -152,7 +175,7 @@ def _create_params(curve, coords, infty):
coord_model = AffineCoordinateModel(model)
else:
if coords not in model.coordinates:
- raise ValueError("Coordinate model not supported for curve.")
+ raise ValueError("Coordinate model not supported for curve model.")
coord_model = model.coordinates[coords]
for assumption in coord_model.assumptions:
# Try to execute assumption, if it works, check with curve parameters
@@ -176,9 +199,9 @@ def _create_params(curve, coords, infty):
for curve_param, value in params.items():
expr = expr.subs(curve_param, k(value))
if (
- len(expr.free_symbols) > 1
- or (param := str(expr.free_symbols.pop()))
- not in coord_model.parameters
+ len(expr.free_symbols) > 1
+ or (param := str(expr.free_symbols.pop()))
+ not in coord_model.parameters
):
raise ValueError(
f"This coordinate model couldn't be loaded due to an unsupported assumption ({assumption_string})."
@@ -189,7 +212,8 @@ def _create_params(curve, coords, infty):
params[param] = Mod(int(root), field)
break
else:
- raise UnsatisfiedAssumptionError(
+ raise_unsatisified_assumption(
+ getconfig().ec.unsatisfied_coordinate_assumption_action,
f"Coordinate model {coord_model} has an unsatisifed assumption on the {param} parameter (0 = {expr})."
)
@@ -230,9 +254,9 @@ def _create_params(curve, coords, infty):
@public
def load_category(
- file: Union[str, Path, BinaryIO, IO[bytes]],
- coords: Union[str, Callable[[str], str]],
- infty: Union[bool, Callable[[str], bool]] = True,
+ file: Union[str, Path, BinaryIO, IO[bytes]],
+ coords: Union[str, Callable[[str], str]],
+ infty: Union[bool, Callable[[str], bool]] = True,
) -> DomainParameterCategory:
"""
Load a category of domain parameters containing several curves from a JSON file.
@@ -268,7 +292,7 @@ def load_category(
@public
def load_params(
- file: Union[str, Path, BinaryIO], coords: str, infty: bool = True
+ file: Union[str, Path, BinaryIO], coords: str, infty: bool = True
) -> DomainParameters:
"""
Load a curve from a JSON file.
@@ -291,10 +315,120 @@ def load_params(
@public
+def load_params_ecgen(
+ file: Union[str, Path, BinaryIO], coords: str, infty: bool = True
+) -> DomainParameters:
+ """
+ Load a curve from a file that is output of `ecgen <https://github.com/J08nY/ecgen>`_.
+
+ :param file: The file to load from.
+ :param coords: The name of the coordinate system to use.
+ :param infty: Whether to use the special :py:class:InfinityPoint (`True`) or try to use the
+ point at infinity of the coordinate system.
+ :return: The curve.
+ """
+ if isinstance(file, (str, Path)):
+ with open(file, "rb") as f:
+ ecgen = json.load(f)
+ elif isinstance(file, (RawIOBase, BufferedIOBase, BinaryIO)):
+ ecgen = json.load(file)
+ else:
+ raise TypeError
+ ecgen = ecgen[0]
+ if "m" in ecgen["field"]:
+ raise ValueError("Binary extension field curves not supported")
+ if len(ecgen["subgroups"]) != 1:
+ raise ValueError("Can not represent curve with two subgroups.")
+ curve_dict = {
+ "form": "Weierstrass",
+ "field": {
+ "type": "Prime",
+ "p": ecgen["field"]["p"]
+ },
+ "order": ecgen["subgroups"][0]["order"], # Take just the first subgroup
+ "cofactor": ecgen["subgroups"][0]["cofactor"],
+ "params": {
+ "a": {
+ "raw": ecgen["a"]
+ },
+ "b": {
+ "raw": ecgen["b"]
+ }
+ },
+ "generator": {
+ "x": {
+ "raw": ecgen["subgroups"][0]["x"]
+ },
+ "y": {
+ "raw": ecgen["subgroups"][0]["y"]
+ }
+ },
+ "name": None,
+ "category": None
+ }
+ return _create_params(curve_dict, coords, infty)
+
+
+@public
+def load_params_ectester(
+ file: Union[str, Path, BinaryIO], coords: str, infty: bool = True
+) -> DomainParameters:
+ """
+ Load a curve from a file that uses the format of `ECTester <https://github.com/crocs-muni/ECTester>`_.
+
+ :param file: The file to load from.
+ :param coords: The name of the coordinate system to use.
+ :param infty: Whether to use the special :py:class:InfinityPoint (`True`) or try to use the
+ point at infinity of the coordinate system.
+ :return: The curve.
+ """
+ if isinstance(file, (str, Path)):
+ with open(file, "r") as f:
+ reader = csv.reader(f)
+ line = next(iter(reader))
+ elif isinstance(file, (RawIOBase, BufferedIOBase, BinaryIO)):
+ reader = csv.reader(list(map(lambda line: line.decode(), file.readlines())))
+ line = next(iter(reader))
+ else:
+ raise TypeError
+ if len(line) != 7:
+ raise ValueError("Binary extension field curves not supported")
+ # line = p,a,b,gx,gy,n,h (all in hex)
+ curve_dict = {
+ "form": "Weierstrass",
+ "field": {
+ "type": "Prime",
+ "p": line[0]
+ },
+ "order": line[5],
+ "cofactor": line[6],
+ "params": {
+ "a": {
+ "raw": line[1]
+ },
+ "b": {
+ "raw": line[2]
+ }
+ },
+ "generator": {
+ "x": {
+ "raw": line[3]
+ },
+ "y": {
+ "raw": line[4]
+ }
+ },
+ "name": None,
+ "category": None
+ }
+ return _create_params(curve_dict, coords, infty)
+
+
+@public
def get_category(
- category: str,
- coords: Union[str, Callable[[str], str]],
- infty: Union[bool, Callable[[str], bool]] = True,
+ category: str,
+ coords: Union[str, Callable[[str], str]],
+ infty: Union[bool, Callable[[str], bool]] = True,
) -> DomainParameterCategory:
"""
Retrieve a category from the std-curves database at https://github.com/J08nY/std-curves.
@@ -307,20 +441,18 @@ def get_category(
as argument the name of the curve and returns the infinity option to use for that curve.
:return: The category.
"""
- listing = resource_listdir(__name__, "std")
- categories = [
- entry for entry in listing if resource_isdir(__name__, join("std", entry))
- ]
+ categories = {
+ entry.name: entry for entry in files("pyecsca.ec").joinpath("std").iterdir() if entry.is_dir()
+ }
if category not in categories:
raise ValueError(f"Category {category} not found.")
- json_path = join("std", category, "curves.json")
- with resource_stream(__name__, json_path) as f:
+ with categories[category].joinpath("curves.json").open("rb") as f:
return load_category(f, coords, infty)
@public
def get_params(
- category: str, name: str, coords: str, infty: bool = True
+ category: str, name: str, coords: str, infty: bool = True
) -> DomainParameters:
"""
Retrieve a curve from a set of stored parameters.
@@ -334,14 +466,12 @@ def get_params(
point at infinity of the coordinate system.
:return: The curve.
"""
- listing = resource_listdir(__name__, "std")
- categories = [
- entry for entry in listing if resource_isdir(__name__, join("std", entry))
- ]
+ categories = {
+ entry.name: entry for entry in files("pyecsca.ec").joinpath("std").iterdir() if entry.is_dir()
+ }
if category not in categories:
raise ValueError(f"Category {category} not found.")
- json_path = join("std", category, "curves.json")
- with resource_stream(__name__, json_path) as f:
+ with categories[category].joinpath("curves.json").open("rb") as f:
category_json = json.load(f)
curve = None
for curve in category_json["curves"]:
diff --git a/pyecsca/ec/point.py b/pyecsca/ec/point.py
index c4da538..b63c924 100644
--- a/pyecsca/ec/point.py
+++ b/pyecsca/ec/point.py
@@ -203,7 +203,7 @@ class Point:
return self.coords == other.coords
def __hash__(self):
- return hash((self.coordinate_model.name, tuple(self.coords.keys()), tuple(self.coords.values()))) + 13
+ return hash((self.coordinate_model, tuple(self.coords.keys()), tuple(self.coords.values())))
def __str__(self):
args = ", ".join([f"{key}={val}" for key, val in self.coords.items()])
@@ -254,7 +254,7 @@ class InfinityPoint(Point):
return self.coordinate_model == other.coordinate_model
def __hash__(self):
- return hash(self.coordinate_model.name) + 13
+ return hash((self.coordinate_model, 0))
def __str__(self):
return "Infinity"
diff --git a/pyecsca/ec/signature.py b/pyecsca/ec/signature.py
index a65adbc..abad783 100644
--- a/pyecsca/ec/signature.py
+++ b/pyecsca/ec/signature.py
@@ -43,7 +43,7 @@ class SignatureResult:
return self.r == other.r and self.s == other.s
def __hash__(self):
- return hash((self.r, self.s)) + 11
+ return hash((self.r, self.s))
def __str__(self):
return f"(r={self.r}, s={self.s})"
@@ -74,6 +74,7 @@ class ECDSAAction(Action):
class ECDSASignAction(ECDSAAction):
"""ECDSA signing."""
+ # TODO: Make this a ResultAction
privkey: Mod
def __init__(
@@ -94,6 +95,7 @@ class ECDSASignAction(ECDSAAction):
class ECDSAVerifyAction(ECDSAAction):
"""ECDSA verification."""
+ # TODO: Make this a ResultAction
signature: SignatureResult
pubkey: Point
diff --git a/pyecsca/ec/std b/pyecsca/ec/std
-Subproject cd41e851723dfebd76a978717c0d89569c49597
+Subproject 32935e4291eb90c7d86baf082a3c0f0bfb4bcca
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/misc/cfg.py b/pyecsca/misc/cfg.py
index 2affb27..ee9c95d 100644
--- a/pyecsca/misc/cfg.py
+++ b/pyecsca/misc/cfg.py
@@ -111,13 +111,14 @@ class ECConfig:
- ``"gmp"``: Requires the GMP library and `gmpy2` package.
- ``"python"``: Doesn't require anything.
+ - ``"symbolic"``: Requires sympy.
"""
return self._mod_implementation
@mod_implementation.setter
def mod_implementation(self, value: str):
- if value not in ("python", "gmp"):
- raise ValueError("Bad Mod implementaiton, can be one of 'python' or 'gmp'.")
+ if value not in ("python", "gmp", "symbolic"):
+ raise ValueError("Bad Mod implementaiton, can be one of 'python', 'gmp' or 'symbolic'.")
self._mod_implementation = value
diff --git a/pyecsca/sca/attack/leakage_model.py b/pyecsca/sca/attack/leakage_model.py
index e589940..f9adcff 100644
--- a/pyecsca/sca/attack/leakage_model.py
+++ b/pyecsca/sca/attack/leakage_model.py
@@ -5,6 +5,8 @@ from typing import Literal, ClassVar
from numpy.random import default_rng
from public import public
+from ...sca.trace import Trace
+
if sys.version_info[0] < 3 or sys.version_info[0] == 3 and sys.version_info[1] < 10:
def hw(i):
return bin(i).count("1")
@@ -14,7 +16,18 @@ else:
@public
-class NormalNoice:
+class Noise:
+ pass
+
+
+@public
+class ZeroNoise(Noise):
+ def __call__(self, *args, **kwargs):
+ return args[0]
+
+
+@public
+class NormalNoice(Noise):
"""
https://www.youtube.com/watch?v=SAfq55aiqPc
"""
@@ -24,8 +37,11 @@ class NormalNoice:
self.mean = mean
self.sdev = sdev
- def __call__(self, *args, **kwargs) -> float:
- return args[0] + self.rng.normal(self.mean, self.sdev)
+ def __call__(self, *args, **kwargs):
+ arg = args[0]
+ if isinstance(arg, Trace):
+ return Trace(arg.samples + self.rng.normal(self.mean, self.sdev, len(arg.samples)))
+ return arg + self.rng.normal(self.mean, self.sdev)
@public
diff --git a/pyecsca/sca/re/rpa.py b/pyecsca/sca/re/rpa.py
index 51b9738..212e147 100644
--- a/pyecsca/sca/re/rpa.py
+++ b/pyecsca/sca/re/rpa.py
@@ -5,8 +5,12 @@ Provides functionality inspired by the Refined-Power Analysis attack by Goubin.
`<https://dl.acm.org/doi/10.5555/648120.747060>`_
"""
from public import public
-from typing import MutableMapping, Optional
+from typing import MutableMapping, Optional, Callable, List
+from collections import Counter
+from sympy import FF, sympify, Poly, symbols
+
+from ...ec.coordinates import AffineCoordinateModel
from ...ec.formula import (
FormulaAction,
DoublingFormula,
@@ -16,9 +20,12 @@ from ...ec.formula import (
DifferentialAdditionFormula,
LadderFormula,
)
-from ...ec.mult import ScalarMultiplicationAction, PrecomputationAction
+from ...ec.mod import Mod
+from ...ec.mult import ScalarMultiplicationAction, PrecomputationAction, ScalarMultiplier
+from ...ec.params import DomainParameters
+from ...ec.model import ShortWeierstrassModel, MontgomeryModel
from ...ec.point import Point
-from ...ec.context import Context, Action
+from ...ec.context import Context, Action, local
@public
@@ -79,3 +86,100 @@ class MultipleContext(Context):
def __repr__(self):
return f"{self.__class__.__name__}({self.base!r}, multiples={self.points.values()!r})"
+
+
+def rpa_point_0y(params: DomainParameters) -> Optional[Point]:
+ """Construct an (affine) RPA point (0, y) for given domain parameters."""
+ if isinstance(params.curve.model, ShortWeierstrassModel):
+ if not params.curve.parameters["b"].is_residue():
+ return None
+ y = params.curve.parameters["b"].sqrt()
+ # TODO: We can take the negative as well.
+ return Point(AffineCoordinateModel(params.curve.model), x=Mod(0, params.curve.prime), y=y)
+ elif isinstance(params.curve.model, MontgomeryModel):
+ return Point(AffineCoordinateModel(params.curve.model), x=Mod(0, params.curve.prime),
+ y=Mod(0, params.curve.prime))
+ else:
+ raise NotImplementedError
+
+
+def rpa_point_x0(params: DomainParameters) -> Optional[Point]:
+ """Construct an (affine) RPA point (x, 0) for given domain parameters."""
+ if isinstance(params.curve.model, ShortWeierstrassModel):
+ if (params.order * params.cofactor) % 2 != 0:
+ return None
+ k = FF(params.curve.prime)
+ expr = sympify("x^3 + a * x + b", evaluate=False)
+ expr = expr.subs("a", k(int(params.curve.parameters["a"])))
+ expr = expr.subs("b", k(int(params.curve.parameters["b"])))
+ poly = Poly(expr, symbols("x"), domain=k)
+ roots = poly.ground_roots()
+ # TODO: There may be more roots.
+ if not roots:
+ return None
+ x = Mod(int(next(iter(roots.keys()))), params.curve.prime)
+ return Point(AffineCoordinateModel(params.curve.model), x=x, y=Mod(0, params.curve.prime))
+ elif isinstance(params.curve.model, MontgomeryModel):
+ return Point(AffineCoordinateModel(params.curve.model), x=Mod(0, params.curve.prime),
+ y=Mod(0, params.curve.prime))
+ else:
+ raise NotImplementedError
+
+
+def rpa_distinguish(params: DomainParameters, mults: List[ScalarMultiplier], oracle: Callable[[int, Point], bool]) -> List[ScalarMultiplier]:
+ """
+ Distinguish the scalar multiplier used (from the possible :paramref:`~.rpa_distinguish.mults`) using
+ an RPA :paramref:`~.rpa_distinguish.oracle`.
+
+ :param params: The domain parameters to use.
+ :param mults: The list of possible multipliers.
+ :param oracle: An oracle that returns `True` when an RPA point is encountered during scalar multiplication of the input by the scalar.
+ :return: The list of possible multipliers after distinguishing (ideally just one).
+ """
+ P0 = rpa_point_0y(params) or rpa_point_x0(params)
+ if not P0:
+ raise ValueError("There are no RPA-points on the provided curve.")
+ print(f"Got RPA point {P0}")
+ while True:
+ scalar = int(Mod.random(params.order))
+ print(f"Got scalar {scalar}")
+ print([mult.__class__.__name__ for mult in mults])
+ mults_to_multiples = {}
+ counts: Counter = Counter()
+ for mult in mults:
+ with local(MultipleContext()) as ctx:
+ mult.init(params, params.generator)
+ mult.multiply(scalar)
+ multiples = set(ctx.points.values())
+ mults_to_multiples[mult] = multiples
+ counts.update(multiples)
+
+ # TODO: This lower part can be repeated a few times for the same scalar above, which could reuse
+ # the computed multiples. Can be done until there is some distinguishing multiple.
+ # However, the counts variable needs to be recomputed for the new subset of multipliers.
+ nhalf = len(mults) / 2
+ best_distinguishing_multiple = None
+ best_count = None
+ best_nhalf_distance = None
+ for multiple, count in counts.items():
+ if best_distinguishing_multiple is None or abs(count - nhalf) < best_nhalf_distance:
+ best_distinguishing_multiple = multiple
+ best_count = count
+ best_nhalf_distance = abs(count - nhalf)
+ print(f"Chosen best distinguishing multiple {best_distinguishing_multiple} count={best_count} n={len(mults)}")
+ if best_count in (0, len(mults)):
+ continue
+
+ multiple_inverse = Mod(best_distinguishing_multiple, params.order).inverse()
+ P0_inverse = params.curve.affine_multiply(P0, int(multiple_inverse))
+ response = oracle(scalar, P0_inverse)
+ print(f"Oracle response -> {response}")
+ for mult in mults:
+ print(mult.__class__.__name__, best_distinguishing_multiple in mults_to_multiples[mult])
+ filt = (lambda mult: best_distinguishing_multiple in mults_to_multiples[mult]) if response else (lambda mult: best_distinguishing_multiple not in mults_to_multiples[mult])
+ mults = list(filter(filt, mults))
+ print([mult.__class__.__name__ for mult in mults])
+ print()
+
+ if len(mults) == 1:
+ return mults
diff --git a/pyecsca/sca/re/zvp.py b/pyecsca/sca/re/zvp.py
new file mode 100644
index 0000000..22f6f79
--- /dev/null
+++ b/pyecsca/sca/re/zvp.py
@@ -0,0 +1,34 @@
+"""
+Provides functionality inspired by the Zero-value point attack.
+
+ Zero-Value Point Attacks on Elliptic Curve Cryptosystem, Toru Akishita & Tsuyoshi Takagi , ISC '03
+ `<https://doi.org/10.1007/10958513_17>`_
+"""
+from typing import List
+
+from sympy import symbols
+
+from ...ec.context import DefaultContext, local
+from ...ec.formula import Formula
+from ...ec.mod import SymbolicMod
+from ...ec.point import Point
+from ...misc.cfg import TemporaryConfig
+
+
+def unroll_formula(formula: Formula, prime: int) -> List[SymbolicMod]:
+ """
+ Unroll a given formula symbolically to obtain symbolic expressions for its intermediate values.
+
+ :param formula: Formula to unroll.
+ :param prime: Field to unroll over.
+ :return: List of symbolic intermediate values.
+ """
+ inputs = [Point(formula.coordinate_model,
+ **{var: SymbolicMod(symbols(var + str(i)), prime) for var in formula.coordinate_model.variables})
+ for i in
+ range(1, 1 + formula.num_inputs)]
+ params = {var: SymbolicMod(symbols(var), prime) for var in formula.coordinate_model.curve_model.parameter_names}
+ with local(DefaultContext()) as ctx, TemporaryConfig() as cfg:
+ cfg.ec.mod_implementation = "symbolic"
+ formula(prime, *inputs, **params)
+ return [op_result.value for op_result in ctx.actions.get_by_index([0])[0].op_results]
diff --git a/pyecsca/sca/stacked_traces/combine.py b/pyecsca/sca/stacked_traces/combine.py
index 5849150..cbdfe04 100644
--- a/pyecsca/sca/stacked_traces/combine.py
+++ b/pyecsca/sca/stacked_traces/combine.py
@@ -8,8 +8,8 @@ from math import sqrt
from public import public
from typing import Callable, Union, Tuple, cast
-from pyecsca.sca.trace.trace import CombinedTrace
-from pyecsca.sca.stacked_traces import StackedTraces
+from ...sca.trace.trace import CombinedTrace
+from ...sca.stacked_traces import StackedTraces
TPB = Union[int, Tuple[int, ...]]
CudaCTX = Tuple[
diff --git a/pyecsca/sca/stacked_traces/stacked_traces.py b/pyecsca/sca/stacked_traces/stacked_traces.py
index 09169bd..f2c67fc 100644
--- a/pyecsca/sca/stacked_traces/stacked_traces.py
+++ b/pyecsca/sca/stacked_traces/stacked_traces.py
@@ -4,7 +4,7 @@ import numpy as np
from public import public
from typing import Any, Mapping, Sequence
-from pyecsca.sca.trace_set.base import TraceSet
+from ...sca.trace_set.base import TraceSet
@public
diff --git a/pyecsca/sca/trace/trace.py b/pyecsca/sca/trace/trace.py
index 367125b..4388643 100644
--- a/pyecsca/sca/trace/trace.py
+++ b/pyecsca/sca/trace/trace.py
@@ -78,7 +78,7 @@ class Trace:
def __hash__(self):
# This will have collisions, but those can be sorted out by the equality check above.
- return hash(str(self.samples)) + hash(self.meta)
+ return hash((str(self.samples), tuple(self.meta.items())))
def with_samples(self, samples: ndarray) -> "Trace":
"""
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/pyproject.toml b/pyproject.toml
index c8a704d..baa97f4 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -39,7 +39,9 @@
"datashader",
"xarray",
"astunparse",
- "numba==0.57.1"
+ "numba==0.57.1",
+ "networkx",
+ "importlib-resources"
]
[project.urls]
@@ -56,7 +58,7 @@
"leia" = ["smartleia"]
"gmp" = ["gmpy2"]
"dev" = ["mypy", "flake8", "interrogate", "pyinstrument", "black", "types-setuptools"]
-"test" = ["nose2", "parameterized", "coverage"]
+"test" = ["pytest>=7.0.0", "coverage", "pytest-cov", "pytest-sugar"]
"doc" = ["sphinx", "sphinx-autodoc-typehints", "nbsphinx", "sphinx-paramlinks", "sphinx_design"]
[tool.setuptools.packages.find]
@@ -65,3 +67,12 @@ namespaces = true
[tool.setuptools.package-data]
pyecsca = ["ec/efd/*/*", "ec/efd/*/*/*", "ec/efd/*/*/*/*", "ec/std/*", "ec/std/*/*"]
+
+[tool.pytest.ini_options]
+testpaths = ["test"]
+markers = [
+ "slow: marks tests as slow (deselect with '-m \"not slow\"')",
+]
+filterwarnings = [
+ "ignore:Deprecated call to `pkg_resources.declare_namespace"
+]
diff --git a/test/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/data/__init__.py b/test/data/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/data/__init__.py
diff --git a/test/data/divpoly/__init__.py b/test/data/divpoly/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/data/divpoly/__init__.py
diff --git a/test/data/divpoly/mult_21.json b/test/data/divpoly/mult_21.json
new file mode 100644
index 0000000..48cbffa
--- /dev/null
+++ b/test/data/divpoly/mult_21.json
@@ -0,0 +1,2655 @@
+{
+ "mx": [
+ {
+ "(441, )": 1,
+ "(439, )": 97020,
+ "(438, )": 201598948346408346749138595589353587508,
+ "(437, )": 2275087122,
+ "(436, )": 310927262294181614419684484799262713780,
+ "(435, )": 317115504108870610776237589705194616859,
+ "(434, )": 238190928241589059369233464629769964853,
+ "(433, )": 266943660106099362756522197679976453573,
+ "(432, )": 153402333328171964086545270263710950709,
+ "(431, )": 36156248285858384861491399844719874576,
+ "(430, )": 68618309294440875124825847895032400444,
+ "(429, )": 81940275054596141681907203204492700810,
+ "(428, )": 273753275173965199194690519988001633001,
+ "(427, )": 127847879045220942151327669972684376682,
+ "(426, )": 240758424215832426364068522313012307488,
+ "(425, )": 217871952225849850895313921444897728002,
+ "(424, )": 232672952704936920906008614649513644537,
+ "(423, )": 185901179922516094335268011309493505746,
+ "(422, )": 71804483167657044917361360877762428045,
+ "(421, )": 328924279902831759147615962118628857414,
+ "(420, )": 213847077814364959620618689284156308308,
+ "(419, )": 301963109234488219225325411695528431176,
+ "(418, )": 142445144641188869013561649444761773594,
+ "(417, )": 327586862048307731115415194150731394450,
+ "(416, )": 272376532309912010065408557454171503251,
+ "(415, )": 185973012054262471449814863116686785056,
+ "(414, )": 262964103403213342622112261573457138827,
+ "(413, )": 146290005613090870012473748380231850753,
+ "(412, )": 56303885539055160848300484988550228974,
+ "(411, )": 333562722813401640101596406354852585620,
+ "(410, )": 235148570567944996746039107624091955747,
+ "(409, )": 41393170909955506026232732971622861184,
+ "(408, )": 63413117717684753646768717524553451868,
+ "(407, )": 107976081242114324264908973696825563872,
+ "(406, )": 14202008571489982110582297357361445421,
+ "(405, )": 145587211802351290421216675037319750324,
+ "(404, )": 119591548141022064657984141234857404996,
+ "(403, )": 191296977171299053949529654508561863636,
+ "(402, )": 174417341429655887445754612203640100094,
+ "(401, )": 130147058822586892633439673761690971876,
+ "(400, )": 168649173072565927025228844545805928937,
+ "(399, )": 24284290393331064466349364921333227450,
+ "(398, )": 326689030046966179294090309774332684729,
+ "(397, )": 253454171712156501293158273942654984982,
+ "(396, )": 2377564135650784239731885354448370314,
+ "(395, )": 266946719784124013108802285620338595588,
+ "(394, )": 198038095484422492233132035142816231324,
+ "(393, )": 322754405494530684447473983660907223523,
+ "(392, )": 134735236013828689669783344861934666613,
+ "(391, )": 28993671125729325173659240067668932758,
+ "(390, )": 210414684507736204127172002492286362435,
+ "(389, )": 128292972085545059915021611868095008525,
+ "(388, )": 154294474791779794351921114336902507332,
+ "(387, )": 293638412369158419952600069079428070631,
+ "(386, )": 15937170635697155843421759986482269349,
+ "(385, )": 254556806205834611498245593556508856349,
+ "(384, )": 106682839681744230138142869149594605744,
+ "(383, )": 337943938460632327044816057116099049622,
+ "(382, )": 331609468588999374830320006211796187798,
+ "(381, )": 117579206076478060658278584032868896729,
+ "(380, )": 11443394716770489019879137007692664899,
+ "(379, )": 303135506971633991042615404238108774106,
+ "(378, )": 208510295416554701524381039198388799805,
+ "(377, )": 109487310941930016575272627881419383934,
+ "(376, )": 119156583731204455826024510875480593997,
+ "(375, )": 137774341493838036431893685183253746601,
+ "(374, )": 165433541951145498207226457398777769198,
+ "(373, )": 271088806339047508848043870357027007614,
+ "(372, )": 17762796589534617769710665713177840068,
+ "(371, )": 96390389702357371564869148251081920976,
+ "(370, )": 158752633248117234893337683528667126941,
+ "(369, )": 232610581771572299282056823559505701856,
+ "(368, )": 132443924448906020019465287028487368325,
+ "(367, )": 130718528882110797421724471162040858869,
+ "(366, )": 250667224314238998743937062726538093014,
+ "(365, )": 86091785757609782501334114312911182592,
+ "(364, )": 333855312884459020774564449386569472981,
+ "(363, )": 219336857361305061072572349936345758137,
+ "(362, )": 339321972032800035442104120130694853714,
+ "(361, )": 117688460350761414110080839606608812091,
+ "(360, )": 10305998390280874116638184880217185934,
+ "(359, )": 112428680577179613052971663542897078207,
+ "(358, )": 142807399134714191572173344334236973269,
+ "(357, )": 163688402059398261484897656845157841365,
+ "(356, )": 285478028132761619953175014238074755983,
+ "(355, )": 184268815268580435040773191309599858816,
+ "(354, )": 52940337960788099324118751017968384589,
+ "(353, )": 234925443340083138487935803852969609268,
+ "(352, )": 103202033462272873563809651975746877332,
+ "(351, )": 122417750132724102881819625216481220278,
+ "(350, )": 36291872418828397993920867899551653754,
+ "(349, )": 225911899488326820146377927228375380475,
+ "(348, )": 231209822301227773724655991503365677112,
+ "(347, )": 154613288723197989710294465073059415351,
+ "(346, )": 317154941611151795644647289466125108516,
+ "(345, )": 35134344409855494521532234124586436029,
+ "(344, )": 18318239337787000274845161034286523344,
+ "(343, )": 263030184889358333679156807800992365763,
+ "(342, )": 239233917129296608365988828518443883955,
+ "(341, )": 245759100370003206102043147724251463812,
+ "(340, )": 131664244334700997594755034850428092520,
+ "(339, )": 73646504382319380782633661107221898542,
+ "(338, )": 117871760754826501971048585481472894081,
+ "(337, )": 57780194985122501082000345293170897504,
+ "(336, )": 55618947435831685549398775134529344013,
+ "(335, )": 256526002354306834146777083253494695606,
+ "(334, )": 156396395661307658011468137161398923274,
+ "(333, )": 40499396482412728600678402400219405867,
+ "(332, )": 8618851443185748762470646085401555453,
+ "(331, )": 101119930000666808830737425694658611542,
+ "(330, )": 147441382500553470814308140925047585872,
+ "(329, )": 237349408386789139465038840577749324622,
+ "(328, )": 129931439177416879029264629085412967406,
+ "(327, )": 46031949832238926021858740668844782615,
+ "(326, )": 204376523475693267104334187208753245236,
+ "(325, )": 245485944385965646389021304491312692908,
+ "(324, )": 161341455731438424590650401623491874705,
+ "(323, )": 318837270671128640744903513975087529250,
+ "(322, )": 173361319083376533046790005046710234887,
+ "(321, )": 210008900362286193035247194444010106071,
+ "(320, )": 239745008473263324476607387370455605651,
+ "(319, )": 331725036142064444330064940141863545304,
+ "(318, )": 75756305036865478074469353065287909215,
+ "(317, )": 94617616681351920531854375980784302447,
+ "(316, )": 11044898908781085099625367264609292830,
+ "(315, )": 243272495764694639684762789870792992850,
+ "(314, )": 195814871244278531434328383496929092646,
+ "(313, )": 131262954174303734074569934081885400292,
+ "(312, )": 289711941919466128129391457912447087410,
+ "(311, )": 176833573271385887623529168237585575199,
+ "(310, )": 320614168818864495038930655185925900725,
+ "(309, )": 192882298293840845982761400870831395288,
+ "(308, )": 45224405385678327370890595432527068551,
+ "(307, )": 111071247173430170888252804473123351454,
+ "(306, )": 103792075787720512104131565014551530392,
+ "(305, )": 185169794995380653785533798940598436063,
+ "(304, )": 308599408841508364784356902710706362263,
+ "(303, )": 301084486143133189703018414829528585893,
+ "(302, )": 147246278025768969109897289766423081356,
+ "(301, )": 104659145200821087890231741360122925507,
+ "(300, )": 241887527954030462618204153922473247269,
+ "(299, )": 225118567436612830577702638028033035614,
+ "(298, )": 329850728543791265799120390115341846778,
+ "(297, )": 124329001804718987989270750855983154836,
+ "(296, )": 77494943934880393564492797477955571306,
+ "(295, )": 35844983648460980397312261101400671412,
+ "(294, )": 285539275323895630114837103615522235537,
+ "(293, )": 65319844603627599719466112221441916912,
+ "(292, )": 326668212931717786494280779402870589426,
+ "(291, )": 19196893031895824489520264781189108919,
+ "(290, )": 312567580761706482497863280165700716443,
+ "(289, )": 219211407955099550119115081515206857557,
+ "(288, )": 187382666919641367012948635867316697545,
+ "(287, )": 188792639874882687879814970060940441638,
+ "(286, )": 104957756923069370494274664808512394668,
+ "(285, )": 6229970600772557627622005661235795134,
+ "(284, )": 120984990640582898669120069422112314204,
+ "(283, )": 83008022858463538496098504623520990054,
+ "(282, )": 186486862218848904516874316756959990019,
+ "(281, )": 161761762385015609470541514966054031892,
+ "(280, )": 93687743656189326463782473151958161042,
+ "(279, )": 229837813728569029516886921977700292341,
+ "(278, )": 243121785684739209623364533526656383563,
+ "(277, )": 66335528926735779057043836343188205468,
+ "(276, )": 95148252763381049972162179412452887888,
+ "(275, )": 100569597192190476458102758148771883029,
+ "(274, )": 249103191625782863113515022864853602809,
+ "(273, )": 261924318498154198383397389529424662770,
+ "(272, )": 63740731308446457073493590404384208186,
+ "(271, )": 242786502504464173990994718604001547371,
+ "(270, )": 178278624240702538270490407401404653958,
+ "(269, )": 279865702387241398115874657224365380676,
+ "(268, )": 174537669878927887162859319092305982672,
+ "(267, )": 87232855049292505455894293008042261704,
+ "(266, )": 191017856832484695560511861959295196156,
+ "(265, )": 139847865583383581760015528696201932061,
+ "(264, )": 128688000514920428908649192211411082688,
+ "(263, )": 247281474963512755638914096851400554890,
+ "(262, )": 221435214144339981041078172650409422290,
+ "(261, )": 244241660848945214666251475509059431210,
+ "(260, )": 308408741860281681991194536282307897754,
+ "(259, )": 136393741124551059805626255769344527247,
+ "(258, )": 46805288958965070745765921644811012731,
+ "(257, )": 226209005273482670725479525178980654281,
+ "(256, )": 302845603689940847947396737732062052366,
+ "(255, )": 225697754817650995926889942027583962553,
+ "(254, )": 336357005383311103344651633881649733102,
+ "(253, )": 278453258633105061254331842586691493794,
+ "(252, )": 197917881895763148757602470505147772564,
+ "(251, )": 32963044278178100002928971415239102619,
+ "(250, )": 169405515805487465541858077176078892593,
+ "(249, )": 54239763060729779687622681371960887919,
+ "(248, )": 13580036187058208789514932133314080949,
+ "(247, )": 204874968039980489621036226018268892222,
+ "(246, )": 44748315624751184341607925000092044722,
+ "(245, )": 202099559385412234257348154207717789255,
+ "(244, )": 300427428706225712262133286003997098296,
+ "(243, )": 171195113001299024495192603719779610176,
+ "(242, )": 44751574993773033753351494040154613039,
+ "(241, )": 236740128449651842267469028893053899807,
+ "(240, )": 243827045965232143328755833335267105220,
+ "(239, )": 165575333559622408970448065516488248784,
+ "(238, )": 315707792911137181918942599619199567584,
+ "(237, )": 111784066211592730387397929063424341989,
+ "(236, )": 46025156782724558035637993768706387790,
+ "(235, )": 278180811767935363293622462360102154858,
+ "(234, )": 216983454093124266791205574366784771542,
+ "(233, )": 70634060337761702788544976853841702984,
+ "(232, )": 237465165779370751553121026679974258857,
+ "(231, )": 277003368019691372353352545972135455190,
+ "(230, )": 158215812991267889714235198089381240863,
+ "(229, )": 37058883453036728383368447233498907395,
+ "(228, )": 159415030378147572005595509098851486683,
+ "(227, )": 104715581993305072535674812704703191622,
+ "(226, )": 130194725305907925895509998130707395655,
+ "(225, )": 54170119604911522747043688691134898977,
+ "(224, )": 271710272810585935398666491072396821427,
+ "(223, )": 154832519654847823248190540113164900416,
+ "(222, )": 31683726362235972683174906632109423596,
+ "(221, )": 281828970789222666498055138417545985614,
+ "(220, )": 231595016585561851889956460296025080,
+ "(219, )": 324222189460329266485490747727443463561,
+ "(218, )": 91247293668902012672950649839499052753,
+ "(217, )": 31407509602119338590075279226429413488,
+ "(216, )": 170611989430027210602805170003417329137,
+ "(215, )": 107604900277664217869353369547731865860,
+ "(214, )": 326451504732837904467096217284817147077,
+ "(213, )": 170917583423849892922724428116760250251,
+ "(212, )": 160626311783467723825429999844649576812,
+ "(211, )": 183848220517598196190234822178021439891,
+ "(210, )": 309782572134890608815530179046787660890,
+ "(209, )": 220263089198665719161846823840315394233,
+ "(208, )": 8644806525413275781945145107206123182,
+ "(207, )": 20851910290006859057512892503690382688,
+ "(206, )": 218684336470313469266194008793666914136,
+ "(205, )": 149861304045318257927240767216653109923,
+ "(204, )": 56084453613460202979828566519060213234,
+ "(203, )": 124328105791369544330306492914766381989,
+ "(202, )": 184210113942090198015083409618448379980,
+ "(201, )": 22584189839794165620840178310900471574,
+ "(200, )": 324447507136149006018478178445553809239,
+ "(199, )": 57412380321424742937141375961962411738,
+ "(198, )": 58157607670498218595035852083829220560,
+ "(197, )": 43904907699849846215617735053641735705,
+ "(196, )": 52238169114326661567509924248011149410,
+ "(195, )": 178962017195674465389997270669587738441,
+ "(194, )": 320085271054247591671020176920682220953,
+ "(193, )": 182572755577066666778948292840520690042,
+ "(192, )": 98340301400655714154217580186521202073,
+ "(191, )": 133321425498751528586508407694382757009,
+ "(190, )": 62914336972736509070965737361371652919,
+ "(189, )": 15251451368642550114421013127010303367,
+ "(188, )": 207552468437509785817274380848657641677,
+ "(187, )": 38264363837323908509857489769894231366,
+ "(186, )": 209680564959616147168177856599876393663,
+ "(185, )": 4187331146218846817744559160572463157,
+ "(184, )": 91598091373307760032202631639451784568,
+ "(183, )": 71242792181361944088984414617376427901,
+ "(182, )": 291394576189965198124342542979308671250,
+ "(181, )": 325915934401867240099937935691174572810,
+ "(180, )": 79915098167806909060933744665002793053,
+ "(179, )": 133249317771536310979833721115464552843,
+ "(178, )": 188599866277146255706193730810586587453,
+ "(177, )": 134721706216780043764173406746876154192,
+ "(176, )": 253581166559489775313533464468798072751,
+ "(175, )": 332416082530597894132715331643798797534,
+ "(174, )": 100751931061353586424970537764057405492,
+ "(173, )": 69441494541392728304319123269674460311,
+ "(172, )": 271400883502314307079168546996437365202,
+ "(171, )": 272016239058438978264979961031067458281,
+ "(170, )": 240308319781137078202533474877609945469,
+ "(169, )": 330320008613089596908014436059842158620,
+ "(168, )": 3241449527094841056662891294281882744,
+ "(167, )": 60466715981548127800230137891093041246,
+ "(166, )": 227169035601680143073433411370215069287,
+ "(165, )": 293225105724477005256419568907987565660,
+ "(164, )": 115389618877503150921977826305862742009,
+ "(163, )": 311906595383266871426971958379505069046,
+ "(162, )": 75958486306231516233680921380398052605,
+ "(161, )": 261565437930143737093915650403627026281,
+ "(160, )": 220367267951525163129942168245151517620,
+ "(159, )": 6853180945661662986442678721110188588,
+ "(158, )": 303270289825012805239198355475327269145,
+ "(157, )": 271690786488530729356250573014707458957,
+ "(156, )": 79384069775347411502534173349810701716,
+ "(155, )": 125738695753625404475409200711868887171,
+ "(154, )": 265731054705676209532536849960434164662,
+ "(153, )": 182820635343102126152946344453947245508,
+ "(152, )": 74534267367059142658245734891314529588,
+ "(151, )": 114912469964451862360526526759339672374,
+ "(150, )": 151516749560799125436838515198355262860,
+ "(149, )": 301361015759271037783324519455560025348,
+ "(148, )": 235694758047571370940312077469819556081,
+ "(147, )": 226861968722301633755882605680516328753,
+ "(146, )": 41049804028156940592595912282297221131,
+ "(145, )": 305299637533178699370660159974543702304,
+ "(144, )": 130145661368107556171825423636491067294,
+ "(143, )": 230015703871707359639818574204272225754,
+ "(142, )": 330314391516603166716764360206977938488,
+ "(141, )": 23900714190716775402005751607003786957,
+ "(140, )": 336147636104052615279694709479075489503,
+ "(139, )": 245109870408212582318057482988638313633,
+ "(138, )": 300670052615479835072538431558676146909,
+ "(137, )": 19228793548802218875404534870961194813,
+ "(136, )": 63023175247052200544506229746302842549,
+ "(135, )": 133275478373540124529441268300065824448,
+ "(134, )": 305074381152628659733278422377514738460,
+ "(133, )": 100262470415968315196956576405141812020,
+ "(132, )": 192021641481122999950115170210430821305,
+ "(131, )": 18305314625597843152301379073032460852,
+ "(130, )": 243000406168917118996021303903399118802,
+ "(129, )": 134701535946144018518280686142681894738,
+ "(128, )": 122396627172813488737603531878221966864,
+ "(127, )": 11739746199354246218349038154305551295,
+ "(126, )": 102150936510735672662504313050456552115,
+ "(125, )": 308475869111634760665726879262287224783,
+ "(124, )": 58134697884515267612102547730513199554,
+ "(123, )": 232459068252094978730041099443975747119,
+ "(122, )": 252484985015697093096599542850753444303,
+ "(121, )": 49596962725529252908372217419205748135,
+ "(120, )": 30901114625862507431026994987259563195,
+ "(119, )": 236039137683024734342372783770425456438,
+ "(118, )": 234831851350407853468840648852408827306,
+ "(117, )": 174635163864205022112742787366310978420,
+ "(116, )": 154698751164617972108452545867725755058,
+ "(115, )": 123570329296187999463185705610913914580,
+ "(114, )": 55813035634587949683256788070630575560,
+ "(113, )": 284390112999300439109615753472556498057,
+ "(112, )": 91431639600807753964968027258040190788,
+ "(111, )": 286791145872526646350271481414524618531,
+ "(110, )": 317968175946948298118869564181190202055,
+ "(109, )": 315363589365915304060936877502578182230,
+ "(108, )": 325066570254460407460578006121017006021,
+ "(107, )": 66126495439077092589305089224956466094,
+ "(106, )": 329785625469704754061121719895926064193,
+ "(105, )": 287209560053824675765265991467341672836,
+ "(104, )": 23883590460834210903620433761270176699,
+ "(103, )": 230691474556566263314398473395696987030,
+ "(102, )": 281121911936210030332093104492202236992,
+ "(101, )": 229493211210843637293851400465946780778,
+ "(100, )": 8346048265596523956895990721378566211,
+ "(99, )": 312075734021763297478529394319707414887,
+ "(98, )": 70290669087917785710193171288526747855,
+ "(97, )": 36869690097405253736171970707808378673,
+ "(96, )": 197937440433595781378574674005968937776,
+ "(95, )": 87871135273153054701213321873215834368,
+ "(94, )": 66783672985478748617592338679887064903,
+ "(93, )": 151644456000674461306552632059295414898,
+ "(92, )": 229019938655506334294384503287381219823,
+ "(91, )": 99500390603452290107810077626861412168,
+ "(90, )": 293995183402692093260777158295021934888,
+ "(89, )": 231630855415824631088282056088029975615,
+ "(88, )": 315190528120149793068907513889130985259,
+ "(87, )": 39391448992147121885410105601462357673,
+ "(86, )": 293543452321522390777942015401898792359,
+ "(85, )": 24649375785611773263400926339478405265,
+ "(84, )": 240872318316709102176547063970097656380,
+ "(83, )": 183526711810047906880212068769733982387,
+ "(82, )": 257842308783317664301796828412346798588,
+ "(81, )": 49936107297292562551428406631513305627,
+ "(80, )": 45803140569212523317150252144644536287,
+ "(79, )": 7192925833597238534107355535199528934,
+ "(78, )": 256539443295052386221023848110791745723,
+ "(77, )": 155855054542096679150442633582062388577,
+ "(76, )": 10041787447488811741365481228736034281,
+ "(75, )": 118160228434263396147226334693169604240,
+ "(74, )": 38454605073052271158865970607098256918,
+ "(73, )": 252747625306539655963403167351100215110,
+ "(72, )": 76939491704717040651005055987507199913,
+ "(71, )": 225784265425754518495709634519051300999,
+ "(70, )": 197734196780618870057576060931213255234,
+ "(69, )": 22747119250934703255984259947161324870,
+ "(68, )": 237173259761459602737429439508516467112,
+ "(67, )": 149369914969347277594026488746590773357,
+ "(66, )": 145195311692643050980810218131847354089,
+ "(65, )": 93590407234288848990639441682021852956,
+ "(64, )": 247841952276313769825332521912751503047,
+ "(63, )": 54118901191443517070250548601985486436,
+ "(62, )": 47311103561763719008669247508971692965,
+ "(61, )": 215266983154379865521844494370287411314,
+ "(60, )": 199106775683283638727996368737815019188,
+ "(59, )": 63490807678296155582533323541121320095,
+ "(58, )": 40898500300775358933769952246472783782,
+ "(57, )": 7976201031532205306764376276468645521,
+ "(56, )": 128530894014297823266271104137203298687,
+ "(55, )": 153106156430977315312735022072603264095,
+ "(54, )": 291895594882496017353313380337427848815,
+ "(53, )": 125697265352495285228623498159810750877,
+ "(52, )": 156243545491951426973703036633345820039,
+ "(51, )": 166494512657545519707143097858645517794,
+ "(50, )": 17545649806805731680077542435328506984,
+ "(49, )": 84735514026036113309500934112610523362,
+ "(48, )": 54102418773983135702139135790814874073,
+ "(47, )": 223692601971635651076392348159416778571,
+ "(46, )": 272017522321897354081420307459003408082,
+ "(45, )": 119792452862595991836058891383644038795,
+ "(44, )": 142778975650728600005787188201629980433,
+ "(43, )": 290150048237463918590108203072939758405,
+ "(42, )": 148935513386187933767745198950767142523,
+ "(41, )": 9917809338260230480142131022184957022,
+ "(40, )": 327281863414046186981573673451635787306,
+ "(39, )": 54663296408720004394329886166435829596,
+ "(38, )": 239981330431249426842251214174379349613,
+ "(37, )": 337758229505096600956098524083493616709,
+ "(36, )": 252634475326521176838015794204553418925,
+ "(35, )": 31180251655522266557613296112312187757,
+ "(34, )": 44079208540206236827908778910962352366,
+ "(33, )": 250682759863906069336928902386107939839,
+ "(32, )": 66797797301445974619075052834166831077,
+ "(31, )": 169145615393683883086475628860701165529,
+ "(30, )": 338905684537211254788320184589077887822,
+ "(29, )": 52498502841622213057752195005332242647,
+ "(28, )": 178851689722118100523214706273592043422,
+ "(27, )": 71825342766230310105294482794310692907,
+ "(26, )": 289677341163612207715399265601872561069,
+ "(25, )": 236925198040579678942027946678869537085,
+ "(24, )": 134386226684684609227819392532162924850,
+ "(23, )": 221317458244257588945118479162062685686,
+ "(22, )": 60171929941764286196853012566006379292,
+ "(21, )": 279780359405134602453895310152504434924,
+ "(20, )": 135358445324866239900741527677260184456,
+ "(19, )": 294071560303592335124053797293279019957,
+ "(18, )": 74480744387788368558713000359402319189,
+ "(17, )": 76905125543079288351688363666309805436,
+ "(16, )": 221371062063899680105868913092053746514,
+ "(15, )": 63636281792073537233418192461060847798,
+ "(14, )": 25616638684508438553576354564618806069,
+ "(13, )": 217248264406182827770023658413224008213,
+ "(12, )": 325988819566852583032623155289226176825,
+ "(11, )": 32072119334060785804543679374811818803,
+ "(10, )": 275254141688470716649115782553925027803,
+ "(9, )": 182001442802124581848922700380200301420,
+ "(8, )": 13711710171648406044770139180866270306,
+ "(7, )": 324184189548634070784091701105955757710,
+ "(6, )": 288280673788849802995512341414972719795,
+ "(5, )": 17000327112279048912052162119381327572,
+ "(4, )": 254619592230160421754477147800808719354,
+ "(3, )": 156051637888178851935664257174652066283,
+ "(2, )": 179439419374757651990488155747802832596,
+ "(1, )": 159543934916531652563571025206865012651,
+ "(0, )": 74326875737871892797207286624209954525
+ },
+ {
+ "(440, )": 441,
+ "(438, )": 340282366762482138434845932244671637195,
+ "(437, )": 94272837787031781331747290627616492722,
+ "(436, )": 13800464370,
+ "(435, )": 80183708130810209828183058111183103334,
+ "(434, )": 95979575679762141691763754227747012385,
+ "(433, )": 2197279286266752937146945672797658906,
+ "(432, )": 238864491711088835977212132385584529510,
+ "(431, )": 185896658498438514841098887978414249667,
+ "(430, )": 331204208423123859927332123384656963116,
+ "(429, )": 192370308558257330350805288120538544601,
+ "(428, )": 188443932400177892899721689372254242823,
+ "(427, )": 327000200753412403693709196529238381398,
+ "(426, )": 52669826392758677331713790720879848419,
+ "(425, )": 60223222768282137267521160890685871813,
+ "(424, )": 279047939290236800397671594088004741051,
+ "(423, )": 22415020479219493287084117258096423294,
+ "(422, )": 330909592891290307157457066689154514282,
+ "(421, )": 71495011805856441408059042593976758788,
+ "(420, )": 84989231052644057890551155454525852727,
+ "(419, )": 13885865452288773361634391676682642072,
+ "(418, )": 239896591135433963774251897918870925568,
+ "(417, )": 97891743064069256852251910450888911444,
+ "(416, )": 248364318592807402398477459046814257114,
+ "(415, )": 295797569104589359093831826301865552383,
+ "(414, )": 229023336235800126264174541664940494381,
+ "(413, )": 279017966173064319071116933994619335571,
+ "(412, )": 285201709617599199017960463062428566275,
+ "(411, )": 182213436091222239770640619867063802377,
+ "(410, )": 93728292658922224041473115608203480663,
+ "(409, )": 143931851940060773994973722706347372323,
+ "(408, )": 160658650402142065252249079615650646817,
+ "(407, )": 328768420252122945269644243164842519762,
+ "(406, )": 261526008923442987682234429966671564656,
+ "(405, )": 13871811548450637435144991697765957862,
+ "(404, )": 299270881850333289106150866086162981711,
+ "(403, )": 137931124864937287765071758458770463989,
+ "(402, )": 197152747558309808689194521372782762072,
+ "(401, )": 304925729469799544149570020243706325407,
+ "(400, )": 137042430964782293626954208434206973741,
+ "(399, )": 31623065089666680612466757407058601332,
+ "(398, )": 10863110884990861474467734377825742175,
+ "(397, )": 234596043637945836127810503802331767302,
+ "(396, )": 224433532288653678408001485562108894289,
+ "(395, )": 110158615469299247677808345589999829509,
+ "(394, )": 43246352286967117549421241439910919959,
+ "(393, )": 146146004660080502362121913150825386431,
+ "(392, )": 296027356893580543662038661173991602538,
+ "(391, )": 139520646425289805873111897559608956570,
+ "(390, )": 138836591301560746823299082964226073554,
+ "(389, )": 220706461737147399951534432277440710958,
+ "(388, )": 243644293873637008138318810886241018149,
+ "(387, )": 21327404773200099251481426375896877517,
+ "(386, )": 228765725278783452810619032086959992495,
+ "(385, )": 45400733021642170856606162569729478850,
+ "(384, )": 28111254208161794610821662595565908571,
+ "(383, )": 199425422065514229658783719593560423377,
+ "(382, )": 328855789097884856961950643799297146141,
+ "(381, )": 303009802944481282243667117987393539136,
+ "(380, )": 83219995127753710764954466780452280263,
+ "(379, )": 90419400541837135719645623871244841991,
+ "(378, )": 12734501215599496551337332312947600350,
+ "(377, )": 304943044039727756579093519202524743804,
+ "(376, )": 181004532800595836372120969155542605811,
+ "(375, )": 151170616937984737753563203069379334407,
+ "(374, )": 27450509466894929208763189733712418052,
+ "(373, )": 232064547010873332996330979060689947817,
+ "(372, )": 76187668756519126780340548088084166932,
+ "(371, )": 301451228240293143283969288589576609705,
+ "(370, )": 17235844556528369133472880813678545208,
+ "(369, )": 230627988485740964374420228272772986880,
+ "(368, )": 147354599574027222632955913276146749626,
+ "(367, )": 331859182382687509317114675428976910341,
+ "(366, )": 144918777717342776200416161840797191069,
+ "(365, )": 126582524340649727184123430605397661793,
+ "(364, )": 194371840788833317159057216973730845803,
+ "(363, )": 20747218524365988817030033245777687082,
+ "(362, )": 148120041161755287492598283597626956729,
+ "(361, )": 331484832153113028294405158066211329588,
+ "(360, )": 44027391064181966547475345759389636088,
+ "(359, )": 18699638571386156428354271454589705724,
+ "(358, )": 304869373632422273392867790390982443239,
+ "(357, )": 290185054150202654164132579786976634885,
+ "(356, )": 128067454816841772137253729659167152793,
+ "(355, )": 293284951370547541640104166929673139503,
+ "(354, )": 173389543965837169219023935245833471399,
+ "(353, )": 303149456459484285422340387129560524068,
+ "(352, )": 252898566941611046721050462296279823433,
+ "(351, )": 180409740281931898655537952428966565721,
+ "(350, )": 238565879915572225843265960469609595888,
+ "(349, )": 17108527258838965769641426010581714202,
+ "(348, )": 315148040296915464377458776103621284413,
+ "(347, )": 68490669566724382319221127917200354372,
+ "(346, )": 225038142208166931493925110983152204103,
+ "(345, )": 33690116818266660341391807621811129392,
+ "(344, )": 10003317852741855643216675401591183694,
+ "(343, )": 93671764170962319141291541935865977985,
+ "(342, )": 116692977086549124347424616619392080102,
+ "(341, )": 181172021808293266655024738110807889875,
+ "(340, )": 212759493476786152463631101452540172594,
+ "(339, )": 107325241639333770801611880052202504630,
+ "(338, )": 135758853186147096299628998250896908497,
+ "(337, )": 262091841156642434138200485798765124890,
+ "(336, )": 230416276976566766127167631815227341098,
+ "(335, )": 24749116960613392998513198678683299951,
+ "(334, )": 338292280636594141245582046200236211648,
+ "(333, )": 231414956405351030822934482971251836702,
+ "(332, )": 53431738836370469463170755581300038316,
+ "(331, )": 284148176705893078346117906272174429304,
+ "(330, )": 205415968423770035077800968069568189651,
+ "(329, )": 307158229733244442942491047536128264815,
+ "(328, )": 318824090415286717844310634281747196785,
+ "(327, )": 111802376964334753458932856342145663075,
+ "(326, )": 173779832709071680859199743019764272269,
+ "(325, )": 186891156727628186081940065683745948130,
+ "(324, )": 251931642299097552432038874081065824457,
+ "(323, )": 142865820392824797790490219146666866177,
+ "(322, )": 163785835759660002457349217174980615656,
+ "(321, )": 195545322513751876172958809377107605404,
+ "(320, )": 40670982237589493916211279080876808254,
+ "(319, )": 93039193949362884594189174115105458595,
+ "(318, )": 337195670321378563952634248918250846188,
+ "(317, )": 129042041998944529626688774087331454518,
+ "(316, )": 60994022708869068531784724120421165183,
+ "(315, )": 257033564848824175272223925462873989976,
+ "(314, )": 330239112532282415437316223193494278022,
+ "(313, )": 35584315633058775768817602351109263869,
+ "(312, )": 311619183749976783519819547629238564954,
+ "(311, )": 241831574459927375261321325504334002906,
+ "(310, )": 63446102399920058097005737577364419825,
+ "(309, )": 5576167144405259205017479417245368972,
+ "(308, )": 149231124472184104675340321551108913373,
+ "(307, )": 199724326683710004384958278799203645033,
+ "(306, )": 72602564659014749889862634191296367366,
+ "(305, )": 287173835930379170338055381738897421813,
+ "(304, )": 41426263615035975808486016703434164715,
+ "(303, )": 85352586933158148295966359121125025410,
+ "(302, )": 291215847684405529391555892052079147931,
+ "(301, )": 286606629133094937317678850656395010367,
+ "(300, )": 305629227241006987264628432922496153378,
+ "(299, )": 198299257444381655409124301775194544606,
+ "(298, )": 73504860181207758809556429336418328580,
+ "(297, )": 271116686648286410656785087992696812332,
+ "(296, )": 331594532374244949831354622392391594609,
+ "(295, )": 193553438574791215706004868866938234197,
+ "(294, )": 339173912432962623614772069539930201607,
+ "(293, )": 281732680609534700880156705334368068676,
+ "(292, )": 282172274409038078833623556065237229442,
+ "(291, )": 321236953017197727050957135432126854061,
+ "(290, )": 276921899786883197139718298551655927610,
+ "(289, )": 43223554258981284990953806949002657823,
+ "(288, )": 61010755788119680204803025653795212939,
+ "(287, )": 161500287406837046168070960490367399997,
+ "(286, )": 137531064011899887593019183422977368128,
+ "(285, )": 225762971652215331536039873911153978675,
+ "(284, )": 91529027268066032522006674412453020176,
+ "(283, )": 262144073032506017632134589206291945600,
+ "(282, )": 144863332189945386942788857078523903370,
+ "(281, )": 5645122840705188172781146284471867226,
+ "(280, )": 189780058696547012573922033814390090188,
+ "(279, )": 86959071530190470003309872978417599401,
+ "(278, )": 256678558175444502729788771434476826918,
+ "(277, )": 128274242389455987868567714351985194860,
+ "(276, )": 224638107774902804590679059453820009218,
+ "(275, )": 51250584244998318255570657306518708212,
+ "(274, )": 88562310885339435869117416255438323791,
+ "(273, )": 266320616358849843178360620339939460133,
+ "(272, )": 233569740854655600196574576427735277503,
+ "(271, )": 182512720209000375749127637656664117390,
+ "(270, )": 198676233587504701944947476935596851770,
+ "(269, )": 205430107917634213955001454051324435031,
+ "(268, )": 336726218514473695397305278150921747573,
+ "(267, )": 118508325491754017804252961673833601566,
+ "(266, )": 5817338994650765766767875672982229470,
+ "(265, )": 312191545593482092428944292210791246667,
+ "(264, )": 214338771189764691517939541027817406184,
+ "(263, )": 102406807217066212900098469238355237223,
+ "(262, )": 299563178973973493660139959091994451271,
+ "(261, )": 117728163955750874289830057802423933023,
+ "(260, )": 34013777467844118410759704333138493105,
+ "(259, )": 153337844228220380388014425734620207831,
+ "(258, )": 128538628085094653062125280572332728217,
+ "(257, )": 235409187024488044896170572297173409404,
+ "(256, )": 195900898803439846235163095893948922633,
+ "(255, )": 334803832370871131575270994315754697096,
+ "(254, )": 138811592121170099861668236477558515922,
+ "(253, )": 246301063300127828991385628667287464084,
+ "(252, )": 40621610279402530821540036665447047712,
+ "(251, )": 149985837521626550364486629068023502042,
+ "(250, )": 324305676501134992481701464610887793266,
+ "(249, )": 194974483390068162088280100738382226506,
+ "(248, )": 305511594242393980362927228683456177342,
+ "(247, )": 145182317838485316307977923862010820634,
+ "(246, )": 246550530967192389218127127143881614822,
+ "(245, )": 111039152332858471134213548425861154262,
+ "(244, )": 186952412101327885947140724628709810939,
+ "(243, )": 251481374489452682845488731920457391019,
+ "(242, )": 140269157719509800788899520930432404756,
+ "(241, )": 207244301392004691743251713742756568565,
+ "(240, )": 334999046664397618960989358920314455022,
+ "(239, )": 260149620539840459928929234904603514896,
+ "(238, )": 122700932704777848946921393139411296150,
+ "(237, )": 263100329029791925351126370089547734644,
+ "(236, )": 140437198391322221349892775468983672737,
+ "(235, )": 337473425794598221158408707944026603723,
+ "(234, )": 34666751817150387854249175956729252361,
+ "(233, )": 177203178531926941643937140197357204362,
+ "(232, )": 159010593036938644936690496549513112620,
+ "(231, )": 94638689545399892629580475622686259268,
+ "(230, )": 11993516348001315696657183777784864341,
+ "(229, )": 303841714628127487305203173651428071764,
+ "(228, )": 17439690508897507311494362974308312182,
+ "(227, )": 53138397918495276049646244003625300010,
+ "(226, )": 128192571041098635795049369570055636571,
+ "(225, )": 217991474631158201296623495582108950945,
+ "(224, )": 147854234330877566548529674620066728144,
+ "(223, )": 246367154988429153565052679509242154851,
+ "(222, )": 89470268405558711021722594105318799506,
+ "(221, )": 288667415132379703365215887051014206321,
+ "(220, )": 50318185115512431144235264871230987581,
+ "(219, )": 91099120565801037014593745018804675105,
+ "(218, )": 338862221439289651043585956755005230028,
+ "(217, )": 125022533821435633371834103463515392296,
+ "(216, )": 273799241806648539902269793571654323213,
+ "(215, )": 155179193110507414082967892859985068351,
+ "(214, )": 264218535952060016254861222999768327765,
+ "(213, )": 274909560349355972131904519040473929541,
+ "(212, )": 223490200311452006732962725712417565436,
+ "(211, )": 302336912876099219840606128270150186423,
+ "(210, )": 15701530930176776307425897885097561345,
+ "(209, )": 11869181897095011518699510336513430922,
+ "(208, )": 105135348771424202648123754077655480798,
+ "(207, )": 29610866513306518065727651315167746816,
+ "(206, )": 50225384560320033160308106611426730639,
+ "(205, )": 245637812400386505098392357684496982922,
+ "(204, )": 306107039260249390518872556520913828618,
+ "(203, )": 79714899008849194794108906378260297338,
+ "(202, )": 48127767028354670277231657101760129701,
+ "(201, )": 265273638532179914104433251928362073281,
+ "(200, )": 32426120593776790703611026267207377011,
+ "(199, )": 268960836840305717133043671175436776972,
+ "(198, )": 232904745369913379296581859438762420617,
+ "(197, )": 273087800308826582781491308322989757546,
+ "(196, )": 174092358488566277910529031766099429195,
+ "(195, )": 33560450555846031257723839033711568330,
+ "(194, )": 116778023869958136066492306174518360059,
+ "(193, )": 263864323502832331351594678784020852614,
+ "(192, )": 41726245417828680857265463960238918480,
+ "(191, )": 314879155946739932038433930805517326663,
+ "(190, )": 320042936143813043858692243949137123169,
+ "(189, )": 282517828152075630435738636246554631767,
+ "(188, )": 302047356785772266870725913001261053300,
+ "(187, )": 307050960177948339369278723426738978345,
+ "(186, )": 19606115762590340916934133609401168245,
+ "(185, )": 239968921648965596288061418858806081389,
+ "(184, )": 286080203825824879205022595803043435544,
+ "(183, )": 277455815107388523678161935704397356354,
+ "(182, )": 289456284251561597077886641947887781452,
+ "(181, )": 236200411360828589866305732835843337641,
+ "(180, )": 200126679513115392395211119863778400122,
+ "(179, )": 233544148966760622210715055770824794065,
+ "(178, )": 66390776772428784424202617604336561472,
+ "(177, )": 137944855099196360529422642560704960423,
+ "(176, )": 188630590367998313084449024415360715295,
+ "(175, )": 26105955154766218618764372550084535399,
+ "(174, )": 43008895139098406296496691379497723795,
+ "(173, )": 65716275928889955415161132026638182181,
+ "(172, )": 148929715511246784980941539198163129757,
+ "(171, )": 147704156298511298825766470184477630775,
+ "(170, )": 18283597095163623578073645746324110388,
+ "(169, )": 273230054581778561356978548312565836980,
+ "(168, )": 227960186836015636916013365019340597250,
+ "(167, )": 11844731582651924992281388506962742502,
+ "(166, )": 304722228023227867937592260503423843340,
+ "(165, )": 324166961835463912650863987671492249354,
+ "(164, )": 230250756268747529439620188458730643713,
+ "(163, )": 192738146868062913663135625832406305020,
+ "(162, )": 150692209824597048930566428231173251396,
+ "(161, )": 332002122322053252569173143433454891798,
+ "(160, )": 190222392044656910895125458320951900950,
+ "(159, )": 215113222317986064898914872780782710019,
+ "(158, )": 186289609815773044041229976275459322742,
+ "(157, )": 14688450978597956577009917270113392736,
+ "(156, )": 219950262739454099594390080651804536199,
+ "(155, )": 70442324067161192679959260817314661738,
+ "(154, )": 14521578992933396717859137096656636597,
+ "(153, )": 187202939647886860147217698008101740872,
+ "(152, )": 318901950570391480781263214668434859336,
+ "(151, )": 269082159585401611459725029027900535156,
+ "(150, )": 177990076861932019743373825976505030671,
+ "(149, )": 126205458538120590030134699318510296328,
+ "(148, )": 133109874930143151746201336168955347259,
+ "(147, )": 144603766829615669034975503515081838075,
+ "(146, )": 294048247211213547987152713054538312874,
+ "(145, )": 58735050718641366981477617083741514109,
+ "(144, )": 32360197257693611858606346951297865006,
+ "(143, )": 312125138692788834112383283484448732882,
+ "(142, )": 211244176819374316665029509940842437069,
+ "(141, )": 47699620654215390082675403983385178451,
+ "(140, )": 321460057871502638958270630237422087771,
+ "(139, )": 97817972562609242634204118164838487735,
+ "(138, )": 150869807292489536509771893657799388575,
+ "(137, )": 91127832664040375657129153785488880032,
+ "(136, )": 6633753825643563997119393292482321956,
+ "(135, )": 302751428530735504023893208725706792355,
+ "(134, )": 190889868132526079146984193292952604994,
+ "(133, )": 43118705798336925513284207456278436957,
+ "(132, )": 194808934351297541809928977538229053654,
+ "(131, )": 112188697735361389008678695298284147441,
+ "(130, )": 10963532341766883988604555961635397869,
+ "(129, )": 97532463226327542510100988098314699508,
+ "(128, )": 254219187159793965666907849606692214777,
+ "(127, )": 302596222256553380902371644916456660484,
+ "(126, )": 164025472903951469359757446392708821852,
+ "(125, )": 114339793729146671846503422976480968929,
+ "(124, )": 257615459008090665967916760316891754290,
+ "(123, )": 262634147631483153626846363409122414587,
+ "(122, )": 303514265406732356721903901235790125307,
+ "(121, )": 289540524047927345574132419821134879813,
+ "(120, )": 241953891345483882103139614550063157848,
+ "(119, )": 34169528629740875492988438001861842862,
+ "(118, )": 134399415526485301460273596687576485534,
+ "(117, )": 21397376181282874526810103072108650496,
+ "(116, )": 189453077708247680341397319814900170084,
+ "(115, )": 327690922917486335668890186183100963242,
+ "(114, )": 203078464493366114281849492911896470553,
+ "(113, )": 235873708567306885389864801084995031060,
+ "(112, )": 333777075148594349357714953750132521111,
+ "(111, )": 163988131174047445340711256735003018479,
+ "(110, )": 83186132694778952707946788337698512737,
+ "(109, )": 199813101146251569234020985083106269154,
+ "(108, )": 169107936005853405474566106246354449622,
+ "(107, )": 134932540588358152593251691040984704431,
+ "(106, )": 121118921195043956045070470595505073990,
+ "(105, )": 123305269160746163422632145429353451137,
+ "(104, )": 179868336583267367308134474806111992930,
+ "(103, )": 114541204054904537686570512993847974226,
+ "(102, )": 197932808728683278204361680389861917202,
+ "(101, )": 104752491972260361450979703271391533027,
+ "(100, )": 88443520317211227850712282722928273446,
+ "(99, )": 216911655648606741916725261803822286537,
+ "(98, )": 169506668489382950009450482051065806467,
+ "(97, )": 34869510953537361796056519525861879454,
+ "(96, )": 66544183879969579249245930183554600114,
+ "(95, )": 336346447311304670206328798125250196249,
+ "(94, )": 237032191002161084677315023075555336605,
+ "(93, )": 287892665035025545637291305563118147034,
+ "(92, )": 240107640913466537167660101611701853927,
+ "(91, )": 209353685187997171195561238880270762817,
+ "(90, )": 7438536877639807236588993445984634571,
+ "(89, )": 41320524485315179503463278973874060163,
+ "(88, )": 91746536211622659618097316391809711755,
+ "(87, )": 63972619298614113945459089316983807943,
+ "(86, )": 984522709974503403977768152357634866,
+ "(85, )": 71402564122835216529594714964809267698,
+ "(84, )": 111116030406692058849844237429371398475,
+ "(83, )": 194946735772834159844832121472346625144,
+ "(82, )": 108487827054913623512251205831110349391,
+ "(81, )": 304123193320099411981373450347306301336,
+ "(80, )": 320723845383538481667162779067238281915,
+ "(79, )": 105686971374844068442886757552282411873,
+ "(78, )": 261631993966157723664829282956396517025,
+ "(77, )": 47529895563658698363365625295606124035,
+ "(76, )": 278865374308950746116406441557441807761,
+ "(75, )": 240426568937586626571237265188788783303,
+ "(74, )": 254536817657888287153003371644389076543,
+ "(73, )": 174267066723157821719104308632655137249,
+ "(72, )": 203679008138183242385336834096299886997,
+ "(71, )": 59607754951118478971851140764244441511,
+ "(70, )": 288326857002692662260116585367342997457,
+ "(69, )": 213182232030686812418663528970408477418,
+ "(68, )": 211424969788048487754094602462654152494,
+ "(67, )": 6148052212015794136874050882436030435,
+ "(66, )": 36447409337381547070666465788420935605,
+ "(65, )": 268101014693254083177845407322127777577,
+ "(64, )": 236329552462300018901741603269631209203,
+ "(63, )": 70889824132317383877924306172635477287,
+ "(62, )": 134931006785290833401228553411642179549,
+ "(61, )": 91805369480546222593315462308070633000,
+ "(60, )": 285049111389301693088784016435037343186,
+ "(59, )": 284355421583204038350508460356499189371,
+ "(58, )": 164099431860615919427595182896829160952,
+ "(57, )": 43004500084810225014403706085469058485,
+ "(56, )": 181366628950560934618904437418648108951,
+ "(55, )": 298965558761706426076647215107753700733,
+ "(54, )": 245665194426593695186858948601959319099,
+ "(53, )": 234687016510352269183632591035888912928,
+ "(52, )": 326915818132144928165847054558321787043,
+ "(51, )": 220507440887040912420443647462853621953,
+ "(50, )": 313683602172495401614021454298380723874,
+ "(49, )": 320420473687847471877199209290837740196,
+ "(48, )": 137088730157715072810765964002548721039,
+ "(47, )": 292566087446004217736838014422415408403,
+ "(46, )": 13851265882638473006092645732188751151,
+ "(45, )": 269561289296377132712057887948699106323,
+ "(44, )": 244993470704932386411122785929399492404,
+ "(43, )": 226634301509318426311657915949961453796,
+ "(42, )": 20148073309556757548395833762314956483,
+ "(41, )": 172941378436426746523897153273163705561,
+ "(40, )": 262931983119369067211454126329459335518,
+ "(39, )": 117183102860347277104972968317774345010,
+ "(38, )": 252954510470541245717152704273472483022,
+ "(37, )": 31814071008674020389358792077809896902,
+ "(36, )": 127654085830845200708143346200828769505,
+ "(35, )": 107939655435687178157310639050911912337,
+ "(34, )": 217754234930238324324837870405351846749,
+ "(33, )": 52615808976052275416021235975355165781,
+ "(32, )": 179998465092732523358052639174061051344,
+ "(31, )": 168287898594547556940802780141616032152,
+ "(30, )": 319733474318367129922154895814648863827,
+ "(29, )": 128545141971115355150550961364385180330,
+ "(28, )": 327857437773299528710766935878990357644,
+ "(27, )": 147614693557171416535889204860182507099,
+ "(26, )": 271532460902211829118507794185121755152,
+ "(25, )": 300499290656897837231817222723760920792,
+ "(24, )": 214971060985098131877399997300663243523,
+ "(23, )": 41959705611205027431816030402444184952,
+ "(22, )": 76689803310003169109155303600056396412,
+ "(21, )": 318328377109345190352573738888873235499,
+ "(20, )": 247352352959260103058030322672277467001,
+ "(19, )": 210037187839704582642352751660479225285,
+ "(18, )": 20369401939280942907126149964685799603,
+ "(17, )": 7010068575083740630499072425493123181,
+ "(16, )": 245804699036556765535761273363457091500,
+ "(15, )": 311955739101991489011923174994266526294,
+ "(14, )": 52881402712572038120353808407988530198,
+ "(13, )": 320763428992920544142893048761918776957,
+ "(12, )": 317888090163202035775447874263956162233,
+ "(11, )": 160593640780900535439106939354897864256,
+ "(10, )": 320370959379109026316093943480983576915,
+ "(9, )": 70910939250118147735728438689984603005,
+ "(8, )": 134372213129697543244486653549126468882,
+ "(7, )": 94206994993471600674804815673240295684,
+ "(6, )": 290162137145063871765267160916706029691,
+ "(5, )": 189896206842760435839703210401323775344,
+ "(4, )": 283066512518775963647185018045792989150,
+ "(3, )": 191644774388994368495732509977025924922,
+ "(2, )": 902050147780858048170417023380844920,
+ "(1, )": 181871219391920767336363464300245387116,
+ "(0, )": 124157886448785963474673161320068328443
+ }
+ ],
+ "my": [
+ {
+ "(0, 1)": -125899823110384709916817034053899382079,
+ "(1, 1)": -20829863361241377950033827753675145008,
+ "(2, 1)": -50717256281754653505345386215503001551,
+ "(3, 1)": 136968133225875897510873910464011096202,
+ "(4, 1)": 76660194237824873028397011243826224139,
+ "(5, 1)": -29332567653680321825369303396788712831,
+ "(6, 1)": 159358857987890770964553097455351492239,
+ "(7, 1)": 81504791307080727910618790248926959881,
+ "(8, 1)": -125365447909893403276130349507649638155,
+ "(9, 1)": 75203138033811964044685154291214648074,
+ "(10, 1)": -36608453784804705011013361466862240651,
+ "(11, 1)": -157825338098648310983029568863403304532,
+ "(12, 1)": -64057237772216003087385593828069438439,
+ "(13, 1)": 110861083993660529555779377668806597938,
+ "(14, 1)": 49070432224218154201558851270994399741,
+ "(15, 1)": -12122101948564836744048155081859593456,
+ "(16, 1)": 1359592210798477496127727872902697725,
+ "(17, 1)": -57716715636214871996750142682686717051,
+ "(18, 1)": -96111370291742147956052805088286175722,
+ "(19, 1)": 166657323983210719661510604848456768153,
+ "(20, 1)": -61552959119587562756566854702005079738,
+ "(21, 1)": 112509960339117413046434074488841036744,
+ "(22, 1)": -60162261927389170938370352989465792488,
+ "(23, 1)": 123419160991938788527567075669046151272,
+ "(24, 1)": 38413185325635240655449254222573493758,
+ "(25, 1)": 293561145634436017079080562221280225,
+ "(26, 1)": -117172681534290964062951461602509799918,
+ "(27, 1)": -43591914884469782330856421747685883350,
+ "(28, 1)": -33781032105501632050939533649141872012,
+ "(29, 1)": -113447169326589023824330308933859933257,
+ "(30, 1)": -164988962077556457333192136445537843057,
+ "(31, 1)": -119846673132724010221072243951909475092,
+ "(32, 1)": -92509849824088865390388496751336193312,
+ "(33, 1)": 147501151850814344252472604158671198136,
+ "(34, 1)": -67151325575383263797278511810173866327,
+ "(35, 1)": -169073344151296557679343636585641418117,
+ "(36, 1)": 131291460285386919603872110664818515962,
+ "(37, 1)": -152611121181265670822681349059527316980,
+ "(38, 1)": -8124938787877948975979169547992997122,
+ "(39, 1)": -102537588503751321880447144004239519477,
+ "(40, 1)": 3820917686604299369177859721936455406,
+ "(41, 1)": -38169491504172777274453273190698254701,
+ "(42, 1)": -49054381979409427112856571083686777301,
+ "(43, 1)": -78750299244725253235717978607652940673,
+ "(44, 1)": -80699098669916402003499409295120656345,
+ "(45, 1)": 149097516355080433239140345529900956089,
+ "(46, 1)": -103718620963289485137457416397570136189,
+ "(47, 1)": -158556589263320740028306706115170916946,
+ "(48, 1)": 123312409658368183799004771803498316992,
+ "(49, 1)": -153529835899622944583596657054209126702,
+ "(50, 1)": -132535011478128176707382978303535410765,
+ "(51, 1)": 47672075800242978164085048691238311898,
+ "(52, 1)": -92351085670068628111520144057061008241,
+ "(53, 1)": 128999957372329962810096199332738592927,
+ "(54, 1)": 66213429377966079219318805455411115378,
+ "(55, 1)": 13642956913007050148987751720088675722,
+ "(56, 1)": 120956004481302134470672355632931994707,
+ "(57, 1)": 38047043049944253939928911936858964711,
+ "(58, 1)": -135512232251351249988484593343903843548,
+ "(59, 1)": -105471813135592171107305755272238154349,
+ "(60, 1)": 166523048220162944020801560878266123024,
+ "(61, 1)": 113542581490980454861983177330982786759,
+ "(62, 1)": 20135323607249786968300433092853365872,
+ "(63, 1)": 31080668714115238014831570494215436699,
+ "(64, 1)": 29187504089278004455619781200280515551,
+ "(65, 1)": -146050119489326261862602691925650914587,
+ "(66, 1)": -82286173831560749643375210648972707993,
+ "(67, 1)": -50840058606514445497735032834552740100,
+ "(68, 1)": 71856277811542977842197850751199188216,
+ "(69, 1)": -139401182261439141207147786360453338572,
+ "(70, 1)": -146974680886062988531880857961657357016,
+ "(71, 1)": -113256766434185825780481802428278061393,
+ "(72, 1)": 95299950850431009535012163205453852638,
+ "(73, 1)": 127795030407073905134867832580003243361,
+ "(74, 1)": 45290923981915161017305356426864568755,
+ "(75, 1)": -162836847191710466511168913109656932536,
+ "(76, 1)": -86886328814683589583663574418514475985,
+ "(77, 1)": 54955643006832915532680796722022877639,
+ "(78, 1)": 103777980174256399871495543778074895210,
+ "(79, 1)": 74698452863142907413226995708600030509,
+ "(80, 1)": -53149679069445561932006042929210885077,
+ "(81, 1)": -36763288043390866779934530179290420962,
+ "(82, 1)": 18227749188205474674702552247581196482,
+ "(83, 1)": 77648570462686380100579538062616198932,
+ "(84, 1)": 66043215754293457312622013900955314136,
+ "(85, 1)": -146156887782202771401715724747488220231,
+ "(86, 1)": 51190692210786060224880521151901349570,
+ "(87, 1)": -118384437982988923916309691763567322677,
+ "(88, 1)": 96666667912128252768474823222631713370,
+ "(89, 1)": 4154731628043907908995372087039514296,
+ "(90, 1)": -1958283289985440879055267683878351560,
+ "(91, 1)": -135655191727998225730047511469988446288,
+ "(92, 1)": -29864635683583436705884202669600988207,
+ "(93, 1)": 158959986148247851410594950472010773055,
+ "(94, 1)": -157506010390178494122070000400296797671,
+ "(95, 1)": -20616913843416718796392728018450563881,
+ "(96, 1)": -120672963360137398597099449487467645588,
+ "(97, 1)": -65180678881085522331485688163831202005,
+ "(98, 1)": 112601231782673613846288481889733304336,
+ "(99, 1)": -96981119584046357503166685104857578974,
+ "(100, 1)": 58038693425773846190826930111824769603,
+ "(101, 1)": -16733374180244274805835059782180261367,
+ "(102, 1)": 81292914154335519532249308080986940375,
+ "(103, 1)": -144153017451097622324523233860067470680,
+ "(104, 1)": -67040043046359455496084913755207961276,
+ "(105, 1)": 140212379642495162037143767838652286185,
+ "(106, 1)": 151741239378602274713545251543883998942,
+ "(107, 1)": 128158651826721683482139055183618469812,
+ "(108, 1)": -119916960949902262337670986964180846947,
+ "(109, 1)": 67298448138732608116925571441772448214,
+ "(110, 1)": 114137873998718610225714277792828269753,
+ "(111, 1)": 160938191473792526865045066549040224109,
+ "(112, 1)": -143869477023873877234195769005199676246,
+ "(113, 1)": -55464414876753413088688883923343419727,
+ "(114, 1)": -67394536534987908185669499425086826250,
+ "(115, 1)": -19468662692880146960292188998489396658,
+ "(116, 1)": -126048279426756942810204379551672448205,
+ "(117, 1)": -146068756888821888920579173137011298075,
+ "(118, 1)": 82088076693060255986040661752107077577,
+ "(119, 1)": 169842445914567910547116280576709840922,
+ "(120, 1)": 78754103372873388653089068898395464363,
+ "(121, 1)": -124765675145924177612682606883234999709,
+ "(122, 1)": 40474526400604368040557382465593544982,
+ "(123, 1)": -136936670910928498144353754695359690106,
+ "(124, 1)": -15744243290867531270167978729630008992,
+ "(125, 1)": -121350460871945937413383521862449919677,
+ "(126, 1)": 151428591486245263450537251249318974572,
+ "(127, 1)": 434979533890396236487720432271463612,
+ "(128, 1)": -7111366466078034485278893742143864173,
+ "(129, 1)": -74447207721669266615547520843171918684,
+ "(130, 1)": -28334874609857944755648838130027714640,
+ "(131, 1)": -142869152396976931774984389422444385891,
+ "(132, 1)": 140412708194038249342750102141860585154,
+ "(133, 1)": -64095325528340354979491515719796794588,
+ "(134, 1)": -163417441115545112567250098685166602950,
+ "(135, 1)": -141607217311012263090143807139065857295,
+ "(136, 1)": 31875858579701800834774254385318999906,
+ "(137, 1)": -113278723397319047151737900461313092382,
+ "(138, 1)": 89750818604859018557632372165021574837,
+ "(139, 1)": 84523628004501475829630788945145118720,
+ "(140, 1)": -107327782003030892073374818945095223682,
+ "(141, 1)": -110349459521594271616362528947455723346,
+ "(142, 1)": -59301867048846761294551186401642659304,
+ "(143, 1)": 57375341728397211332941264726432606079,
+ "(144, 1)": 69608362389625871761620687676337298402,
+ "(145, 1)": -133160184952959787475335326934010802134,
+ "(146, 1)": 19650973480398074877563166337307178074,
+ "(147, 1)": -52492701395034195207215501095694838798,
+ "(148, 1)": 24959251488776864307894162464762808419,
+ "(149, 1)": -166477067887625679695968888655895639766,
+ "(150, 1)": -8050902307224115913176195791669473629,
+ "(151, 1)": 161807572438904938632943909325483541030,
+ "(152, 1)": -65870379267104607150818278153113821185,
+ "(153, 1)": -5474629835437140760565101428342625940,
+ "(154, 1)": -55697306135740080074322562190145346934,
+ "(155, 1)": 23862210858974359341727233830094294498,
+ "(156, 1)": 165155707282372937458989321959544193224,
+ "(157, 1)": -84527720320315718225802107523257302654,
+ "(158, 1)": -158773079264601841620830117880435493700,
+ "(159, 1)": 166721586868453660597254341503389463292,
+ "(160, 1)": -14486275412956225725290936636989342675,
+ "(161, 1)": -91828294940912687142142739170649398544,
+ "(162, 1)": 1045389098320366497103570146828235199,
+ "(163, 1)": -91788704362191522320823481391984655849,
+ "(164, 1)": 73015303693743946240254970821060852212,
+ "(165, 1)": 13845534876421505370366433002280667920,
+ "(166, 1)": 43749785416822822422427511730207376775,
+ "(167, 1)": 19162320336296227198241882720797002975,
+ "(168, 1)": 54515419627999614999101736199571585235,
+ "(169, 1)": -153883371485329315985107716979938704687,
+ "(170, 1)": -164825573829893142123520529703859504984,
+ "(171, 1)": -95721153604517860457124731667043624065,
+ "(172, 1)": 18126956501861726451584440610949818368,
+ "(173, 1)": -130412237563979346026685104795721986092,
+ "(174, 1)": -83684992576066038286308675557816736837,
+ "(175, 1)": -82012365313796771365941326198768895658,
+ "(176, 1)": 156506033241184211365622845392655563150,
+ "(177, 1)": -115693804993966925938566923221113346219,
+ "(178, 1)": -48523471744224818175042519884819616973,
+ "(179, 1)": 136942654881185129655296797704142866726,
+ "(180, 1)": 42530370790636015552493327934737506875,
+ "(181, 1)": 115678510137359171491801895852046393407,
+ "(182, 1)": -17516113066135541554337800360227460643,
+ "(183, 1)": -148386245941823003253064141716125260995,
+ "(184, 1)": -24052732251264228220688017988296644830,
+ "(185, 1)": 21721391188427920989362121390468979415,
+ "(186, 1)": -55633372178073743322343379363267295356,
+ "(187, 1)": 50850501579448893420138849112530057940,
+ "(188, 1)": 122759526030224907399420783280533775959,
+ "(189, 1)": -72240759762078865034757623310438351580,
+ "(190, 1)": -75101564440173707567613006526695377356,
+ "(191, 1)": -94203257323401681270347340939647907560,
+ "(192, 1)": 130244072199098427079101866366079664896,
+ "(193, 1)": -46094298530722877862799444946492770110,
+ "(194, 1)": -89870638603148097200280368538443809376,
+ "(195, 1)": -134057864126833445272486476062580271091,
+ "(196, 1)": -59324047799703923390007788703009320008,
+ "(197, 1)": 94368341094917733944482970458578247544,
+ "(198, 1)": -86318174331865168829902562393359049661,
+ "(199, 1)": 136853519021613409622934689234865626713,
+ "(200, 1)": 126558062045907254173143732563921895304,
+ "(201, 1)": 83184813235904825325797579995410409239,
+ "(202, 1)": -97072869085172857137942536807741720663,
+ "(203, 1)": -39846490828020466536517771552121671958,
+ "(204, 1)": -100669202233238898711446176000051358639,
+ "(205, 1)": 30712180662960566853875136700343714486,
+ "(206, 1)": -79704499605624430146752712076052702257,
+ "(207, 1)": 78897550388803627232348798989212717928,
+ "(208, 1)": -112284207215866442227487695270066555689,
+ "(209, 1)": 159688636228594883417339276433105179007,
+ "(210, 1)": 121661012638810469253440703870580521772,
+ "(211, 1)": 168783531439943812413253820983827548464,
+ "(212, 1)": -63054941274833783949524486548127344732,
+ "(213, 1)": 66197933795669092074609903036729705573,
+ "(214, 1)": -37260193059379314877277065897364942530,
+ "(215, 1)": 42899762562077246813670275212567559913,
+ "(216, 1)": -156350301544343312301360541830491619915,
+ "(217, 1)": 98262560463551675010550071646887899431,
+ "(218, 1)": -41015026488459340558432750634296250234,
+ "(219, 1)": -112681188635427186256382977904958989372,
+ "(220, 1)": -101446964811550987082562637430671340741,
+ "(221, 1)": -36148672259515339574368861657030180005,
+ "(222, 1)": 73567564282601885028567267630922445335,
+ "(223, 1)": -162536316731464531554896759422625368225,
+ "(224, 1)": -12597128295515100894046232200728366676,
+ "(225, 1)": -16762351992765823711270566753141669367,
+ "(226, 1)": -40131107334147130509985239340975865648,
+ "(227, 1)": 26752546558493694446726826503101185111,
+ "(228, 1)": -59317561807509261887657173581973001288,
+ "(229, 1)": 156697419993738463021223799533119056877,
+ "(230, 1)": 29529907594517680588050549497008042162,
+ "(231, 1)": -48286482864312058263753960754352619817,
+ "(232, 1)": 50551160911754637959338132683220245323,
+ "(233, 1)": -157137069439392150302690398344033307868,
+ "(234, 1)": 87449040986596249206995291885091399616,
+ "(235, 1)": -156251065535343549665195118516052106952,
+ "(236, 1)": -96526234645134434828092836177129565885,
+ "(237, 1)": -147609980492758061186424399103660251814,
+ "(238, 1)": 45040455411233734383915610059670407595,
+ "(239, 1)": -164569344087430549150530228619245670020,
+ "(240, 1)": -158131478822499337039380791447179690754,
+ "(241, 1)": -150058580676407741458329249602442501042,
+ "(242, 1)": 150036118618107086809169150535067857729,
+ "(243, 1)": 25967367206387270336444265502670174674,
+ "(244, 1)": -164124237073994871301288563159052266875,
+ "(245, 1)": 144385463590440844105528816170725421943,
+ "(246, 1)": 151548650936307795283917865942848515600,
+ "(247, 1)": 93522334892028102413068518411664882765,
+ "(248, 1)": -158890935845215715532082288940778285357,
+ "(249, 1)": 91469228511663131566459617165140355487,
+ "(250, 1)": -129915568667790712651082756980397265587,
+ "(251, 1)": -50482774051966276100344603680192303647,
+ "(252, 1)": 20928973356097191488009602899798451561,
+ "(253, 1)": -124406931720601719571751654948182802225,
+ "(254, 1)": 23444755749737347631853531908893174519,
+ "(255, 1)": 111011112292980601715167326544924942933,
+ "(256, 1)": -41305838990806416116829701282656477308,
+ "(257, 1)": -167439592569969896789596471872846043575,
+ "(258, 1)": 54458237946988291367137876093558654374,
+ "(259, 1)": -62034218786482447035155610557997338283,
+ "(260, 1)": 21763548275115314459976800356898241583,
+ "(261, 1)": -98700947283510290588220608331443486268,
+ "(262, 1)": 103331648462446720403206471321885706792,
+ "(263, 1)": 83055057143747810499800408212743816088,
+ "(264, 1)": -58690828949470875484536717011178299444,
+ "(265, 1)": 6741766542373330386073460875930662546,
+ "(266, 1)": 110212770142452927273257974801094953504,
+ "(267, 1)": 51208684169220173276403652947592474640,
+ "(268, 1)": -79459380179203884677482914616272606788,
+ "(269, 1)": 148992155588702453712695748373926928816,
+ "(270, 1)": -161266902138141119641004890894566247736,
+ "(271, 1)": -44339510682073213814112452498741580168,
+ "(272, 1)": -41680413755228003252272553475551652131,
+ "(273, 1)": -24104481423313755819451614399459423268,
+ "(274, 1)": 100505858477671909461762628046451163167,
+ "(275, 1)": -83736062391823431543638987159252960228,
+ "(276, 1)": 54710917546370168102512002679073917063,
+ "(277, 1)": 110037339045076304782742365077282550677,
+ "(278, 1)": 127775569740176279106598944505158278924,
+ "(279, 1)": 131133296545726671608167341182211098225,
+ "(280, 1)": 93807626170375222993108788595335660358,
+ "(281, 1)": -135980779244828136457452875268909050327,
+ "(282, 1)": -71565352882208221172242623771169342330,
+ "(283, 1)": -150410466922733905789158799771835297105,
+ "(284, 1)": -17187713456928078600897898774674881542,
+ "(285, 1)": -30541092311623872837281173601491155072,
+ "(286, 1)": -83281892616069728369719695655409177429,
+ "(287, 1)": 20526538290450360846958206475383487513,
+ "(288, 1)": -35370949690292254809980011772025623226,
+ "(289, 1)": 85400979948372923497225257996607464182,
+ "(290, 1)": -59317109835694363388513496372254861923,
+ "(291, 1)": 161862863566128703703744408831468519051,
+ "(292, 1)": -131203091339933409396397258350092568330,
+ "(293, 1)": -80632925695611579902174654487761522761,
+ "(294, 1)": -106558810331092487443579145639407298562,
+ "(295, 1)": -106595663900625796970839174690391698459,
+ "(296, 1)": -101040735579304759634051774331228870800,
+ "(297, 1)": 168655632751179013173656662268690151163,
+ "(298, 1)": -134727467533503376455707988332154596202,
+ "(299, 1)": -98679314351889273606575604443838756849,
+ "(300, 1)": 24497282639593212630758116274315326345,
+ "(301, 1)": 24617220458859146667487692387935927886,
+ "(302, 1)": 129796558094194966947174628686704414731,
+ "(303, 1)": 165758536796322846734273161722556812174,
+ "(304, 1)": -20127226884597544984764058802547728555,
+ "(305, 1)": 83603297204424179314709254902008730780,
+ "(306, 1)": -91411017107065220489422906119793583085,
+ "(307, 1)": -72032277108760753888610775533489813683,
+ "(308, 1)": -150907281371204022028328237239552474090,
+ "(309, 1)": 69633112926091327285591627645030700013,
+ "(310, 1)": -22164327286870947173235253303883729272,
+ "(311, 1)": 7266290394535370437416773425975776200,
+ "(312, 1)": 147179844943491133182253979558376744356,
+ "(313, 1)": -96553345117096107109257340496468748442,
+ "(314, 1)": -19725930775913450241602803642986969296,
+ "(315, 1)": -913160482714007806792792744683864473,
+ "(316, 1)": 95452298060360570717882527221929906837,
+ "(317, 1)": -128460276867795256993256512403103998684,
+ "(318, 1)": 100346856177207859192211455671127261578,
+ "(319, 1)": 93991172720100550687575477258070196432,
+ "(320, 1)": -91300335826908875255767522925133420710,
+ "(321, 1)": -165687072187485099918060815044433615051,
+ "(322, 1)": 118697607799635402993696810683603311019,
+ "(323, 1)": -71038318450318409436258742229787791608,
+ "(324, 1)": -14965429818363573595444728186645980667,
+ "(325, 1)": -87650826043885646746006232681802608805,
+ "(326, 1)": -51806740932180458154513487874411843936,
+ "(327, 1)": 126497204717805836119674433949703948903,
+ "(328, 1)": 53833774911045714587717374052758631053,
+ "(329, 1)": 161390278494575929257465052371131888490,
+ "(330, 1)": -117599663974481301682912021727183837316,
+ "(331, 1)": -156958696413453222210299183239723596445,
+ "(332, 1)": -108464522783186636790874351673304961552,
+ "(333, 1)": -80686621862671018238427240281919271889,
+ "(334, 1)": -129833852935566379474455067525975989621,
+ "(335, 1)": -42963057045209717694279436717221566074,
+ "(336, 1)": -154309229006759225809525610215531463799,
+ "(337, 1)": -109782378956713284231009211897032788991,
+ "(338, 1)": -90017365724315775605802235848612768741,
+ "(339, 1)": -36346955998827831633478893931780379400,
+ "(340, 1)": 46590627626828834462972479697922459020,
+ "(341, 1)": -164539167212441359769616373585325977842,
+ "(342, 1)": 75771181427272680552701139280278995150,
+ "(343, 1)": -81068368459700316517802553443087289781,
+ "(344, 1)": 86276199334152745604793013993972757899,
+ "(345, 1)": -152949450451132655557729509788943431144,
+ "(346, 1)": 168310393960293224059137092563971802972,
+ "(347, 1)": -78264588414872664684979726220342930686,
+ "(348, 1)": 168217500982954079147391314570178509702,
+ "(349, 1)": 128718598816991855998773081432334273125,
+ "(350, 1)": -149161477250525842404701104917105399869,
+ "(351, 1)": 151432053772683899061660952840942746092,
+ "(352, 1)": -155317215607597775659874360328133891513,
+ "(353, 1)": 152798216501348855892304820498330062424,
+ "(354, 1)": -45388580994229545217567135235141975434,
+ "(355, 1)": -67966297873169995218750046477242230704,
+ "(356, 1)": 79244085004682456334701739544579633518,
+ "(357, 1)": -47503190592680453425132835857854495227,
+ "(358, 1)": -14267300915148016589550938154801968121,
+ "(359, 1)": -43377251732869956267966304558780886385,
+ "(360, 1)": 77184906037964454521452131149297078806,
+ "(361, 1)": 1082520427137866753361656650651503557,
+ "(362, 1)": 9787952850566662599795005784389261500,
+ "(363, 1)": -164205115810726266745010038252866834815,
+ "(364, 1)": 56698789171992560439382151201011648190,
+ "(365, 1)": -87700058168218351909273696628048328275,
+ "(366, 1)": 39471056393500243928980470321539965513,
+ "(367, 1)": -151036701769364905857806143070028895908,
+ "(368, 1)": -143326629572397478760803438424691673135,
+ "(369, 1)": -78767689668015362570199004140656411319,
+ "(370, 1)": -129541290480519818861431817537596309242,
+ "(371, 1)": 91291750553667611253091455988290640921,
+ "(372, 1)": 54699985594747148791893728819898938117,
+ "(373, 1)": 113643632245977725783370956902318919904,
+ "(374, 1)": 134456589532019718015529402183328227078,
+ "(375, 1)": -167350078670414237252259923256626160347,
+ "(376, 1)": -125729879377891461665852874247298387023,
+ "(377, 1)": -321315235091087058521524156812376603,
+ "(378, 1)": 124754730745516972491517317077646757211,
+ "(379, 1)": 29584433836736461421142505464151100914,
+ "(380, 1)": -40390958425292457965865169942110940697,
+ "(381, 1)": 136073545197312895282503388618881193006,
+ "(382, 1)": -155498482834477566749436491122449357811,
+ "(383, 1)": -82504512250951664394919017982033198906,
+ "(384, 1)": 31774208681498773950525620519874807455,
+ "(385, 1)": -146483410833699190262386772533312049407,
+ "(386, 1)": 52308942002071498714355728973063079201,
+ "(387, 1)": 87208870131331151747848619420671299095,
+ "(388, 1)": -86081072242756439799008435678702953655,
+ "(389, 1)": -93314864714275069917186129614652315812,
+ "(390, 1)": 158330045702855360103660232603423755597,
+ "(391, 1)": 24580438175636411955863288594088685633,
+ "(392, 1)": -47082418308086498855861185979364317767,
+ "(393, 1)": -38695555949568169614583308779120399361,
+ "(394, 1)": -27934999137833093405167182415569753622,
+ "(395, 1)": -154370599893583405882793235436528782427,
+ "(396, 1)": -165182219990740843181458685349190053391,
+ "(397, 1)": 144328595265862791720744978291243892259,
+ "(398, 1)": 12182002477311017773841291518478124797,
+ "(399, 1)": -134262471699634885976999540848853989518,
+ "(400, 1)": -9256925921968081568659266617106222903,
+ "(401, 1)": 122372366281995316533956797262770322627,
+ "(402, 1)": 79905668027589034379419176207237229336,
+ "(403, 1)": -56863595446920637323153578624906930061,
+ "(404, 1)": -144317271644110012315203505387194694473,
+ "(405, 1)": 64615737639321062323234973759271926583,
+ "(406, 1)": -116539441060160058471528980741493527807,
+ "(407, 1)": 89922525272354145971942081360053519685,
+ "(408, 1)": 47687390247259558863307670141854237594,
+ "(409, 1)": 65145161066808615270171712733534869384,
+ "(410, 1)": 139517528019832211465836396226925128170,
+ "(411, 1)": 135717492315049428492638951987536566349,
+ "(412, 1)": -127222735119693736110993192099538961259,
+ "(413, 1)": 101663377979511048053397966508965060122,
+ "(414, 1)": 7868497976135009661555432085205563384,
+ "(415, 1)": -151616956785949854708950462379231117915,
+ "(416, 1)": 166186774817051696879706677024079717147,
+ "(417, 1)": 89884871059198892989673516413635555627,
+ "(418, 1)": 20920924683959418372591054196411373450,
+ "(419, 1)": 74499207163524283518465648586571592475,
+ "(420, 1)": -26807830470543509136359865110816336663,
+ "(421, 1)": -15883858845963974044389859493709947416,
+ "(422, 1)": 5811128337769015154133211498617534069,
+ "(423, 1)": 137664392916648250406853334936337204707,
+ "(424, 1)": -143972601332876783853685958658966333171,
+ "(425, 1)": -105925805649898952055247021847076522494,
+ "(426, 1)": 165942019156161800326828811836095756641,
+ "(427, 1)": -140793899621626277820101149496962539328,
+ "(428, 1)": 88233196878625682028556442291792263082,
+ "(429, 1)": 81811856398108266674850326503970325764,
+ "(430, 1)": -140101345544981000897388655143967212558,
+ "(431, 1)": 140730300566137019895397074043688573664,
+ "(432, 1)": 101583281028122957146656639170377396030,
+ "(433, 1)": -39662187303436979712637448686877861408,
+ "(434, 1)": -34370239012825166501542517869120665314,
+ "(435, 1)": -893370639835456805148612824774348339,
+ "(436, 1)": -113803119447500536957459329096384366247,
+ "(437, 1)": 692616813070710083560711373231327798,
+ "(438, 1)": 66314773112668968199466163664863571290,
+ "(439, 1)": 70756567417617956571010945854706604894,
+ "(440, 1)": -1031913323835851156378578544126142158,
+ "(441, 1)": 37972791968482540094183440202757773936,
+ "(442, 1)": -35161058920878326281732849761041524460,
+ "(443, 1)": -158280136296053098249864557356795018015,
+ "(444, 1)": -29078240708887863397922853145773478183,
+ "(445, 1)": -42131595742356785953670121065009603103,
+ "(446, 1)": 129742160306833884852258895353111931076,
+ "(447, 1)": 68965545673761089040414061361303859830,
+ "(448, 1)": 119824879169081002546506259412180550448,
+ "(449, 1)": -155366789780035282078231268019217837492,
+ "(450, 1)": -8388802048831311760571637907277724470,
+ "(451, 1)": 24668846429103839766715406304038951693,
+ "(452, 1)": -130590766327670753232192430933196997671,
+ "(453, 1)": 22449804108231293994030442631851259096,
+ "(454, 1)": 4827553698956397294273196420150391963,
+ "(455, 1)": 113308191781631257569160362435355385699,
+ "(456, 1)": -34875560132095689518091218660243346970,
+ "(457, 1)": -106847805320508791083650308924000397487,
+ "(458, 1)": -63329221349116138198617880093067061508,
+ "(459, 1)": -133219430577319167113943261226263974092,
+ "(460, 1)": 53390949315396761847372091069390058401,
+ "(461, 1)": 10710274354971972456927369861994542699,
+ "(462, 1)": -118395212250147521756563641829013627706,
+ "(463, 1)": 53856870385685418074088912742142974409,
+ "(464, 1)": -66984724979535218956449799848378152972,
+ "(465, 1)": 13622052363042670723574942435439474405,
+ "(466, 1)": -148173969536996912668654484066596503908,
+ "(467, 1)": -162310857357480260377755654708115230626,
+ "(468, 1)": 21986174183696231242156996020952563719,
+ "(469, 1)": -77169664114247570106200104113603098858,
+ "(470, 1)": 134538296195689941314160826314170630324,
+ "(471, 1)": 24451273755841684922418252412983756930,
+ "(472, 1)": 140691058551398525203130654945899933515,
+ "(473, 1)": 85419173074476178765489340423067477932,
+ "(474, 1)": 152191700510794356842372343640841528159,
+ "(475, 1)": 610638944037692163935718491871400449,
+ "(476, 1)": -55403055366013565071321043834292676242,
+ "(477, 1)": 3745316706562384876246988768652394998,
+ "(478, 1)": -31423328653136088407989605655980842306,
+ "(479, 1)": -147207366518966658928916414592583743967,
+ "(480, 1)": -116468554930152563822453841953673498776,
+ "(481, 1)": -15205193448593680912439696237011242168,
+ "(482, 1)": -96989183603755166889380909086111794606,
+ "(483, 1)": 44805144207684297735800843613711746480,
+ "(484, 1)": 114646087769372253125379062910428990671,
+ "(485, 1)": -104030705607210892589828900773982999233,
+ "(486, 1)": -122876798469375787181497723996700277834,
+ "(487, 1)": -39664716565705351773000255754542550304,
+ "(488, 1)": -102550992565851977462827139724881265380,
+ "(489, 1)": -71101572682458369630902702997002901077,
+ "(490, 1)": 77923579904063483454661547727252163670,
+ "(491, 1)": -86708171664958221945092610770091712972,
+ "(492, 1)": -124424815503876207487801564955469236111,
+ "(493, 1)": 77241285232465822491147761235603375758,
+ "(494, 1)": -161604801284718875743382795795882714896,
+ "(495, 1)": 28019273313697026463138196644924234188,
+ "(496, 1)": -170043707293617850104316579838417033916,
+ "(497, 1)": -51570134582303148956804367188235348739,
+ "(498, 1)": -18196741429457924307575442062957968438,
+ "(499, 1)": -31551180934650373764087297516590737432,
+ "(500, 1)": -131130749055039290034370211577403980246,
+ "(501, 1)": -102580810524337299216428207702528539451,
+ "(502, 1)": 117896416766630630026274202911843214972,
+ "(503, 1)": 54175433542802665448794444874818666386,
+ "(504, 1)": -36088172645509539970915744027914228537,
+ "(505, 1)": -12713146518712354460384459591803638878,
+ "(506, 1)": 122681359852607296337009254351380084021,
+ "(507, 1)": -73703823920086068792099593019070422801,
+ "(508, 1)": 30600435444403993109547621443356009033,
+ "(509, 1)": 96751188953374944151293635990150065298,
+ "(510, 1)": -120544097098075909174467388954572159452,
+ "(511, 1)": -99465795352392338048833533817306765117,
+ "(512, 1)": -134576045335113654909357267008371803023,
+ "(513, 1)": 13371112045989779932278476268747876797,
+ "(514, 1)": 1143454139157786947942204976582286234,
+ "(515, 1)": 70130283775492459147168849098494347408,
+ "(516, 1)": 66638030720066684194289454242482072458,
+ "(517, 1)": 5243348354499693930217221724538821243,
+ "(518, 1)": 117247862158586361052387914851240416757,
+ "(519, 1)": -129011149404617679540019364827708527014,
+ "(520, 1)": 145217338892182814756581185369674375885,
+ "(521, 1)": 101158560132377016671530665616485691849,
+ "(522, 1)": 114162741831944531419404373633287709757,
+ "(523, 1)": 23587474269336965270811090662649174210,
+ "(524, 1)": -105097938267228177684712429237321796042,
+ "(525, 1)": 13283376952342220469470201514311066136,
+ "(526, 1)": 21549303334214981796975035700612474861,
+ "(527, 1)": 164810938630500081057339164483838658451,
+ "(528, 1)": 55259798119333588724425968983282119300,
+ "(529, 1)": -49682155961081473817272271635898181793,
+ "(530, 1)": 90660945537886431670958822213954616862,
+ "(531, 1)": 54425285172000906114935314936429309561,
+ "(532, 1)": -131407880092085471944277465620096920274,
+ "(533, 1)": 95952655006933236249759174392614979046,
+ "(534, 1)": 95748603220523290647294628678223575878,
+ "(535, 1)": 23540062298292011664491772687014288904,
+ "(536, 1)": 81542834920072406794987750465505831714,
+ "(537, 1)": -71874183944225702266276320660292288231,
+ "(538, 1)": -23125942046237999474859671882185923253,
+ "(539, 1)": -75314766628976181584032963598154951959,
+ "(540, 1)": -115699644903765045609087022215214560944,
+ "(541, 1)": -45020120224849112256694533029712825161,
+ "(542, 1)": -129348850334994493480495101462595722800,
+ "(543, 1)": -60823037157243624855248296056682386173,
+ "(544, 1)": 127086259597383271723213858032864467469,
+ "(545, 1)": 5082506291590337163025508699893909336,
+ "(546, 1)": 141830557443299490088749658877612089389,
+ "(547, 1)": 93461421302644623140592274491404359679,
+ "(548, 1)": 13458294375861458525456729027127235577,
+ "(549, 1)": -45579082481283952126196176061062781257,
+ "(550, 1)": -74695789678673995595909314220338325303,
+ "(551, 1)": -28255945525966978450466075514174009312,
+ "(552, 1)": 130855706454976532213782988262649922291,
+ "(553, 1)": 107283637384022061964884997952854462304,
+ "(554, 1)": -63705175384125558709389747378220519621,
+ "(555, 1)": -115736482559843822238494185392561641969,
+ "(556, 1)": 24740401086329198355440162930616123428,
+ "(557, 1)": 48394818724209804822634298533401791632,
+ "(558, 1)": 79238554552704321773788815164656159554,
+ "(559, 1)": -24303431666757436122271368363070974241,
+ "(560, 1)": -34980023648843722939538070755354962958,
+ "(561, 1)": 150633181607244824761453305150822082859,
+ "(562, 1)": -87721602483234747273819082466428913255,
+ "(563, 1)": -25072560233679355811350914858461190445,
+ "(564, 1)": 42527629958407557176728313956098099653,
+ "(565, 1)": 63590733861471027141913798961312992618,
+ "(566, 1)": -7372119023836733023898247541838224559,
+ "(567, 1)": 130997000725546010155557539398578465836,
+ "(568, 1)": 149439453257172092473841111337865721981,
+ "(569, 1)": -166941975761988302471344511033226391258,
+ "(570, 1)": 167805003299363321179287970951625489818,
+ "(571, 1)": 83866914606690445735868774155950378635,
+ "(572, 1)": 150690704742626460902043314335039004534,
+ "(573, 1)": 58669033348378391452388414769751623999,
+ "(574, 1)": 40559968286990171155015618359055704689,
+ "(575, 1)": -167022404258060317119206202291763678163,
+ "(576, 1)": -39000605592674768744084222902533183455,
+ "(577, 1)": -81649955086881702020520959046711402766,
+ "(578, 1)": 18194249406908557415755237999032828332,
+ "(579, 1)": -71171794660931710769971156509835411506,
+ "(580, 1)": 120473496548195373179690972283496852943,
+ "(581, 1)": 78689338433948302360103418589220695089,
+ "(582, 1)": -112348981530325547554318584458977145705,
+ "(583, 1)": 101155854286958273026199602425857406651,
+ "(584, 1)": 135892441118592091819205656771204523957,
+ "(585, 1)": 101939033491347968123945864388249953186,
+ "(586, 1)": -129153478068262916742346725952166481134,
+ "(587, 1)": -53882151274965288327357679754672552625,
+ "(588, 1)": -18611077535798982431224934846475952488,
+ "(589, 1)": 45828826852854711325276461765930545318,
+ "(590, 1)": 99078931047148978475234230010054549363,
+ "(591, 1)": -72227270839926937539390130269124760462,
+ "(592, 1)": 54860632767714163073592137154139261039,
+ "(593, 1)": -27712631670755442665766996447381026797,
+ "(594, 1)": -81082738602404599334502652096171918926,
+ "(595, 1)": -19783873983818129716204071194855574370,
+ "(596, 1)": 26977726970990236778899947339052676486,
+ "(597, 1)": -145902312809019869540883869553670237911,
+ "(598, 1)": -164755999576785782349282980436336791737,
+ "(599, 1)": -85246863667243818204557795565250903445,
+ "(600, 1)": 35833041273485580214917867593453596417,
+ "(601, 1)": -23289931001851519658143037841923272943,
+ "(602, 1)": -118892438833526889792129306515717448346,
+ "(603, 1)": -114638981542036780079812588545897887720,
+ "(604, 1)": 154513648974099251243607090929139292068,
+ "(605, 1)": -169644453190837042385068852007266342750,
+ "(606, 1)": 148878641776096342602739225620054029686,
+ "(607, 1)": 18089501449407656900426001993154229818,
+ "(608, 1)": 52932261414013058241140388259395513637,
+ "(609, 1)": -124145869645781304640477404751520307075,
+ "(610, 1)": -124217567854919673125050716906487766836,
+ "(611, 1)": 430124331875484255101295364538710898,
+ "(612, 1)": -106700111178202286236413527517990084364,
+ "(613, 1)": 99160568582399540224563262080685803202,
+ "(614, 1)": 26568223262173920527635752334868351629,
+ "(615, 1)": -117087154673930471207394993145914065294,
+ "(616, 1)": -170031756217935276364672833218631204331,
+ "(617, 1)": -148185564687955500636663026337993078535,
+ "(618, 1)": -41440362888321317642767841915323622396,
+ "(619, 1)": -6099393139789265036085637677902208697,
+ "(620, 1)": 52426129539013349541541122175675201179,
+ "(621, 1)": -8787418006297473429696478442919481826,
+ "(622, 1)": 102053306807724185583054786826526808160,
+ "(623, 1)": -167426120525075877922288375420494950451,
+ "(624, 1)": 17898698260552152396005855386637089127,
+ "(625, 1)": -89460100852385988157861720545234780585,
+ "(626, 1)": -170039997045875274970113037681631963093,
+ "(627, 1)": 167021585074720949341283105909424955,
+ "(628, 1)": 31271818271706093176019068873069851683,
+ "(629, 1)": 128821306870256591766006091113070979695,
+ "(630, 1)": -50393455200884896682969053146322058740,
+ "(631, 1)": 64361748489962141001108119091568706222,
+ "(632, 1)": -129600076834564138727499220755349267925,
+ "(633, 1)": 134182124536149908010963320007428632706,
+ "(634, 1)": -158515650138250305691165911520030119318,
+ "(635, 1)": -97279650229821057859279319014179496801,
+ "(636, 1)": -51577692744158028015976877800953828799,
+ "(637, 1)": -128296034850894557278378391433263309891,
+ "(638, 1)": -142425098123253575434748677756976641479,
+ "(639, 1)": 161468648341907224183925080786028240383,
+ "(640, 1)": -164569206351284620773334175633719051534,
+ "(641, 1)": 84110030670905212085776996847702459767,
+ "(642, 1)": 86835176552614297426998218863346018844,
+ "(643, 1)": 48105608258512480297487053730361072942,
+ "(644, 1)": -68681206810400967492075748231769168875,
+ "(645, 1)": -19394473449921841039345821262647843830,
+ "(646, 1)": 115390228736495972500205659236849472883,
+ "(647, 1)": -55942389147288234881002461545531836893,
+ "(648, 1)": 87577040139130615846780835050039762930,
+ "(649, 1)": 39688321643471480952244334864844371131,
+ "(650, 1)": 131767211934499774720575471441854703322,
+ "(651, 1)": 128196020754688843327115404061379390160,
+ "(652, 1)": 33647226043432054385651442782863648659,
+ "(653, 1)": -158678832015943158122009928959790100604,
+ "(654, 1)": -52549332890891462393960317779190944636,
+ "(655, 1)": -77907207520398043849721255897545343808,
+ "(656, 1)": -73889757005295627048501082237139352409,
+ "(657, 1)": 112477782331116624439534376470193279056,
+ "(658, 1)": 159881312661066236243594697105969186352,
+ "(659, 1)": 12946873704030947960680182666184552122,
+ "(660, 1)": 52335033000061757956204983414896700468,
+ "(661, 1)": -63842046931959563931735809104504265279,
+ "(662, 1)": -53825431136670274970976769609796618305,
+ "(663, 1)": -53055796518328480135071437301123454601,
+ "(664, 1)": -162439112378905320376519416415928797533,
+ "(665, 1)": -64056321333047649928474477705287083380,
+ "(666, 1)": 165306727883216797766740217146289171585,
+ "(667, 1)": -234440190916190434508738970058165549,
+ "(668, 1)": 160454242055589554153179999614530884232,
+ "(669, 1)": -147847442603388777977864179192535061737,
+ "(670, 1)": 35930495042180617945847370229983140861,
+ "(671, 1)": -61650909731728372929853018765092981498,
+ "(672, 1)": -72562768956976445848496462623256549688,
+ "(673, 1)": -131317512980126984699961094054411526198,
+ "(674, 1)": -35747830101370840870351795034907157824,
+ "(675, 1)": 75492123385717552112656262848357889442,
+ "(676, 1)": 58245060129239015113769158755545692039,
+ "(677, 1)": -107996637806412005819155004214204042738,
+ "(678, 1)": 85483011311983361249167642105401256204,
+ "(679, 1)": 134070688567521523590758983924242341701,
+ "(680, 1)": -103086000087594810474245393488233341470,
+ "(681, 1)": -26543614019544208555298324610767926223,
+ "(682, 1)": -98044044988922395331529132575951674067,
+ "(683, 1)": -159446553459662330166614482245958228069,
+ "(684, 1)": 1467707201661392934485265760786345681,
+ "(685, 1)": 12471204661731504143092656249886572962,
+ "(686, 1)": 149266094092445359665197753295812515990,
+ "(687, 1)": -17348289969405396176598991950812944293,
+ "(688, 1)": 110117150207826451478678443065239616508,
+ "(689, 1)": -56794296953871404898707682347528716975,
+ "(690, 1)": 8559983058539282265352266984442028216,
+ "(691, 1)": 113541041180754290059116926250073711833,
+ "(692, 1)": -62321054196346855849394637822711053507,
+ "(693, 1)": -64221134328945603332125802516072604318,
+ "(694, 1)": 152507535653542731217724775070090241522,
+ "(695, 1)": 62534546742725232414606171646212481546,
+ "(696, 1)": 22465806697083950328389265726598110876,
+ "(697, 1)": 156432727220451267722276749560105970924,
+ "(698, 1)": -92752723157826997783230786287489279153,
+ "(699, 1)": -46495543809802567513494105893684628846,
+ "(700, 1)": -120507985902879616935042509710575311545,
+ "(701, 1)": -86735981604050899071958173684968900248,
+ "(702, 1)": -27148387599689898850920695406099474293,
+ "(703, 1)": -17208749080070526466195881295637989974,
+ "(704, 1)": 122286733807880765830012064170791474191,
+ "(705, 1)": -113141943344880142078301718878152932761,
+ "(706, 1)": 39442206961702265323099565304916580022,
+ "(707, 1)": -76968907354010099081312167734446856762,
+ "(708, 1)": 116986417356712276136924144615545299417,
+ "(709, 1)": -24433066561648368786006267139173889121,
+ "(710, 1)": 25080328219924458080803384242390122119,
+ "(711, 1)": -146715740631149727912342980882159521838,
+ "(712, 1)": -79882484658650232134522253570001178716,
+ "(713, 1)": 158583329759641319830317067512756274741,
+ "(714, 1)": -68814659036355746015781972270730392314,
+ "(715, 1)": 42041705711558775534892327208044159280,
+ "(716, 1)": -122469576508736578601929261277825813888,
+ "(717, 1)": 93856135315054351969321683142408590198,
+ "(718, 1)": -58327495279185676540502371278753430292,
+ "(719, 1)": 144352967437113149674082653205831495661,
+ "(720, 1)": -142074391190277215017118500489944963401,
+ "(721, 1)": 30573630562107066262123795966181344968,
+ "(722, 1)": -121930249431935033847566612403356839864,
+ "(723, 1)": 25156970053157527532567952439025071951,
+ "(724, 1)": 126409218806292330611802551163103182866,
+ "(725, 1)": -116785342535606628407392623902451079177,
+ "(726, 1)": 61589222194126740344362028242708479886,
+ "(727, 1)": -96429427159773868592883549721211985688,
+ "(728, 1)": 103320415636180493127626593225343113061,
+ "(729, 1)": 60314056891052456585337453993335121733,
+ "(730, 1)": 73072403829804076861110309131400191991,
+ "(731, 1)": 96289790316597021412661549833612599409,
+ "(732, 1)": -101116045388973629961371073018697960700,
+ "(733, 1)": 45252779228424801182547054651542977954,
+ "(734, 1)": 113475533601508681525371585797963533688,
+ "(735, 1)": -146558717295106469720763973408558144078,
+ "(736, 1)": -111366497122078232433515239785181079651,
+ "(737, 1)": -1690946316936344673053082278985877924,
+ "(738, 1)": -73315509097753734902222591290357222507,
+ "(739, 1)": 132839691731940086584090886121731311537,
+ "(740, 1)": -66661734799875736276914388452139409866,
+ "(741, 1)": -130482275390319995870361488582951707849,
+ "(742, 1)": -11158073885940079668418568508712905631,
+ "(743, 1)": -84593144544974460902666940120338844045,
+ "(744, 1)": 78222981418702774514160450182963627628,
+ "(745, 1)": 991322447247355532346275162764147644,
+ "(746, 1)": -90381058748185315819986718740643357161,
+ "(747, 1)": 24058224138718123573334592303269690975,
+ "(748, 1)": 127106101254212316071120327881415058516,
+ "(749, 1)": -99498542340857459222319858008770368849,
+ "(750, 1)": 99567354671370868118001199324842306573,
+ "(751, 1)": -15328930934381796070177774377203143258,
+ "(752, 1)": -6734078315591005925222657150892625583,
+ "(753, 1)": 103542732865066317310404599685401457870,
+ "(754, 1)": -143346380819996596759663795487866087439,
+ "(755, 1)": -162990001735490559417944559686584803169,
+ "(756, 1)": -82770842955189113090577076425776835450,
+ "(757, 1)": -131434159816797770849296148013047659481,
+ "(758, 1)": -120577991665719976536382403341211562420,
+ "(759, 1)": 167401801373994182725232918985445719880,
+ "(760, 1)": -78710658070600432376128015036381983286,
+ "(761, 1)": 16333013553294333546923472730669069766,
+ "(762, 1)": -112422458816887716314583520498361372848,
+ "(763, 1)": -117908639625223879286721475660732122749,
+ "(764, 1)": -160000533194778609967192245199549458229,
+ "(765, 1)": 120880069058727155042653933826244036678,
+ "(766, 1)": -138593914304635147003364474883865874423,
+ "(767, 1)": -156782522045601303864263281759479678840,
+ "(768, 1)": 77766363103040572763368894967782309233,
+ "(769, 1)": -145369190090649076920958416345539399623,
+ "(770, 1)": -153590811051703886562628305124858869292,
+ "(771, 1)": -154943039454612260605552983205528154534,
+ "(772, 1)": 112656551139681557825567640280410498714,
+ "(773, 1)": 166325165263706734668590705688184654587,
+ "(774, 1)": -160453446718103894273472703955311446291,
+ "(775, 1)": -144262718021481529371309735338762436041,
+ "(776, 1)": -77079745117916220890337934225008116820,
+ "(777, 1)": 14614822101524130727366396874276316112,
+ "(778, 1)": -155362507659280223822886009165815306189,
+ "(779, 1)": 27644776179579822526085926048559352832,
+ "(780, 1)": 123494748155323378559604261033768738408,
+ "(781, 1)": -162939717689731853775934106983245902764,
+ "(782, 1)": -17124241337125070607014315782737047089,
+ "(783, 1)": -13312722437888575973732021851851865919,
+ "(784, 1)": -55290289842173880920138882416134825457,
+ "(785, 1)": -153992124176631077588647379554343653044,
+ "(786, 1)": -48378213292356052792591488745748776309,
+ "(787, 1)": -104140112851624292057262899612737970362,
+ "(788, 1)": -103388367044707482154063390169821542820,
+ "(789, 1)": 89210353659162792197214917219846136507,
+ "(790, 1)": -99673176191734129644119915711115833403,
+ "(791, 1)": 10908275096608821807421654135117693644,
+ "(792, 1)": 89376661973644260263054911291401884625,
+ "(793, 1)": 62846771512812552784342165848925511747,
+ "(794, 1)": -64019789725351272521438907328224548325,
+ "(795, 1)": -75028934724359929817003793446653966837,
+ "(796, 1)": -83943758147496086895504334229460025646,
+ "(797, 1)": 11560273744584749489653643797193342789,
+ "(798, 1)": 106375341639107582190495388703563389859,
+ "(799, 1)": -118458793622103017445986613776893819362,
+ "(800, 1)": -166253543189201312486653922931075630771,
+ "(801, 1)": 31941239127612727861793107459709369901,
+ "(802, 1)": -72061634460342638144793956577550801289,
+ "(803, 1)": 138934167556951915716843010560823717903,
+ "(804, 1)": -111639593318768221255439045551999221646,
+ "(805, 1)": -129735730947318886088101711402443555686,
+ "(806, 1)": 105497669099788819245114410581617780526,
+ "(807, 1)": -152842041596373702686815527881681265440,
+ "(808, 1)": 3517937536369099710795167965355589448,
+ "(809, 1)": 73516427867479333973859273049877207299,
+ "(810, 1)": 116777506338619171585371886889182389869,
+ "(811, 1)": -127138409938161110754659997999154713382,
+ "(812, 1)": 124713799102985910960476363118400848159,
+ "(813, 1)": -89523736693015943064638452640250707152,
+ "(814, 1)": 75931773829653130615194937067268584862,
+ "(815, 1)": 16918116366737737267148207647849469958,
+ "(816, 1)": -7084974555808645919992390838291988101,
+ "(817, 1)": 67693276756431159095772937961658636788,
+ "(818, 1)": -113922871442338635409288027063188498721,
+ "(819, 1)": -108295309854965531897620943959020506443,
+ "(820, 1)": 82481878340862221293611813596162468277,
+ "(821, 1)": -105955319833960942278320318026007193848,
+ "(822, 1)": -118319711999998750793176394105288685978,
+ "(823, 1)": -11786370468091904959836629830504975757,
+ "(824, 1)": 112280033128517974517826469346977477840,
+ "(825, 1)": 16528687864639660732004361564347685759,
+ "(826, 1)": -114515334446171004312391160767877908012,
+ "(827, 1)": -105756290960459188510500072295670774456,
+ "(828, 1)": -92235908558690098088298592867292000219,
+ "(829, 1)": 141297455499041029789685074110204090820,
+ "(830, 1)": 93829170075516274952719218685064922284,
+ "(831, 1)": -99602212108307616894496055206591898052,
+ "(832, 1)": 43279070902794449847530919459393355646,
+ "(833, 1)": 120354902403878832469682309629853806068,
+ "(834, 1)": 66462310294044634535579258326921228050,
+ "(835, 1)": 114919779438445963328722264114257472396,
+ "(836, 1)": -24389129768128073924093861911327495877,
+ "(837, 1)": 51376086971832110639006653195629016500,
+ "(838, 1)": -34233565154378213114682554014927295925,
+ "(839, 1)": 20214643722888440839482136968061701789,
+ "(840, 1)": -63018999839386589109123364805385072709,
+ "(841, 1)": -159900607341240748386516665573795295878,
+ "(842, 1)": 157696233937897868119287946393622606266,
+ "(843, 1)": -75810045765900983172016613454925069165,
+ "(844, 1)": 8486228977366310752652059467599238241,
+ "(845, 1)": -72807809056999357839761720017549501086,
+ "(846, 1)": -61581751014287679720168775328838720433,
+ "(847, 1)": -18321327934483933620493596514616305920,
+ "(848, 1)": -23128290728778036884546553940913695895,
+ "(849, 1)": -27346263111167325919227730403584737954,
+ "(850, 1)": 96898795497459141362862512741201287907,
+ "(851, 1)": -119308143567132350285351008393335669798,
+ "(852, 1)": -26697175206047057686336512604909047743,
+ "(853, 1)": 56488223143221060382862258539052664854,
+ "(854, 1)": 168179880533796889842583524123717830848,
+ "(855, 1)": -30812145535524129553866952971903036744,
+ "(856, 1)": 89126078373695233297340011668061820312,
+ "(857, 1)": -71048378566637706763881732678484883039,
+ "(858, 1)": 120679879674063600468479893462914006105,
+ "(859, 1)": 54053880652827953901603937964042977295,
+ "(860, 1)": 4447225394587902705616459149196979697,
+ "(861, 1)": 32206786369015423531466688257987838002,
+ "(862, 1)": -82018087618710762708618711456281165272,
+ "(863, 1)": -39576707206139324756440429323916731776,
+ "(864, 1)": 69796372624342192210262653884691033920,
+ "(865, 1)": 76140833113865661145990649920938994633,
+ "(866, 1)": -90623482032204582663041705922920609726,
+ "(867, 1)": -1519366322028093878202190228149461443,
+ "(868, 1)": -48706013694401797142747291460231131670,
+ "(869, 1)": 54427692555316632041902876822591128120,
+ "(870, 1)": -118927075457685052358803804547857519960,
+ "(871, 1)": 65070482151612461931710666945703810684,
+ "(872, 1)": -16885709027349925678622835906294470459,
+ "(873, 1)": -18464954095538479581690018706515560831,
+ "(874, 1)": -155942468263261924521973975166113639541,
+ "(875, 1)": 4552388678540145958223564255505775726,
+ "(876, 1)": -7564898896632,
+ "(877, 1)": 48146352500800972717803036602767724333,
+ "(878, 1)": -137613168,
+ "(880, 1)": 882
+ },
+ {
+ "(0, 0)": -95215135865853493651647305235364260575,
+ "(1, 0)": -69635163521113154710271086021233208296,
+ "(2, 0)": -118803209435111174683154662326281922969,
+ "(3, 0)": 96668159617770178930857741369498019516,
+ "(4, 0)": -48015887854112646506847760221320362646,
+ "(5, 0)": 3754056944107361441033204328762931230,
+ "(6, 0)": 82491554046824940892817127504494894760,
+ "(7, 0)": 92255580431081344614480260506666584583,
+ "(8, 0)": -2481687478181546889868113945893987173,
+ "(9, 0)": 121895569215947688539958255223418580083,
+ "(10, 0)": 76948476783569360342289679186709185824,
+ "(11, 0)": -38001117283237769823477923244574737195,
+ "(12, 0)": 85554992757936551368378140984137554741,
+ "(13, 0)": -124225171862218359371723807726983756701,
+ "(14, 0)": 66977634606066537949445664508055689805,
+ "(15, 0)": -120750947704259457540904579548327988127,
+ "(16, 0)": -136415136501850904224107068717733554303,
+ "(17, 0)": -129806931533375278382276039217105621652,
+ "(18, 0)": 142608094928441268372771823207290860056,
+ "(19, 0)": -141486577771584272464753767893525667439,
+ "(20, 0)": -160766329183686553896170117302168337116,
+ "(21, 0)": 162812511401152069113611747579037519572,
+ "(22, 0)": -93889781430314607681956865197258302058,
+ "(23, 0)": 74324714632072885291941640785876226706,
+ "(24, 0)": 91688507100163279309073694520012630524,
+ "(25, 0)": -117163192262590109072324823266179719139,
+ "(26, 0)": 135246958742832068183923413019729881098,
+ "(27, 0)": -17889094475226517489193465248086568365,
+ "(28, 0)": 29953296073632497470732526094259212332,
+ "(29, 0)": -33206011312087311881958508406984182365,
+ "(30, 0)": 16667376158424062330686071270667818262,
+ "(31, 0)": 71425153678471234997279667290533299334,
+ "(32, 0)": -45419886606476497777964489170043015858,
+ "(33, 0)": 121475784389002492577933180793492698180,
+ "(34, 0)": -168009424582891060647440245173157335801,
+ "(35, 0)": 52669974025177242511654025228302202211,
+ "(36, 0)": 164331318914827817994390284438567561344,
+ "(37, 0)": -190455815022318330796924442650925750,
+ "(38, 0)": 166023865105941643221860477352283636411,
+ "(39, 0)": 65185880070148925773851769490927134379,
+ "(40, 0)": -4484306513257173464314244106727122943,
+ "(41, 0)": -12354075402087986589078306831516251105,
+ "(42, 0)": -90929140534053587077773168398077169158,
+ "(43, 0)": -57445027053049420948838146252125514613,
+ "(44, 0)": 8148166824432725656141720635581211273,
+ "(45, 0)": -122074305504044419799951297582093595248,
+ "(46, 0)": -7520704583217469468664607372162992163,
+ "(47, 0)": 95842691246249844268685579954598578665,
+ "(48, 0)": 100704033715667301876089114060824894296,
+ "(49, 0)": 20998202665249411329039933794642285871,
+ "(50, 0)": -92175851843470109229717302224645691964,
+ "(51, 0)": -24973980619087702437439617320256999269,
+ "(52, 0)": -165361775058346956179993115016499496188,
+ "(53, 0)": -75081152086989456581625155748370037421,
+ "(54, 0)": -68175871605124794706772158192097870869,
+ "(55, 0)": -88597300379864704051039380709652347230,
+ "(56, 0)": -29825691923217368729774026671749021698,
+ "(57, 0)": -82917893927944415686145756898553558177,
+ "(58, 0)": 11583819028529864454524570167678973878,
+ "(59, 0)": -26742583459107932461083953469668910630,
+ "(60, 0)": -72857447986648542274809121864760339651,
+ "(61, 0)": -45633354304851321707249208082776675966,
+ "(62, 0)": -29451416743150127774055895616863266446,
+ "(63, 0)": -80854363417876698585862240414871492927,
+ "(64, 0)": -154727939609127908433909346131284234767,
+ "(65, 0)": 148799548356754163321803910165177251811,
+ "(66, 0)": -99207519274193030413931982747070872566,
+ "(67, 0)": 43910152951818445255143456590424872427,
+ "(68, 0)": 122810283447722230318025059324594280543,
+ "(69, 0)": -98598356234071962429097631166492206639,
+ "(70, 0)": 65915394970211107366970224467026154749,
+ "(71, 0)": 128028620844482718614218394669419472373,
+ "(72, 0)": 114969094894369367621501340556515347858,
+ "(73, 0)": 51697196991060085230612295431386666059,
+ "(74, 0)": 138478458469903598739229117495756304207,
+ "(75, 0)": -22233601024621851044308696105470932425,
+ "(76, 0)": -29140058465722570702903871641310026888,
+ "(77, 0)": 162438615024504838552511149193254810349,
+ "(78, 0)": -118383959455801467493431257237972218097,
+ "(79, 0)": 34413769207340695300086566823676008759,
+ "(80, 0)": -102071996159059123689965136842090943859,
+ "(81, 0)": 62445310875298889959926993198458707945,
+ "(82, 0)": -22440252351184257314656966197686062493,
+ "(83, 0)": 731708610657833595659686100090396293,
+ "(84, 0)": 49090783469955810741106617152098923273,
+ "(85, 0)": -17398520902236477611519074120300774684,
+ "(86, 0)": 12913332269836092183375484636455599480,
+ "(87, 0)": 23334268618706274252721889463086367733,
+ "(88, 0)": -104252368433498530294707585749241656295,
+ "(89, 0)": -108702758524306302668135566635030254117,
+ "(90, 0)": -53339431151390836383296580708918584381,
+ "(91, 0)": -152670347647917513717059314742372964134,
+ "(92, 0)": 59587034733089532881492676876763957361,
+ "(93, 0)": 141297437117069763327964605472584133221,
+ "(94, 0)": 130911274870432655593569902216632546083,
+ "(95, 0)": 6150650725365299599134099946112108027,
+ "(96, 0)": -74056861157935143762155217379333090732,
+ "(97, 0)": -152091027609199245063919278193771761853,
+ "(98, 0)": 132968664034423245042417653565142278802,
+ "(99, 0)": 46837928086198624013349047416664862958,
+ "(100, 0)": -11602708595135748080085454507732488613,
+ "(101, 0)": 4520431311697686872269982317941370397,
+ "(102, 0)": -2918640660465074446157658013963859351,
+ "(103, 0)": 4629319922232364160757402836666942282,
+ "(104, 0)": 69670142292388608885779153548551324524,
+ "(105, 0)": 97616903437769831985678967545861118218,
+ "(106, 0)": 72719603009336789395774384431159800818,
+ "(107, 0)": 113521875705553108259113242528750986208,
+ "(108, 0)": 36613829242167475118237784108590138031,
+ "(109, 0)": 142418925495248425888410164548840811622,
+ "(110, 0)": -48358365952470533010809202713633156649,
+ "(111, 0)": 7735876904341364410643369986985684592,
+ "(112, 0)": 40214116667563767257299417218912682212,
+ "(113, 0)": 158273241725070312455063388132226897112,
+ "(114, 0)": -35413175365142286651472143899060996083,
+ "(115, 0)": -119277278269278119902969754430195605514,
+ "(116, 0)": -11250231342070045502122549703398674541,
+ "(117, 0)": 77559373391315337447234135114475974532,
+ "(118, 0)": 3916298800619502172326416614841003162,
+ "(119, 0)": -65768306924087021115852559071561455874,
+ "(120, 0)": 82616633061236638203809498016748939956,
+ "(121, 0)": 10941576588379970316876888325469732362,
+ "(122, 0)": 15346606904105795845291682116361122037,
+ "(123, 0)": 140884629485789475879988670688337810327,
+ "(124, 0)": 68536551903861111551816813297037198058,
+ "(125, 0)": -34934021839936137008547545294208791278,
+ "(126, 0)": 11346130392764358442748273202819764632,
+ "(127, 0)": 62910525030853404097723436946135719573,
+ "(128, 0)": 83118767267798556149378153396542495132,
+ "(129, 0)": 87528898141699517101902254360385801830,
+ "(130, 0)": 128682054034543940445541410068049491901,
+ "(131, 0)": 123650217423223525499471009808110625983,
+ "(132, 0)": -143063520655060453136975546435725467908,
+ "(133, 0)": 139294957321132647096183722269605542429,
+ "(134, 0)": -138282045532370569087731684440086414819,
+ "(135, 0)": 25944216847456714744274555912614124926,
+ "(136, 0)": -79054965604418201482618502154026822113,
+ "(137, 0)": 44107340640840193871854958013960389580,
+ "(138, 0)": 89274181879751798682443639898762724586,
+ "(139, 0)": -34393450124488842678581990974932645833,
+ "(140, 0)": -138781946372961340169589048909448399878,
+ "(141, 0)": -81520419876563983267838594698699808035,
+ "(142, 0)": -7784939806109652978954983532953610928,
+ "(143, 0)": 35190378795392721889011517532785698781,
+ "(144, 0)": -132493536956048954822874690248680070863,
+ "(145, 0)": -44923939450090926314321899284010647738,
+ "(146, 0)": 19482170874659485951578927047527637235,
+ "(147, 0)": -42984570149163629472083643955688369946,
+ "(148, 0)": -155844138210506116194817871618275353200,
+ "(149, 0)": 13944862144460958588653069294231137254,
+ "(150, 0)": -155662649167552162208106563270937389278,
+ "(151, 0)": 6991423744107589753032036358390584590,
+ "(152, 0)": -3560177884543780076759298637866985266,
+ "(153, 0)": 118555045811961840528131050966363933096,
+ "(154, 0)": 95297129741931169419293483035789956195,
+ "(155, 0)": 41973505753508757638789105503456179831,
+ "(156, 0)": 10344433762625113149055579331178631661,
+ "(157, 0)": 130411033183035433788112298791998016346,
+ "(158, 0)": -31890364319018367096658888008750145489,
+ "(159, 0)": 55080949842831864349550775148945189534,
+ "(160, 0)": 108904305163992079302101115820875492517,
+ "(161, 0)": 2495015403960228398156458493676083737,
+ "(162, 0)": 164443516174660641429797947284614763590,
+ "(163, 0)": 147169541595167174569344631208081575802,
+ "(164, 0)": 13843327337035212970223080896105767025,
+ "(165, 0)": 3935013969507495140409183364183861472,
+ "(166, 0)": -46448680459940667170774304690592438454,
+ "(167, 0)": -82592081130600588180946329099808662639,
+ "(168, 0)": 115998757284603742484944662891099668062,
+ "(169, 0)": 129917797975387842351511301470217113251,
+ "(170, 0)": -56237100225373015313677435624118261605,
+ "(171, 0)": 159362869660898284299038603474303364649,
+ "(172, 0)": 87463587384693595896937066898475240823,
+ "(173, 0)": 158355839609598375722288706179291741121,
+ "(174, 0)": -158049157462841587594214333280685299967,
+ "(175, 0)": -76983507963501620785753992696229517133,
+ "(176, 0)": 170140288193836493156309533157838427692,
+ "(177, 0)": -73926522566799417363202386532398654861,
+ "(178, 0)": 127510305875793854421373614977652063335,
+ "(179, 0)": 117424188438278211029417844151079353662,
+ "(180, 0)": -117227949208880758052367308704645091466,
+ "(181, 0)": -82514442721561723621153685439482522203,
+ "(182, 0)": -23942670528560596842691346333808632770,
+ "(183, 0)": -78357680274573456828367996056100241292,
+ "(184, 0)": 87706694738455252743824972773986051180,
+ "(185, 0)": 3854776483841904143447743560791326995,
+ "(186, 0)": -56554563222885683246828300315934350356,
+ "(187, 0)": 79085298855352830493124770252030831193,
+ "(188, 0)": 100037438762165658817719236242831078144,
+ "(189, 0)": -114246260161720387625390958931290759749,
+ "(190, 0)": -93358737930298784459476755041304386381,
+ "(191, 0)": 154071655564015230062313487255137225086,
+ "(192, 0)": -91357116575551823421314045505456338132,
+ "(193, 0)": 53280751630899658517553344765773991584,
+ "(194, 0)": -3154162992853972081575897891878887202,
+ "(195, 0)": 145938398760256995088300391899456584223,
+ "(196, 0)": 56077473124071776705408171088067948164,
+ "(197, 0)": 4936859974205881277541275701762366470,
+ "(198, 0)": -126122091208968448579617928489488653656,
+ "(199, 0)": -33197204137494124346076863016512228178,
+ "(200, 0)": 54465498319000499339724623694000867645,
+ "(201, 0)": -22148419700751756996533417726734573305,
+ "(202, 0)": -131536659643931855557409168719637763296,
+ "(203, 0)": 99965478927518163185620832484096998665,
+ "(204, 0)": 48470906900925772930215732596469298649,
+ "(205, 0)": 47651362234070220969809233200564173880,
+ "(206, 0)": -127042475422918888309903662835199565319,
+ "(207, 0)": -125277373697812683871267719331366113336,
+ "(208, 0)": 59561286352753515963847857503134298237,
+ "(209, 0)": -154425823336654063413117312538697693465,
+ "(210, 0)": 34063219564282942895520689862264954869,
+ "(211, 0)": 37429334655789966713073820490130489755,
+ "(212, 0)": 9966752019051430476643584736805753062,
+ "(213, 0)": 43828221374345498655678976439753444435,
+ "(214, 0)": 112560304170006386732229594036216304045,
+ "(215, 0)": 73648429832191241865670281955373559362,
+ "(216, 0)": 38920561300120114629940961765836590629,
+ "(217, 0)": 148402600144506968491753405019647276052,
+ "(218, 0)": 133309498509755359996954932952973952495,
+ "(219, 0)": -123980562395044006692404338716268720062,
+ "(220, 0)": -4405890177649271480965887313602116086,
+ "(221, 0)": -153997528408890423963081712257337678888,
+ "(222, 0)": -54001581161983503230205495523008146245,
+ "(223, 0)": -3217357454410562101733971290531655653,
+ "(224, 0)": -169813083690988054407587501753608034251,
+ "(225, 0)": -137775546514804148741898153040309153256,
+ "(226, 0)": -23537932903630554654760917694998432032,
+ "(227, 0)": 130120049321865603598084938652825692632,
+ "(228, 0)": -97373303432008194606018779190032963123,
+ "(229, 0)": 105625562150061758042070426796039971663,
+ "(230, 0)": 73657224468418754968794316661489386133,
+ "(231, 0)": 157736725862102911267309324335279111390,
+ "(232, 0)": -110577580047788837161239973385782515684,
+ "(233, 0)": 164665434857549927434814180664375400893,
+ "(234, 0)": -84553451301696855978576162491619274663,
+ "(235, 0)": -117491351387916153746351787791919114302,
+ "(236, 0)": 38668852880855552180444342620334863442,
+ "(237, 0)": 48924849353755936079096681984311071459,
+ "(238, 0)": -19015456032885334288396174348109733318,
+ "(239, 0)": 10903296022016396544421472641214275027,
+ "(240, 0)": 44593084406000438373453948017482714466,
+ "(241, 0)": 54970207154766908019568153245010373476,
+ "(242, 0)": -100199080644157397571530930003635205275,
+ "(243, 0)": -107951348782101915334486218171529825233,
+ "(244, 0)": 143830210779867443522071497774819360059,
+ "(245, 0)": 54803234442365098406344863526841532479,
+ "(246, 0)": -91429734085800580097063146159438109838,
+ "(247, 0)": -83286653856162830647986248809172384245,
+ "(248, 0)": 151975588746133598385642500750735821157,
+ "(249, 0)": 75473679197415355765605769961588709608,
+ "(250, 0)": -149690471061339167212467349151046183332,
+ "(251, 0)": -123651061551743221597739096586469914952,
+ "(252, 0)": -153449687277077895338104943951742420267,
+ "(253, 0)": 463230546477482403872750762249066298,
+ "(254, 0)": 163163554960798028172172731226139094630,
+ "(255, 0)": -47285911298162774780655480150577311851,
+ "(256, 0)": -154025816526573266976834933478590016250,
+ "(257, 0)": -60282361721199288370739916542528549126,
+ "(258, 0)": 105642669951938160215702004536904949621,
+ "(259, 0)": -19143245198780174047074401323228938054,
+ "(260, 0)": 67593756104254077312924244781555378407,
+ "(261, 0)": 87547993366627775012749412979726141261,
+ "(262, 0)": -102814813212078659424206187057207542831,
+ "(263, 0)": 62384650717014333689997146024100687587,
+ "(264, 0)": -106846832079507492073910888424708368352,
+ "(265, 0)": -31787310107997102832294166418449485998,
+ "(266, 0)": -143531020961127473689048580248557228898,
+ "(267, 0)": -118321675891786560677652805605100872593,
+ "(268, 0)": 136515592525978071239219799912136795860,
+ "(269, 0)": 89538847254843632869932942511643465438,
+ "(270, 0)": -51924382032188062615739207968786569792,
+ "(271, 0)": -36031211196833873854802094366546747698,
+ "(272, 0)": 34620304535158343494086461616193334773,
+ "(273, 0)": 17962901098031354622743168684030423979,
+ "(274, 0)": -131197063676527776119742263628154188782,
+ "(275, 0)": -115969099024054558505191269090302000666,
+ "(276, 0)": -10364642183606733325543302084706224284,
+ "(277, 0)": -142836231522261730757149366887316156009,
+ "(278, 0)": -119618774181141493337575809959179429004,
+ "(279, 0)": -62056003265295622309252129770994093915,
+ "(280, 0)": -64414770008422330333201565370664678419,
+ "(281, 0)": 104379206965048452030991226108193851369,
+ "(282, 0)": -145556950097822369173310155161856540725,
+ "(283, 0)": -74086813617569037101529324924537255142,
+ "(284, 0)": -14100255394311909740571556684443594709,
+ "(285, 0)": 94792615103943272635050869648104149987,
+ "(286, 0)": 45431218223086265596849422541029956354,
+ "(287, 0)": 13697201457212258586297767235133108004,
+ "(288, 0)": 76124265907422579681398090896829539296,
+ "(289, 0)": -16644172247492889980034014190661414663,
+ "(290, 0)": 35231938154495239963414710528199215062,
+ "(291, 0)": 72143570910757543644245744234762456853,
+ "(292, 0)": 61138919437014388516568839268041409886,
+ "(293, 0)": 40367280504880699049700583012434421535,
+ "(294, 0)": 125739833623265387056039149308619148802,
+ "(295, 0)": -56786997839720343291992579623519570206,
+ "(296, 0)": 81516280176624942325874949924559130859,
+ "(297, 0)": -144200474403173033264948335241062143635,
+ "(298, 0)": -77790117291699055996838770183387505970,
+ "(299, 0)": 78103340568633130644414442285789706924,
+ "(300, 0)": 97882915440270447127303201068550877397,
+ "(301, 0)": -81595531045628239374110015366935291743,
+ "(302, 0)": 82010161012549195664716252763309746509,
+ "(303, 0)": -75676001644243756612340036877405414697,
+ "(304, 0)": -51182670623604389048008072218532080879,
+ "(305, 0)": 24581326407076495098480479705602357477,
+ "(306, 0)": 50753182811024553069069359728944171738,
+ "(307, 0)": 152418106304005435081276172815447298394,
+ "(308, 0)": 26707257231791934342418147480300958790,
+ "(309, 0)": 10678358872142733640042851280916108632,
+ "(310, 0)": 107581431583253026850144485567332875401,
+ "(311, 0)": 145753310191129460800640445690439436596,
+ "(312, 0)": -121055037030525385977640472490852237752,
+ "(313, 0)": -35962825595069255045779738062932217987,
+ "(314, 0)": -22693710492006166924705710700758445952,
+ "(315, 0)": 104331142750363668467353576490950558500,
+ "(316, 0)": 23577193486118993113877640910275098926,
+ "(317, 0)": 53319368170327395231216874647939457820,
+ "(318, 0)": 18828987084488904365871447911404297622,
+ "(319, 0)": -160127669797288627589718201872119799398,
+ "(320, 0)": -120188860689491295250933189228301087423,
+ "(321, 0)": 164047776625927978952051053659515529556,
+ "(322, 0)": 78168991488301460491065354404134072182,
+ "(323, 0)": 25035556552493295609695362693198407778,
+ "(324, 0)": 57500317469205357648931548364782175241,
+ "(325, 0)": -23308677856561260032999562713235502962,
+ "(326, 0)": -19041848400428976634873615374439257746,
+ "(327, 0)": -153336702872912255019698058851836262233,
+ "(328, 0)": -54295455586836639906094091934508145260,
+ "(329, 0)": 136451000236112662471206670509799094154,
+ "(330, 0)": -56753257519687442082591255113927565913,
+ "(331, 0)": -1131837334144940351171254131644061434,
+ "(332, 0)": 89821726741350140878433446318465564826,
+ "(333, 0)": -140968311731472016168782108411367015879,
+ "(334, 0)": -7392416400925834220088150909073249355,
+ "(335, 0)": 136008089472190177393422359504881834268,
+ "(336, 0)": -51212990821480596109880391491804590162,
+ "(337, 0)": -128464554700236205959480761765737422178,
+ "(338, 0)": 34154320954271834129983317090765840947,
+ "(339, 0)": -101250356954165065265172497367003553382,
+ "(340, 0)": 46521425195160708128681339817156883645,
+ "(341, 0)": -86286721404271893462892003432471605214,
+ "(342, 0)": 135740540426028943991172557117818934805,
+ "(343, 0)": -4092265334849715401800080986538683889,
+ "(344, 0)": 88783534106479298134119999885952445227,
+ "(345, 0)": 5042923245991067293344331621529308594,
+ "(346, 0)": -103998330152237288796170271829115450098,
+ "(347, 0)": 108993984284643149223549989523912577381,
+ "(348, 0)": 81097242851651278520797188547605659749,
+ "(349, 0)": 12337379678978307952652724089907183474,
+ "(350, 0)": -72984804281989822208834002531309516682,
+ "(351, 0)": -28606852630258439533956092414464270739,
+ "(352, 0)": 23949637780734913312069812270606589317,
+ "(353, 0)": -74211388265783708609705147623538146758,
+ "(354, 0)": 146457428557154981780408646648484246521,
+ "(355, 0)": 147588522165683362349005486272690174417,
+ "(356, 0)": 28874032029682743588906264670067342101,
+ "(357, 0)": -39116902651644256204174362648835711396,
+ "(358, 0)": 159837770923903114992971662785434069444,
+ "(359, 0)": -157787152404351092703531592410125424837,
+ "(360, 0)": -70966590573753100538049593380543441327,
+ "(361, 0)": -164382015529930333633966300967426372371,
+ "(362, 0)": 71918498863055624609896913607975335077,
+ "(363, 0)": 44575964366391594911744411740460880845,
+ "(364, 0)": -114439917954668749324653233469747412943,
+ "(365, 0)": 86712756118407155750695429678920407693,
+ "(366, 0)": 140176826156488871091127151734755267374,
+ "(367, 0)": 122925318931879660701493301862524771815,
+ "(368, 0)": -128741844659527397178557549408872705756,
+ "(369, 0)": -115235820183142171543691995312479707888,
+ "(370, 0)": 90989870626903919398549215835701775273,
+ "(371, 0)": 139872283751442739174545879435029215839,
+ "(372, 0)": 93595635212480236867235974135875052478,
+ "(373, 0)": -129400623925247380123462038671389284228,
+ "(374, 0)": 162816483918974385465181891660392919376,
+ "(375, 0)": -67937319314310323693324953733463829207,
+ "(376, 0)": -96363651777098414842661007925816650872,
+ "(377, 0)": -105426441780407835204423246534576889946,
+ "(378, 0)": 70715304801157357170569181597220592073,
+ "(379, 0)": -161775243565504822695773522602150218851,
+ "(380, 0)": 147613204356088752732099350760845059632,
+ "(381, 0)": 83673372677534862212787589741256403499,
+ "(382, 0)": -124860979091821087822453586258767020447,
+ "(383, 0)": 159668332890174705398231090927482111338,
+ "(384, 0)": -45783310389421543608669868680202435716,
+ "(385, 0)": 98803020477991128896097292559018942499,
+ "(386, 0)": 68160024689505817135741561287783361414,
+ "(387, 0)": -76335423858314276965123362892368348095,
+ "(388, 0)": -111020951347880917036005107125574740660,
+ "(389, 0)": -146264851128120396489091497646868151515,
+ "(390, 0)": -121337600813419946214974558482865733971,
+ "(391, 0)": -147313422919856430066938292808770239808,
+ "(392, 0)": -145166371073204740121027527371509930930,
+ "(393, 0)": -22039631565433149425078664618992203702,
+ "(394, 0)": 100715125512904652778064388252911523005,
+ "(395, 0)": 17898244079303192190730775826201407502,
+ "(396, 0)": 70012559703972084033093853838471843885,
+ "(397, 0)": 28238864642897004257127603301623750284,
+ "(398, 0)": 156024513146977735611288788072551797778,
+ "(399, 0)": -106545977794964082901854695764876253916,
+ "(400, 0)": -84334367854789401754960646791430659927,
+ "(401, 0)": 59009734175720564970617175674522935225,
+ "(402, 0)": -86657735645610240447341630288897057149,
+ "(403, 0)": 105210946145253487836936950481689745669,
+ "(404, 0)": 4145084353282423259530861281937766152,
+ "(405, 0)": -142449216225297459906336736206560750289,
+ "(406, 0)": 105352059462505362108359569566208897778,
+ "(407, 0)": 83347430962590522044662563875998779569,
+ "(408, 0)": 122347076216717604535250177366741263606,
+ "(409, 0)": -66822136827426487628144810415911811299,
+ "(410, 0)": 37615812830323116588912071714715737464,
+ "(411, 0)": 17105847207686921899259662104594927362,
+ "(412, 0)": 123810269684944903623846666848914287388,
+ "(413, 0)": -143883532130719188713449324495357138399,
+ "(414, 0)": -101847486418503314475603245858375331973,
+ "(415, 0)": -162112232024000671854741299034816321769,
+ "(416, 0)": -123309951125113877583831424702841363457,
+ "(417, 0)": 85206451411182510649975360545263007440,
+ "(418, 0)": -120103055444915245631941923818572954522,
+ "(419, 0)": 79277493342078836713517503063051614898,
+ "(420, 0)": -101990074892167177351440846171691235276,
+ "(421, 0)": -74473233325212378363672169252262388829,
+ "(422, 0)": -121872923760386013317156773343202545349,
+ "(423, 0)": -151672578931151577057390597734941075636,
+ "(424, 0)": 99530105857545664447711118278618797342,
+ "(425, 0)": -166472607405331244820480303596822017416,
+ "(426, 0)": -95659174241523055847523816799161576015,
+ "(427, 0)": -154251090969815588435128469084402321308,
+ "(428, 0)": 120455994740420946527727693435332470246,
+ "(429, 0)": 51005306652663892676297940509799212793,
+ "(430, 0)": -64716896185903054063119238363694053438,
+ "(431, 0)": -161205977026566941922481020926234130242,
+ "(432, 0)": -162096785607513597536744803196473006316,
+ "(433, 0)": -58568913525357792738135080257083808078,
+ "(434, 0)": 45639157976912380627078314682402610492,
+ "(435, 0)": 66257686385497931885086632279613217920,
+ "(436, 0)": -83882227252506209405440838286831131227,
+ "(437, 0)": -41530591624937481294965750657294117710,
+ "(438, 0)": 148712358078412259976734191681755495085,
+ "(439, 0)": 25389190049975085747996429056982012156,
+ "(440, 0)": 44058538722053817873573960104738503071,
+ "(441, 0)": 142348993331366701463154712083948375992,
+ "(442, 0)": -68028906151077203965416292941674219407,
+ "(443, 0)": 149156906389894014110810217283359550789,
+ "(444, 0)": -127733368966072907135911154306419905148,
+ "(445, 0)": 121211943917804199376910169687356501020,
+ "(446, 0)": -129005675139018529791056888316906789158,
+ "(447, 0)": 119712104903079683680334768552851682927,
+ "(448, 0)": -15218796831780834815015154246906166310,
+ "(449, 0)": -42204855068852924884233127195657361043,
+ "(450, 0)": -124066222402940790013621659130361477868,
+ "(451, 0)": -73944203945728730363931831264551641178,
+ "(452, 0)": 42154238753875322102854312370047649323,
+ "(453, 0)": 95583030654745548529946024220549761440,
+ "(454, 0)": -72700502812065383663012489633914561874,
+ "(455, 0)": 77006819947738820284504862950245327447,
+ "(456, 0)": -101326293951626759801742764325529010192,
+ "(457, 0)": 144476756542143268739586440444352783707,
+ "(458, 0)": -144167625773396839730025750937802654707,
+ "(459, 0)": -69545221169587071876458651626495293986,
+ "(460, 0)": 55936037307326187889742802095321631820,
+ "(461, 0)": -132880374893584040697828524598590008053,
+ "(462, 0)": 153293136810645333452114673214948076839,
+ "(463, 0)": 111544686791633630571070110693172338538,
+ "(464, 0)": -63749024266164095106698938535243095216,
+ "(465, 0)": 132954362570926296998872111966522208438,
+ "(466, 0)": 82442157981388089629420869288528832275,
+ "(467, 0)": 164884773593542099530363695376294288996,
+ "(468, 0)": -125473034261473819787587670380754713649,
+ "(469, 0)": 2853777874649277430074380687889929668,
+ "(470, 0)": 100507418438070344757277201922633265898,
+ "(471, 0)": 97022066564559978812307173287923774257,
+ "(472, 0)": 58149453148938111778100472514262836843,
+ "(473, 0)": 86468089794429495777153800530388665844,
+ "(474, 0)": 119625586359473770498136559263996258144,
+ "(475, 0)": 1654123524005620711633240621870897354,
+ "(476, 0)": -20640803980052037194593620714387285293,
+ "(477, 0)": -14432072443761893285908854692904131295,
+ "(478, 0)": -122529654645955442491279234434449511079,
+ "(479, 0)": 151305100018667398763409673780134491875,
+ "(480, 0)": -45270640077095632385685799221844090341,
+ "(481, 0)": -130363635247196037909310959937324769770,
+ "(482, 0)": 75298782494944408366683140419756830474,
+ "(483, 0)": -30691094417371530286402364046473039736,
+ "(484, 0)": -303197472342312418601001571649279235,
+ "(485, 0)": -73594925611851112144647543228940239771,
+ "(486, 0)": -145425517379590652687292707124514874861,
+ "(487, 0)": 79475149110194904381645277978093031330,
+ "(488, 0)": 153125046913631628965405620955934800930,
+ "(489, 0)": -47910064941096930182472905005285759487,
+ "(490, 0)": 98991666653282161041984824786592612251,
+ "(491, 0)": -7255310075953484732132405695618492525,
+ "(492, 0)": -23926217901393978978641463759729911219,
+ "(493, 0)": -161653483425641021498483866669500353017,
+ "(494, 0)": 60606511421431421569837717661899084119,
+ "(495, 0)": 8730931074894274036299198069340762364,
+ "(496, 0)": -13326365569645896377014265216333811420,
+ "(497, 0)": -45278374050867452169990733122137805790,
+ "(498, 0)": -166893148121271485724722820965727119605,
+ "(499, 0)": 133808639331292792035472477536449645107,
+ "(500, 0)": -5536289840696116921030855570998217944,
+ "(501, 0)": 123744448758902568761161403920196092988,
+ "(502, 0)": -158630117390769578832718637199994043753,
+ "(503, 0)": 141987434407009207368873399669684702743,
+ "(504, 0)": 73774685447223421690694406981606119210,
+ "(505, 0)": -15579919091268510802589484973584810829,
+ "(506, 0)": -140517499112279734701358292043327602549,
+ "(507, 0)": -123263040926174367459852069605604559393,
+ "(508, 0)": -117284209734139894318036355463679368476,
+ "(509, 0)": 162590545201093967274760619103919466988,
+ "(510, 0)": -138801325602608239421531200525558693874,
+ "(511, 0)": 45733793318049424472364115693861681775,
+ "(512, 0)": 155012826493168171646687493510006464904,
+ "(513, 0)": -121343673115432599056043317167495446650,
+ "(514, 0)": 2788182338723026797850580945553809119,
+ "(515, 0)": 141214313413871441508805074270741897814,
+ "(516, 0)": 114221690530227220957279004153022381766,
+ "(517, 0)": 73856342258501319223407852994734691847,
+ "(518, 0)": 67948631732742394995483872400228265215,
+ "(519, 0)": -82624108484502074375386133780683607163,
+ "(520, 0)": -165143413588954693253425479884572319991,
+ "(521, 0)": -113550102967992171221019828594162685254,
+ "(522, 0)": 131180504169721467160499835404812832267,
+ "(523, 0)": 164422713928344282732720615272486593509,
+ "(524, 0)": 157980231782162104362263482262854493880,
+ "(525, 0)": -164535718644255252940930394176816849377,
+ "(526, 0)": -31225353889562600307917509035046364740,
+ "(527, 0)": -60646062450155763966720217341561984925,
+ "(528, 0)": -96950233886561722014601761631819412339,
+ "(529, 0)": 77008287467968324180873563138345644242,
+ "(530, 0)": -4997872489015742544728343214110400888,
+ "(531, 0)": -2202395447842202964413412764545989511,
+ "(532, 0)": 57478095273387845043095340584937890565,
+ "(533, 0)": -145705677979547998055927000772524724859,
+ "(534, 0)": -102935487599280398874644321117435564893,
+ "(535, 0)": 143649118778497972419661400513032796773,
+ "(536, 0)": -89038304569148187971461117048569701005,
+ "(537, 0)": -45029837896366546303331400288433846073,
+ "(538, 0)": 19032560126825381188580714108204185353,
+ "(539, 0)": -158508131558511784763966326781035256462,
+ "(540, 0)": 79120878133609244650517186422561785242,
+ "(541, 0)": 28603998023399676929749006701914687185,
+ "(542, 0)": 65757691388701874747859916644177031150,
+ "(543, 0)": 72691922249338035054974336270463527217,
+ "(544, 0)": 129010265500650440917003661740929453910,
+ "(545, 0)": 80256719281541042032246705214229026271,
+ "(546, 0)": -21061132550283983771367061162716903521,
+ "(547, 0)": 165805406436167401233005042461863960774,
+ "(548, 0)": 113599655127609455847395518900059443544,
+ "(549, 0)": 96964270902560568840423856889839503489,
+ "(550, 0)": 67662840522325901368205026647015202622,
+ "(551, 0)": -82022774870782805953455083341039144094,
+ "(552, 0)": 6100136605794926620684126309229400665,
+ "(553, 0)": -19626146382403430025145110769973357761,
+ "(554, 0)": -31038901596104973752277995245982837335,
+ "(555, 0)": -68367015348640280541186050704771610718,
+ "(556, 0)": -153667021069877568696955575817329133832,
+ "(557, 0)": 25209357017366486814765650775941423328,
+ "(558, 0)": -22859159814672150085005583192324232233,
+ "(559, 0)": -154136032607225218114405047230107033102,
+ "(560, 0)": -136574384336658168487190901833680114619,
+ "(561, 0)": 97119890397376601974169032241142219324,
+ "(562, 0)": -32343289844758779352268915196590034014,
+ "(563, 0)": -20458222319791570243016621828066855253,
+ "(564, 0)": -133530524389386826049460636433339871598,
+ "(565, 0)": -119730534173208319363388378341940491192,
+ "(566, 0)": 105745360074349395617850913825333108056,
+ "(567, 0)": 143838816343355455627228825614672639639,
+ "(568, 0)": 39190575296848492142221327626836615386,
+ "(569, 0)": 151296918080753581730296211067053482808,
+ "(570, 0)": 13270089066315449719353507490280790645,
+ "(571, 0)": 31546478146451830781104606445062538982,
+ "(572, 0)": 146403816190039212602024520671673208886,
+ "(573, 0)": -126194715618922530521814769568566830827,
+ "(574, 0)": 167876308622698256110531769940126595534,
+ "(575, 0)": 94537717949551111820987884009544103164,
+ "(576, 0)": 91132020946486161407842485869010894463,
+ "(577, 0)": -72699415601509752213384249933024285083,
+ "(578, 0)": -99549812363285969814182438223590590826,
+ "(579, 0)": 118955466017239699300950990000531678560,
+ "(580, 0)": 117473696009552458224728000797204195142,
+ "(581, 0)": -76768892640254460361540198837990407759,
+ "(582, 0)": 87829778823771504829131716165459798902,
+ "(583, 0)": -22767408277705487390875068211575666677,
+ "(584, 0)": -13840777403524625662425714456440880052,
+ "(585, 0)": 45103739548172109224192330683418946622,
+ "(586, 0)": -11291307005673376594972191710244298247,
+ "(587, 0)": -126231492442188213125148186268746334395,
+ "(588, 0)": 68766723854900005626103147019901605203,
+ "(589, 0)": 45161629098996725374816654851978395645,
+ "(590, 0)": -6857173706993157538074548674497757356,
+ "(591, 0)": 35353421533912367297849454197606302984,
+ "(592, 0)": -92523977336804313611454842166729641382,
+ "(593, 0)": 131435972889417498551185801820349633279,
+ "(594, 0)": -21025892173220995341221605331665321759,
+ "(595, 0)": 144730372358736537689125641268452451076,
+ "(596, 0)": -137724331304562991925054402513720291502,
+ "(597, 0)": 22324519524932728091794524743235726502,
+ "(598, 0)": 5328537093951599494657310029110149466,
+ "(599, 0)": -86930497259051491217338242713545766979,
+ "(600, 0)": 84467694340792797390573091789190593702,
+ "(601, 0)": -16900800814740785415458854265568301827,
+ "(602, 0)": 5791442651499726290963703726616502547,
+ "(603, 0)": -48401071351382590502178109649304939781,
+ "(604, 0)": -23701857575231309998690523078654566712,
+ "(605, 0)": -145197088356451341716357041592425456280,
+ "(606, 0)": 66987097346590375726315099716473740317,
+ "(607, 0)": -94451483288855112823833837523352328655,
+ "(608, 0)": 50494673294611566034896235393668434113,
+ "(609, 0)": -165531438273063060541655197482568497963,
+ "(610, 0)": 17180560214429396743834123072593867353,
+ "(611, 0)": 159183972140405939655672291905397735269,
+ "(612, 0)": -160656804413792085838978366425461536903,
+ "(613, 0)": 164251013176477463639059511266381860412,
+ "(614, 0)": -83225335627861817860525419551557585067,
+ "(615, 0)": -19134268559772726850776155534826217726,
+ "(616, 0)": -60153315302721360776605760640129422856,
+ "(617, 0)": -57214522054655968982872015626060272788,
+ "(618, 0)": 108585122643791880791055020383595180666,
+ "(619, 0)": -83974270087391182174023970237274629471,
+ "(620, 0)": 32743999077308106227015597173108907233,
+ "(621, 0)": -100939486718806652974397415203146075295,
+ "(622, 0)": -13971833884713873630606676760556474107,
+ "(623, 0)": -40987919882744959078630995698268337412,
+ "(624, 0)": -35298757319149370913077397622857113178,
+ "(625, 0)": -155703439274062120886010376153661501628,
+ "(626, 0)": 148602157264699539267679273100694409380,
+ "(627, 0)": 111994979807550190608384267122051071902,
+ "(628, 0)": 156028728538593962418291653853610685256,
+ "(629, 0)": 51368207833085284750671895560128331508,
+ "(630, 0)": -31297462582699303437737135634617403375,
+ "(631, 0)": -57808915384350644659990134162740435369,
+ "(632, 0)": 31068678823447670521280147595841180505,
+ "(633, 0)": 95974590473834171502664035146148363087,
+ "(634, 0)": -148880946101213602845527741379666533510,
+ "(635, 0)": 131401930185021352635347139980699617884,
+ "(636, 0)": 40547232872518751949568429036005189966,
+ "(637, 0)": -119579677590813499916846786077880583543,
+ "(638, 0)": -10244016150543405470652064926144794431,
+ "(639, 0)": 77426967613672161081366947928178433859,
+ "(640, 0)": 143102658147448064869093679908392988109,
+ "(641, 0)": -71706327594465183194506459171629837763,
+ "(642, 0)": -21716423397118024799717145797402775272,
+ "(643, 0)": -99209741868007476433386226330690105190,
+ "(644, 0)": 166074207294401966302052302244661944163,
+ "(645, 0)": -84190467884682076479412003631639834201,
+ "(646, 0)": -49936530984840544066332984717248046054,
+ "(647, 0)": -51953275989860591426928070355838162370,
+ "(648, 0)": 63962881312804266943070456104242626327,
+ "(649, 0)": -96285035215793313096631966633245370695,
+ "(650, 0)": 23826645180902563730067338324161481860,
+ "(651, 0)": 58978932411225640017162112893868392011,
+ "(652, 0)": -71577849250468039521288236380347363998,
+ "(653, 0)": 60321938259422794001050310011263315290,
+ "(654, 0)": -131669936901890603824655000733955776673,
+ "(655, 0)": 42195951946018264272277310297653880329,
+ "(656, 0)": 144485473238994540769119137872723084299,
+ "(657, 0)": -132371629261507379126170254588494742283,
+ "(658, 0)": 93200757884002300685759450825166545115,
+ "(659, 0)": -77788728500282692992075224574179184422,
+ "(660, 0)": 26749505204634724718992839080547927482,
+ "(661, 0)": -13868713075972353294339745337584355993,
+ "(662, 0)": -166668867717213441452574923820250362216,
+ "(663, 0)": -39127764512828531053998634157677887037,
+ "(664, 0)": -133435498480252534790505428389353161575,
+ "(665, 0)": -94944953503601592171485227106306236161,
+ "(666, 0)": 55288497875085384525875163645852869844,
+ "(667, 0)": -38830308602089096566090097705394714839,
+ "(668, 0)": -76322017899191845412877444767289685927,
+ "(669, 0)": 105947277126832268805993216684228748247,
+ "(670, 0)": -37030002657399322096925549317269744602,
+ "(671, 0)": 132659347664926314739827551151043811009,
+ "(672, 0)": -54679831772470725110291766428661234881,
+ "(673, 0)": 130222298159660173323626331984289727744,
+ "(674, 0)": 55097091941229985592803598275819915773,
+ "(675, 0)": 50024921436508389311466775228699046300,
+ "(676, 0)": 100676068273962493196341107658095272442,
+ "(677, 0)": 130933331548000313765315372958846898868,
+ "(678, 0)": -158437006647093655076426628214967242768,
+ "(679, 0)": 46007435466179905696727345447646061462,
+ "(680, 0)": 136305981407960823232217712630022874374,
+ "(681, 0)": -32891650771802131352859410925256927024,
+ "(682, 0)": 145795970194176824700125345614461382921,
+ "(683, 0)": -4275578558847631492642058679018514377,
+ "(684, 0)": 129893550787437872108764213500097378980,
+ "(685, 0)": 118955303969210197027352603571385595158,
+ "(686, 0)": 57037239495680113336606385657346737112,
+ "(687, 0)": 111742564297969630477849431546236880502,
+ "(688, 0)": -123598810642648123944312384480414872765,
+ "(689, 0)": -139850085397546783562700903572918567310,
+ "(690, 0)": -34398005297852767184901552699100050044,
+ "(691, 0)": -160268529451879041511989330340556514009,
+ "(692, 0)": 80785586365969248658112705106268245323,
+ "(693, 0)": 49103134866888415205128860717028666416,
+ "(694, 0)": -66008947819344558298157196783602189769,
+ "(695, 0)": 15011479118319453290653762496810800582,
+ "(696, 0)": -155673540532457283417277238822748966119,
+ "(697, 0)": -161682392651922480082416188086857638442,
+ "(698, 0)": 61809387368494170748137778121162089320,
+ "(699, 0)": -18703335330502771176242522171523686141,
+ "(700, 0)": -122552335828685390992865143020437458526,
+ "(701, 0)": -25874871944026625019315775896980401307,
+ "(702, 0)": 106146432128087778383374268591853914812,
+ "(703, 0)": 72305994668214709118853309324496757870,
+ "(704, 0)": -111021265813871549993584208237912162086,
+ "(705, 0)": 68238556303107411543188529250956442104,
+ "(706, 0)": 102666047598924401042848613784408606843,
+ "(707, 0)": 55897818979755968071503515446104054285,
+ "(708, 0)": -143217856666374632317119207581756015360,
+ "(709, 0)": 103953530344256971001179513180161119423,
+ "(710, 0)": -146814428639130131783329196976895875115,
+ "(711, 0)": 93673441771676787573598506959745133040,
+ "(712, 0)": -115265555614253888203966758960941257741,
+ "(713, 0)": -20998072980573279808845161416979466232,
+ "(714, 0)": 138667198815083705231093791878907676766,
+ "(715, 0)": -41607819040353431368576904339774336438,
+ "(716, 0)": 76173400008101651138228036525064594838,
+ "(717, 0)": 109028301988090427366168062932971930483,
+ "(718, 0)": -106853147266977857713204814600270568359,
+ "(719, 0)": -52546278626774846937463006374157266957,
+ "(720, 0)": 8632241966951064656643128575871395701,
+ "(721, 0)": -89079620473387902575406535770724228291,
+ "(722, 0)": 128234098635069785605332824273708422896,
+ "(723, 0)": 108536241107293988535616147574541220894,
+ "(724, 0)": 98592632828655787099700086079323733428,
+ "(725, 0)": 25635608898736233445135521622528546488,
+ "(726, 0)": -18599823324707243765121419854611011146,
+ "(727, 0)": -57938594383444270286115715690576083619,
+ "(728, 0)": -20978286824735108572097013169269037299,
+ "(729, 0)": -113944894118820026439357742199705652003,
+ "(730, 0)": 24315072076704846777538179375689179708,
+ "(731, 0)": -90292269861020716144734285833733703258,
+ "(732, 0)": -87872804077211657732433841358156805445,
+ "(733, 0)": 160644190927125402977070703471778899303,
+ "(734, 0)": -159892367963917899422704786918732694378,
+ "(735, 0)": -5540684682924934921342855154538570314,
+ "(736, 0)": -112180811026334101200537708154540526244,
+ "(737, 0)": 96762995469166616353496009042087541011,
+ "(738, 0)": 103238765458263096343036219191507104055,
+ "(739, 0)": -39203114899737705062305201092167483672,
+ "(740, 0)": -5036512610762760851461206577474670940,
+ "(741, 0)": 38821524602936873651868659038167344177,
+ "(742, 0)": 68242488652667147985405200861687208296,
+ "(743, 0)": 152510737150590202270242123382855821551,
+ "(744, 0)": -126867530967109499383717536445952078474,
+ "(745, 0)": -41519747054801735345843999274394924328,
+ "(746, 0)": 30456797800728897068129599513974163736,
+ "(747, 0)": -92348981405314762394351222186299701575,
+ "(748, 0)": 101534645648681791329168023848594119892,
+ "(749, 0)": -39381457209566035107470433058632572470,
+ "(750, 0)": 80633107223830588774363049937917525478,
+ "(751, 0)": 43737478285091495873103074390014240729,
+ "(752, 0)": -154699486355729127993435313183871989636,
+ "(753, 0)": -131430821669692099183441667624221394152,
+ "(754, 0)": -69333061342818777499114393910135458233,
+ "(755, 0)": -36852578295663122481010501434540754710,
+ "(756, 0)": -13235659769147043515008975863911675019,
+ "(757, 0)": 42104446815161553616467895402637638060,
+ "(758, 0)": 141363767270084587810573687995492084754,
+ "(759, 0)": -88574933780786105079134785378471071906,
+ "(760, 0)": -87684348253026713385536763014748974057,
+ "(761, 0)": -76145288268527560022737331527556433592,
+ "(762, 0)": 90012789292592915911950323951357077618,
+ "(763, 0)": 74322857034146026188735725944464743288,
+ "(764, 0)": -30409004869900927665529449393418370568,
+ "(765, 0)": 137579042156066881156454334663461880673,
+ "(766, 0)": -166149569734372313918397462972685333300,
+ "(767, 0)": 33325380128638854568801312047974900363,
+ "(768, 0)": -116634262388109264681752733314040490297,
+ "(769, 0)": 163467784115724085423874434993843554121,
+ "(770, 0)": -132580985646153666900342700895989154729,
+ "(771, 0)": 132232976803680126888551102635051029923,
+ "(772, 0)": -52689326438885641606982136772961982257,
+ "(773, 0)": 34293663999611707558041531898889639970,
+ "(774, 0)": -53843680606165314452968980161536120610,
+ "(775, 0)": 27270736485556967887064455185957620815,
+ "(776, 0)": 151386001984176495978092149232917206269,
+ "(777, 0)": 70632599181886317676503231951369691567,
+ "(778, 0)": 46680902890133367728754901122071490040,
+ "(779, 0)": 96359827198184532168203849766558095761,
+ "(780, 0)": -146357244590775925262790284255734987651,
+ "(781, 0)": 154493324337844332293427507676746613836,
+ "(782, 0)": 14584649639000144304575295228587759594,
+ "(783, 0)": -24051198074693977099695984633376668109,
+ "(784, 0)": 8473934315471309472542984630487738468,
+ "(785, 0)": -88379487366556486295406376218326178330,
+ "(786, 0)": -48567395901379205796608137532836730240,
+ "(787, 0)": -46526071043583047658566411670219882328,
+ "(788, 0)": 115155924416149686490183141970084950576,
+ "(789, 0)": 169879088961188354578135809405365472244,
+ "(790, 0)": -3065114487702546919606580902417540780,
+ "(791, 0)": 3635352685947913029620789810677029274,
+ "(792, 0)": -139359793676381716912179640155292498970,
+ "(793, 0)": -94401537852858700692572192876156358832,
+ "(794, 0)": -133043580123936369451381038244391535404,
+ "(795, 0)": -17544629266429194637370800774661569725,
+ "(796, 0)": 146242889995621147565796237098244357720,
+ "(797, 0)": 30168722440792092658906364869013752208,
+ "(798, 0)": -157020591677168485093321152949141129467,
+ "(799, 0)": -123463886358173354985088990863266054196,
+ "(800, 0)": -164342040070871170843219758668825564832,
+ "(801, 0)": 84665652562473825281407750393657139172,
+ "(802, 0)": -36887804221629364251095167124704329424,
+ "(803, 0)": 15377357570036672370925116431607603943,
+ "(804, 0)": 40202565660682346245703943344084319774,
+ "(805, 0)": 56621051031946670914634190090569742566,
+ "(806, 0)": 68998911230011820913207446444505918539,
+ "(807, 0)": 86739469792089327477497318640611059270,
+ "(808, 0)": -56467207209400346144985020924256918332,
+ "(809, 0)": 114722189346433287354970903565552528015,
+ "(810, 0)": -121051481704701846247251477085830767582,
+ "(811, 0)": -65306001863306589775101974977738383503,
+ "(812, 0)": 54794263982771118272417684598557132432,
+ "(813, 0)": 154090890439833958786433141181778633034,
+ "(814, 0)": -117944408818415420571521001176029900598,
+ "(815, 0)": -147986383035956505841560940215326443248,
+ "(816, 0)": -24124946180953357651698672325777961797,
+ "(817, 0)": 113728374602525486854705966972317131552,
+ "(818, 0)": 17902080736320743990048164838871418256,
+ "(819, 0)": -106208121433294220440721847495833743253,
+ "(820, 0)": -138934262372310152055396418590265213729,
+ "(821, 0)": -96412411531319121733223916513849598124,
+ "(822, 0)": -82021707724436268684382711201299588702,
+ "(823, 0)": -125742079489748439613305964247388853097,
+ "(824, 0)": -152991553409103830340224853172954203080,
+ "(825, 0)": -79567596077661657539252435713736065669,
+ "(826, 0)": -70372013400650077766954679498422666252,
+ "(827, 0)": 75700908037669465688687211939186910363,
+ "(828, 0)": 87286888731608470640229238768980302282,
+ "(829, 0)": -99900013255686486241257735511015357572,
+ "(830, 0)": 137528600713626187984942844404976314477,
+ "(831, 0)": -36102022323322024105486953133693334007,
+ "(832, 0)": 64158155999248162252377377905011644794,
+ "(833, 0)": -66368610668949394842111501146174649688,
+ "(834, 0)": 62273554819502062542067509873818845702,
+ "(835, 0)": 9986817014994610177557736333654338559,
+ "(836, 0)": -135618956105960760367651504517207502080,
+ "(837, 0)": -67310368645119518081897023017911442214,
+ "(838, 0)": -60580965546029891669836179143357461217,
+ "(839, 0)": -16839884982708883667560395672884196178,
+ "(840, 0)": -131061138354805255383107775132247252127,
+ "(841, 0)": 149495458749452835788875226563467335706,
+ "(842, 0)": -2332201251835045209982347355492478844,
+ "(843, 0)": 34672763202207295511361325387400583582,
+ "(844, 0)": -63345366439793790434535089199743984119,
+ "(845, 0)": -19975219682430007045003530563061736041,
+ "(846, 0)": -19649456692341693149811773496950554468,
+ "(847, 0)": -54955767326179667115944630717750077922,
+ "(848, 0)": -36301637677440570041557364670729433151,
+ "(849, 0)": -23265236572400358349087124865802529621,
+ "(850, 0)": -11526305800888677506088324455956654384,
+ "(851, 0)": 102203964667406634182620183815610740181,
+ "(852, 0)": 89716399093951700551388642466674675239,
+ "(853, 0)": 129971425025857379323610701145029238295,
+ "(854, 0)": -110558905263428317534405273065535185977,
+ "(855, 0)": -43442795916294247964098944178926657741,
+ "(856, 0)": -82078882609191454887057577502332722530,
+ "(857, 0)": 31159065848295360384282248392887538787,
+ "(858, 0)": -21662483055092868885142008727264245907,
+ "(859, 0)": -166717456214770038476987039939117552782,
+ "(860, 0)": -166417933394777417985917081316022872177,
+ "(861, 0)": -131663553485736907064090696352593036794,
+ "(862, 0)": -132835976782750203556743080848508333856,
+ "(863, 0)": -9341250422138467138266027822915257770,
+ "(864, 0)": 90793487633952365236980574748582382495,
+ "(865, 0)": 28283677778330720570875770140293296033,
+ "(866, 0)": 154596484485577077276546511710292645690,
+ "(867, 0)": -112727520513731396697448453411897463222,
+ "(868, 0)": -109816986315935495362175788788554892590,
+ "(869, 0)": 158186962789226913388921194291965597505,
+ "(870, 0)": -89021912426681080409036565305657585231,
+ "(871, 0)": 52754565653812980175518796024307172743,
+ "(872, 0)": 60309709376160427682115060231512421942,
+ "(873, 0)": -46862502241845243910669480508749092925,
+ "(874, 0)": 28807102067685643105321481810413101014,
+ "(875, 0)": -96212324929105928122296957314028858736,
+ "(876, 0)": 3670931811459528,
+ "(877, 0)": -74927100548879103577168617728673172161,
+ "(878, 0)": -321304393872,
+ "(880, 0)": 8168202
+ }
+ ]
+}
diff --git a/test/data/ec/__init__.py b/test/data/ec/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/data/ec/__init__.py
diff --git a/test/data/curve.json b/test/data/ec/curve.json
index c965c90..c965c90 100644
--- a/test/data/curve.json
+++ b/test/data/ec/curve.json
diff --git a/test/data/curves.json b/test/data/ec/curves.json
index 978ab36..978ab36 100644
--- a/test/data/curves.json
+++ b/test/data/ec/curves.json
diff --git a/test/data/ec/ecgen_secp128r1.json b/test/data/ec/ecgen_secp128r1.json
new file mode 100644
index 0000000..a1c4796
--- /dev/null
+++ b/test/data/ec/ecgen_secp128r1.json
@@ -0,0 +1,24 @@
+[{
+ "field": {
+ "p": "0xfffffffdffffffffffffffffffffffff"
+ },
+ "seed": "0x000e0d4d696e6768756151750cc03a4473d03679",
+ "a": "0xfffffffdfffffffffffffffffffffffc",
+ "b": "0xe87579c11079f43dd824993c2cee5ed3",
+ "order": "0xfffffffe0000000075a30d1b9038a115",
+ "subgroups": [
+ {
+ "x": "0x161ff7528b899b2d0c28607ca52c5b86",
+ "y": "0xcf5ac8395bafeb13c02da292dded7a83",
+ "order": "0xfffffffe0000000075a30d1b9038a115",
+ "cofactor": "0x1",
+ "points": [
+ {
+ "x": "0x42d2d24d7c0faa3c89b4568396d603c4",
+ "y": "0x992617de3aa2dfdf8da948913a69f185",
+ "order": "0xfffffffe0000000075a30d1b9038a115"
+ }
+ ]
+ }
+ ]
+}]
diff --git a/test/data/ec/ectester_secp128r1.csv b/test/data/ec/ectester_secp128r1.csv
new file mode 100644
index 0000000..f86a00d
--- /dev/null
+++ b/test/data/ec/ectester_secp128r1.csv
@@ -0,0 +1 @@
+0xfffffffdffffffffffffffffffffffff,0xfffffffdfffffffffffffffffffffffc,0xe87579c11079f43dd824993c2cee5ed3,0x161ff7528b899b2d0c28607ca52c5b86,0xcf5ac8395bafeb13c02da292dded7a83,0xfffffffe0000000075a30d1b9038a115,0x1
diff --git a/test/data/sca/__init__.py b/test/data/sca/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/data/sca/__init__.py
diff --git a/test/data/chipwhisperer_keylist.npy b/test/data/sca/chipwhisperer_keylist.npy
index c709dc7..c709dc7 100644
--- a/test/data/chipwhisperer_keylist.npy
+++ b/test/data/sca/chipwhisperer_keylist.npy
Binary files differ
diff --git a/test/data/chipwhisperer_knownkey.npy b/test/data/sca/chipwhisperer_knownkey.npy
index 82c97cd..82c97cd 100644
--- a/test/data/chipwhisperer_knownkey.npy
+++ b/test/data/sca/chipwhisperer_knownkey.npy
Binary files differ
diff --git a/test/data/chipwhisperer_settings.cwset b/test/data/sca/chipwhisperer_settings.cwset
index e6d0ad4..e6d0ad4 100644
--- a/test/data/chipwhisperer_settings.cwset
+++ b/test/data/sca/chipwhisperer_settings.cwset
diff --git a/test/data/chipwhisperer_textin.npy b/test/data/sca/chipwhisperer_textin.npy
index 22b93e1..22b93e1 100644
--- a/test/data/chipwhisperer_textin.npy
+++ b/test/data/sca/chipwhisperer_textin.npy
Binary files differ
diff --git a/test/data/chipwhisperer_textout.npy b/test/data/sca/chipwhisperer_textout.npy
index 0ac8831..0ac8831 100644
--- a/test/data/chipwhisperer_textout.npy
+++ b/test/data/sca/chipwhisperer_textout.npy
Binary files differ
diff --git a/test/data/chipwhisperer_traces.npy b/test/data/sca/chipwhisperer_traces.npy
index df72f86..df72f86 100644
--- a/test/data/chipwhisperer_traces.npy
+++ b/test/data/sca/chipwhisperer_traces.npy
Binary files differ
diff --git a/test/data/config_chipwhisperer_.cfg b/test/data/sca/config_chipwhisperer_.cfg
index dcc3129..dcc3129 100644
--- a/test/data/config_chipwhisperer_.cfg
+++ b/test/data/sca/config_chipwhisperer_.cfg
diff --git a/test/data/example.trs b/test/data/sca/example.trs
index a432e69..a432e69 100644
--- a/test/data/example.trs
+++ b/test/data/sca/example.trs
Binary files differ
diff --git a/test/data/target.py b/test/data/sca/target.py
index 72fc463..3ed71d1 100755
--- a/test/data/target.py
+++ b/test/data/sca/target.py
@@ -4,7 +4,10 @@ from sys import stdout
if __name__ == "__main__":
while True:
- line = input()
+ try:
+ line = input()
+ except EOFError:
+ break
char = line[0]
content = line[1:]
if char == "d":
diff --git a/test/data/test.h5 b/test/data/sca/test.h5
index f51b5fd..f51b5fd 100644
--- a/test/data/test.h5
+++ b/test/data/sca/test.h5
Binary files differ
diff --git a/test/data/test.pickle b/test/data/sca/test.pickle
index 43f7f07..43f7f07 100644
--- a/test/data/test.pickle
+++ b/test/data/sca/test.pickle
Binary files differ
diff --git a/test/ec/conftest.py b/test/ec/conftest.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/ec/conftest.py
diff --git a/test/ec/perf_divpoly.py b/test/ec/perf_divpoly.py
new file mode 100755
index 0000000..2937af1
--- /dev/null
+++ b/test/ec/perf_divpoly.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+import click
+
+from pyecsca.ec.divpoly import mult_by_n
+from pyecsca.ec.params import get_params
+from datetime import datetime
+
+
+@click.command()
+@click.option("-n", type=click.INT, default=21)
+def main(n):
+ p256 = get_params("secg", "secp256r1", "projective")
+
+ ns = []
+ durs = []
+ mems = []
+ for i in range(2, n):
+ start = datetime.now()
+ mx, my = mult_by_n(p256.curve, i)
+ end = datetime.now()
+ duration = (end - start).total_seconds()
+ memory = (mx[0].degree() + mx[1].degree() + my[0].degree() + my[1].degree()) * 32
+ ns.append(i)
+ durs.append((end - start).total_seconds())
+ mems.append(memory)
+ print(i, duration, memory, sep=",")
+
+
+if __name__ == "__main__":
+ main()
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_configuration.py b/test/ec/test_configuration.py
index d2ab3f5..17fb6f7 100644
--- a/test/ec/test_configuration.py
+++ b/test/ec/test_configuration.py
@@ -1,4 +1,4 @@
-from unittest import TestCase
+import pytest
from pyecsca.ec.configuration import (
all_configurations,
@@ -11,89 +11,46 @@ from pyecsca.ec.configuration import (
)
from pyecsca.ec.model import ShortWeierstrassModel
from pyecsca.ec.mult import LTRMultiplier
-from .utils import slow
-class ConfigurationTests(TestCase):
- def base_independents(self):
- return {
- "hash_type": HashType.SHA1,
- "mod_rand": RandomMod.SAMPLE,
- "mult": Multiplication.BASE,
- "sqr": Squaring.BASE,
- "red": Reduction.BASE,
- "inv": Inversion.GCD,
- }
+@pytest.fixture(scope="module")
+def base_independents():
+ return {"hash_type": HashType.SHA1, "mod_rand": RandomMod.SAMPLE, "mult": Multiplication.BASE, "sqr": Squaring.BASE,
+ "red": Reduction.BASE, "inv": Inversion.GCD, }
- @slow
- def test_all(self):
- j = 0
- for _ in all_configurations(model=ShortWeierstrassModel()):
- j += 1
- def test_weierstrass_projective(self):
- model = ShortWeierstrassModel()
- coords = model.coordinates["projective"]
- configs = list(
- all_configurations(model=model, coords=coords, **self.base_independents())
- )
- self.assertEqual(len(configs), 1960)
+@pytest.mark.slow
+def test_all():
+ j = 0
+ for _ in all_configurations(model=ShortWeierstrassModel()):
+ j += 1
- def test_mult_class(self):
- model = ShortWeierstrassModel()
- coords = model.coordinates["projective"]
- scalarmult = LTRMultiplier
- configs = list(
- all_configurations(
- model=model,
- coords=coords,
- scalarmult=scalarmult,
- **self.base_independents()
- )
- )
- self.assertEqual(len(configs), 560)
- def test_one(self):
- model = ShortWeierstrassModel()
- coords = model.coordinates["projective"]
- scalarmult = {
- "cls": LTRMultiplier,
- "add": coords.formulas["add-1998-cmo"],
- "dbl": coords.formulas["dbl-1998-cmo"],
- "scl": None,
- "always": True,
- "complete": False,
- "short_circuit": True,
- }
- configs = list(
- all_configurations(
- model=model,
- coords=coords,
- scalarmult=scalarmult,
- **self.base_independents()
- )
- )
- self.assertEqual(len(configs), 1)
- scalarmult = LTRMultiplier(
- coords.formulas["add-1998-cmo"],
- coords.formulas["dbl-1998-cmo"],
- None,
- True,
- False,
- True,
- )
- configs = list(
- all_configurations(
- model=model,
- coords=coords,
- scalarmult=scalarmult,
- **self.base_independents()
- )
- )
- self.assertEqual(len(configs), 1)
- configs = list(
- all_configurations(
- model=model, scalarmult=scalarmult, **self.base_independents()
- )
- )
- self.assertEqual(len(configs), 1)
+def test_weierstrass_projective(base_independents):
+ model = ShortWeierstrassModel()
+ coords = model.coordinates["projective"]
+ configs = list(all_configurations(model=model, coords=coords, **base_independents))
+ assert len(configs) == 1960
+
+
+def test_mult_class(base_independents):
+ model = ShortWeierstrassModel()
+ coords = model.coordinates["projective"]
+ scalarmult = LTRMultiplier
+ configs = list(all_configurations(model=model, coords=coords, scalarmult=scalarmult, **base_independents))
+ assert len(configs) == 560
+
+
+def test_one(base_independents):
+ model = ShortWeierstrassModel()
+ coords = model.coordinates["projective"]
+ scalarmult = {"cls": LTRMultiplier, "add": coords.formulas["add-1998-cmo"], "dbl": coords.formulas["dbl-1998-cmo"],
+ "scl": None, "always": True, "complete": False, "short_circuit": True, }
+ configs = list(all_configurations(model=model, coords=coords, scalarmult=scalarmult, **base_independents))
+ assert len(configs) == 1
+ scalarmult = LTRMultiplier(coords.formulas["add-1998-cmo"], coords.formulas["dbl-1998-cmo"], None, True, False,
+ True, )
+ configs = list(all_configurations(model=model, coords=coords, scalarmult=scalarmult, **base_independents))
+ assert len(configs) == 1
+ configs = list(all_configurations(model=model, scalarmult=scalarmult, **base_independents))
+ assert len(configs) == 1
diff --git a/test/ec/test_context.py b/test/ec/test_context.py
index 9cd74a3..9ec7962 100644
--- a/test/ec/test_context.py
+++ b/test/ec/test_context.py
@@ -1,4 +1,4 @@
-from unittest import TestCase
+import pytest
from pyecsca.ec.context import (
local,
@@ -7,90 +7,95 @@ from pyecsca.ec.context import (
PathContext
)
from pyecsca.ec.key_generation import KeyGeneration
-from pyecsca.ec.params import get_params
from pyecsca.ec.mod import RandomModAction
from pyecsca.ec.mult import LTRMultiplier, ScalarMultiplicationAction
-class TreeTests(TestCase):
- def test_walk_by_key(self):
- tree = Tree()
- tree["a"] = Tree()
- tree["a"]["1"] = Tree()
- tree["a"]["2"] = Tree()
- self.assertIn("a", tree)
- self.assertIsInstance(tree.get_by_key([]), Tree)
- self.assertIsInstance(tree.get_by_key(["a"]), Tree)
- self.assertIsInstance(tree.get_by_key(["a", "1"]), Tree)
+def test_walk_by_key():
+ tree = Tree()
+ tree["a"] = Tree()
+ tree["a"]["1"] = Tree()
+ tree["a"]["2"] = Tree()
+ assert "a" in tree
+ assert isinstance(tree.get_by_key([]), Tree)
+ assert isinstance(tree.get_by_key(["a"]), Tree)
+ assert isinstance(tree.get_by_key(["a", "1"]), Tree)
- def test_walk_by_index(self):
- tree = Tree()
- a = Tree()
- tree["a"] = a
- d = Tree()
- b = Tree()
- tree["a"]["d"] = d
- tree["a"]["b"] = b
- self.assertIn("a", tree)
- with self.assertRaises(ValueError):
- tree.get_by_index([])
- self.assertEqual(tree.get_by_index([0]), ("a", a))
- self.assertEqual(tree.get_by_index([0, 0]), ("d", d))
+def test_walk_by_index():
+ tree = Tree()
+ a = Tree()
+ tree["a"] = a
+ d = Tree()
+ b = Tree()
+ tree["a"]["d"] = d
+ tree["a"]["b"] = b
+ assert "a" in tree
+ with pytest.raises(ValueError):
+ tree.get_by_index([])
- def test_repr(self):
- tree = Tree()
- tree["a"] = Tree()
- tree["a"]["1"] = Tree()
- tree["a"]["2"] = Tree()
- txt = tree.repr()
- self.assertEqual(txt.count("\t"), 2)
- self.assertEqual(txt.count("\n"), 3)
+ assert tree.get_by_index([0]) == ("a", a)
+ assert tree.get_by_index([0, 0]) == ("d", d)
-class ContextTests(TestCase):
- def setUp(self):
- self.secp128r1 = get_params("secg", "secp128r1", "projective")
- self.base = self.secp128r1.generator
- self.coords = self.secp128r1.curve.coordinate_model
- self.mult = LTRMultiplier(
- self.coords.formulas["add-1998-cmo"],
- self.coords.formulas["dbl-1998-cmo"],
- self.coords.formulas["z"],
- always=True,
- )
- self.mult.init(self.secp128r1, self.base)
+def test_repr():
+ tree = Tree()
+ tree["a"] = Tree()
+ tree["a"]["1"] = Tree()
+ tree["a"]["2"] = Tree()
+ txt = tree.repr()
+ assert txt.count("\t") == 2
+ assert txt.count("\n") == 3
- def test_null(self):
- with local() as ctx:
- self.mult.multiply(59)
- self.assertIs(ctx, None)
- def test_default(self):
- with local(DefaultContext()) as ctx:
- result = self.mult.multiply(59)
- self.assertEqual(len(ctx.actions), 1)
- action = next(iter(ctx.actions.keys()))
- self.assertIsInstance(action, ScalarMultiplicationAction)
- self.assertEqual(result, action.result)
+@pytest.fixture()
+def mult(secp128r1):
+ base = secp128r1.generator
+ coords = secp128r1.curve.coordinate_model
+ mult = LTRMultiplier(
+ coords.formulas["add-1998-cmo"],
+ coords.formulas["dbl-1998-cmo"],
+ coords.formulas["z"],
+ always=True,
+ )
+ mult.init(secp128r1, base)
+ return mult
- def test_default_no_enter(self):
- with local(DefaultContext()) as default, self.assertRaises(ValueError):
- default.exit_action(RandomModAction(7))
- def test_path(self):
- with local(PathContext([0, 1])) as ctx:
- key_generator = KeyGeneration(self.mult, self.secp128r1, True)
- key_generator.generate()
- self.assertIsInstance(ctx.value, ScalarMultiplicationAction)
- with local(PathContext([0, 1, 7])) as ctx:
- key_generator = KeyGeneration(self.mult, self.secp128r1, True)
- key_generator.generate()
+def test_null(mult):
+ with local() as ctx:
+ mult.multiply(59)
+ assert ctx is None
- def test_str(self):
- with local(DefaultContext()) as default:
- self.mult.multiply(59)
- str(default)
- str(default.actions)
- with local(None):
- self.mult.multiply(59)
+
+def test_default(mult):
+ with local(DefaultContext()) as ctx:
+ result = mult.multiply(59)
+ assert len(ctx.actions) == 1
+ action = next(iter(ctx.actions.keys()))
+ assert isinstance(action, ScalarMultiplicationAction)
+ assert result == action.result
+
+
+def test_default_no_enter():
+ with local(DefaultContext()) as default, pytest.raises(ValueError):
+ default.exit_action(RandomModAction(7))
+
+
+def test_path(mult, secp128r1):
+ with local(PathContext([0, 1])) as ctx:
+ key_generator = KeyGeneration(mult, secp128r1, True)
+ key_generator.generate()
+ assert isinstance(ctx.value, ScalarMultiplicationAction)
+ with local(PathContext([0, 1, 7])):
+ key_generator = KeyGeneration(mult, secp128r1, True)
+ key_generator.generate()
+
+
+def test_str(mult):
+ with local(DefaultContext()) as default:
+ mult.multiply(59)
+ assert str(default) is not None
+ assert str(default.actions) is not None
+ with local(None):
+ mult.multiply(59)
diff --git a/test/ec/test_curve.py b/test/ec/test_curve.py
index 345d3de..cd0639a 100644
--- a/test/ec/test_curve.py
+++ b/test/ec/test_curve.py
@@ -1,177 +1,187 @@
from binascii import unhexlify
-from unittest import TestCase
+import pytest
from pyecsca.ec.coordinates import AffineCoordinateModel
from pyecsca.ec.curve import EllipticCurve
-from pyecsca.ec.params import get_params
+from pyecsca.ec.error import UnsatisfiedAssumptionError
from pyecsca.ec.mod import Mod
from pyecsca.ec.model import MontgomeryModel
from pyecsca.ec.point import Point, InfinityPoint
-class CurveTests(TestCase):
- def setUp(self):
- self.secp128r1 = get_params("secg", "secp128r1", "projective")
- self.base = self.secp128r1.generator
- self.affine_base = self.base.to_affine()
- self.curve25519 = get_params("other", "Curve25519", "xz")
- self.ed25519 = get_params("other", "Ed25519", "projective")
+def test_init(secp128r1):
+ with pytest.raises(ValueError):
+ EllipticCurve(
+ MontgomeryModel(),
+ secp128r1.curve.coordinate_model,
+ 1,
+ InfinityPoint(secp128r1.curve.coordinate_model),
+ parameters={},
+ )
- def test_init(self):
- with self.assertRaises(ValueError):
- EllipticCurve(
- MontgomeryModel(),
- self.secp128r1.curve.coordinate_model,
- 1,
- InfinityPoint(self.secp128r1.curve.coordinate_model),
- parameters={},
- )
+ with pytest.raises(ValueError):
+ EllipticCurve(
+ secp128r1.curve.model,
+ secp128r1.curve.coordinate_model,
+ 15,
+ InfinityPoint(secp128r1.curve.coordinate_model),
+ parameters={"c": 0},
+ )
- with self.assertRaises(ValueError):
- EllipticCurve(
- self.secp128r1.curve.model,
- self.secp128r1.curve.coordinate_model,
- 15,
- InfinityPoint(self.secp128r1.curve.coordinate_model),
- parameters={"c": 0},
- )
+ with pytest.raises(ValueError):
+ EllipticCurve(
+ secp128r1.curve.model,
+ secp128r1.curve.coordinate_model,
+ 15,
+ InfinityPoint(secp128r1.curve.coordinate_model),
+ parameters={"a": Mod(1, 5), "b": Mod(2, 5)},
+ )
- with self.assertRaises(ValueError):
- EllipticCurve(
- self.secp128r1.curve.model,
- self.secp128r1.curve.coordinate_model,
- 15,
- InfinityPoint(self.secp128r1.curve.coordinate_model),
- parameters={"a": Mod(1, 5), "b": Mod(2, 5)},
- )
- def test_is_neutral(self):
- self.assertTrue(
- self.secp128r1.curve.is_neutral(
- InfinityPoint(self.secp128r1.curve.coordinate_model)
- )
- )
+def test_to_coords(secp128r1):
+ affine = secp128r1.to_affine()
+ m1_coords = affine.curve.model.coordinates["projective-1"]
+ m3_coords = affine.curve.model.coordinates["projective-3"]
+ with pytest.raises(UnsatisfiedAssumptionError):
+ affine.to_coords(m1_coords)
+ affine.to_coords(m3_coords)
- def test_is_on_curve(self):
- self.assertTrue(self.secp128r1.curve.is_on_curve(self.secp128r1.curve.neutral))
- pt = Point(
- self.secp128r1.curve.coordinate_model,
- X=Mod(0x161FF7528B899B2D0C28607CA52C5B86, self.secp128r1.curve.prime),
- Y=Mod(0xCF5AC8395BAFEB13C02DA292DDED7A83, self.secp128r1.curve.prime),
- Z=Mod(1, self.secp128r1.curve.prime),
- )
- self.assertTrue(self.secp128r1.curve.is_on_curve(pt))
- self.assertTrue(self.secp128r1.curve.is_on_curve(pt.to_affine()))
- other = Point(
- self.secp128r1.curve.coordinate_model,
- X=Mod(0x161FF7528B899B2D0C28607CA52C5B86, self.secp128r1.curve.prime),
- Y=Mod(0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA, self.secp128r1.curve.prime),
- Z=Mod(1, self.secp128r1.curve.prime),
- )
- self.assertFalse(self.secp128r1.curve.is_on_curve(other))
- self.assertFalse(self.secp128r1.curve.is_on_curve(self.curve25519.generator))
- def test_affine_add(self):
- pt = Point(
- AffineCoordinateModel(self.secp128r1.curve.model),
- x=Mod(0xEB916224EDA4FB356421773573297C15, self.secp128r1.curve.prime),
- y=Mod(0xBCDAF32A2C08FD4271228FEF35070848, self.secp128r1.curve.prime),
- )
- self.assertIsNotNone(self.secp128r1.curve.affine_add(self.affine_base, pt))
+def test_to_affine(secp128r1):
+ affine = secp128r1.to_affine()
+ model = AffineCoordinateModel(affine.curve.model)
+ assert affine.curve.coordinate_model == model
+ assert affine.generator.coordinate_model == model
- added = self.secp128r1.curve.affine_add(self.affine_base, self.affine_base)
- doubled = self.secp128r1.curve.affine_double(self.affine_base)
- self.assertEqual(added, doubled)
- self.assertEqual(
- self.secp128r1.curve.affine_add(self.secp128r1.curve.neutral, pt), pt
- )
- self.assertEqual(
- self.secp128r1.curve.affine_add(pt, self.secp128r1.curve.neutral), pt
- )
- def test_affine_double(self):
- self.assertIsNotNone(self.secp128r1.curve.affine_double(self.affine_base))
- self.assertEqual(
- self.secp128r1.curve.affine_double(self.secp128r1.curve.neutral),
- self.secp128r1.curve.neutral,
- )
+def test_is_neutral(secp128r1):
+ assert secp128r1.curve.is_neutral(
+ InfinityPoint(secp128r1.curve.coordinate_model)
+ )
- def test_affine_negate(self):
- self.assertIsNotNone(self.secp128r1.curve.affine_negate(self.affine_base))
- self.assertEqual(
- self.secp128r1.curve.affine_negate(self.secp128r1.curve.neutral),
- self.secp128r1.curve.neutral,
- )
- with self.assertRaises(ValueError):
- self.secp128r1.curve.affine_negate(self.base)
- with self.assertRaises(ValueError):
- self.secp128r1.curve.affine_negate(self.curve25519.generator)
- def test_affine_multiply(self):
- expected = self.affine_base
- expected = self.secp128r1.curve.affine_double(expected)
- expected = self.secp128r1.curve.affine_double(expected)
- expected = self.secp128r1.curve.affine_add(expected, self.affine_base)
- expected = self.secp128r1.curve.affine_double(expected)
- self.assertEqual(
- self.secp128r1.curve.affine_multiply(self.affine_base, 10), expected
- )
- self.assertEqual(
- self.secp128r1.curve.affine_multiply(self.secp128r1.curve.neutral, 10),
- self.secp128r1.curve.neutral,
- )
- with self.assertRaises(ValueError):
- self.secp128r1.curve.affine_multiply(self.base, 10)
- with self.assertRaises(ValueError):
- self.secp128r1.curve.affine_multiply(self.curve25519.generator, 10)
+def test_is_on_curve(secp128r1, curve25519):
+ assert secp128r1.curve.is_on_curve(secp128r1.curve.neutral)
+ pt = Point(
+ secp128r1.curve.coordinate_model,
+ X=Mod(0x161FF7528B899B2D0C28607CA52C5B86, secp128r1.curve.prime),
+ Y=Mod(0xCF5AC8395BAFEB13C02DA292DDED7A83, secp128r1.curve.prime),
+ Z=Mod(1, secp128r1.curve.prime),
+ )
+ assert secp128r1.curve.is_on_curve(pt)
+ assert secp128r1.curve.is_on_curve(pt.to_affine())
+ other = Point(
+ secp128r1.curve.coordinate_model,
+ X=Mod(0x161FF7528B899B2D0C28607CA52C5B86, secp128r1.curve.prime),
+ Y=Mod(0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA, secp128r1.curve.prime),
+ Z=Mod(1, secp128r1.curve.prime),
+ )
+ assert not secp128r1.curve.is_on_curve(other)
+ assert not secp128r1.curve.is_on_curve(curve25519.generator)
+
- def test_affine_neutral(self):
- self.assertIsNone(self.secp128r1.curve.affine_neutral)
- self.assertIsNone(self.curve25519.curve.affine_neutral)
- self.assertIsNotNone(self.ed25519.curve.affine_neutral)
+def test_affine_add(secp128r1):
+ pt = Point(
+ AffineCoordinateModel(secp128r1.curve.model),
+ x=Mod(0xEB916224EDA4FB356421773573297C15, secp128r1.curve.prime),
+ y=Mod(0xBCDAF32A2C08FD4271228FEF35070848, secp128r1.curve.prime),
+ )
+ affine_base = secp128r1.generator.to_affine()
+ assert secp128r1.curve.affine_add(affine_base, pt) is not None
- def test_affine_random(self):
- for params in [self.secp128r1, self.curve25519, self.ed25519]:
- for _ in range(20):
- pt = params.curve.affine_random()
- self.assertIsNotNone(pt)
- self.assertTrue(params.curve.is_on_curve(pt))
+ added = secp128r1.curve.affine_add(affine_base, affine_base)
+ doubled = secp128r1.curve.affine_double(affine_base)
+ assert added == doubled
+ assert secp128r1.curve.affine_add(secp128r1.curve.neutral, pt) == pt
+ assert secp128r1.curve.affine_add(pt, secp128r1.curve.neutral) == pt
- def test_neutral_is_affine(self):
- self.assertFalse(self.secp128r1.curve.neutral_is_affine)
- self.assertFalse(self.curve25519.curve.neutral_is_affine)
- self.assertTrue(self.ed25519.curve.neutral_is_affine)
- def test_eq(self):
- self.assertEqual(self.secp128r1.curve, self.secp128r1.curve)
- self.assertNotEqual(self.secp128r1.curve, self.curve25519.curve)
- self.assertNotEqual(self.secp128r1.curve, None)
+def test_affine_double(secp128r1):
+ affine_base = secp128r1.generator.to_affine()
+ assert secp128r1.curve.affine_double(affine_base) is not None
+ assert secp128r1.curve.affine_double(secp128r1.curve.neutral) == \
+ secp128r1.curve.neutral
- def test_decode(self):
- affine_curve = self.secp128r1.curve.to_affine()
- affine_point = self.secp128r1.generator.to_affine()
- decoded = affine_curve.decode_point(bytes(affine_point))
- self.assertEqual(decoded, affine_point)
- 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)
+def test_affine_negate(secp128r1, curve25519):
+ affine_base = secp128r1.generator.to_affine()
+ assert secp128r1.curve.affine_negate(affine_base) is not None
+ assert secp128r1.curve.affine_negate(secp128r1.curve.neutral) == \
+ secp128r1.curve.neutral
+ with pytest.raises(ValueError):
+ secp128r1.curve.affine_negate(secp128r1.generator)
+ with pytest.raises(ValueError):
+ secp128r1.curve.affine_negate(curve25519.generator)
- 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"))
+def test_affine_multiply(secp128r1, curve25519):
+ affine_base = secp128r1.generator.to_affine()
+ expected = affine_base
+ expected = secp128r1.curve.affine_double(expected)
+ expected = secp128r1.curve.affine_double(expected)
+ expected = secp128r1.curve.affine_add(expected, affine_base)
+ expected = secp128r1.curve.affine_double(expected)
+ assert secp128r1.curve.affine_multiply(affine_base, 10) == expected
+ assert secp128r1.curve.affine_multiply(secp128r1.curve.neutral, 10) == \
+ secp128r1.curve.neutral
+ with pytest.raises(ValueError):
+ secp128r1.curve.affine_multiply(secp128r1.generator, 10)
+ with pytest.raises(ValueError):
+ secp128r1.curve.affine_multiply(curve25519.generator, 10)
+
+
+def test_affine_neutral(secp128r1, curve25519, ed25519):
+ assert secp128r1.curve.affine_neutral is None
+ assert curve25519.curve.affine_neutral is None
+ assert ed25519.curve.affine_neutral is not None
+
+
+def test_neutral_is_affine(secp128r1, curve25519, ed25519):
+ assert not secp128r1.curve.neutral_is_affine
+ assert not curve25519.curve.neutral_is_affine
+ assert ed25519.curve.neutral_is_affine
+
+
+@pytest.mark.parametrize("curve_name", ["secp128r1", "curve25519", "ed25519"])
+def test_affine_random(curve_name, request):
+ params = request.getfixturevalue(curve_name)
+ for _ in range(20):
+ pt = params.curve.affine_random()
+ assert pt is not None
+ assert params.curve.is_on_curve(pt)
+
+
+def test_eq(secp128r1, curve25519):
+ assert secp128r1.curve == secp128r1.curve
+ assert secp128r1.curve != curve25519.curve
+ assert secp128r1.curve is not None
+
+
+def test_decode(secp128r1):
+ affine_curve = secp128r1.curve.to_affine()
+ affine_point = secp128r1.generator.to_affine()
+ decoded = affine_curve.decode_point(bytes(affine_point))
+ assert decoded == affine_point
+
+ affine_compressed_bytes = unhexlify("03161ff7528b899b2d0c28607ca52c5b86")
+ decoded_compressed = affine_curve.decode_point(affine_compressed_bytes)
+ assert decoded_compressed == affine_point
+ affine_compressed_bytes = unhexlify("02161ff7528b899b2d0c28607ca52c5b86")
+ decoded_compressed = affine_curve.decode_point(affine_compressed_bytes)
+ decoded_compressed = secp128r1.curve.affine_negate(decoded_compressed)
+ assert decoded_compressed == affine_point
+
+ infinity_bytes = unhexlify("00")
+ decoded_infinity = affine_curve.decode_point(infinity_bytes)
+ assert affine_curve.neutral == decoded_infinity
+
+ with pytest.raises(ValueError):
+ affine_curve.decode_point(unhexlify("03161ff7528b899b2d0c28607ca52c5b"))
+ with pytest.raises(ValueError):
+ affine_curve.decode_point(
+ unhexlify("04161ff7528b899b2d0c28607ca52c5b2c5b2c5b2c5b")
+ )
+ with pytest.raises(ValueError):
+ affine_curve.decode_point(unhexlify("7a161ff7528b899b2d0c28607ca52c5b86"))
+ with pytest.raises(ValueError):
+ affine_curve.decode_point(unhexlify("03161ff7528b899b2d0c28607ca52c5b88"))
diff --git a/test/ec/test_divpoly.py b/test/ec/test_divpoly.py
new file mode 100644
index 0000000..07eed76
--- /dev/null
+++ b/test/ec/test_divpoly.py
@@ -0,0 +1,112 @@
+import json
+from importlib_resources import files
+
+import test.data.divpoly
+from sympy import FF
+from pyecsca.ec.divpoly import a_invariants, b_invariants, divpoly0, divpoly, mult_by_n
+
+
+def test_ainvs(secp128r1):
+ ainvs = a_invariants(secp128r1.curve)
+ assert ainvs == (0, 0, 0, 340282366762482138434845932244680310780, 308990863222245658030922601041482374867)
+
+
+def test_binvs(secp128r1):
+ binvs = b_invariants(secp128r1.curve)
+ assert binvs == (0, 340282366762482138434845932244680310777, 215116352601536216819152607431888567119,
+ 340282366762482138434845932244680310774)
+
+
+def test_divpoly0(secp128r1):
+ # Data from sagemath
+ coeffs = [11, 0, 340282366762482138434845932244680302401, 211962053797180672439257756222135086642,
+ 340282366762482138434845932244678441564, 115415922367823003571854983213102698477,
+ 152803211743444076787231275062278784385, 68540219804769369063918923691867278088,
+ 43207172520353703997069627419519708522, 83208285732019037267730920881743782729,
+ 93286967763556583502947234289842152563, 324950611928652823046744874201355360259,
+ 244242343224213805514200367379671854852, 307096814154284337284845014037169929735,
+ 180946781765592277412990188457219828893, 301253861469456022084288029442105687698,
+ 58053323975526190296189278379252064657, 224437885189054146208302696540070489578,
+ 281987318191429654256483850017931541622, 21449216018131966691124843738286677726,
+ 10958264881628724646042625283328121348, 104868338562600481545003572552335444641,
+ 127205813185570107009206143413997395181, 116865717360861207318274706645935808417,
+ 281460458922812844939222119784601506753, 336607098463310980140968249747513775735,
+ 304486486784143285234063826161805094682, 194935097339732797131694429642153881938,
+ 193523171473792085604518744912658246509, 204844449336357293979832621297234119270,
+ 244481753281744913785581086721299830802, 46816299473081369405217767361380254657,
+ 303070923752707405164354702252828590781, 222516549119176621389776816552836322766,
+ 292006660232236762950883960515487362063, 53617127992846936725441702182362940200,
+ 242498306026562585655027965022211017540, 25039963304689451659955607939868533124,
+ 328580435950647191774558154445103295305, 24226614081978788956695324769468902511,
+ 147945052666123617872720080832548744564, 287190187011075399698210761813202261601,
+ 117131681517270554750959286838283723521, 35018410385280384289320020556813474742,
+ 83939964512240352730304831725346032711, 147219996946006689656600631222993527180,
+ 280430477096741745234510250577626566690, 32753113267385981127807026368593329576,
+ 105134319561523011785486683031223863934, 206456116679151691099661865534540095270,
+ 116180470443213022739312068090342951131, 245850120846480965440408943459023315919,
+ 45805943896736805301879725516256422457, 226777421435695229777151315574975350291,
+ 283680841707610526659029980964566557627, 53168487339451866167506032177471934158,
+ 69212302225932892622760219621519562036, 183916411340675637978873336955593385541,
+ 119478537598919956688656337369481692789, 234767298887335988751880131162396819780,
+ 218412162101425422347176804186940045781]
+ K = FF(secp128r1.curve.prime)
+ poly = divpoly0(secp128r1.curve, 11)[11]
+ computed = list(map(K, poly.all_coeffs()))
+ assert coeffs == computed
+
+
+def test_divpoly(secp128r1):
+ # Data from sagemath
+ K = FF(secp128r1.curve.prime)
+ coeffs_0 = {(0,): K(16020440675387382717114730680672549016), (1,): K(269851015321770885610377847857290470365),
+ (2,): K(340282366762482138434845932244680310693), (3,): K(109469325440469337582450480850803806492),
+ (4,): K(340282366762482138434845932244680310753), (6,): K(2)}
+ assert divpoly(secp128r1.curve, 4, 0).as_dict() == coeffs_0
+ coeffs_1 = {(6, 1): K(4), (4, 1): K(340282366762482138434845932244680310723),
+ (3, 1): K(218938650880938675164900961701607612984), (2, 1): K(340282366762482138434845932244680310603),
+ (1, 1): K(199419663881059632785909763469900629947), (0, 1): K(32040881350774765434229461361345098032)}
+ assert divpoly(secp128r1.curve, 4, 1).as_dict() == coeffs_1
+ coeffs_2 = {(9,): K(8), (7,): K(340282366762482138434845932244680310639),
+ (6,): K(187545273439985507098415273777631738640), (4,): K(117928913205007755574446043156465405646),
+ (3,): K(244159722710157842132157548160645018307), (2,): K(200234655086793134086408617236124137371),
+ (1,): K(51914434605509249526780779992574428819), (0,): K(60581150995923875019702403440670701629)}
+ assert divpoly(secp128r1.curve, 4, 2).as_dict() == coeffs_2
+
+
+def test_mult_by_n(secp128r1):
+ # Data from sagemath
+ K = FF(secp128r1.curve.prime)
+ coeffs_mx_num = [1, 0, 6, 250332028321891843231386649625583487328, 9]
+ coeffs_mx_denom = [4, 0, 340282366762482138434845932244680310771, 215116352601536216819152607431888567119]
+ coeffs_my_num = {(6, 1): K(8), (4, 1): K(340282366762482138434845932244680310663),
+ (3, 1): K(97594934999395211894955991158534915185),
+ (2, 1): K(340282366762482138434845932244680310423),
+ (1, 1): K(58556960999637127136973594695120949111),
+ (0, 1): K(64081762701549530868458922722690196064)}
+ coeffs_my_denom = {(6, 0): K(64), (4, 0): K(340282366762482138434845932244680310399),
+ (3, 0): K(78075947999516169515964792926827932148), (2, 0): K(576),
+ (1, 0): K(106054522763933629886951553464196514339),
+ (0, 0): K(276200604060932607566387009521990114935)}
+ mx, my = mult_by_n(secp128r1.curve, 2)
+ mx_num, mx_denom = mx
+ assert coeffs_mx_num == list(map(K, mx_num.all_coeffs()))
+ assert coeffs_mx_denom == list(map(K, mx_denom.all_coeffs()))
+ my_num, my_denom = my
+ assert my_num.as_dict() == coeffs_my_num
+ assert my_denom.as_dict() == coeffs_my_denom
+
+
+def test_mult_by_n_large(secp128r1):
+ K = FF(secp128r1.curve.prime)
+ mx, my = mult_by_n(secp128r1.curve, 21)
+ with files(test.data.divpoly).joinpath("mult_21.json").open("r") as f:
+ sage_data = json.load(f)
+ sage_data["mx"][0] = {eval(key): K(val) for key, val in sage_data["mx"][0].items()}
+ sage_data["mx"][1] = {eval(key): K(val) for key, val in sage_data["mx"][1].items()}
+ sage_data["my"][0] = {eval(key): K(val) for key, val in sage_data["my"][0].items()}
+ sage_data["my"][1] = {eval(key): K(val) for key, val in sage_data["my"][1].items()}
+
+ assert mx[0].as_dict() == sage_data["mx"][0]
+ assert mx[1].as_dict() == sage_data["mx"][1]
+ assert my[0].as_dict() == sage_data["my"][0]
+ assert my[1].as_dict() == sage_data["my"][1]
diff --git a/test/ec/test_formula.py b/test/ec/test_formula.py
index ffae4c4..420e0b3 100644
--- a/test/ec/test_formula.py
+++ b/test/ec/test_formula.py
@@ -1,5 +1,4 @@
-from unittest import TestCase
-
+import pytest
from sympy import FF, symbols
from pyecsca.ec.mod import SymbolicMod, Mod
@@ -9,99 +8,115 @@ from pyecsca.ec.params import get_params
from pyecsca.ec.point import Point
-class FormulaTests(TestCase):
- def setUp(self):
- self.secp128r1 = get_params("secg", "secp128r1", "projective")
- self.add = self.secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
- self.dbl = self.secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
- self.mdbl = self.secp128r1.curve.coordinate_model.formulas["mdbl-2007-bl"]
- self.jac_secp128r1 = get_params("secg", "secp128r1", "jacobian")
- self.jac_dbl = self.jac_secp128r1.curve.coordinate_model.formulas[
- "dbl-1998-hnm"
- ]
+@pytest.fixture()
+def add(secp128r1):
+ return secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
- def test_wrong_call(self):
- with self.assertRaises(ValueError):
- self.add(self.secp128r1.curve.prime)
- with self.assertRaises(ValueError):
- self.add(
- self.secp128r1.curve.prime,
- self.secp128r1.generator.to_affine(),
- self.secp128r1.generator.to_affine(),
- )
- def test_indices(self):
- self.assertEqual(self.add.input_index, 1)
- self.assertEqual(self.add.output_index, 3)
+@pytest.fixture()
+def dbl(secp128r1):
+ return secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
- def test_inputs_outputs(self):
- self.assertEqual(self.add.inputs, {"X1", "Y1", "Z1", "X2", "Y2", "Z2"})
- self.assertEqual(self.add.outputs, {"X3", "Y3", "Z3"})
- def test_eq(self):
- self.assertEqual(self.add, self.add)
- self.assertNotEqual(self.add, self.dbl)
+@pytest.fixture()
+def mdbl(secp128r1):
+ return secp128r1.curve.coordinate_model.formulas["mdbl-2007-bl"]
- def test_num_ops(self):
- self.assertEqual(self.add.num_operations, 33)
- self.assertEqual(self.add.num_multiplications, 17)
- self.assertEqual(self.add.num_divisions, 0)
- self.assertEqual(self.add.num_inversions, 0)
- self.assertEqual(self.add.num_powers, 0)
- self.assertEqual(self.add.num_squarings, 6)
- self.assertEqual(self.add.num_addsubs, 10)
- def test_assumptions(self):
- res = self.mdbl(
- self.secp128r1.curve.prime,
- self.secp128r1.generator,
- **self.secp128r1.curve.parameters
+def test_wrong_call(secp128r1, add):
+ with pytest.raises(ValueError):
+ add(secp128r1.curve.prime)
+ with pytest.raises(ValueError):
+ add(
+ secp128r1.curve.prime,
+ secp128r1.generator.to_affine(),
+ secp128r1.generator.to_affine(),
)
- self.assertIsNotNone(res)
- coords = {
- name: value * 5 for name, value in self.secp128r1.generator.coords.items()
- }
- other = Point(self.secp128r1.generator.coordinate_model, **coords)
- with self.assertRaises(UnsatisfiedAssumptionError):
- self.mdbl(
- self.secp128r1.curve.prime, other, **self.secp128r1.curve.parameters
- )
- with TemporaryConfig() as cfg:
- cfg.ec.unsatisfied_formula_assumption_action = "ignore"
- pt = self.mdbl(
- self.secp128r1.curve.prime, other, **self.secp128r1.curve.parameters
- )
- self.assertIsNotNone(pt)
- def test_parameters(self):
- res = self.jac_dbl(
- self.secp128r1.curve.prime,
- self.jac_secp128r1.generator,
- **self.jac_secp128r1.curve.parameters
- )
- self.assertIsNotNone(res)
+def test_indices(add):
+ assert add.input_index == 1
+ assert add.output_index == 3
+
+
+def test_inputs_outputs(add):
+ assert add.inputs == {"X1", "Y1", "Z1", "X2", "Y2", "Z2"}
+ assert add.outputs == {"X3", "Y3", "Z3"}
+
+
+def test_eq(add, dbl):
+ assert add == add
+ assert add != dbl
+
- def test_symbolic(self):
- p = self.secp128r1.curve.prime
- k = FF(p)
- coords = self.secp128r1.curve.coordinate_model
- sympy_params = {
- key: SymbolicMod(k(int(value)), p)
- for key, value in self.secp128r1.curve.parameters.items()
- }
- symbolic_point = Point(
- coords, **{key: SymbolicMod(symbols(key), p) for key in coords.variables}
+def test_num_ops(add):
+ assert add.num_operations == 33
+ assert add.num_multiplications == 17
+ assert add.num_divisions == 0
+ assert add.num_inversions == 0
+ assert add.num_powers == 0
+ assert add.num_squarings == 6
+ assert add.num_addsubs == 10
+
+
+def test_assumptions(secp128r1, mdbl):
+ res = mdbl(
+ secp128r1.curve.prime,
+ secp128r1.generator,
+ **secp128r1.curve.parameters
+ )
+ assert res is not None
+
+ coords = {
+ name: value * 5 for name, value in secp128r1.generator.coords.items()
+ }
+ other = Point(secp128r1.generator.coordinate_model, **coords)
+ with pytest.raises(UnsatisfiedAssumptionError):
+ mdbl(
+ secp128r1.curve.prime, other, **secp128r1.curve.parameters
)
- symbolic_double = self.dbl(p, symbolic_point, **sympy_params)[0]
- generator_double = self.dbl(
- p, self.secp128r1.generator, **self.secp128r1.curve.parameters
- )[0]
- for outer_var in coords.variables:
- symbolic_val = getattr(symbolic_double, outer_var).x
- generator_val = getattr(generator_double, outer_var).x
- for inner_var in coords.variables:
- symbolic_val = symbolic_val.subs(
- inner_var, k(getattr(self.secp128r1.generator, inner_var).x)
- )
- self.assertEqual(Mod(int(symbolic_val), p), Mod(generator_val, p))
+ with TemporaryConfig() as cfg:
+ cfg.ec.unsatisfied_formula_assumption_action = "ignore"
+ pt = mdbl(
+ secp128r1.curve.prime, other, **secp128r1.curve.parameters
+ )
+ assert pt is not None
+
+
+def test_parameters():
+ jac_secp128r1 = get_params("secg", "secp128r1", "jacobian")
+ jac_dbl = jac_secp128r1.curve.coordinate_model.formulas[
+ "dbl-1998-hnm"
+ ]
+
+ res = jac_dbl(
+ jac_secp128r1.curve.prime,
+ jac_secp128r1.generator,
+ **jac_secp128r1.curve.parameters
+ )
+ assert res is not None
+
+
+def test_symbolic(secp128r1, dbl):
+ p = secp128r1.curve.prime
+ k = FF(p)
+ coords = secp128r1.curve.coordinate_model
+ sympy_params = {
+ key: SymbolicMod(k(int(value)), p)
+ for key, value in secp128r1.curve.parameters.items()
+ }
+ symbolic_point = Point(
+ coords, **{key: SymbolicMod(symbols(key), p) for key in coords.variables}
+ )
+ symbolic_double = dbl(p, symbolic_point, **sympy_params)[0]
+ generator_double = dbl(
+ p, secp128r1.generator, **secp128r1.curve.parameters
+ )[0]
+ for outer_var in coords.variables:
+ symbolic_val = getattr(symbolic_double, outer_var).x
+ generator_val = getattr(generator_double, outer_var).x
+ for inner_var in coords.variables:
+ symbolic_val = symbolic_val.subs(
+ inner_var, k(getattr(secp128r1.generator, inner_var).x)
+ )
+ assert Mod(int(symbolic_val), p) == Mod(generator_val, p)
diff --git a/test/ec/test_key_agreement.py b/test/ec/test_key_agreement.py
index 240c174..14bd138 100644
--- a/test/ec/test_key_agreement.py
+++ b/test/ec/test_key_agreement.py
@@ -1,8 +1,4 @@
-from unittest import TestCase
-
-from parameterized import parameterized
-
-from pyecsca.ec.params import get_params
+import pytest
from pyecsca.ec.key_agreement import (
ECDH_NONE,
ECDH_SHA1,
@@ -15,31 +11,33 @@ from pyecsca.ec.mod import Mod
from pyecsca.ec.mult import LTRMultiplier
-class KeyAgreementTests(TestCase):
- def setUp(self):
- self.secp128r1 = get_params("secg", "secp128r1", "projective")
- self.add = self.secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
- self.dbl = self.secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
- self.mult = LTRMultiplier(self.add, self.dbl)
- self.priv_a = Mod(0xDEADBEEF, self.secp128r1.order)
- self.mult.init(self.secp128r1, self.secp128r1.generator)
- self.pub_a = self.mult.multiply(int(self.priv_a))
- self.priv_b = Mod(0xCAFEBABE, self.secp128r1.order)
- self.pub_b = self.mult.multiply(int(self.priv_b))
+@pytest.fixture()
+def mult(secp128r1):
+ add = secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
+ dbl = secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
+ return LTRMultiplier(add, dbl)
+
+
+@pytest.fixture()
+def keypair_a(secp128r1, mult):
+ priv_a = Mod(0xDEADBEEF, secp128r1.order)
+ mult.init(secp128r1, secp128r1.generator)
+ pub_a = mult.multiply(int(priv_a))
+ return priv_a, pub_a
+
+
+@pytest.fixture()
+def keypair_b(secp128r1, mult):
+ priv_b = Mod(0xCAFEBABE, secp128r1.order)
+ mult.init(secp128r1, secp128r1.generator)
+ pub_b = mult.multiply(int(priv_b))
+ return priv_b, pub_b
+
- @parameterized.expand(
- [
- ("NONE", ECDH_NONE),
- ("SHA1", ECDH_SHA1),
- ("SHA224", ECDH_SHA224),
- ("SHA256", ECDH_SHA256),
- ("SHA384", ECDH_SHA384),
- ("SHA512", ECDH_SHA512),
- ]
- )
- def test_all(self, name, algo):
- result_ab = algo(self.mult, self.secp128r1, self.pub_a, self.priv_b).perform()
- result_ba = algo(self.mult, self.secp128r1, self.pub_b, self.priv_a).perform()
- self.assertEqual(result_ab, result_ba)
+@pytest.mark.parametrize("algo", [ECDH_NONE, ECDH_SHA1, ECDH_SHA224, ECDH_SHA256, ECDH_SHA384, ECDH_SHA512])
+def test_ka(algo, mult, secp128r1, keypair_a, keypair_b):
+ result_ab = algo(mult, secp128r1, keypair_a[1], keypair_b[0]).perform()
+ result_ba = algo(mult, secp128r1, keypair_b[1], keypair_a[0]).perform()
+ assert result_ab == result_ba
- # TODO: Add KAT-based tests here.
+# TODO: Add KAT-based tests here.
diff --git a/test/ec/test_key_generation.py b/test/ec/test_key_generation.py
index 7eb26f0..512aaac 100644
--- a/test/ec/test_key_generation.py
+++ b/test/ec/test_key_generation.py
@@ -1,25 +1,24 @@
-from unittest import TestCase
+import pytest
-from pyecsca.ec.params import get_params
from pyecsca.ec.key_generation import KeyGeneration
from pyecsca.ec.mult import LTRMultiplier
-class KeyGenerationTests(TestCase):
- def setUp(self):
- self.secp128r1 = get_params("secg", "secp128r1", "projective")
- self.add = self.secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
- self.dbl = self.secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
- self.mult = LTRMultiplier(self.add, self.dbl)
+@pytest.fixture()
+def mult(secp128r1):
+ add = secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
+ dbl = secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
+ return LTRMultiplier(add, dbl)
- def test_basic(self):
- generator = KeyGeneration(self.mult, self.secp128r1)
- priv, pub = generator.generate()
- self.assertIsNotNone(priv)
- self.assertIsNotNone(pub)
- self.assertTrue(self.secp128r1.curve.is_on_curve(pub))
- generator = KeyGeneration(self.mult, self.secp128r1, True)
- priv, pub = generator.generate()
- self.assertIsNotNone(priv)
- self.assertIsNotNone(pub)
- self.assertTrue(self.secp128r1.curve.is_on_curve(pub))
+
+def test_basic(secp128r1, mult):
+ generator = KeyGeneration(mult, secp128r1)
+ priv, pub = generator.generate()
+ assert priv is not None
+ assert pub is not None
+ assert secp128r1.curve.is_on_curve(pub)
+ generator = KeyGeneration(mult, secp128r1, True)
+ priv, pub = generator.generate()
+ assert priv is not None
+ assert pub is not None
+ assert secp128r1.curve.is_on_curve(pub)
diff --git a/test/ec/test_mod.py b/test/ec/test_mod.py
index 62022b0..55522b0 100644
--- a/test/ec/test_mod.py
+++ b/test/ec/test_mod.py
@@ -1,6 +1,7 @@
import warnings
+
+import pytest
from sympy import FF, symbols
-from unittest import TestCase
from pyecsca.ec.mod import (
Mod,
@@ -22,153 +23,147 @@ from pyecsca.ec.error import (
from pyecsca.misc.cfg import getconfig, TemporaryConfig
-class ModTests(TestCase):
- def test_gcd(self):
- self.assertEqual(gcd(15, 20), 5)
- self.assertEqual(extgcd(15, 0), (1, 0, 15))
- self.assertEqual(extgcd(15, 20), (-1, 1, 5))
+def test_gcd():
+ assert gcd(15, 20) == 5
+ assert extgcd(15, 0) == (1, 0, 15)
+ assert extgcd(15, 20) == (-1, 1, 5)
- def test_jacobi(self):
- self.assertEqual(jacobi(5, 1153486465415345646578465454655646543248656451), 1)
- self.assertEqual(
- jacobi(564786456646845, 46874698564153465453246546545456849797895547657), -1
- )
- self.assertEqual(
- jacobi(564786456646845, 46874698564153465453246546545456849797895), 0
- )
- def test_miller_rabin(self):
- self.assertTrue(miller_rabin(2))
- self.assertTrue(miller_rabin(3))
- self.assertTrue(miller_rabin(5))
- self.assertFalse(miller_rabin(8))
- self.assertTrue(
- miller_rabin(0xE807561107CCF8FA82AF74FD492543A918CA2E9C13750233A9)
- )
- self.assertFalse(
- miller_rabin(0x6F6889DEB08DA211927370810F026EB4C17B17755F72EA005)
- )
+def test_jacobi():
+ assert jacobi(5, 1153486465415345646578465454655646543248656451) == 1
+ assert jacobi(564786456646845, 46874698564153465453246546545456849797895547657) == -1
+ assert jacobi(564786456646845, 46874698564153465453246546545456849797895) == 0
- def test_inverse(self):
- p = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
- self.assertEqual(
- Mod(
- 0x702BDAFD3C1C837B23A1CB196ED7F9FADB333C5CFE4A462BE32ADCD67BFB6AC1, p
- ).inverse(),
- Mod(0x1CB2E5274BBA085C4CA88EEDE75AE77949E7A410C80368376E97AB22EB590F9D, p),
- )
- with self.assertRaises(NonInvertibleError):
- Mod(0, p).inverse()
- with self.assertRaises(NonInvertibleError):
- Mod(5, 10).inverse()
- getconfig().ec.no_inverse_action = "warning"
- with warnings.catch_warnings(record=True) as w:
- Mod(0, p).inverse()
- self.assertTrue(issubclass(w[0].category, NonInvertibleWarning))
- with warnings.catch_warnings(record=True) as w:
- Mod(5, 10).inverse()
- self.assertTrue(issubclass(w[0].category, NonInvertibleWarning))
- getconfig().ec.no_inverse_action = "ignore"
+
+def test_miller_rabin():
+ assert miller_rabin(2)
+ assert miller_rabin(3)
+ assert miller_rabin(5)
+ assert not miller_rabin(8)
+ assert miller_rabin(0xE807561107CCF8FA82AF74FD492543A918CA2E9C13750233A9)
+ assert not miller_rabin(0x6F6889DEB08DA211927370810F026EB4C17B17755F72EA005)
+
+
+def test_inverse():
+ p = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
+ assert Mod(
+ 0x702BDAFD3C1C837B23A1CB196ED7F9FADB333C5CFE4A462BE32ADCD67BFB6AC1, p
+ ).inverse() == Mod(0x1CB2E5274BBA085C4CA88EEDE75AE77949E7A410C80368376E97AB22EB590F9D, p)
+ with pytest.raises(NonInvertibleError):
+ Mod(0, p).inverse()
+ with pytest.raises(NonInvertibleError):
+ Mod(5, 10).inverse()
+ getconfig().ec.no_inverse_action = "warning"
+ with warnings.catch_warnings(record=True) as w:
Mod(0, p).inverse()
+ assert issubclass(w[0].category, NonInvertibleWarning)
+ with warnings.catch_warnings(record=True) as w:
Mod(5, 10).inverse()
- getconfig().ec.no_inverse_action = "error"
+ assert issubclass(w[0].category, NonInvertibleWarning)
+ getconfig().ec.no_inverse_action = "ignore"
+ Mod(0, p).inverse()
+ Mod(5, 10).inverse()
+ getconfig().ec.no_inverse_action = "error"
- def test_is_residue(self):
- self.assertTrue(Mod(4, 11).is_residue())
- self.assertFalse(Mod(11, 31).is_residue())
- self.assertTrue(Mod(0, 7).is_residue())
- self.assertTrue(Mod(1, 2).is_residue())
- def test_sqrt(self):
- p = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
- self.assertIn(
- Mod(
- 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC, p
- ).sqrt(),
- (
- 0x9ADD512515B70D9EC471151C1DEC46625CD18B37BDE7CA7FB2C8B31D7033599D,
- 0x6522AED9EA48F2623B8EEAE3E213B99DA32E74C9421835804D374CE28FCCA662,
- ),
- )
- with self.assertRaises(NonResidueError):
- Mod(
- 0x702BDAFD3C1C837B23A1CB196ED7F9FADB333C5CFE4A462BE32ADCD67BFB6AC1, p
- ).sqrt()
- getconfig().ec.non_residue_action = "warning"
- with warnings.catch_warnings(record=True) as w:
- Mod(
- 0x702BDAFD3C1C837B23A1CB196ED7F9FADB333C5CFE4A462BE32ADCD67BFB6AC1, p
- ).sqrt()
- self.assertTrue(issubclass(w[0].category, NonResidueWarning))
- getconfig().ec.non_residue_action = "ignore"
+def test_is_residue():
+ assert Mod(4, 11).is_residue()
+ assert not Mod(11, 31).is_residue()
+ assert Mod(0, 7).is_residue()
+ assert Mod(1, 2).is_residue()
+
+
+def test_sqrt():
+ p = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF
+ assert Mod(
+ 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC, p
+ ).sqrt() in (
+ 0x9ADD512515B70D9EC471151C1DEC46625CD18B37BDE7CA7FB2C8B31D7033599D,
+ 0x6522AED9EA48F2623B8EEAE3E213B99DA32E74C9421835804D374CE28FCCA662,
+ )
+ with pytest.raises(NonResidueError):
+ Mod(
+ 0x702BDAFD3C1C837B23A1CB196ED7F9FADB333C5CFE4A462BE32ADCD67BFB6AC1, p
+ ).sqrt()
+ getconfig().ec.non_residue_action = "warning"
+ with warnings.catch_warnings(record=True) as w:
Mod(
0x702BDAFD3C1C837B23A1CB196ED7F9FADB333C5CFE4A462BE32ADCD67BFB6AC1, p
).sqrt()
- with TemporaryConfig() as cfg:
- cfg.ec.non_residue_action = "warning"
- with warnings.catch_warnings(record=True) as w:
- Mod(
- 0x702BDAFD3C1C837B23A1CB196ED7F9FADB333C5CFE4A462BE32ADCD67BFB6AC1,
- p,
- ).sqrt()
- self.assertTrue(issubclass(w[0].category, NonResidueWarning))
- self.assertEqual(Mod(0, p).sqrt(), Mod(0, p))
- q = 0x75D44FEE9A71841AE8403C0C251FBAD
- self.assertIn(
- Mod(0x591E0DB18CF1BD81A11B2985A821EB3, q).sqrt(),
- (0x113B41A1A2B73F636E73BE3F9A3716E, 0x64990E4CF7BA44B779CC7DCC8AE8A3F),
- )
- getconfig().ec.non_residue_action = "error"
+ assert issubclass(w[0].category, NonResidueWarning)
+ getconfig().ec.non_residue_action = "ignore"
+ Mod(
+ 0x702BDAFD3C1C837B23A1CB196ED7F9FADB333C5CFE4A462BE32ADCD67BFB6AC1, p
+ ).sqrt()
+ with TemporaryConfig() as cfg:
+ cfg.ec.non_residue_action = "warning"
+ with warnings.catch_warnings(record=True) as w:
+ Mod(
+ 0x702BDAFD3C1C837B23A1CB196ED7F9FADB333C5CFE4A462BE32ADCD67BFB6AC1,
+ p,
+ ).sqrt()
+ assert issubclass(w[0].category, NonResidueWarning)
+ assert Mod(0, p).sqrt() == Mod(0, p)
+ q = 0x75D44FEE9A71841AE8403C0C251FBAD
+ assert Mod(0x591E0DB18CF1BD81A11B2985A821EB3, q).sqrt() in \
+ (0x113B41A1A2B73F636E73BE3F9A3716E, 0x64990E4CF7BA44B779CC7DCC8AE8A3F)
+ getconfig().ec.non_residue_action = "error"
+
- def test_eq(self):
- self.assertEqual(Mod(1, 7), 1)
- self.assertNotEqual(Mod(1, 7), "1")
- self.assertEqual(Mod(1, 7), Mod(1, 7))
- self.assertNotEqual(Mod(1, 7), Mod(5, 7))
- self.assertNotEqual(Mod(1, 7), Mod(1, 5))
+def test_eq():
+ assert Mod(1, 7) == 1
+ assert Mod(1, 7) != "1"
+ assert Mod(1, 7) == Mod(1, 7)
+ assert Mod(1, 7) != Mod(5, 7)
+ assert Mod(1, 7) != Mod(1, 5)
- def test_pow(self):
- a = Mod(5, 7)
- self.assertEqual(a ** (-1), a.inverse())
- self.assertEqual(a ** 0, Mod(1, 7))
- self.assertEqual(a ** (-2), a.inverse() ** 2)
- def test_wrong_mod(self):
- a = Mod(5, 7)
- b = Mod(4, 11)
- with self.assertRaises(ValueError):
- a + b
+def test_pow():
+ a = Mod(5, 7)
+ assert a ** (-1) == a.inverse()
+ assert a ** 0 == Mod(1, 7)
+ assert a ** (-2) == a.inverse() ** 2
- def test_wrong_pow(self):
- a = Mod(5, 7)
- c = Mod(4, 11)
- with self.assertRaises(TypeError):
- a ** c
- def test_other(self):
- a = Mod(5, 7)
- b = Mod(3, 7)
- self.assertEqual(int(-a), 2)
- self.assertEqual(str(a), "5")
- self.assertEqual(6 - a, Mod(1, 7))
- self.assertNotEqual(a, b)
- self.assertEqual(a / b, Mod(4, 7))
- self.assertEqual(a // b, Mod(4, 7))
- self.assertEqual(5 / b, Mod(4, 7))
- self.assertEqual(5 // b, Mod(4, 7))
- self.assertEqual(a / 3, Mod(4, 7))
- self.assertEqual(a // 3, Mod(4, 7))
- self.assertEqual(divmod(a, b), (Mod(1, 7), Mod(2, 7)))
- self.assertEqual(a + b, Mod(1, 7))
- self.assertEqual(5 + b, Mod(1, 7))
- self.assertEqual(a + 3, Mod(1, 7))
- self.assertNotEqual(a, 6)
- self.assertIsNotNone(hash(a))
+def test_wrong_mod():
+ a = Mod(5, 7)
+ b = Mod(4, 11)
+ with pytest.raises(ValueError):
+ a + b
- def test_undefined(self):
- u = Undefined()
- for k, meth in u.__class__.__dict__.items():
- if k in (
+
+def test_wrong_pow():
+ a = Mod(5, 7)
+ c = Mod(4, 11)
+ with pytest.raises(TypeError):
+ a ** c
+
+
+def test_other():
+ a = Mod(5, 7)
+ b = Mod(3, 7)
+ assert int(-a) == 2
+ assert str(a) == "5"
+ assert 6 - a == Mod(1, 7)
+ assert a != b
+ assert a / b == Mod(4, 7)
+ assert a // b == Mod(4, 7)
+ assert 5 / b == Mod(4, 7)
+ assert 5 // b == Mod(4, 7)
+ assert a / 3 == Mod(4, 7)
+ assert a // 3 == Mod(4, 7)
+ assert divmod(a, b) == (Mod(1, 7), Mod(2, 7))
+ assert a + b == Mod(1, 7)
+ assert 5 + b == Mod(1, 7)
+ assert a + 3 == Mod(1, 7)
+ assert a != 6
+ assert hash(a) is not None
+
+
+def test_undefined():
+ u = Undefined()
+ for k, meth in u.__class__.__dict__.items():
+ if k in (
"__module__",
"__new__",
"__init__",
@@ -179,52 +174,54 @@ class ModTests(TestCase):
"__slots__",
"x",
"n"
- ):
- continue
- args = [5 for _ in range(meth.__code__.co_argcount - 1)]
- if k == "__repr__":
- self.assertEqual(meth(u), "Undefined")
- elif k in ("__eq__", "__ne__"):
- assert not meth(u, *args)
- else:
- try:
- res = meth(u, *args)
- self.assertEqual(res, NotImplemented)
- except NotImplementedError:
- pass
+ ):
+ continue
+ args = [5 for _ in range(meth.__code__.co_argcount - 1)]
+ if k == "__repr__":
+ assert meth(u) == "Undefined"
+ elif k in ("__eq__", "__ne__"):
+ assert not meth(u, *args)
+ else:
+ try:
+ res = meth(u, *args)
+ assert res == NotImplemented
+ except NotImplementedError:
+ pass
+
+
+def test_implementation():
+ if not has_gmp:
+ pytest.skip("Only makes sense if more Mod implementations are available.")
+ with TemporaryConfig() as cfg:
+ cfg.ec.mod_implementation = "python"
+ assert isinstance(Mod(5, 7), RawMod)
- def test_implementation(self):
- if not has_gmp:
- self.skipTest("Only makes sense if more Mod implementations are available.")
- with TemporaryConfig() as cfg:
- cfg.ec.mod_implementation = "python"
- self.assertIsInstance(Mod(5, 7), RawMod)
- def test_symbolic(self):
- x = symbols("x")
- p = 13
- k = FF(p)
- sx = SymbolicMod(x, p)
- a = k(3)
- b = k(5)
- r = sx * a + b
- self.assertIsInstance(r, SymbolicMod)
- self.assertEqual(r.n, p)
- sa = SymbolicMod(a, p)
- sb = SymbolicMod(b, p)
- self.assertEqual(sa, 3)
- self.assertEqual(sa.inverse(), SymbolicMod(k(9), p))
- self.assertEqual(1 / sa, SymbolicMod(k(9), p))
- self.assertEqual(sa + sb, 8)
- self.assertEqual(1 + sa, 4)
- self.assertEqual(sa - 1, 2)
- self.assertEqual(1 - sa, 11)
- self.assertEqual(sa + 1, 4)
- self.assertEqual(-sa, 10)
- self.assertEqual(sa / 2, 8)
- self.assertEqual(2 / sa, 5)
- self.assertEqual(sa // 2, 8)
- self.assertEqual(2 // sa, 5)
- self.assertEqual(int(sa), 3)
- self.assertNotEqual(sa, sb)
- self.assertIsNotNone(hash(sa))
+def test_symbolic():
+ x = symbols("x")
+ p = 13
+ k = FF(p)
+ sx = SymbolicMod(x, p)
+ a = k(3)
+ b = k(5)
+ r = sx * a + b
+ assert isinstance(r, SymbolicMod)
+ assert r.n == p
+ sa = SymbolicMod(a, p)
+ sb = SymbolicMod(b, p)
+ assert sa == 3
+ assert sa.inverse() == SymbolicMod(k(9), p)
+ assert 1 / sa == SymbolicMod(k(9), p)
+ assert sa + sb == 8
+ assert 1 + sa == 4
+ assert sa - 1 == 2
+ assert 1 - sa == 11
+ assert sa + 1 == 4
+ assert -sa == 10
+ assert sa / 2 == 8
+ assert 2 / sa == 5
+ assert sa // 2 == 8
+ assert 2 // sa == 5
+ assert int(sa) == 3
+ assert sa != sb
+ assert hash(sa) is not None
diff --git a/test/ec/test_model.py b/test/ec/test_model.py
index d1c03c3..d5c5afe 100644
--- a/test/ec/test_model.py
+++ b/test/ec/test_model.py
@@ -1,5 +1,3 @@
-from unittest import TestCase
-
from pyecsca.ec.model import (
ShortWeierstrassModel,
MontgomeryModel,
@@ -8,9 +6,8 @@ from pyecsca.ec.model import (
)
-class CurveModelTests(TestCase):
- def test_load(self):
- self.assertGreater(len(ShortWeierstrassModel().coordinates), 0)
- self.assertGreater(len(MontgomeryModel().coordinates), 0)
- self.assertGreater(len(EdwardsModel().coordinates), 0)
- self.assertGreater(len(TwistedEdwardsModel().coordinates), 0)
+def test_load():
+ assert len(ShortWeierstrassModel().coordinates) > 0
+ assert len(MontgomeryModel().coordinates) > 0
+ assert len(EdwardsModel().coordinates) > 0
+ assert len(TwistedEdwardsModel().coordinates) > 0
diff --git a/test/ec/test_mult.py b/test/ec/test_mult.py
index 5200520..c7edd03 100644
--- a/test/ec/test_mult.py
+++ b/test/ec/test_mult.py
@@ -1,8 +1,6 @@
-from unittest import TestCase
-from parameterized import parameterized
+import pytest
-from pyecsca.ec.params import get_params
from pyecsca.ec.mult import (
LTRMultiplier,
RTLMultiplier,
@@ -13,320 +11,316 @@ from pyecsca.ec.mult import (
DifferentialLadderMultiplier,
CoronMultiplier,
)
-from pyecsca.ec.point import InfinityPoint
+from pyecsca.ec.point import InfinityPoint, Point
from .utils import cartesian
-class ScalarMultiplierTests(TestCase):
- def setUp(self):
- self.secp128r1 = get_params("secg", "secp128r1", "projective")
- self.base = self.secp128r1.generator
- self.coords = self.secp128r1.curve.coordinate_model
+def get_formulas(coords, *names):
+ return [coords.formulas[name] for name in names if name is not None]
- self.curve25519 = get_params("other", "Curve25519", "xz")
- self.base25519 = self.curve25519.generator
- self.coords25519 = self.curve25519.curve.coordinate_model
- def get_formulas(self, coords, *names):
- return [coords.formulas[name] for name in names if name is not None]
+def assert_pt_equality(one: Point, other: Point, scale):
+ if scale:
+ assert one == other
+ else:
+ assert one.equals(other)
- def assertPointEquality(self, one, other, scale):
- if scale:
- self.assertEqual(one, other)
- else:
- assert one.equals(other)
- def do_basic_test(
- self, mult_class, params, base, add, dbl, scale, neg=None, **kwargs
- ):
- mult = mult_class(
- *self.get_formulas(params.curve.coordinate_model, add, dbl, neg, scale),
- **kwargs
- )
- mult.init(params, base)
- res = mult.multiply(314)
- other = mult.multiply(157)
- mult.init(params, other)
- other = mult.multiply(2)
- self.assertPointEquality(res, other, scale)
- mult.init(params, base)
- self.assertEqual(InfinityPoint(params.curve.coordinate_model), mult.multiply(0))
- return res
+def do_basic_test(
+ mult_class, params, base, add, dbl, scale, neg=None, **kwargs
+):
+ mult = mult_class(
+ *get_formulas(params.curve.coordinate_model, add, dbl, neg, scale),
+ **kwargs
+ )
+ mult.init(params, base)
+ res = mult.multiply(314)
+ other = mult.multiply(157)
+ mult.init(params, other)
+ other = mult.multiply(2)
+ assert_pt_equality(res, other, scale)
+ mult.init(params, base)
+ assert InfinityPoint(params.curve.coordinate_model) == mult.multiply(0)
+ return res
+
+
+@pytest.mark.parametrize("name,add,dbl,scale",
+ [
+ ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"),
+ ("complete", "add-2016-rcb", "dbl-2016-rcb", None),
+ ("none", "add-1998-cmo", "dbl-1998-cmo", None),
+ ])
+def test_rtl(secp128r1, name, add, dbl, scale):
+ do_basic_test(RTLMultiplier, secp128r1, secp128r1.generator, add, dbl, scale)
- @parameterized.expand(
- [
- ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"),
- ("complete", "add-2016-rcb", "dbl-2016-rcb", None),
- ("none", "add-1998-cmo", "dbl-1998-cmo", None),
- ]
+
+@pytest.mark.parametrize("name,add,dbl,scale",
+ [
+ ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"),
+ ("complete", "add-2016-rcb", "dbl-2016-rcb", None),
+ ("none", "add-1998-cmo", "dbl-1998-cmo", None),
+ ])
+def test_ltr(secp128r1, name, add, dbl, scale):
+ a = do_basic_test(
+ LTRMultiplier, secp128r1, secp128r1.generator, add, dbl, scale
+ )
+ b = do_basic_test(
+ LTRMultiplier, secp128r1, secp128r1.generator, add, dbl, scale, always=True
+ )
+ c = do_basic_test(
+ LTRMultiplier, secp128r1, secp128r1.generator, add, dbl, scale, complete=False
)
- def test_rtl(self, name, add, dbl, scale):
- self.do_basic_test(RTLMultiplier, self.secp128r1, self.base, add, dbl, scale)
+ d = do_basic_test(
+ LTRMultiplier,
+ secp128r1,
+ secp128r1.generator,
+ add,
+ dbl,
+ scale,
+ always=True,
+ complete=False,
+ )
+ assert_pt_equality(a, b, scale)
+ assert_pt_equality(b, c, scale)
+ assert_pt_equality(c, d, scale)
+
+
+@pytest.mark.parametrize("name,add,dbl,scale",
+ [
+ ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"),
+ ("complete", "add-2016-rcb", "dbl-2016-rcb", None),
+ ("none", "add-1998-cmo", "dbl-1998-cmo", None),
+ ]
+ )
+def test_coron(secp128r1, name, add, dbl, scale):
+ do_basic_test(CoronMultiplier, secp128r1, secp128r1.generator, add, dbl, scale)
- @parameterized.expand(
- [
- ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"),
- ("complete", "add-2016-rcb", "dbl-2016-rcb", None),
- ("none", "add-1998-cmo", "dbl-1998-cmo", None),
- ]
+
+def test_ladder(curve25519):
+ a = do_basic_test(
+ LadderMultiplier,
+ curve25519,
+ curve25519.generator,
+ "ladd-1987-m",
+ "dbl-1987-m",
+ "scale",
)
- def test_ltr(self, name, add, dbl, scale):
- a = self.do_basic_test(
- LTRMultiplier, self.secp128r1, self.base, add, dbl, scale
- )
- b = self.do_basic_test(
- LTRMultiplier, self.secp128r1, self.base, add, dbl, scale, always=True
- )
- c = self.do_basic_test(
- LTRMultiplier, self.secp128r1, self.base, add, dbl, scale, complete=False
- )
- d = self.do_basic_test(
- LTRMultiplier,
- self.secp128r1,
- self.base,
- add,
- dbl,
- scale,
- always=True,
- complete=False,
- )
- self.assertPointEquality(a, b, scale)
- self.assertPointEquality(b, c, scale)
- self.assertPointEquality(c, d, scale)
+ b = do_basic_test(
+ LadderMultiplier,
+ curve25519,
+ curve25519.generator,
+ "ladd-1987-m",
+ "dbl-1987-m",
+ "scale",
+ complete=False,
+ )
+ assert_pt_equality(a, b, True)
+
- @parameterized.expand(
- [
- ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"),
- ("complete", "add-2016-rcb", "dbl-2016-rcb", None),
- ("none", "add-1998-cmo", "dbl-1998-cmo", None),
- ]
+@pytest.mark.parametrize("name,add,dbl,scale",
+ [
+ ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"),
+ ("complete", "add-2016-rcb", "dbl-2016-rcb", None),
+ ("none", "add-1998-cmo", "dbl-1998-cmo", None),
+ ])
+def test_simple_ladder(secp128r1, name, add, dbl, scale):
+ do_basic_test(
+ SimpleLadderMultiplier, secp128r1, secp128r1.generator, add, dbl, scale
)
- def test_coron(self, name, add, dbl, scale):
- self.do_basic_test(CoronMultiplier, self.secp128r1, self.base, add, dbl, scale)
- def test_ladder(self):
- a = self.do_basic_test(
- LadderMultiplier,
- self.curve25519,
- self.base25519,
- "ladd-1987-m",
- "dbl-1987-m",
- "scale",
- )
- b = self.do_basic_test(
- LadderMultiplier,
- self.curve25519,
- self.base25519,
- "ladd-1987-m",
- "dbl-1987-m",
- "scale",
- complete=False,
- )
- self.assertPointEquality(a, b, True)
- @parameterized.expand(
- [
- ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"),
- ("complete", "add-2016-rcb", "dbl-2016-rcb", None),
- ("none", "add-1998-cmo", "dbl-1998-cmo", None),
- ]
+@pytest.mark.parametrize("name,num,complete",
+ [
+ ("15", 15, True),
+ ("15", 15, False),
+ ("2355498743", 2355498743, True),
+ ("2355498743", 2355498743, False),
+ (
+ "325385790209017329644351321912443757746",
+ 325385790209017329644351321912443757746,
+ True,
+ ),
+ (
+ "325385790209017329644351321912443757746",
+ 325385790209017329644351321912443757746,
+ False,
+ ),
+ ])
+def test_ladder_differential(curve25519, name, num, complete):
+ ladder = LadderMultiplier(
+ curve25519.curve.coordinate_model.formulas["ladd-1987-m"],
+ curve25519.curve.coordinate_model.formulas["dbl-1987-m"],
+ curve25519.curve.coordinate_model.formulas["scale"],
+ complete=complete,
)
- def test_simple_ladder(self, name, add, dbl, scale):
- self.do_basic_test(
- SimpleLadderMultiplier, self.secp128r1, self.base, add, dbl, scale
- )
+ differential = DifferentialLadderMultiplier(
+ curve25519.curve.coordinate_model.formulas["dadd-1987-m"],
+ curve25519.curve.coordinate_model.formulas["dbl-1987-m"],
+ curve25519.curve.coordinate_model.formulas["scale"],
+ complete=complete,
+ )
+ ladder.init(curve25519, curve25519.generator)
+ res_ladder = ladder.multiply(num)
+ differential.init(curve25519, curve25519.generator)
+ res_differential = differential.multiply(num)
+ assert res_ladder == res_differential
+ assert InfinityPoint(curve25519.curve.coordinate_model) == differential.multiply(0)
+
- @parameterized.expand(
- [
- ("15", 15, True),
- ("15", 15, False),
- ("2355498743", 2355498743, True),
- ("2355498743", 2355498743, False),
- (
- "325385790209017329644351321912443757746",
- 325385790209017329644351321912443757746,
- True,
- ),
- (
- "325385790209017329644351321912443757746",
- 325385790209017329644351321912443757746,
- False,
- ),
- ]
+@pytest.mark.parametrize("name,add,dbl,neg,scale",
+ [
+ ("scaled", "add-1998-cmo", "dbl-1998-cmo", "neg", "z"),
+ ("complete", "add-2016-rcb", "dbl-2016-rcb", "neg", None),
+ ("none", "add-1998-cmo", "dbl-1998-cmo", "neg", None),
+ ])
+def test_binary_naf(secp128r1, name, add, dbl, neg, scale):
+ do_basic_test(
+ BinaryNAFMultiplier, secp128r1, secp128r1.generator, add, dbl, scale, neg
)
- def test_ladder_differential(self, name, num, complete):
- ladder = LadderMultiplier(
- self.coords25519.formulas["ladd-1987-m"],
- self.coords25519.formulas["dbl-1987-m"],
- self.coords25519.formulas["scale"],
- complete=complete,
- )
- differential = DifferentialLadderMultiplier(
- self.coords25519.formulas["dadd-1987-m"],
- self.coords25519.formulas["dbl-1987-m"],
- self.coords25519.formulas["scale"],
- complete=complete,
- )
- ladder.init(self.curve25519, self.base25519)
- res_ladder = ladder.multiply(num)
- differential.init(self.curve25519, self.base25519)
- res_differential = differential.multiply(num)
- self.assertEqual(res_ladder, res_differential)
- self.assertEqual(InfinityPoint(self.coords25519), differential.multiply(0))
- @parameterized.expand(
- [
- ("scaled", "add-1998-cmo", "dbl-1998-cmo", "neg", "z"),
- ("complete", "add-2016-rcb", "dbl-2016-rcb", "neg", None),
- ("none", "add-1998-cmo", "dbl-1998-cmo", "neg", None),
- ]
+
+@pytest.mark.parametrize("name,add,dbl,neg,width,scale",
+ [
+ ("scaled3", "add-1998-cmo", "dbl-1998-cmo", "neg", 3, "z"),
+ ("none3", "add-1998-cmo", "dbl-1998-cmo", "neg", 3, None),
+ ("complete3", "add-2016-rcb", "dbl-2016-rcb", "neg", 3, None),
+ ("scaled5", "add-1998-cmo", "dbl-1998-cmo", "neg", 5, "z"),
+ ("none5", "add-1998-cmo", "dbl-1998-cmo", "neg", 5, None),
+ ("complete5", "add-2016-rcb", "dbl-2016-rcb", "neg", 5, None),
+ ])
+def test_window_naf(secp128r1, name, add, dbl, neg, width, scale):
+ formulas = get_formulas(secp128r1.curve.coordinate_model, add, dbl, neg, scale)
+ mult = WindowNAFMultiplier(*formulas[:3], width, *formulas[3:])
+ mult.init(secp128r1, secp128r1.generator)
+ res = mult.multiply(157 * 789)
+ other = mult.multiply(157)
+ mult.init(secp128r1, other)
+ other = mult.multiply(789)
+ assert_pt_equality(res, other, scale)
+ mult.init(secp128r1, secp128r1.generator)
+ assert InfinityPoint(secp128r1.curve.coordinate_model) == mult.multiply(0)
+
+ mult = WindowNAFMultiplier(
+ *formulas[:3], width, *formulas[3:], precompute_negation=True
)
- def test_binary_naf(self, name, add, dbl, neg, scale):
- self.do_basic_test(
- BinaryNAFMultiplier, self.secp128r1, self.base, add, dbl, scale, neg
- )
+ mult.init(secp128r1, secp128r1.generator)
+ res_precompute = mult.multiply(157 * 789)
+ assert_pt_equality(res_precompute, res, scale)
+
- @parameterized.expand(
- [
- ("scaled3", "add-1998-cmo", "dbl-1998-cmo", "neg", 3, "z"),
- ("none3", "add-1998-cmo", "dbl-1998-cmo", "neg", 3, None),
- ("complete3", "add-2016-rcb", "dbl-2016-rcb", "neg", 3, None),
- ("scaled5", "add-1998-cmo", "dbl-1998-cmo", "neg", 5, "z"),
- ("none5", "add-1998-cmo", "dbl-1998-cmo", "neg", 5, None),
- ("complete5", "add-2016-rcb", "dbl-2016-rcb", "neg", 5, None),
- ]
+@pytest.mark.parametrize("name,num,add,dbl",
+ cartesian(
+ [
+ ("10", 10),
+ ("2355498743", 2355498743),
+ (
+ "325385790209017329644351321912443757746",
+ 325385790209017329644351321912443757746,
+ ),
+ ],
+ [("add-1998-cmo", "dbl-1998-cmo"), ("add-2016-rcb", "dbl-2016-rcb")],
+ )
+ )
+def test_basic_multipliers(secp128r1, name, num, add, dbl):
+ ltr = LTRMultiplier(
+ secp128r1.curve.coordinate_model.formulas[add],
+ secp128r1.curve.coordinate_model.formulas[dbl],
+ secp128r1.curve.coordinate_model.formulas["z"],
+ )
+ with pytest.raises(ValueError):
+ ltr.multiply(1)
+ ltr.init(secp128r1, secp128r1.generator)
+ res_ltr = ltr.multiply(num)
+ rtl = RTLMultiplier(
+ secp128r1.curve.coordinate_model.formulas[add],
+ secp128r1.curve.coordinate_model.formulas["dbl-1998-cmo"],
+ secp128r1.curve.coordinate_model.formulas["z"],
)
- def test_window_naf(self, name, add, dbl, neg, width, scale):
- formulas = self.get_formulas(self.coords, add, dbl, neg, scale)
- mult = WindowNAFMultiplier(*formulas[:3], width, *formulas[3:])
- mult.init(self.secp128r1, self.base)
- res = mult.multiply(157 * 789)
- other = mult.multiply(157)
- mult.init(self.secp128r1, other)
- other = mult.multiply(789)
- self.assertPointEquality(res, other, scale)
- mult.init(self.secp128r1, self.base)
- self.assertEqual(InfinityPoint(self.coords), mult.multiply(0))
+ with pytest.raises(ValueError):
+ rtl.multiply(1)
+ rtl.init(secp128r1, secp128r1.generator)
+ res_rtl = rtl.multiply(num)
+ assert res_ltr == res_rtl
- mult = WindowNAFMultiplier(
- *formulas[:3], width, *formulas[3:], precompute_negation=True
- )
- mult.init(self.secp128r1, self.base)
- res_precompute = mult.multiply(157 * 789)
- self.assertPointEquality(res_precompute, res, scale)
+ ltr_always = LTRMultiplier(
+ secp128r1.curve.coordinate_model.formulas[add],
+ secp128r1.curve.coordinate_model.formulas[dbl],
+ secp128r1.curve.coordinate_model.formulas["z"],
+ always=True,
+ )
+ rtl_always = RTLMultiplier(
+ secp128r1.curve.coordinate_model.formulas[add],
+ secp128r1.curve.coordinate_model.formulas[dbl],
+ secp128r1.curve.coordinate_model.formulas["z"],
+ always=True,
+ )
+ ltr_always.init(secp128r1, secp128r1.generator)
+ rtl_always.init(secp128r1, secp128r1.generator)
+ res_ltr_always = ltr_always.multiply(num)
+ res_rtl_always = rtl_always.multiply(num)
+ assert res_ltr == res_ltr_always
+ assert res_rtl == res_rtl_always
- @parameterized.expand(
- cartesian(
- [
- ("10", 10),
- ("2355498743", 2355498743),
- (
- "325385790209017329644351321912443757746",
- 325385790209017329644351321912443757746,
- ),
- ],
- [("add-1998-cmo", "dbl-1998-cmo"), ("add-2016-rcb", "dbl-2016-rcb")],
- )
+ bnaf = BinaryNAFMultiplier(
+ secp128r1.curve.coordinate_model.formulas[add],
+ secp128r1.curve.coordinate_model.formulas[dbl],
+ secp128r1.curve.coordinate_model.formulas["neg"],
+ secp128r1.curve.coordinate_model.formulas["z"],
)
- def test_basic_multipliers(self, name, num, add, dbl):
- ltr = LTRMultiplier(
- self.coords.formulas[add],
- self.coords.formulas[dbl],
- self.coords.formulas["z"],
- )
- with self.assertRaises(ValueError):
- ltr.multiply(1)
- ltr.init(self.secp128r1, self.base)
- res_ltr = ltr.multiply(num)
- rtl = RTLMultiplier(
- self.coords.formulas[add],
- self.coords.formulas["dbl-1998-cmo"],
- self.coords.formulas["z"],
- )
- with self.assertRaises(ValueError):
- rtl.multiply(1)
- rtl.init(self.secp128r1, self.base)
- res_rtl = rtl.multiply(num)
- self.assertEqual(res_ltr, res_rtl)
+ with pytest.raises(ValueError):
+ bnaf.multiply(1)
+ bnaf.init(secp128r1, secp128r1.generator)
+ res_bnaf = bnaf.multiply(num)
+ assert res_bnaf == res_ltr
- ltr_always = LTRMultiplier(
- self.coords.formulas[add],
- self.coords.formulas[dbl],
- self.coords.formulas["z"],
- always=True,
- )
- rtl_always = RTLMultiplier(
- self.coords.formulas[add],
- self.coords.formulas[dbl],
- self.coords.formulas["z"],
- always=True,
- )
- ltr_always.init(self.secp128r1, self.base)
- rtl_always.init(self.secp128r1, self.base)
- res_ltr_always = ltr_always.multiply(num)
- res_rtl_always = rtl_always.multiply(num)
- self.assertEqual(res_ltr, res_ltr_always)
- self.assertEqual(res_rtl, res_rtl_always)
+ wnaf = WindowNAFMultiplier(
+ secp128r1.curve.coordinate_model.formulas[add],
+ secp128r1.curve.coordinate_model.formulas[dbl],
+ secp128r1.curve.coordinate_model.formulas["neg"],
+ 3,
+ secp128r1.curve.coordinate_model.formulas["z"],
+ )
+ with pytest.raises(ValueError):
+ wnaf.multiply(1)
+ wnaf.init(secp128r1, secp128r1.generator)
+ res_wnaf = wnaf.multiply(num)
+ assert res_wnaf == res_ltr
- bnaf = BinaryNAFMultiplier(
- self.coords.formulas[add],
- self.coords.formulas[dbl],
- self.coords.formulas["neg"],
- self.coords.formulas["z"],
- )
- with self.assertRaises(ValueError):
- bnaf.multiply(1)
- bnaf.init(self.secp128r1, self.base)
- res_bnaf = bnaf.multiply(num)
- self.assertEqual(res_bnaf, res_ltr)
+ ladder = SimpleLadderMultiplier(
+ secp128r1.curve.coordinate_model.formulas[add],
+ secp128r1.curve.coordinate_model.formulas[dbl],
+ secp128r1.curve.coordinate_model.formulas["z"],
+ )
+ with pytest.raises(ValueError):
+ ladder.multiply(1)
+ ladder.init(secp128r1, secp128r1.generator)
+ res_ladder = ladder.multiply(num)
+ assert res_ladder == res_ltr
- wnaf = WindowNAFMultiplier(
- self.coords.formulas[add],
- self.coords.formulas[dbl],
- self.coords.formulas["neg"],
- 3,
- self.coords.formulas["z"],
- )
- with self.assertRaises(ValueError):
- wnaf.multiply(1)
- wnaf.init(self.secp128r1, self.base)
- res_wnaf = wnaf.multiply(num)
- self.assertEqual(res_wnaf, res_ltr)
+ coron = CoronMultiplier(
+ secp128r1.curve.coordinate_model.formulas[add],
+ secp128r1.curve.coordinate_model.formulas[dbl],
+ secp128r1.curve.coordinate_model.formulas["z"],
+ )
+ with pytest.raises(ValueError):
+ coron.multiply(1)
+ coron.init(secp128r1, secp128r1.generator)
+ res_coron = coron.multiply(num)
+ assert res_coron == res_ltr
- ladder = SimpleLadderMultiplier(
- self.coords.formulas[add],
- self.coords.formulas[dbl],
- self.coords.formulas["z"],
- )
- with self.assertRaises(ValueError):
- ladder.multiply(1)
- ladder.init(self.secp128r1, self.base)
- res_ladder = ladder.multiply(num)
- self.assertEqual(res_ladder, res_ltr)
- coron = CoronMultiplier(
- self.coords.formulas[add],
- self.coords.formulas[dbl],
- self.coords.formulas["z"],
- )
- with self.assertRaises(ValueError):
- coron.multiply(1)
- coron.init(self.secp128r1, self.base)
- res_coron = coron.multiply(num)
- self.assertEqual(res_coron, res_ltr)
+def test_init_fail(curve25519, secp128r1):
+ mult = DifferentialLadderMultiplier(
+ curve25519.curve.coordinate_model.formulas["dadd-1987-m"],
+ curve25519.curve.coordinate_model.formulas["dbl-1987-m"],
+ curve25519.curve.coordinate_model.formulas["scale"],
+ )
+ with pytest.raises(ValueError):
+ mult.init(secp128r1, secp128r1.generator)
- def test_init_fail(self):
- mult = DifferentialLadderMultiplier(
- self.coords25519.formulas["dadd-1987-m"],
- self.coords25519.formulas["dbl-1987-m"],
- self.coords25519.formulas["scale"],
+ with pytest.raises(ValueError):
+ LadderMultiplier(
+ curve25519.curve.coordinate_model.formulas["ladd-1987-m"],
+ scl=curve25519.curve.coordinate_model.formulas["scale"],
+ complete=False,
)
- with self.assertRaises(ValueError):
- mult.init(self.secp128r1, self.base)
-
- with self.assertRaises(ValueError):
- LadderMultiplier(
- self.coords25519.formulas["ladd-1987-m"],
- scl=self.coords25519.formulas["scale"],
- complete=False,
- )
diff --git a/test/ec/test_naf.py b/test/ec/test_naf.py
index bdc176a..3e7c444 100644
--- a/test/ec/test_naf.py
+++ b/test/ec/test_naf.py
@@ -1,9 +1,6 @@
-from unittest import TestCase
-
from pyecsca.ec.naf import naf, wnaf
-class NafTests(TestCase):
- def test_nafs(self):
- i = 0b1100110101001101011011
- self.assertListEqual(naf(i), wnaf(i, 2))
+def test_nafs():
+ i = 0b1100110101001101011011
+ assert naf(i) == wnaf(i, 2)
diff --git a/test/ec/test_op.py b/test/ec/test_op.py
index e418350..94edcc3 100644
--- a/test/ec/test_op.py
+++ b/test/ec/test_op.py
@@ -1,49 +1,30 @@
from ast import parse
-from unittest import TestCase
-from parameterized import parameterized
-
-from pyecsca.ec.formula import OpResult
+import pytest
from pyecsca.ec.mod import Mod
from pyecsca.ec.op import CodeOp, OpType
-class OpTests(TestCase):
- @parameterized.expand(
- [
- ("add", "x = a+b", "x = a+b", OpType.Add),
- ("sub", "x = a-b", "x = a-b", OpType.Sub),
- ("mul", "y = a*b", "y = a*b", OpType.Mult),
- ("div", "z = a/b", "z = a/b", OpType.Div),
- ("inv", "z = 1/b", "z = 1/b", OpType.Inv),
- ("pow", "b = a**d", "b = a^d", OpType.Pow),
- ("sqr", "b = a**2", "b = a^2", OpType.Sqr),
- ("id1", "b = 7", "b = 7", OpType.Id),
- ("id2", "b = a", "b = a", OpType.Id),
- ]
- )
- def test_str(self, name, module, result, op_type):
- code = parse(module, mode="exec")
- op = CodeOp(code)
- self.assertEqual(str(op), result)
- self.assertEqual(op.operator, op_type)
+@pytest.mark.parametrize("name,module,result,op_type",
+ [("add", "x = a+b", "x = a+b", OpType.Add), ("sub", "x = a-b", "x = a-b", OpType.Sub),
+ ("mul", "y = a*b", "y = a*b", OpType.Mult), ("div", "z = a/b", "z = a/b", OpType.Div),
+ ("inv", "z = 1/b", "z = 1/b", OpType.Inv), ("pow", "b = a**d", "b = a^d", OpType.Pow),
+ ("sqr", "b = a**2", "b = a^2", OpType.Sqr), ("id1", "b = 7", "b = 7", OpType.Id),
+ ("id2", "b = a", "b = a", OpType.Id), ])
+def test_str(name, module, result, op_type):
+ code = parse(module, mode="exec")
+ op = CodeOp(code)
+ assert str(op) == result
+ assert op.operator == op_type
- @parameterized.expand(
- [
- ("add", "x = a+b", {"a": Mod(5, 21), "b": Mod(7, 21)}, Mod(12, 21)),
- ("sub", "x = a-b", {"a": Mod(7, 21), "b": Mod(5, 21)}, Mod(2, 21)),
- ]
- )
- def test_call(self, name, module, locals, result):
- code = parse(module, mode="exec")
- op = CodeOp(code)
- res = op(**locals)
- self.assertEqual(res, result)
+@pytest.mark.parametrize("name,module,locals,result",
+ [("add", "x = a+b", {"a": Mod(5, 21), "b": Mod(7, 21)}, Mod(12, 21)),
+ ("sub", "x = a-b", {"a": Mod(7, 21), "b": Mod(5, 21)}, Mod(2, 21)), ])
+def test_call(name, module, locals, result):
+ code = parse(module, mode="exec")
+ op = CodeOp(code)
+ res = op(**locals)
+ assert res == result
-class OpResultTests(TestCase):
- def test_str(self):
- for op in (OpType.Add, OpType.Sub, OpType.Mult, OpType.Div):
- res = OpResult("X1", Mod(0, 5), op, Mod(2, 5), Mod(3, 5))
- self.assertEqual(str(res), "X1")
- self.assertEqual(repr(res), f"X1 = 2{op.op_str}3")
+# TODO: Add op_type tests
diff --git a/test/ec/test_params.py b/test/ec/test_params.py
index 833272d..ceaef48 100644
--- a/test/ec/test_params.py
+++ b/test/ec/test_params.py
@@ -1,122 +1,144 @@
-from unittest import TestCase
+from importlib_resources import files, as_file
-from parameterized import parameterized
+import pytest
+import test.data.ec
from pyecsca.ec.mod import Mod
from pyecsca.ec.point import Point, InfinityPoint
from pyecsca.misc.cfg import TemporaryConfig
from pyecsca.ec.coordinates import AffineCoordinateModel
from pyecsca.ec.error import UnsatisfiedAssumptionError
-from pyecsca.ec.params import get_params, load_params, load_category, get_category, DomainParameters
+from pyecsca.ec.params import get_params, load_params, load_category, get_category, DomainParameters, \
+ load_params_ectester, load_params_ecgen
from pyecsca.ec.model import ShortWeierstrassModel
from pyecsca.ec.curve import EllipticCurve
-class DomainParameterTests(TestCase):
- def setUp(self):
- self.secp128r1 = get_params("secg", "secp128r1", "projective")
- self.curve25519 = get_params("other", "Curve25519", "xz")
+def test_eq(secp128r1, curve25519):
+ assert secp128r1 == secp128r1
+ assert secp128r1 != curve25519
+ assert secp128r1 is not None
- def test_eq(self):
- self.assertEqual(self.secp128r1, self.secp128r1)
- self.assertNotEqual(self.secp128r1, self.curve25519)
- self.assertNotEqual(self.secp128r1, None)
- def test_str(self):
- self.assertEqual(str(self.secp128r1), "DomainParameters(secg/secp128r1)")
+def test_str(secp128r1):
+ assert str(secp128r1) == "DomainParameters(secg/secp128r1)"
- @parameterized.expand(
- [
- ("secg/secp128r1", "projective"),
- ("secg/secp256r1", "projective"),
- ("secg/secp521r1", "projective"),
- ("other/Curve25519", "xz"),
- ("other/Ed25519", "projective"),
- ("other/Ed448", "projective"),
- ("other/E-222", "projective"),
- ]
- )
- def test_get_params(self, name, coords):
- params = get_params(*name.split("/"), coords)
- try:
- assert params.curve.is_on_curve(params.generator)
- except NotImplementedError:
- pass
- @parameterized.expand(
- [
- ("anssi", "projective"),
- (
- "brainpool",
- lambda name: "projective" if name.endswith("r1") else "jacobian",
- ),
- ]
- )
- def test_get_category(self, name, coords):
- get_category(name, coords)
+@pytest.mark.parametrize("name,coords",
+ [
+ ("secg/secp128r1", "projective"),
+ ("secg/secp256r1", "projective"),
+ ("secg/secp521r1", "projective"),
+ ("other/Curve25519", "xz"),
+ ("other/Ed25519", "projective"),
+ ("other/Ed448", "projective"),
+ ("other/E-222", "projective"),
+ ])
+def test_get_params(name, coords):
+ params = get_params(*name.split("/"), coords)
+ try:
+ assert params.curve.is_on_curve(params.generator)
+ except NotImplementedError:
+ pass
+
- def test_load_params(self):
- params = load_params("test/data/curve.json", "projective")
+@pytest.mark.parametrize("name,coords",
+ [
+ ("anssi", "projective"),
+ (
+ "brainpool",
+ lambda name: "projective" if name.endswith("r1") else "jacobian",
+ ),
+ ])
+def test_get_category(name, coords):
+ get_category(name, coords)
+
+
+def test_load_params():
+ with as_file(files(test.data.ec).joinpath("curve.json")) as path:
+ params = load_params(path, "projective")
try:
assert params.curve.is_on_curve(params.generator)
except NotImplementedError:
pass
- def test_load_category(self):
- category = load_category("test/data/curves.json", "yz")
- self.assertEqual(len(category), 1)
- @parameterized.expand(
- [
- ("no_category/some", "else"),
- ("secg/no_curve", "else"),
- ("secg/secp128r1", "some"),
- ]
- )
- def test_unknown(self, name, coords):
- with self.assertRaises(ValueError):
- get_params(*name.split("/"), coords)
+def test_load_params_ectester(secp128r1):
+ with as_file(files(test.data.ec).joinpath("ectester_secp128r1.csv")) as path:
+ params = load_params_ectester(path, "projective")
+ assert params.curve.is_on_curve(params.generator)
+ assert params == secp128r1
+
+
+def test_load_params_ecgen(secp128r1):
+ with as_file(files(test.data.ec).joinpath("ecgen_secp128r1.json")) as path:
+ params = load_params_ecgen(path, "projective")
+ assert params.curve.is_on_curve(params.generator)
+ assert params == secp128r1
+
+
+def test_load_category():
+ with as_file(files(test.data.ec).joinpath("curves.json")) as path:
+ category = load_category(path, "yz")
+ assert len(category) == 1
+
+
+@pytest.mark.parametrize("name,coords",
+ [
+ ("no_category/some", "else"),
+ ("secg/no_curve", "else"),
+ ("secg/secp128r1", "some"),
+ ])
+def test_unknown(name, coords):
+ with pytest.raises(ValueError):
+ get_params(*name.split("/"), coords)
+
+
+def test_assumption():
+ with pytest.raises(UnsatisfiedAssumptionError):
+ get_params("secg", "secp128r1", "projective-1")
+ with TemporaryConfig() as cfg:
+ cfg.ec.unsatisfied_coordinate_assumption_action = "ignore"
+ params = get_params("secg", "secp128r1", "projective-1")
+ assert params is not None
+ assert get_params("secg", "secp128r1", "projective-3") is not None
+
+
+def test_infty():
+ with pytest.raises(ValueError):
+ get_params("other", "Ed25519", "modified", False)
+ assert get_params("secg", "secp128r1", "projective", False) is not None
+
+
+def test_no_binary():
+ with pytest.raises(ValueError):
+ get_params("secg", "sect163r1", "something")
- def test_assumption(self):
- with self.assertRaises(UnsatisfiedAssumptionError):
- get_params("secg", "secp128r1", "projective-1")
- with TemporaryConfig() as cfg:
- cfg.ec.unsatisfied_coordinate_assumption_action = "ignore"
- params = get_params("secg", "secp128r1", "projective-1")
- self.assertIsNotNone(params)
- self.assertIsNotNone(get_params("secg", "secp128r1", "projective-3"))
- def test_infty(self):
- with self.assertRaises(ValueError):
- get_params("other", "Ed25519", "modified", False)
- self.assertIsNotNone(get_params("secg", "secp128r1", "projective", False))
+def test_no_extension():
+ with pytest.raises(ValueError):
+ get_params("other", "Fp254n2BNa", "something")
- def test_no_binary(self):
- with self.assertRaises(ValueError):
- get_params("secg", "sect163r1", "something")
- def test_no_extension(self):
- with self.assertRaises(ValueError):
- get_params("other", "Fp254n2BNa", "something")
+def test_affine():
+ aff = get_params("secg", "secp128r1", "affine")
+ assert isinstance(aff.curve.coordinate_model, AffineCoordinateModel)
- def test_affine(self):
- aff = get_params("secg", "secp128r1", "affine")
- self.assertIsInstance(aff.curve.coordinate_model, AffineCoordinateModel)
- def test_custom_params(self):
- model = ShortWeierstrassModel()
- coords = model.coordinates["projective"]
- p = 0xd7d1247f
- a = Mod(0xa4a44016, p)
- b = Mod(0x73f76716, p)
- n = 0xd7d2a475
- h = 1
- gx, gy, gz = Mod(0x54eed6d7, p), Mod(0x6f1e55ac, p), Mod(1, p)
- generator = Point(coords, X=gx, Y=gy, Z=gz)
- neutral = InfinityPoint(coords)
+def test_custom_params():
+ model = ShortWeierstrassModel()
+ coords = model.coordinates["projective"]
+ p = 0xd7d1247f
+ a = Mod(0xa4a44016, p)
+ b = Mod(0x73f76716, p)
+ n = 0xd7d2a475
+ h = 1
+ gx, gy, gz = Mod(0x54eed6d7, p), Mod(0x6f1e55ac, p), Mod(1, p)
+ generator = Point(coords, X=gx, Y=gy, Z=gz)
+ neutral = InfinityPoint(coords)
- curve = EllipticCurve(model, coords, p, neutral, {"a": a, "b": b})
- params = DomainParameters(curve, generator, n, h)
- self.assertIsNotNone(params)
- res = params.curve.affine_double(generator.to_affine())
- self.assertIsNotNone(res)
+ curve = EllipticCurve(model, coords, p, neutral, {"a": a, "b": b})
+ params = DomainParameters(curve, generator, n, h)
+ assert params is not None
+ res = params.curve.affine_double(generator.to_affine())
+ assert res is not None
diff --git a/test/ec/test_point.py b/test/ec/test_point.py
index b2096be..4a5a6f6 100644
--- a/test/ec/test_point.py
+++ b/test/ec/test_point.py
@@ -5,6 +5,7 @@ from pyecsca.ec.params import get_params
from pyecsca.ec.mod import Mod
from pyecsca.ec.model import ShortWeierstrassModel, MontgomeryModel
from pyecsca.ec.point import Point, InfinityPoint
+import pytest
class PointTests(TestCase):
@@ -14,131 +15,146 @@ class PointTests(TestCase):
self.coords = self.secp128r1.curve.coordinate_model
self.affine = AffineCoordinateModel(ShortWeierstrassModel())
- def test_construction(self):
- with self.assertRaises(ValueError):
- Point(self.coords)
- def test_to_affine(self):
- pt = Point(
- self.coords,
- X=Mod(0x161FF7528B899B2D0C28607CA52C5B86, self.secp128r1.curve.prime),
- Y=Mod(0xCF5AC8395BAFEB13C02DA292DDED7A83, self.secp128r1.curve.prime),
- Z=Mod(1, self.secp128r1.curve.prime),
- )
- affine = pt.to_affine()
+@pytest.fixture()
+def coords(secp128r1):
+ return secp128r1.curve.coordinate_model
- self.assertIsInstance(affine.coordinate_model, AffineCoordinateModel)
- self.assertSetEqual(set(affine.coords.keys()), set(self.affine.variables))
- self.assertEqual(affine.coords["x"], pt.coords["X"])
- self.assertEqual(affine.coords["y"], pt.coords["Y"])
- self.assertEqual(affine.to_affine(), affine)
- affine = InfinityPoint(self.coords).to_affine()
- self.assertIsInstance(affine, InfinityPoint)
+@pytest.fixture()
+def affine_model():
+ return AffineCoordinateModel(ShortWeierstrassModel())
- def test_to_model(self):
- affine = Point(
- self.affine,
- x=Mod(0xABCD, self.secp128r1.curve.prime),
- y=Mod(0xEF, self.secp128r1.curve.prime),
- )
- projective_model = self.coords
- other = affine.to_model(projective_model, self.secp128r1.curve)
- self.assertEqual(other.coordinate_model, projective_model)
- self.assertSetEqual(set(other.coords.keys()), set(projective_model.variables))
- self.assertEqual(other.coords["X"], affine.coords["x"])
- self.assertEqual(other.coords["Y"], affine.coords["y"])
- self.assertEqual(other.coords["Z"], Mod(1, self.secp128r1.curve.prime))
+def test_construction(coords):
+ with pytest.raises(ValueError):
+ Point(coords)
- infty = InfinityPoint(AffineCoordinateModel(self.secp128r1.curve.model))
- other_infty = infty.to_model(self.coords, self.secp128r1.curve)
- self.assertIsInstance(other_infty, InfinityPoint)
- with self.assertRaises(ValueError):
- self.base.to_model(self.coords, self.secp128r1.curve)
+def test_to_affine(secp128r1, coords, affine_model):
+ pt = Point(
+ coords,
+ X=Mod(0x161FF7528B899B2D0C28607CA52C5B86, secp128r1.curve.prime),
+ Y=Mod(0xCF5AC8395BAFEB13C02DA292DDED7A83, secp128r1.curve.prime),
+ Z=Mod(1, secp128r1.curve.prime),
+ )
+ affine = pt.to_affine()
- def test_to_from_affine(self):
- pt = Point(
- self.coords,
- X=Mod(0x161FF7528B899B2D0C28607CA52C5B86, self.secp128r1.curve.prime),
- Y=Mod(0xCF5AC8395BAFEB13C02DA292DDED7A83, self.secp128r1.curve.prime),
- Z=Mod(1, self.secp128r1.curve.prime),
- )
- other = pt.to_affine().to_model(self.coords, self.secp128r1.curve)
- self.assertEqual(pt, other)
+ assert isinstance(affine.coordinate_model, AffineCoordinateModel)
+ assert set(affine.coords.keys()) == set(affine_model.variables)
+ assert affine.coords["x"] == pt.coords["X"]
+ assert affine.coords["y"] == pt.coords["Y"]
+ assert affine.to_affine() == affine
- def test_equals(self):
- pt = Point(
- self.coords,
- X=Mod(0x4, self.secp128r1.curve.prime),
- Y=Mod(0x6, self.secp128r1.curve.prime),
- Z=Mod(2, self.secp128r1.curve.prime),
- )
- other = Point(
- self.coords,
- X=Mod(0x2, self.secp128r1.curve.prime),
- Y=Mod(0x3, self.secp128r1.curve.prime),
- Z=Mod(1, self.secp128r1.curve.prime),
- )
- third = Point(
- self.coords,
- X=Mod(0x5, self.secp128r1.curve.prime),
- Y=Mod(0x3, self.secp128r1.curve.prime),
- Z=Mod(1, self.secp128r1.curve.prime),
- )
- self.assertTrue(pt.equals(other))
- self.assertNotEqual(pt, other)
- self.assertFalse(pt.equals(2))
- self.assertNotEqual(pt, 2)
- self.assertFalse(pt.equals(third))
- self.assertNotEqual(pt, third)
- self.assertTrue(pt.equals_scaled(other))
- self.assertTrue(pt.equals_affine(other))
- self.assertFalse(pt.equals_scaled(third))
+ affine = InfinityPoint(coords).to_affine()
+ assert isinstance(affine, InfinityPoint)
- infty_one = InfinityPoint(self.coords)
- infty_other = InfinityPoint(self.coords)
- self.assertTrue(infty_one.equals(infty_other))
- self.assertTrue(infty_one.equals_affine(infty_other))
- self.assertTrue(infty_one.equals_scaled(infty_other))
- self.assertEqual(infty_one, infty_other)
- self.assertFalse(pt.equals(infty_one))
- self.assertFalse(pt.equals_affine(infty_one))
- self.assertFalse(pt.equals_scaled(infty_one))
- mont = MontgomeryModel()
- different = Point(
- mont.coordinates["xz"],
- X=Mod(
- 0x64DACCD2656420216545E5F65221EB,
- 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,
- ),
- Z=Mod(1, 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA),
- )
- self.assertFalse(pt.equals(different))
- self.assertNotEqual(pt, different)
+def test_to_model(secp128r1, coords, affine_model):
+ affine = Point(
+ affine_model,
+ x=Mod(0xABCD, secp128r1.curve.prime),
+ y=Mod(0xEF, secp128r1.curve.prime),
+ )
+ projective_model = coords
+ other = affine.to_model(projective_model, secp128r1.curve)
- def test_bytes(self):
- pt = Point(
- self.coords,
- X=Mod(0x4, self.secp128r1.curve.prime),
- Y=Mod(0x6, self.secp128r1.curve.prime),
- Z=Mod(2, self.secp128r1.curve.prime),
- )
- self.assertEqual(
- bytes(pt),
- b"\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02",
- )
- self.assertEqual(bytes(InfinityPoint(self.coords)), b"\x00")
+ assert other.coordinate_model == projective_model
+ assert set(other.coords.keys()) == set(projective_model.variables)
+ assert other.coords["X"] == affine.coords["x"]
+ assert other.coords["Y"] == affine.coords["y"]
+ assert other.coords["Z"] == Mod(1, secp128r1.curve.prime)
- def test_iter(self):
- pt = Point(
- self.coords,
- X=Mod(0x4, self.secp128r1.curve.prime),
- Y=Mod(0x6, self.secp128r1.curve.prime),
- Z=Mod(2, self.secp128r1.curve.prime),
- )
- t = tuple(pt)
- self.assertEqual(len(t), 3)
- self.assertEqual(len(pt), 3)
+ infty = InfinityPoint(AffineCoordinateModel(secp128r1.curve.model))
+ other_infty = infty.to_model(coords, secp128r1.curve)
+ assert isinstance(other_infty, InfinityPoint)
+
+ with pytest.raises(ValueError):
+ secp128r1.generator.to_model(coords, secp128r1.curve)
+
+
+def test_to_from_affine(secp128r1, coords):
+ pt = Point(
+ coords,
+ X=Mod(0x161FF7528B899B2D0C28607CA52C5B86, secp128r1.curve.prime),
+ Y=Mod(0xCF5AC8395BAFEB13C02DA292DDED7A83, secp128r1.curve.prime),
+ Z=Mod(1, secp128r1.curve.prime),
+ )
+ other = pt.to_affine().to_model(coords, secp128r1.curve)
+ assert pt == other
+
+
+def test_equals(secp128r1, coords):
+ pt = Point(
+ coords,
+ X=Mod(0x4, secp128r1.curve.prime),
+ Y=Mod(0x6, secp128r1.curve.prime),
+ Z=Mod(2, secp128r1.curve.prime),
+ )
+ other = Point(
+ coords,
+ X=Mod(0x2, secp128r1.curve.prime),
+ Y=Mod(0x3, secp128r1.curve.prime),
+ Z=Mod(1, secp128r1.curve.prime),
+ )
+ third = Point(
+ coords,
+ X=Mod(0x5, secp128r1.curve.prime),
+ Y=Mod(0x3, secp128r1.curve.prime),
+ Z=Mod(1, secp128r1.curve.prime),
+ )
+ assert pt.equals(other)
+ assert pt != other
+ assert not pt.equals(2) # type: ignore
+ assert pt != 2
+ assert not pt.equals(third)
+ assert pt != third
+ assert pt.equals_scaled(other)
+ assert pt.equals_affine(other)
+ assert not pt.equals_scaled(third)
+
+ infty_one = InfinityPoint(coords)
+ infty_other = InfinityPoint(coords)
+ assert infty_one.equals(infty_other)
+ assert infty_one.equals_affine(infty_other)
+ assert infty_one.equals_scaled(infty_other)
+ assert infty_one == infty_other
+ assert not pt.equals(infty_one)
+ assert not pt.equals_affine(infty_one)
+ assert not pt.equals_scaled(infty_one)
+
+ mont = MontgomeryModel()
+ different = Point(
+ mont.coordinates["xz"],
+ X=Mod(
+ 0x64DACCD2656420216545E5F65221EB,
+ 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,
+ ),
+ Z=Mod(1, 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA),
+ )
+ assert not pt.equals(different)
+ assert pt != different
+
+
+def test_bytes(secp128r1, coords):
+ pt = Point(
+ coords,
+ X=Mod(0x4, secp128r1.curve.prime),
+ Y=Mod(0x6, secp128r1.curve.prime),
+ Z=Mod(2, secp128r1.curve.prime),
+ )
+ assert bytes(pt) == \
+ b"\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"
+ assert bytes(InfinityPoint(coords)) == b"\x00"
+
+
+def test_iter(secp128r1, coords):
+ pt = Point(
+ coords,
+ X=Mod(0x4, secp128r1.curve.prime),
+ Y=Mod(0x6, secp128r1.curve.prime),
+ Z=Mod(2, secp128r1.curve.prime),
+ )
+ t = tuple(pt)
+ assert len(t) == 3
+ assert len(pt) == 3
diff --git a/test/ec/test_regress.py b/test/ec/test_regress.py
index 13e6655..f032de2 100644
--- a/test/ec/test_regress.py
+++ b/test/ec/test_regress.py
@@ -1,10 +1,11 @@
from typing import cast
-from unittest import TestCase, skip
+from unittest import TestCase
+
+import pytest
from sympy import symbols
from pyecsca.ec.coordinates import AffineCoordinateModel
from pyecsca.ec.curve import EllipticCurve
-from pyecsca.ec.error import UnsatisfiedAssumptionError
from pyecsca.ec.formula import AdditionFormula, DoublingFormula, ScalingFormula
from pyecsca.ec.mod import Mod, SymbolicMod
from pyecsca.ec.model import MontgomeryModel, EdwardsModel
@@ -13,101 +14,101 @@ from pyecsca.ec.mult import LTRMultiplier
from pyecsca.ec.point import Point, InfinityPoint
-class RegressionTests(TestCase):
- def test_issue_7(self):
- secp128r1 = get_params("secg", "secp128r1", "projective")
- base = secp128r1.generator
- coords = secp128r1.curve.coordinate_model
- add = cast(AdditionFormula, coords.formulas["add-1998-cmo"])
- dbl = cast(DoublingFormula, coords.formulas["dbl-1998-cmo"])
- scl = cast(ScalingFormula, coords.formulas["z"])
- mult = LTRMultiplier(
- add, dbl, scl, always=False, complete=False, short_circuit=True
- )
- mult.init(secp128r1, base)
- pt = mult.multiply(13613624287328732)
- self.assertIsInstance(pt.coords["X"], Mod)
- self.assertIsInstance(pt.coords["Y"], Mod)
- self.assertIsInstance(pt.coords["Z"], Mod)
- mult.init(secp128r1, pt)
- a = mult.multiply(1)
- self.assertNotIsInstance(a.coords["X"].x, float)
- self.assertNotIsInstance(a.coords["Y"].x, float)
- self.assertNotIsInstance(a.coords["Z"].x, float)
+def test_issue_7():
+ secp128r1 = get_params("secg", "secp128r1", "projective")
+ base = secp128r1.generator
+ coords = secp128r1.curve.coordinate_model
+ add = cast(AdditionFormula, coords.formulas["add-1998-cmo"])
+ dbl = cast(DoublingFormula, coords.formulas["dbl-1998-cmo"])
+ scl = cast(ScalingFormula, coords.formulas["z"])
+ mult = LTRMultiplier(add, dbl, scl, always=False, complete=False, short_circuit=True)
+ mult.init(secp128r1, base)
+ pt = mult.multiply(13613624287328732)
+ assert isinstance(pt.coords["X"], Mod)
+ assert isinstance(pt.coords["Y"], Mod)
+ assert isinstance(pt.coords["Z"], Mod)
+ mult.init(secp128r1, pt)
+ a = mult.multiply(1)
+ assert not isinstance(a.coords["X"].x, float)
+ assert not isinstance(a.coords["Y"].x, float)
+ assert not isinstance(a.coords["Z"].x, float)
+
+
+def test_issue_8():
+ e222 = get_params("other", "E-222", "projective")
+ base = e222.generator
+ affine_base = base.to_affine()
+ affine_double = e222.curve.affine_double(affine_base)
+ affine_triple = e222.curve.affine_add(affine_base, affine_double)
+ assert affine_double is not None
+ assert affine_triple is not None
+
+
+def test_issue_9():
+ model = MontgomeryModel()
+ coords = model.coordinates["xz"]
+ p = 19
+ neutral = Point(coords, X=Mod(1, p), Z=Mod(0, p))
+ curve = EllipticCurve(model, coords, p, neutral, {"a": Mod(8, p), "b": Mod(1, p)})
+ base = Point(coords, X=Mod(12, p), Z=Mod(1, p))
+ formula = coords.formulas["dbl-1987-m-2"]
+ res = formula(p, base, **curve.parameters)[0]
+ assert res is not None
+ affine_base = Point(AffineCoordinateModel(model), x=Mod(12, p), y=Mod(2, p))
+ dbase = curve.affine_double(affine_base).to_model(coords, curve)
+ ladder = coords.formulas["ladd-1987-m-3"]
+ one, other = ladder(p, base, dbase, base, **curve.parameters)
+ assert one is not None
+ assert other is not None
+
- def test_issue_8(self):
- e222 = get_params("other", "E-222", "projective")
- base = e222.generator
- affine_base = base.to_affine()
- affine_double = e222.curve.affine_double(affine_base)
- affine_triple = e222.curve.affine_add(affine_base, affine_double)
- self.assertIsNotNone(affine_double)
- self.assertIsNotNone(affine_triple)
+def test_issue_10():
+ model = EdwardsModel()
+ coords = model.coordinates["yz"]
+ coords_sqr = model.coordinates["yzsquared"]
+ p = 0x1D
+ c = Mod(1, p)
+ d = Mod(0x1C, p)
+ r = d.sqrt()
+ neutral = Point(coords, Y=c * r, Z=Mod(1, p))
+ curve = EllipticCurve(model, coords, p, neutral, {"c": c, "d": d, "r": r})
+ neutral_affine = Point(AffineCoordinateModel(model), x=Mod(0, p), y=c)
+ assert neutral == neutral_affine.to_model(coords, curve)
+ neutral_sqr = Point(coords_sqr, Y=c ** 2 * r, Z=Mod(1, p))
+ assert neutral_sqr == neutral_affine.to_model(coords_sqr, curve)
- def test_issue_9(self):
- model = MontgomeryModel()
- coords = model.coordinates["xz"]
- p = 19
- neutral = Point(coords, X=Mod(1, p), Z=Mod(0, p))
- curve = EllipticCurve(
- model, coords, p, neutral, {"a": Mod(8, p), "b": Mod(1, p)}
- )
- base = Point(coords, X=Mod(12, p), Z=Mod(1, p))
- formula = coords.formulas["dbl-1987-m-2"]
- res = formula(p, base, **curve.parameters)[0]
- self.assertIsNotNone(res)
- affine_base = Point(AffineCoordinateModel(model), x=Mod(12, p), y=Mod(2, p))
- dbase = curve.affine_double(affine_base).to_model(coords, curve)
- ladder = coords.formulas["ladd-1987-m-3"]
- one, other = ladder(p, base, dbase, base, **curve.parameters)
- self.assertIsNotNone(one)
- self.assertIsNotNone(other)
- def test_issue_10(self):
- model = EdwardsModel()
- coords = model.coordinates["yz"]
- coords_sqr = model.coordinates["yzsquared"]
- p = 0x1D
- c = Mod(1, p)
- d = Mod(0x1C, p)
- r = d.sqrt()
- neutral = Point(coords, Y=c * r, Z=Mod(1, p))
- curve = EllipticCurve(model, coords, p, neutral, {"c": c, "d": d, "r": r})
- neutral_affine = Point(AffineCoordinateModel(model), x=Mod(0, p), y=c)
- self.assertEqual(neutral, neutral_affine.to_model(coords, curve))
- neutral_sqr = Point(coords_sqr, Y=c ** 2 * r, Z=Mod(1, p))
- self.assertEqual(neutral_sqr, neutral_affine.to_model(coords_sqr, curve))
+def test_issue_13():
+ model = EdwardsModel()
+ coords = model.coordinates["yz"]
+ c, r, d = symbols("c r d")
+ p = 53
+ c = SymbolicMod(c, p)
+ r = SymbolicMod(r, p)
+ d = SymbolicMod(d, p)
+ yd, zd, yp, zp, yq, zq = symbols("yd zd yp zp yq zq")
+ PmQ = Point(coords, Y=SymbolicMod(yd, p), Z=SymbolicMod(zd, p))
+ P = Point(coords, Y=SymbolicMod(yp, p), Z=SymbolicMod(zp, p))
+ Q = Point(coords, Y=SymbolicMod(yq, p), Z=SymbolicMod(zq, p))
+ formula = coords.formulas["dadd-2006-g-2"]
+ formula(p, PmQ, P, Q, c=c, r=r, d=d)
- def test_issue_13(self):
- model = EdwardsModel()
- coords = model.coordinates["yz"]
- c, r, d = symbols("c r d")
- p = 53
- c = SymbolicMod(c, p)
- r = SymbolicMod(r, p)
- d = SymbolicMod(d, p)
- yd, zd, yp, zp, yq, zq = symbols("yd zd yp zp yq zq")
- PmQ = Point(coords, Y=SymbolicMod(yd, p), Z=SymbolicMod(zd, p))
- P = Point(coords, Y=SymbolicMod(yp, p), Z=SymbolicMod(zp, p))
- Q = Point(coords, Y=SymbolicMod(yq, p), Z=SymbolicMod(zq, p))
- formula = coords.formulas["dadd-2006-g-2"]
- formula(p, PmQ, P, Q, c=c, r=r, d=d)
- @skip("Unresolved issue currently.")
- def test_issue_14(self):
- model = EdwardsModel()
- coords = model.coordinates["projective"]
- affine = AffineCoordinateModel(model)
- formula = coords.formulas["add-2007-bl-4"]
- p = 19
- c = Mod(2, p)
- d = Mod(10, p)
- curve = EllipticCurve(model, coords, p, InfinityPoint(coords), {"c": c, "d": d})
- Paff = Point(affine, x=Mod(0xD, p), y=Mod(0x9, p))
- P = Paff.to_model(coords, curve)
- Qaff = Point(affine, x=Mod(0x4, p), y=Mod(0x12, p))
- Q = Qaff.to_model(coords, curve)
- PQaff = curve.affine_add(Paff, Qaff)
- R = formula(p, P, Q, **curve.parameters)[0]
- Raff = R.to_affine()
- self.assertEqual(PQaff, Raff)
+@pytest.mark.xfail(reason="Unresolved issue currently.")
+def test_issue_14():
+ model = EdwardsModel()
+ coords = model.coordinates["projective"]
+ affine = AffineCoordinateModel(model)
+ formula = coords.formulas["add-2007-bl-4"]
+ p = 19
+ c = Mod(2, p)
+ d = Mod(10, p)
+ curve = EllipticCurve(model, coords, p, InfinityPoint(coords), {"c": c, "d": d})
+ Paff = Point(affine, x=Mod(0xD, p), y=Mod(0x9, p))
+ P = Paff.to_model(coords, curve)
+ Qaff = Point(affine, x=Mod(0x4, p), y=Mod(0x12, p))
+ Q = Qaff.to_model(coords, curve)
+ PQaff = curve.affine_add(Paff, Qaff)
+ R = formula(p, P, Q, **curve.parameters)[0]
+ Raff = R.to_affine()
+ assert PQaff == Raff
diff --git a/test/ec/test_signature.py b/test/ec/test_signature.py
index f6ab302..04321f2 100644
--- a/test/ec/test_signature.py
+++ b/test/ec/test_signature.py
@@ -1,8 +1,4 @@
-from unittest import TestCase
-
-from parameterized import parameterized
-
-from pyecsca.ec.params import get_params
+import pytest
from pyecsca.ec.mod import Mod
from pyecsca.ec.mult import LTRMultiplier
from pyecsca.ec.signature import (
@@ -17,81 +13,98 @@ from pyecsca.ec.signature import (
)
-class SignatureTests(TestCase):
- def setUp(self):
- self.secp128r1 = get_params("secg", "secp128r1", "projective")
- self.add = self.secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
- self.dbl = self.secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
- self.mult = LTRMultiplier(self.add, self.dbl)
- self.msg = 0xCAFEBABE .to_bytes(4, byteorder="big")
- self.priv = Mod(0xDEADBEEF, self.secp128r1.order)
- self.mult.init(self.secp128r1, self.secp128r1.generator)
- self.pub = self.mult.multiply(self.priv.x)
+@pytest.fixture()
+def add(secp128r1):
+ return secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
+
+
+@pytest.fixture()
+def mult(secp128r1, add):
+ dbl = secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
+ return LTRMultiplier(add, dbl)
+
+
+@pytest.fixture()
+def keypair(secp128r1, mult):
+ priv = Mod(0xDEADBEEF, secp128r1.order)
+ mult.init(secp128r1, secp128r1.generator)
+ pub = mult.multiply(int(priv))
+ return priv, pub
- @parameterized.expand(
- [
- ("SHA1", ECDSA_SHA1),
- ("SHA224", ECDSA_SHA224),
- ("SHA256", ECDSA_SHA256),
- ("SHA384", ECDSA_SHA384),
- ("SHA512", ECDSA_SHA512),
- ]
- )
- def test_all(self, name, algo):
- signer = algo(self.mult, self.secp128r1, privkey=self.priv)
- self.assertTrue(signer.can_sign)
- sig = signer.sign_data(self.msg)
- verifier = algo(self.mult, self.secp128r1, add=self.add, pubkey=self.pub)
- self.assertTrue(verifier.can_verify)
- self.assertTrue(verifier.verify_data(sig, self.msg))
- none = ECDSA_NONE(
- self.mult, self.secp128r1, add=self.add, pubkey=self.pub, privkey=self.priv
- )
- digest = signer.hash_algo(self.msg).digest()
- sig = none.sign_hash(digest)
- self.assertTrue(none.verify_hash(sig, digest))
+@pytest.fixture()
+def msg():
+ return 0xCAFEBABE.to_bytes(4, byteorder="big")
- def test_cannot(self):
- ok = ECDSA_NONE(
- self.mult, self.secp128r1, add=self.add, pubkey=self.pub, privkey=self.priv
- )
- data = b"aaaa"
- sig = ok.sign_data(data)
- no_priv = ECDSA_NONE(self.mult, self.secp128r1, pubkey=self.pub)
- with self.assertRaises(RuntimeError):
- no_priv.sign_data(data)
- with self.assertRaises(RuntimeError):
- no_priv.sign_hash(data)
- no_pubadd = ECDSA_NONE(self.mult, self.secp128r1, privkey=self.priv)
- with self.assertRaises(RuntimeError):
- no_pubadd.verify_data(sig, data)
- with self.assertRaises(RuntimeError):
- no_pubadd.verify_hash(sig, data)
+@pytest.mark.parametrize("name,algo",
+ [
+ ("SHA1", ECDSA_SHA1),
+ ("SHA224", ECDSA_SHA224),
+ ("SHA256", ECDSA_SHA256),
+ ("SHA384", ECDSA_SHA384),
+ ("SHA512", ECDSA_SHA512),
+ ])
+def test_all(secp128r1, mult, keypair, msg, add, name, algo):
+ priv, pub = keypair
+ signer = algo(mult, secp128r1, privkey=keypair[0])
+ assert signer.can_sign
+ sig = signer.sign_data(msg)
+ verifier = algo(mult, secp128r1, add=add, pubkey=pub)
+ assert verifier.can_verify
+ assert verifier.verify_data(sig, msg)
+
+ none = ECDSA_NONE(
+ mult, secp128r1, add=add, pubkey=pub, privkey=priv
+ )
+ digest = signer.hash_algo(msg).digest()
+ sig = none.sign_hash(digest)
+ assert none.verify_hash(sig, digest)
- with self.assertRaises(ValueError):
- Signature(self.mult, self.secp128r1)
- @parameterized.expand(
- [
- ("SHA1", ECDSA_SHA1),
- ("SHA224", ECDSA_SHA224),
- ("SHA256", ECDSA_SHA256),
- ("SHA384", ECDSA_SHA384),
- ("SHA512", ECDSA_SHA512),
- ]
+def test_cannot(secp128r1, add, mult, keypair):
+ priv, pub = keypair
+ ok = ECDSA_NONE(
+ mult, secp128r1, add=add, pubkey=pub, privkey=priv
)
- def test_fixed_nonce(self, name, algo):
- signer = algo(self.mult, self.secp128r1, privkey=self.priv)
- sig_one = signer.sign_data(self.msg, nonce=0xABCDEF)
- sig_other = signer.sign_data(self.msg, nonce=0xABCDEF)
- verifier = algo(self.mult, self.secp128r1, add=self.add, pubkey=self.pub)
- self.assertTrue(verifier.verify_data(sig_one, self.msg))
- self.assertTrue(verifier.verify_data(sig_other, self.msg))
- self.assertEqual(sig_one, sig_other)
+ data = b"aaaa"
+ sig = ok.sign_data(data)
+
+ no_priv = ECDSA_NONE(mult, secp128r1, pubkey=pub)
+ with pytest.raises(RuntimeError):
+ no_priv.sign_data(data)
+ with pytest.raises(RuntimeError):
+ no_priv.sign_hash(data)
+ no_pubadd = ECDSA_NONE(mult, secp128r1, privkey=priv)
+ with pytest.raises(RuntimeError):
+ no_pubadd.verify_data(sig, data)
+ with pytest.raises(RuntimeError):
+ no_pubadd.verify_hash(sig, data)
+
+ with pytest.raises(ValueError):
+ Signature(mult, secp128r1)
+
+
+@pytest.mark.parametrize("name,algo",
+ [
+ ("SHA1", ECDSA_SHA1),
+ ("SHA224", ECDSA_SHA224),
+ ("SHA256", ECDSA_SHA256),
+ ("SHA384", ECDSA_SHA384),
+ ("SHA512", ECDSA_SHA512),
+ ])
+def test_fixed_nonce(secp128r1, mult, keypair, msg, add, name, algo):
+ priv, pub = keypair
+ signer = algo(mult, secp128r1, privkey=priv)
+ sig_one = signer.sign_data(msg, nonce=0xABCDEF)
+ sig_other = signer.sign_data(msg, nonce=0xABCDEF)
+ verifier = algo(mult, secp128r1, add=add, pubkey=pub)
+ assert verifier.verify_data(sig_one, msg)
+ assert verifier.verify_data(sig_other, msg)
+ assert sig_one == sig_other
+
- def test_der(self):
- sig = SignatureResult(0xAAAAA, 0xBBBBB)
- self.assertEqual(sig, SignatureResult.from_DER(sig.to_DER()))
- self.assertNotEqual(sig, "abc")
+def test_der():
+ sig = SignatureResult(0xAAAAA, 0xBBBBB)
+ assert sig == SignatureResult.from_DER(sig.to_DER())
+ assert sig != "abc"
diff --git a/test/ec/test_transformations.py b/test/ec/test_transformations.py
index b15f868..f33c8f1 100644
--- a/test/ec/test_transformations.py
+++ b/test/ec/test_transformations.py
@@ -1,35 +1,34 @@
-from unittest import TestCase
-
from pyecsca.ec.params import get_params
from pyecsca.ec.transformations import M2SW, M2TE, TE2M, SW2M, SW2TE
-class TransformationTests(TestCase):
- def test_montgomery(self):
- curve25519 = get_params("other", "Curve25519", "affine")
- sw = M2SW(curve25519)
- self.assertIsNotNone(sw)
- self.assertTrue(sw.curve.is_on_curve(sw.generator))
- self.assertTrue(sw.curve.is_neutral(sw.curve.neutral))
- te = M2TE(curve25519)
- self.assertIsNotNone(te)
- self.assertTrue(te.curve.is_on_curve(te.generator))
- self.assertTrue(te.curve.is_neutral(te.curve.neutral))
+def test_montgomery():
+ curve25519 = get_params("other", "Curve25519", "affine")
+ sw = M2SW(curve25519)
+ assert sw is not None
+ assert sw.curve.is_on_curve(sw.generator)
+ assert sw.curve.is_neutral(sw.curve.neutral)
+ te = M2TE(curve25519)
+ assert te is not None
+ assert te.curve.is_on_curve(te.generator)
+ assert te.curve.is_neutral(te.curve.neutral)
+
+
+def test_twistededwards():
+ ed25519 = get_params("other", "Ed25519", "affine")
+ m = TE2M(ed25519)
+ assert m is not None
+ assert m.curve.is_on_curve(m.generator)
+ assert m.curve.is_neutral(m.curve.neutral)
- def test_twistededwards(self):
- ed25519 = get_params("other", "Ed25519", "affine")
- m = TE2M(ed25519)
- self.assertIsNotNone(m)
- self.assertTrue(m.curve.is_on_curve(m.generator))
- self.assertTrue(m.curve.is_neutral(m.curve.neutral))
- def test_shortweierstrass(self):
- secp128r2 = get_params("secg", "secp128r2", "affine")
- m = SW2M(secp128r2)
- self.assertIsNotNone(m)
- self.assertTrue(m.curve.is_on_curve(m.generator))
- self.assertTrue(m.curve.is_neutral(m.curve.neutral))
- te = SW2TE(secp128r2)
- self.assertIsNotNone(te)
- self.assertTrue(te.curve.is_on_curve(te.generator))
- self.assertTrue(te.curve.is_neutral(te.curve.neutral))
+def test_shortweierstrass():
+ secp128r2 = get_params("secg", "secp128r2", "affine")
+ m = SW2M(secp128r2)
+ assert m is not None
+ assert m.curve.is_on_curve(m.generator)
+ assert m.curve.is_neutral(m.curve.neutral)
+ te = SW2TE(secp128r2)
+ assert te is not None
+ assert te.curve.is_on_curve(te.generator)
+ assert te.curve.is_neutral(te.curve.neutral)
diff --git a/test/ec/utils.py b/test/ec/utils.py
index 67a9cc0..1f32033 100644
--- a/test/ec/utils.py
+++ b/test/ec/utils.py
@@ -2,11 +2,6 @@ from itertools import product
from functools import reduce
-def slow(func):
- func.slow = 1
- return func
-
-
def cartesian(*items):
for cart in product(*items):
yield reduce(lambda x, y: x + y, cart)
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/perf_combine.py b/test/sca/perf_combine.py
index 9b934d7..b76acb1 100644
--- a/test/sca/perf_combine.py
+++ b/test/sca/perf_combine.py
@@ -1,7 +1,9 @@
#!/usr/bin/env python
import click
+from importlib_resources import files, as_file
from test.utils import Profiler
+import test.data.sca
from pyecsca.sca import (
InspectorTraceSet,
average,
@@ -24,25 +26,26 @@ from pyecsca.sca import (
envvar="DIR",
)
def main(profiler, operations, directory):
- traces = InspectorTraceSet.read("test/data/example.trs")
- with Profiler(profiler, directory, f"combine_average_example_{operations}"):
- for _ in range(operations):
- average(*traces)
- with Profiler(profiler, directory, f"combine_condavg_example_{operations}"):
- for _ in range(operations):
- conditional_average(*traces, condition=lambda trace: trace[0] > 0)
- with Profiler(profiler, directory, f"combine_variance_example_{operations}"):
- for _ in range(operations):
- variance(*traces)
- with Profiler(profiler, directory, f"combine_stddev_example_{operations}"):
- for _ in range(operations):
- standard_deviation(*traces)
- with Profiler(profiler, directory, f"combine_add_example_{operations}"):
- for _ in range(operations):
- add(*traces)
- with Profiler(profiler, directory, f"combine_subtract_example_{operations}"):
- for _ in range(operations):
- subtract(traces[0], traces[1])
+ with as_file(files(test.data.sca).joinpath("example.trs")) as path:
+ traces = InspectorTraceSet.read(path)
+ with Profiler(profiler, directory, f"combine_average_example_{operations}"):
+ for _ in range(operations):
+ average(*traces)
+ with Profiler(profiler, directory, f"combine_condavg_example_{operations}"):
+ for _ in range(operations):
+ conditional_average(*traces, condition=lambda trace: trace[0] > 0)
+ with Profiler(profiler, directory, f"combine_variance_example_{operations}"):
+ for _ in range(operations):
+ variance(*traces)
+ with Profiler(profiler, directory, f"combine_stddev_example_{operations}"):
+ for _ in range(operations):
+ standard_deviation(*traces)
+ with Profiler(profiler, directory, f"combine_add_example_{operations}"):
+ for _ in range(operations):
+ add(*traces)
+ with Profiler(profiler, directory, f"combine_subtract_example_{operations}"):
+ for _ in range(operations):
+ subtract(traces[0], traces[1])
if __name__ == "__main__":
diff --git a/test/sca/test_align.py b/test/sca/test_align.py
index 1db71b3..ad45d86 100644
--- a/test/sca/test_align.py
+++ b/test/sca/test_align.py
@@ -1,4 +1,6 @@
import numpy as np
+import pytest
+from importlib_resources import files, as_file
from pyecsca.sca import (
align_correlation,
align_peaks,
@@ -8,141 +10,140 @@ from pyecsca.sca import (
Trace,
InspectorTraceSet,
)
-from .utils import Plottable, slow
+import test.data.sca
-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")),
- )
- self.assertEqual(len(offsets), 2)
- self.assertEqual(offsets[0], 0)
- self.assertEqual(offsets[1], 3)
+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
+
- @slow
- def test_large_align(self):
- example = InspectorTraceSet.read("test/data/example.trs")
+@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.assertIsNotNone(result)
+ assert result is not None
- @slow
- def test_large_dtw_align(self):
- example = InspectorTraceSet.read("test/data/example.trs")
+
+@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])
- self.assertIsNotNone(result)
+ 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 995099d..f5dc7cc 100644
--- a/test/sca/test_rpa.py
+++ b/test/sca/test_rpa.py
@@ -1,94 +1,95 @@
-from unittest import TestCase
+import io
+from contextlib import redirect_stdout
-from parameterized import parameterized
+import pytest
from pyecsca.ec.context import local
+from pyecsca.ec.model import ShortWeierstrassModel
+from pyecsca.ec.curve import EllipticCurve
+from pyecsca.ec.mod import Mod
from pyecsca.ec.mult import (
LTRMultiplier,
+ RTLMultiplier,
BinaryNAFMultiplier,
WindowNAFMultiplier,
- LadderMultiplier,
- DifferentialLadderMultiplier,
+ SimpleLadderMultiplier,
)
-from pyecsca.ec.params import get_params
-from pyecsca.sca.re.rpa import MultipleContext
+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"]
+
+
+@pytest.fixture()
+def neg(coords):
+ return coords.formulas["neg"]
+
+
+@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
+
+ 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_x0_point(rpa_params):
+ res = rpa_point_x0(rpa_params)
+ assert res is not None
+ assert res.y == 0
+
+
+def test_0y_point(rpa_params):
+ res = rpa_point_0y(rpa_params)
+ assert res is not None
+ assert res.x == 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 299e127..4155b25 100644
--- a/test/sca/test_target.py
+++ b/test/sca/test_target.py
@@ -1,10 +1,12 @@
+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
-from smartcard.pcsc.PCSCExceptions import BaseSCardException
+import pytest
+from importlib_resources import files, as_file
+from smartcard.pcsc.PCSCExceptions import BaseSCardException
+import test.data.sca
from pyecsca.ec.key_agreement import ECDH_SHA1
from pyecsca.ec.key_generation import KeyGeneration
from pyecsca.ec.mod import Mod
@@ -31,461 +33,475 @@ from pyecsca.sca.target.ectester import (
)
if has_pyscard:
- from pyecsca.sca.target.ectester import ECTesterTarget
+ from pyecsca.sca.target.ectester import ECTesterTargetPCSC as ECTesterTarget
else:
- ECTesterTarget = None
+ from pyecsca.sca.target.ectester import ECTesterTarget
class TestTarget(SimpleSerialTarget, BinaryTarget):
- pass
+ __test__ = False
-class BinaryTargetTests(TestCase):
- def test_basic_target(self):
- target_path = join(dirname(realpath(__file__)), "..", "data", "target.py")
+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)
- self.assertIn("r", resp)
- self.assertIn("z", resp)
- self.assertEqual(resp["r"].data, "01020304")
+ assert "r" in resp
+ assert "z" in resp
+ assert resp["r"].data == "01020304"
target.disconnect()
- def test_debug(self):
- target_path = join(dirname(realpath(__file__)), "..", "data", "target.py")
+
+def test_debug():
+ with as_file(files(test.data.sca).joinpath("target.py")) as target_path:
target = TestTarget(["python", target_path], debug_output=True)
- target.connect()
- target.send_cmd(SimpleSerialMessage("d", ""), 500)
- target.disconnect()
+ with redirect_stdout(io.StringIO()) as out:
+ target.connect()
+ target.send_cmd(SimpleSerialMessage("d", ""), 500)
+ target.disconnect()
+ assert out.read() is not None
+
- def test_no_connection(self):
- target_path = join(dirname(realpath(__file__)), "..", "data", "target.py")
- target = TestTarget(target_path)
- with self.assertRaises(ValueError):
+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 self.assertRaises(ValueError):
+ 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_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_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_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(
+ 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
- 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)
- 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()
+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 = 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",
+ 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 e79e5d2..a338a9d 100644
--- a/test/sca/test_traceset.py
+++ b/test/sca/test_traceset.py
@@ -1,10 +1,13 @@
import os.path
import shutil
import tempfile
-from unittest import TestCase
+
+import pytest
+from importlib_resources import files, as_file
import numpy as np
+import test.data.sca
from pyecsca.sca import (
TraceSet,
InspectorTraceSet,
@@ -14,115 +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):
- result = InspectorTraceSet.read("test/data/example.trs")
- 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 open("test/data/example.trs", "rb") as f:
- self.assertIsNotNone(InspectorTraceSet.read(f))
- def test_load_bytes(self):
- with open("test/data/example.trs", "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):
- trace_set = InspectorTraceSet.read("test/data/example.trs")
+
+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):
- result = ChipWhispererTraceSet.read("test/data/config_chipwhisperer_.cfg")
- 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):
- result = PickleTraceSet.read("test/data/test.pickle")
- 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 open("test/data/test.pickle", "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):
- result = HDF5TraceSet.read("test/data/test.h5")
- 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 open("test/data/test.h5", "rb") as f:
- self.assertIsNotNone(HDF5TraceSet.read(f))
- def test_inplace(self):
- with tempfile.TemporaryDirectory() as dirname:
- path = os.path.join(dirname, "test.h5")
- shutil.copy("test/data/test.h5", 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
new file mode 100644
index 0000000..3b6b046
--- /dev/null
+++ b/test/sca/test_zvp.py
@@ -0,0 +1,13 @@
+from pyecsca.sca.re.zvp import unroll_formula
+
+
+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 b00015b..0000000
--- a/test/sca/utils.py
+++ /dev/null
@@ -1,52 +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
-
-
-def slow(func):
- func.slow = 1
- return func
-
-
-def disabled(func):
- func.disabled = 1
- return func
-
-
-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")
diff --git a/unittest.cfg b/unittest.cfg
deleted file mode 100644
index 7c90619..0000000
--- a/unittest.cfg
+++ /dev/null
@@ -1,3 +0,0 @@
-[unittest]
-plugins = nose2.plugins.attrib
- nose2.plugins.doctests