aboutsummaryrefslogtreecommitdiff
path: root/pyecsca
diff options
context:
space:
mode:
authorJ08nY2025-03-13 19:38:48 +0100
committerJ08nY2025-03-13 19:38:48 +0100
commit7c2f12a0111de33330870b2179b71281b59ada29 (patch)
tree80beb7f4e3090a4805d7aa20ffba5cbcc0078902 /pyecsca
parenteccc58127b4c0c10f50e4d05e699d3585391e8a1 (diff)
downloadpyecsca-7c2f12a0111de33330870b2179b71281b59ada29.tar.gz
pyecsca-7c2f12a0111de33330870b2179b71281b59ada29.tar.zst
pyecsca-7c2f12a0111de33330870b2179b71281b59ada29.zip
Diffstat (limited to 'pyecsca')
-rw-r--r--pyecsca/ec/configuration.py1
-rw-r--r--pyecsca/ec/coordinates.py1
-rw-r--r--pyecsca/ec/countermeasures.py18
-rw-r--r--pyecsca/ec/curve.py89
-rw-r--r--pyecsca/ec/divpoly.py9
-rw-r--r--pyecsca/ec/error.py1
-rw-r--r--pyecsca/ec/formula/base.py1
-rw-r--r--pyecsca/ec/formula/code.py1
-rw-r--r--pyecsca/ec/formula/efd.py1
-rw-r--r--pyecsca/ec/formula/fake.py1
-rw-r--r--pyecsca/ec/formula/fliparoo.py2
-rw-r--r--pyecsca/ec/formula/graph.py5
-rw-r--r--pyecsca/ec/formula/metrics.py1
-rw-r--r--pyecsca/ec/key_generation.py1
-rw-r--r--pyecsca/ec/model.py1
-rw-r--r--pyecsca/ec/mult/binary.py1
-rw-r--r--pyecsca/ec/mult/comb.py4
-rw-r--r--pyecsca/ec/mult/fake.py14
-rw-r--r--pyecsca/ec/mult/fixed.py4
-rw-r--r--pyecsca/ec/mult/naf.py4
-rw-r--r--pyecsca/ec/mult/window.py16
-rw-r--r--pyecsca/ec/op.py1
-rw-r--r--pyecsca/ec/point.py1
-rw-r--r--pyecsca/ec/scalar.py1
-rw-r--r--pyecsca/ec/signature.py1
-rw-r--r--pyecsca/ec/transformations.py1
-rw-r--r--pyecsca/misc/cache.py21
-rw-r--r--pyecsca/misc/cfg.py5
-rw-r--r--pyecsca/misc/utils.py1
-rw-r--r--pyecsca/sca/attack/leakage_model.py15
-rw-r--r--pyecsca/sca/re/rpa.py23
-rw-r--r--pyecsca/sca/re/tree.py1
-rw-r--r--pyecsca/sca/re/zvp.py11
-rw-r--r--pyecsca/sca/scope/base.py1
-rw-r--r--pyecsca/sca/scope/chipwhisperer.py1
-rw-r--r--pyecsca/sca/scope/picoscope_alt.py1
-rw-r--r--pyecsca/sca/scope/picoscope_sdk.py190
-rw-r--r--pyecsca/sca/stacked_traces/combine.py29
-rw-r--r--pyecsca/sca/stacked_traces/stacked_traces.py11
-rw-r--r--pyecsca/sca/target/ISO7816.py35
-rw-r--r--pyecsca/sca/target/PCSC.py11
-rw-r--r--pyecsca/sca/target/base.py1
-rw-r--r--pyecsca/sca/target/binary.py1
-rw-r--r--pyecsca/sca/target/chipwhisperer.py5
-rw-r--r--pyecsca/sca/target/ectester.py1
-rw-r--r--pyecsca/sca/target/flash.py1
-rw-r--r--pyecsca/sca/target/leakage.py4
-rw-r--r--pyecsca/sca/target/leia.py11
-rw-r--r--pyecsca/sca/target/serial.py1
-rw-r--r--pyecsca/sca/target/simpleserial.py1
-rw-r--r--pyecsca/sca/trace/align.py1
-rw-r--r--pyecsca/sca/trace/combine.py1
-rw-r--r--pyecsca/sca/trace/edit.py1
-rw-r--r--pyecsca/sca/trace/filter.py1
-rw-r--r--pyecsca/sca/trace/match.py1
-rw-r--r--pyecsca/sca/trace/plot.py1
-rw-r--r--pyecsca/sca/trace/process.py8
-rw-r--r--pyecsca/sca/trace/sampling.py1
-rw-r--r--pyecsca/sca/trace/test.py7
-rw-r--r--pyecsca/sca/trace/trace.py9
-rw-r--r--pyecsca/sca/trace_set/base.py5
-rw-r--r--pyecsca/sca/trace_set/chipwhisperer.py4
-rw-r--r--pyecsca/sca/trace_set/hdf5.py5
-rw-r--r--pyecsca/sca/trace_set/inspector.py9
-rw-r--r--pyecsca/sca/trace_set/pickle.py13
65 files changed, 435 insertions, 195 deletions
diff --git a/pyecsca/ec/configuration.py b/pyecsca/ec/configuration.py
index 40ca59b..a8c5fee 100644
--- a/pyecsca/ec/configuration.py
+++ b/pyecsca/ec/configuration.py
@@ -1,4 +1,5 @@
"""Provides a way to work with and enumerate implementation configurations."""
+
import warnings
from abc import ABC
from dataclasses import dataclass
diff --git a/pyecsca/ec/coordinates.py b/pyecsca/ec/coordinates.py
index 9dcdbbe..8a42b7b 100644
--- a/pyecsca/ec/coordinates.py
+++ b/pyecsca/ec/coordinates.py
@@ -1,4 +1,5 @@
"""Provides a coordinate model class."""
+
from ast import parse, Module
from importlib_resources.abc import Traversable
from importlib_resources import as_file
diff --git a/pyecsca/ec/countermeasures.py b/pyecsca/ec/countermeasures.py
index 19afb06..9fd743a 100644
--- a/pyecsca/ec/countermeasures.py
+++ b/pyecsca/ec/countermeasures.py
@@ -60,6 +60,7 @@ class GroupScalarRandomization(ScalarMultiplierCountermeasure):
&\textbf{return}\ [k + r n]G
"""
+
rand_bits: int
def __init__(self, mult: ScalarMultiplier, rand_bits: int = 32):
@@ -73,7 +74,11 @@ class GroupScalarRandomization(ScalarMultiplierCountermeasure):
def init(self, params: DomainParameters, point: Point):
self.params = params
self.point = point
- self.mult.init(self.params, self.point, bits=params.full_order.bit_length() + self.rand_bits)
+ self.mult.init(
+ self.params,
+ self.point,
+ bits=params.full_order.bit_length() + self.rand_bits,
+ )
def multiply(self, scalar: int) -> Point:
if self.params is None or self.point is None:
@@ -99,6 +104,7 @@ class AdditiveSplitting(ScalarMultiplierCountermeasure):
&\textbf{return}\ [k - r]G + [r]G
"""
+
add: Optional[AdditionFormula]
def __init__(self, mult: ScalarMultiplier, add: Optional[AdditionFormula] = None):
@@ -121,7 +127,9 @@ class AdditiveSplitting(ScalarMultiplierCountermeasure):
if self.add is None:
res = self.mult._add(R, S) # noqa: This is OK.
else:
- res = self.add(self.params.curve.prime, R, S, **self.params.curve.parameters)[0]
+ res = self.add(
+ self.params.curve.prime, R, S, **self.params.curve.parameters
+ )[0]
return action.exit(res)
@@ -140,6 +148,7 @@ class MultiplicativeSplitting(ScalarMultiplierCountermeasure):
&\textbf{return}\ [k r^{-1} \mod n]S
"""
+
rand_bits: int
def __init__(self, mult: ScalarMultiplier, rand_bits: int = 32):
@@ -180,6 +189,7 @@ class EuclideanSplitting(ScalarMultiplierCountermeasure):
&\textbf{return}\ [k_1]G + [k_2]S
"""
+
add: Optional[AdditionFormula]
def __init__(self, mult: ScalarMultiplier, add: Optional[AdditionFormula] = None):
@@ -208,5 +218,7 @@ class EuclideanSplitting(ScalarMultiplierCountermeasure):
if self.add is None:
res = self.mult._add(S, T) # noqa: This is OK.
else:
- res = self.add(self.params.curve.prime, S, T, **self.params.curve.parameters)[0]
+ res = self.add(
+ self.params.curve.prime, S, T, **self.params.curve.parameters
+ )[0]
return action.exit(res)
diff --git a/pyecsca/ec/curve.py b/pyecsca/ec/curve.py
index 8a3c726..67feb60 100644
--- a/pyecsca/ec/curve.py
+++ b/pyecsca/ec/curve.py
@@ -1,4 +1,5 @@
"""Provides an elliptic curve class."""
+
from ast import Module
from astunparse import unparse
from copy import copy
@@ -68,21 +69,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
@@ -130,7 +131,7 @@ class EllipticCurve:
if k.from_sympy(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})."
+ 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:
@@ -146,7 +147,9 @@ class EllipticCurve:
}
locls.update(self.parameters)
for line in formulas:
- exec(compile(line, "", mode="exec"), None, locls) # exec is OK here, skipcq: PYL-W0122
+ exec(
+ compile(line, "", mode="exec"), None, locls
+ ) # exec is OK here, skipcq: PYL-W0122
if not isinstance(locls["x"], Mod):
locls["x"] = mod(locls["x"], self.prime)
if not isinstance(locls["y"], Mod):
@@ -233,7 +236,9 @@ class EllipticCurve:
return None
locls = {**self.parameters}
for line in self.model.base_neutral:
- exec(compile(line, "", mode="exec"), None, locls) # exec is OK here, skipcq: PYL-W0122
+ exec(
+ compile(line, "", mode="exec"), None, locls
+ ) # exec is OK here, skipcq: PYL-W0122
if not isinstance(locls["x"], Mod):
locls["x"] = mod(locls["x"], self.prime)
if not isinstance(locls["y"], Mod):
@@ -269,7 +274,9 @@ class EllipticCurve:
loc = {**self.parameters, **point.coords}
else:
loc = {**self.parameters, **point.to_affine().coords}
- return eval(compile(self.model.equation, "", mode="eval"), loc) # eval is OK here, skipcq: PYL-W0123
+ return eval(
+ compile(self.model.equation, "", mode="eval"), loc
+ ) # eval is OK here, skipcq: PYL-W0123
def to_coords(self, coordinate_model: CoordinateModel) -> "EllipticCurve":
"""
@@ -280,8 +287,13 @@ class EllipticCurve:
"""
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]
+ 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":
"""
@@ -290,8 +302,13 @@ 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:
"""
@@ -325,7 +342,9 @@ class EllipticCurve:
raise ValueError("Encoded point has bad length")
x = mod(int.from_bytes(data, "big"), self.prime)
loc = {**self.parameters, "x": x}
- rhs = eval(compile(self.model.ysquared, "", mode="eval"), loc) # eval is OK here, skipcq: PYL-W0123
+ rhs = eval(
+ compile(self.model.ysquared, "", mode="eval"), loc
+ ) # eval is OK here, skipcq: PYL-W0123
if not rhs.is_residue():
raise ValueError("Point not on curve")
sqrt = rhs.sqrt()
@@ -350,19 +369,25 @@ class EllipticCurve:
:return: Lifted (affine) points, if any.
"""
loc = {**self.parameters, "x": x}
- ysquared = eval(compile(self.model.ysquared, "", mode="eval"), loc) # eval is OK here, skipcq: PYL-W0123
+ ysquared = eval(
+ compile(self.model.ysquared, "", mode="eval"), loc
+ ) # eval is OK here, skipcq: PYL-W0123
if not ysquared.is_residue():
return set()
y = ysquared.sqrt()
- return {Point(AffineCoordinateModel(self.model), x=x, y=y),
- Point(AffineCoordinateModel(self.model), x=x, y=-y)}
+ return {
+ Point(AffineCoordinateModel(self.model), x=x, y=y),
+ Point(AffineCoordinateModel(self.model), x=x, y=-y),
+ }
def affine_random(self) -> Point:
"""Generate a random affine point on the curve."""
while True:
x = Mod.random(self.prime)
loc = {**self.parameters, "x": x}
- ysquared = eval(compile(self.model.ysquared, "", mode="eval"), loc) # eval is OK here, skipcq: PYL-W0123
+ ysquared = eval(
+ compile(self.model.ysquared, "", mode="eval"), loc
+ ) # eval is OK here, skipcq: PYL-W0123
if ysquared.is_residue():
y = ysquared.sqrt()
b = Mod.random(2)
@@ -374,14 +399,22 @@ 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):
- return hash((self.model, self.coordinate_model, self.prime, tuple(self.parameters.keys()), tuple(self.parameters.values())))
+ return hash(
+ (
+ self.model,
+ self.coordinate_model,
+ self.prime,
+ tuple(self.parameters.keys()),
+ tuple(self.parameters.values()),
+ )
+ )
def __str__(self):
return "EllipticCurve"
diff --git a/pyecsca/ec/divpoly.py b/pyecsca/ec/divpoly.py
index 96b7bf3..0809f94 100644
--- a/pyecsca/ec/divpoly.py
+++ b/pyecsca/ec/divpoly.py
@@ -1,6 +1,7 @@
"""
Provides functions for computing division polynomials and the multiplication-by-n map on an elliptic curve.
"""
+
from typing import Tuple, Dict, Set, Mapping, Optional
from public import public
import warnings
@@ -161,9 +162,7 @@ def divpoly0(curve: EllipticCurve, *ns: int) -> Mapping[int, Poly]:
elif i in (1, 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
- )
+ 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:
@@ -293,7 +292,9 @@ def mult_by_n(
mx = mult_by_n_pari(curve, n)
else:
if use_pari:
- warnings.warn("Falling-back to slow mult-by-n map computation due to missing [pari] (cypari2 and libpari) dependency.")
+ warnings.warn(
+ "Falling-back to slow mult-by-n map computation due to missing [pari] (cypari2 and libpari) dependency."
+ )
mx = mult_by_n_own(curve, n)
if x_only:
diff --git a/pyecsca/ec/error.py b/pyecsca/ec/error.py
index b9cd7e7..003292e 100644
--- a/pyecsca/ec/error.py
+++ b/pyecsca/ec/error.py
@@ -1,4 +1,5 @@
"""Contains exceptions and warnings used in the library."""
+
import warnings
from public import public
from pyecsca.misc.cfg import getconfig
diff --git a/pyecsca/ec/formula/base.py b/pyecsca/ec/formula/base.py
index 04d6c19..a556367 100644
--- a/pyecsca/ec/formula/base.py
+++ b/pyecsca/ec/formula/base.py
@@ -1,4 +1,5 @@
"""Provides an abstract base class of a formula."""
+
from abc import ABC
from ast import Expression
from functools import cached_property
diff --git a/pyecsca/ec/formula/code.py b/pyecsca/ec/formula/code.py
index f24cfc6..6eca838 100644
--- a/pyecsca/ec/formula/code.py
+++ b/pyecsca/ec/formula/code.py
@@ -1,4 +1,5 @@
"""Provides a concrete class of a formula that has a constructor and some code."""
+
from typing import List, Any
from ast import Expression
from astunparse import unparse
diff --git a/pyecsca/ec/formula/efd.py b/pyecsca/ec/formula/efd.py
index 7796c11..f837da2 100644
--- a/pyecsca/ec/formula/efd.py
+++ b/pyecsca/ec/formula/efd.py
@@ -1,4 +1,5 @@
"""Provides formulas wrapping the [EFD]_."""
+
from copy import copy
from public import public
diff --git a/pyecsca/ec/formula/fake.py b/pyecsca/ec/formula/fake.py
index 612712d..8b71df6 100644
--- a/pyecsca/ec/formula/fake.py
+++ b/pyecsca/ec/formula/fake.py
@@ -1,4 +1,5 @@
"""Provides "fake" formulas."""
+
from abc import ABC
from typing import Any, Tuple
diff --git a/pyecsca/ec/formula/fliparoo.py b/pyecsca/ec/formula/fliparoo.py
index 4d14f80..7b8d951 100644
--- a/pyecsca/ec/formula/fliparoo.py
+++ b/pyecsca/ec/formula/fliparoo.py
@@ -1,4 +1,5 @@
"""Provides a way to Fliparoo formulas."""
+
from ast import parse
from typing import Iterator, List, Type, Optional
from public import public
@@ -173,7 +174,6 @@ def largest_fliparoo(
class SignedNode:
-
"""
Represents a summand in an expression X1-X2+X3+X4-X5...
Used for creating +/- Fliparoos
diff --git a/pyecsca/ec/formula/graph.py b/pyecsca/ec/formula/graph.py
index e2fb1ee..3020ea9 100644
--- a/pyecsca/ec/formula/graph.py
+++ b/pyecsca/ec/formula/graph.py
@@ -1,4 +1,5 @@
"""Provides tools for working with formulas as graphs."""
+
import matplotlib.pyplot as plt
import networkx as nx
from ast import parse, Expression
@@ -283,7 +284,9 @@ class FormulaGraph:
def networkx_graph(self) -> nx.DiGraph:
graph = nx.DiGraph()
for i, node in enumerate(self.nodes):
- graph.add_node(i, result=node.result, label=node.label, op=getattr(node, "op", None))
+ graph.add_node(
+ i, result=node.result, label=node.label, op=getattr(node, "op", None)
+ )
for node in self.nodes:
for out in node.outgoing_nodes:
graph.add_edge(self.node_index(node), self.node_index(out))
diff --git a/pyecsca/ec/formula/metrics.py b/pyecsca/ec/formula/metrics.py
index 31d0545..f2e9166 100644
--- a/pyecsca/ec/formula/metrics.py
+++ b/pyecsca/ec/formula/metrics.py
@@ -1,4 +1,5 @@
"""Provides metrics for comparing formulas."""
+
import warnings
from public import public
diff --git a/pyecsca/ec/key_generation.py b/pyecsca/ec/key_generation.py
index c583160..f67ad67 100644
--- a/pyecsca/ec/key_generation.py
+++ b/pyecsca/ec/key_generation.py
@@ -1,4 +1,5 @@
"""Provides a key generator for elliptic curve keypairs."""
+
from typing import Tuple
from public import public
diff --git a/pyecsca/ec/model.py b/pyecsca/ec/model.py
index d90f337..15affa2 100644
--- a/pyecsca/ec/model.py
+++ b/pyecsca/ec/model.py
@@ -1,4 +1,5 @@
"""Provides curve model classes for the supported curve models."""
+
from ast import parse, Expression, Module
from typing import List, MutableMapping
from importlib_resources import files, as_file
diff --git a/pyecsca/ec/mult/binary.py b/pyecsca/ec/mult/binary.py
index f0cb5ac..3dc22c3 100644
--- a/pyecsca/ec/mult/binary.py
+++ b/pyecsca/ec/mult/binary.py
@@ -1,4 +1,5 @@
"""Provides binary scalar multipliers (LTR and RTL), that process the scalar as-is, bit-by-bit."""
+
from abc import ABC
from copy import copy
from typing import Optional
diff --git a/pyecsca/ec/mult/comb.py b/pyecsca/ec/mult/comb.py
index 1a6c0c2..3e064d2 100644
--- a/pyecsca/ec/mult/comb.py
+++ b/pyecsca/ec/mult/comb.py
@@ -1,4 +1,5 @@
"""Provides Comb-like scalar multipliers, such as BGMW or Lim-Lee."""
+
from copy import copy
from math import ceil
from typing import MutableMapping, Optional
@@ -12,7 +13,8 @@ from pyecsca.ec.mult import (
ProcessingDirection,
AccumulationOrder,
PrecomputationAction,
- ScalarMultiplicationAction, PrecompMultiplier,
+ ScalarMultiplicationAction,
+ PrecompMultiplier,
)
from pyecsca.ec.params import DomainParameters
from pyecsca.ec.point import Point
diff --git a/pyecsca/ec/mult/fake.py b/pyecsca/ec/mult/fake.py
index 391696b..d3f5b09 100644
--- a/pyecsca/ec/mult/fake.py
+++ b/pyecsca/ec/mult/fake.py
@@ -1,13 +1,21 @@
from typing import List, Type, Callable
-from pyecsca.ec.formula import Formula, AdditionFormula, DifferentialAdditionFormula, DoublingFormula, LadderFormula, \
- NegationFormula
+from pyecsca.ec.formula import (
+ Formula,
+ AdditionFormula,
+ DifferentialAdditionFormula,
+ DoublingFormula,
+ LadderFormula,
+ NegationFormula,
+)
from pyecsca.ec.formula.fake import FakeFormula
from pyecsca.ec.mult import ScalarMultiplier
from pyecsca.ec.params import DomainParameters
-def fake_mult(mult_class: Type[ScalarMultiplier], mult_factory: Callable, params: DomainParameters) -> ScalarMultiplier:
+def fake_mult(
+ mult_class: Type[ScalarMultiplier], mult_factory: Callable, params: DomainParameters
+) -> ScalarMultiplier:
"""
Get a multiplier with `FakeFormula`s.
diff --git a/pyecsca/ec/mult/fixed.py b/pyecsca/ec/mult/fixed.py
index 070aaec..4b817e9 100644
--- a/pyecsca/ec/mult/fixed.py
+++ b/pyecsca/ec/mult/fixed.py
@@ -1,4 +1,5 @@
"""Provides fixed-base scalar multipliers that do a lot of pre-computation (but not combs)."""
+
from copy import copy
from typing import MutableMapping, Optional
@@ -11,7 +12,8 @@ from pyecsca.ec.mult.base import (
ProcessingDirection,
AccumulationOrder,
PrecomputationAction,
- ScalarMultiplicationAction, PrecompMultiplier,
+ ScalarMultiplicationAction,
+ PrecompMultiplier,
)
from pyecsca.ec.params import DomainParameters
from pyecsca.ec.point import Point
diff --git a/pyecsca/ec/mult/naf.py b/pyecsca/ec/mult/naf.py
index b886552..f2e2bcc 100644
--- a/pyecsca/ec/mult/naf.py
+++ b/pyecsca/ec/mult/naf.py
@@ -1,4 +1,5 @@
"""Provides scalar multipliers based on the Non Adjacent Form (NAF) recoding."""
+
from copy import copy
from typing import Optional, List, MutableMapping
from public import public
@@ -9,7 +10,8 @@ from pyecsca.ec.mult.base import (
ProcessingDirection,
AccumulationOrder,
PrecomputationAction,
- AccumulatorMultiplier, PrecompMultiplier,
+ AccumulatorMultiplier,
+ PrecompMultiplier,
)
from pyecsca.ec.formula import (
AdditionFormula,
diff --git a/pyecsca/ec/mult/window.py b/pyecsca/ec/mult/window.py
index 1a0ecec..1340e7e 100644
--- a/pyecsca/ec/mult/window.py
+++ b/pyecsca/ec/mult/window.py
@@ -1,4 +1,5 @@
"""Provides sliding window and fixed window scalar multipliers (including m-ary, for non power-of-2 m)."""
+
from copy import copy
from typing import Optional, MutableMapping
from public import public
@@ -10,7 +11,8 @@ from pyecsca.ec.mult.base import (
ScalarMultiplicationAction,
PrecomputationAction,
ProcessingDirection,
- AccumulatorMultiplier, PrecompMultiplier,
+ AccumulatorMultiplier,
+ PrecompMultiplier,
)
from pyecsca.ec.formula import (
AdditionFormula,
@@ -28,7 +30,9 @@ from pyecsca.ec.scalar import (
@public
-class SlidingWindowMultiplier(AccumulatorMultiplier, PrecompMultiplier, ScalarMultiplier):
+class SlidingWindowMultiplier(
+ AccumulatorMultiplier, PrecompMultiplier, ScalarMultiplier
+):
"""
Sliding window scalar multiplier.
@@ -122,7 +126,9 @@ class SlidingWindowMultiplier(AccumulatorMultiplier, PrecompMultiplier, ScalarMu
@public
-class FixedWindowLTRMultiplier(AccumulatorMultiplier, PrecompMultiplier, ScalarMultiplier):
+class FixedWindowLTRMultiplier(
+ AccumulatorMultiplier, PrecompMultiplier, ScalarMultiplier
+):
"""
Like LTRMultiplier, but m-ary, not binary.
@@ -322,9 +328,7 @@ class WindowBoothMultiplier(AccumulatorMultiplier, PrecompMultiplier, ScalarMult
with ScalarMultiplicationAction(self._point, self._params, scalar) as action:
if scalar == 0:
return action.exit(copy(self._params.curve.neutral))
- scalar_booth = booth_window(
- scalar, self.width, self._bits
- )
+ scalar_booth = booth_window(scalar, self.width, self._bits)
q = copy(self._params.curve.neutral)
for val in scalar_booth:
for _ in range(self.width):
diff --git a/pyecsca/ec/op.py b/pyecsca/ec/op.py
index 250d6a3..5f03b50 100644
--- a/pyecsca/ec/op.py
+++ b/pyecsca/ec/op.py
@@ -1,4 +1,5 @@
"""Provides a class for a code operation."""
+
from ast import (
Module,
walk,
diff --git a/pyecsca/ec/point.py b/pyecsca/ec/point.py
index 1b11e3f..162b9aa 100644
--- a/pyecsca/ec/point.py
+++ b/pyecsca/ec/point.py
@@ -1,4 +1,5 @@
"""Provides a :py:class:`.Point` class and a special :py:class:`.InfinityPoint` class for the point at infinity."""
+
from copy import copy
from typing import Mapping, TYPE_CHECKING
diff --git a/pyecsca/ec/scalar.py b/pyecsca/ec/scalar.py
index 5d20634..dc6101c 100644
--- a/pyecsca/ec/scalar.py
+++ b/pyecsca/ec/scalar.py
@@ -1,4 +1,5 @@
"""Provides functions for computing various scalar representations (like NAF, or different bases)."""
+
from typing import List
from itertools import dropwhile
from public import public
diff --git a/pyecsca/ec/signature.py b/pyecsca/ec/signature.py
index 088c931..b138607 100644
--- a/pyecsca/ec/signature.py
+++ b/pyecsca/ec/signature.py
@@ -1,4 +1,5 @@
"""Provides an implementation of ECDSA (Elliptic Curve Digital Signature Algorithm)."""
+
import hashlib
from typing import Optional, Any
diff --git a/pyecsca/ec/transformations.py b/pyecsca/ec/transformations.py
index 818a6dd..0be3684 100644
--- a/pyecsca/ec/transformations.py
+++ b/pyecsca/ec/transformations.py
@@ -1,4 +1,5 @@
"""Provides functions for transforming curves to different models."""
+
from typing import Tuple, Generator
from public import public
diff --git a/pyecsca/misc/cache.py b/pyecsca/misc/cache.py
index 5f388ad..acde6bf 100644
--- a/pyecsca/misc/cache.py
+++ b/pyecsca/misc/cache.py
@@ -1,4 +1,5 @@
"""Cache some things."""
+
from functools import lru_cache
from sympy import sympify as _orig_sympify, simplify as _orig_simplify, count_ops
from public import public
@@ -14,5 +15,21 @@ def sympify(
@public
@lru_cache(maxsize=256, typed=True)
-def simplify(expr, ratio=1.7, measure=count_ops, rational=False, inverse=False, doit=True, **kwargs):
- return _orig_simplify(expr, ratio=ratio, measure=measure, rational=rational, inverse=inverse, doit=doit, **kwargs)
+def simplify(
+ expr,
+ ratio=1.7,
+ measure=count_ops,
+ rational=False,
+ inverse=False,
+ doit=True,
+ **kwargs,
+):
+ return _orig_simplify(
+ expr,
+ ratio=ratio,
+ measure=measure,
+ rational=rational,
+ inverse=inverse,
+ doit=doit,
+ **kwargs,
+ )
diff --git a/pyecsca/misc/cfg.py b/pyecsca/misc/cfg.py
index 037074d..a7101fa 100644
--- a/pyecsca/misc/cfg.py
+++ b/pyecsca/misc/cfg.py
@@ -3,6 +3,7 @@ Provides functions for runtime configuration of the toolkit.
This includes how errors are handled, or which :py:class:`~pyecsca.ec.mod.Mod` implementation is used.
"""
+
from copy import deepcopy
from contextvars import ContextVar, Token
from typing import Optional
@@ -119,7 +120,9 @@ class ECConfig:
@mod_implementation.setter
def mod_implementation(self, value: str):
if value not in ("python", "gmp", "flint", "symbolic"):
- raise ValueError("Bad Mod implementaiton, can be one of 'python', 'gmp', 'flint' or 'symbolic'.")
+ raise ValueError(
+ "Bad Mod implementaiton, can be one of 'python', 'gmp', 'flint' or 'symbolic'."
+ )
self._mod_implementation = value
diff --git a/pyecsca/misc/utils.py b/pyecsca/misc/utils.py
index 060208f..eb52614 100644
--- a/pyecsca/misc/utils.py
+++ b/pyecsca/misc/utils.py
@@ -1,4 +1,5 @@
"""Just some utilities I promise."""
+
import sys
from ast import parse
from contextlib import contextmanager
diff --git a/pyecsca/sca/attack/leakage_model.py b/pyecsca/sca/attack/leakage_model.py
index c1691d8..fa9a2e3 100644
--- a/pyecsca/sca/attack/leakage_model.py
+++ b/pyecsca/sca/attack/leakage_model.py
@@ -1,6 +1,7 @@
"""
Provides leakage models to simulate leakage.
"""
+
import abc
import sys
from typing import Literal, ClassVar
@@ -11,9 +12,12 @@ from public import public
from pyecsca.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")
+
else:
+
def hw(i):
return i.bit_count()
@@ -43,13 +47,16 @@ class NormalNoice(Noise):
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 Trace(
+ arg.samples + self.rng.normal(self.mean, self.sdev, len(arg.samples))
+ )
return arg + self.rng.normal(self.mean, self.sdev)
@public
class LeakageModel(abc.ABC):
"""An abstract leakage model."""
+
num_args: ClassVar[int]
@abc.abstractmethod
@@ -61,6 +68,7 @@ class LeakageModel(abc.ABC):
@public
class Identity(LeakageModel):
"""Identity leakage model, leaks the thing itself."""
+
num_args = 1
def __call__(self, *args, **kwargs) -> int:
@@ -70,6 +78,7 @@ class Identity(LeakageModel):
@public
class Bit(LeakageModel):
"""Bit leakage model, leaks a selected bit."""
+
num_args = 1
def __init__(self, which: int):
@@ -85,6 +94,7 @@ class Bit(LeakageModel):
@public
class Slice(LeakageModel):
"""Slice leakage model, leaks a slice of bits."""
+
num_args = 1
def __init__(self, begin: int, end: int):
@@ -103,6 +113,7 @@ class Slice(LeakageModel):
@public
class HammingWeight(LeakageModel):
"""Hamming-weight leakage model, leaks the Hamming-weight of the thing."""
+
num_args = 1
def __call__(self, *args, **kwargs) -> int:
@@ -112,6 +123,7 @@ class HammingWeight(LeakageModel):
@public
class HammingDistance(LeakageModel):
"""Hamming-distance leakage model, leaks the Hamming-distance between the two things."""
+
num_args = 2
def __call__(self, *args, **kwargs) -> int:
@@ -121,6 +133,7 @@ class HammingDistance(LeakageModel):
@public
class BitLength(LeakageModel):
"""Bit-length leakage model, leaks the bit-length of the thing."""
+
num_args = 1
def __call__(self, *args, **kwargs) -> int:
diff --git a/pyecsca/sca/re/rpa.py b/pyecsca/sca/re/rpa.py
index 4f30d07..10071b0 100644
--- a/pyecsca/sca/re/rpa.py
+++ b/pyecsca/sca/re/rpa.py
@@ -6,7 +6,17 @@ from copy import copy, deepcopy
from functools import lru_cache
from public import public
-from typing import MutableMapping, Optional, Callable, List, Set, cast, Type, Literal, Union
+from typing import (
+ MutableMapping,
+ Optional,
+ Callable,
+ List,
+ Set,
+ cast,
+ Type,
+ Literal,
+ Union,
+)
from sympy import FF, sympify, Poly, symbols
@@ -404,7 +414,9 @@ class RPA(RE):
@lru_cache(maxsize=256, typed=True)
-def _cached_fake_mult(mult_class: Type[ScalarMultiplier], mult_factory: Callable, params: DomainParameters) -> ScalarMultiplier:
+def _cached_fake_mult(
+ mult_class: Type[ScalarMultiplier], mult_factory: Callable, params: DomainParameters
+) -> ScalarMultiplier:
return fake_mult(mult_class, mult_factory, params)
@@ -416,7 +428,12 @@ def multiples_computed(
mult_factory: Callable,
use_init: bool = False,
use_multiply: bool = True,
- kind: Union[Literal["all"], Literal["input"], Literal["necessary"], Literal["precomp+necessary"]] = "all",
+ kind: Union[
+ Literal["all"],
+ Literal["input"],
+ Literal["necessary"],
+ Literal["precomp+necessary"],
+ ] = "all",
) -> set[int]:
"""
Compute the multiples computed for a given scalar and multiplier (quickly).
diff --git a/pyecsca/sca/re/tree.py b/pyecsca/sca/re/tree.py
index bab749e..152bb3d 100644
--- a/pyecsca/sca/re/tree.py
+++ b/pyecsca/sca/re/tree.py
@@ -42,6 +42,7 @@ Here we grow the trees.
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣤⠾⠛⣿⠙⠛⠶⢦⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀
"""
+
from math import ceil, log2
from copy import deepcopy
from typing import Mapping, Any, Set, List, Tuple, Optional, Dict
diff --git a/pyecsca/sca/re/zvp.py b/pyecsca/sca/re/zvp.py
index 9c12e56..956d0c2 100644
--- a/pyecsca/sca/re/zvp.py
+++ b/pyecsca/sca/re/zvp.py
@@ -3,6 +3,7 @@ Provides functionality inspired by the Zero-value point attack [ZVP]_.
Implements ZVP point construction from [FFD]_.
"""
+
from functools import lru_cache
from typing import List, Set, Tuple, Dict, Type, Callable
from public import public
@@ -518,7 +519,9 @@ def solve_hard_dcp(xonly_polynomial: Poly, curve: EllipticCurve, k: int) -> Set[
if has_pari:
roots = solve_hard_dcp_cypari(xonly_polynomial, curve, k)
else:
- warnings.warn("Falling-back to slow hard-DCP computation due to missing [pari] (cypari2 and libpari) dependency.")
+ warnings.warn(
+ "Falling-back to slow hard-DCP computation due to missing [pari] (cypari2 and libpari) dependency."
+ )
# Substitute in the mult-by-k map
dlog = subs_dlog(xonly_polynomial, k, curve)
# Put in concrete curve parameters
@@ -582,7 +585,9 @@ def solve_hard_dcp_cypari(
@lru_cache(maxsize=256, typed=True)
-def _cached_fake_mult(mult_class: Type[ScalarMultiplier], mult_factory: Callable, params: DomainParameters) -> ScalarMultiplier:
+def _cached_fake_mult(
+ mult_class: Type[ScalarMultiplier], mult_factory: Callable, params: DomainParameters
+) -> ScalarMultiplier:
return fake_mult(mult_class, mult_factory, params)
@@ -593,7 +598,7 @@ def addition_chain(
mult_class: Type[ScalarMultiplier],
mult_factory: Callable,
use_init: bool = False,
- use_multiply: bool = True
+ use_multiply: bool = True,
) -> List[Tuple[str, Tuple[int, ...]]]:
"""
Compute the addition chain for a given scalar and multiplier.
diff --git a/pyecsca/sca/scope/base.py b/pyecsca/sca/scope/base.py
index b9d43af..5c751e9 100644
--- a/pyecsca/sca/scope/base.py
+++ b/pyecsca/sca/scope/base.py
@@ -1,4 +1,5 @@
"""Provides an abstract base class for oscilloscopes."""
+
from enum import Enum, auto
from typing import Tuple, Sequence, Optional
diff --git a/pyecsca/sca/scope/chipwhisperer.py b/pyecsca/sca/scope/chipwhisperer.py
index ba11525..24b4ba1 100644
--- a/pyecsca/sca/scope/chipwhisperer.py
+++ b/pyecsca/sca/scope/chipwhisperer.py
@@ -1,4 +1,5 @@
"""Provides an oscilloscope class using the ChipWhisperer-Lite scope."""
+
from typing import Optional, Tuple, Sequence, Set
import numpy as np
diff --git a/pyecsca/sca/scope/picoscope_alt.py b/pyecsca/sca/scope/picoscope_alt.py
index 86332c0..5a34b0e 100644
--- a/pyecsca/sca/scope/picoscope_alt.py
+++ b/pyecsca/sca/scope/picoscope_alt.py
@@ -1,4 +1,5 @@
"""Provides an oscilloscope class for the PicoScope branded oscilloscopes using the alternative `pico-python <https://github.com/colinoflynn/pico-python>`_ bindings."""
+
from time import time_ns, sleep
import numpy as np
from typing import Optional, Tuple, Sequence, Union
diff --git a/pyecsca/sca/scope/picoscope_sdk.py b/pyecsca/sca/scope/picoscope_sdk.py
index ebb11e5..133b9a2 100644
--- a/pyecsca/sca/scope/picoscope_sdk.py
+++ b/pyecsca/sca/scope/picoscope_sdk.py
@@ -1,4 +1,5 @@
"""Provides an oscilloscope class for PicoScope branded oscilloscopes using the official `picosdk-python-wrappers <https://github.com/picotech/picosdk-python-wrappers>`_."""
+
import ctypes
from math import log2, floor
from time import time_ns, sleep
@@ -36,10 +37,10 @@ from pyecsca.sca.trace import Trace
def adc2volt(
- adc: Union[np.ndarray, ctypes.c_int16],
- volt_range: float,
- adc_minmax: int,
- dtype=np.float32,
+ adc: Union[np.ndarray, ctypes.c_int16],
+ volt_range: float,
+ adc_minmax: int,
+ dtype=np.float32,
) -> Union[np.ndarray, float]: # pragma: no cover
"""
Convert raw adc values to volts.
@@ -58,7 +59,7 @@ def adc2volt(
def volt2adc(
- volt: Union[np.ndarray, float], volt_range: float, adc_minmax: int, dtype=np.float32
+ volt: Union[np.ndarray, float], volt_range: float, adc_minmax: int, dtype=np.float32
) -> Union[np.ndarray, ctypes.c_int16]: # pragma: no cover
"""
Convert volt values to raw adc values.
@@ -117,28 +118,39 @@ class PicoScopeSdk(Scope): # pragma: no cover
size = ctypes.c_int16()
assert_pico_ok(
self._dispatch_call(
- "GetUnitInfo", self.handle, info, ctypes.c_int16(6), ctypes.byref(size), ctypes.c_uint(3)
+ "GetUnitInfo",
+ self.handle,
+ info,
+ ctypes.c_int16(6),
+ ctypes.byref(size),
+ ctypes.c_uint(3),
)
)
self._variant = "".join(chr(i) for i in info[: size.value - 1]) # type: ignore
return self._variant
def setup_frequency(
- self, frequency: int, pretrig: int, posttrig: int
+ self, frequency: int, pretrig: int, posttrig: int
) -> Tuple[int, int]:
return self.set_frequency(frequency, pretrig, posttrig)
def set_channel(
- self, channel: str, enabled: bool, coupling: str, range: float, offset: float
+ self, channel: str, enabled: bool, coupling: str, range: float, offset: float
):
if offset != 0.0:
raise ValueError("Nonzero offset not supported.")
if channel not in self.CHANNELS:
- raise ValueError(f"Channel {channel} not in available channels: {self.CHANNELS.keys()}")
+ raise ValueError(
+ f"Channel {channel} not in available channels: {self.CHANNELS.keys()}"
+ )
if coupling not in self.COUPLING:
- raise ValueError(f"Coupling {coupling} not in available couplings: {self.COUPLING.keys()}")
+ raise ValueError(
+ f"Coupling {coupling} not in available couplings: {self.COUPLING.keys()}"
+ )
if range not in self.RANGES:
- raise ValueError(f"Range {range} not in available ranges: {self.RANGES.keys()}")
+ raise ValueError(
+ f"Range {range} not in available ranges: {self.RANGES.keys()}"
+ )
assert_pico_ok(
self._dispatch_call(
"SetChannel",
@@ -152,20 +164,20 @@ class PicoScopeSdk(Scope): # pragma: no cover
self.ranges[channel] = range
def setup_channel(
- self, channel: str, coupling: str, range: float, offset: float, enable: bool
+ self, channel: str, coupling: str, range: float, offset: float, enable: bool
):
self.set_channel(channel, enable, coupling, range, offset)
def _set_freq(
- self,
- frequency: int,
- pretrig: int,
- posttrig: int,
- period_bound: float,
- timebase_bound: int,
- low_freq: int,
- high_freq: int,
- high_subtract: int,
+ self,
+ frequency: int,
+ pretrig: int,
+ posttrig: int,
+ period_bound: float,
+ timebase_bound: int,
+ low_freq: int,
+ high_freq: int,
+ high_subtract: int,
) -> Tuple[int, int]:
samples = pretrig + posttrig
period = 1 / frequency
@@ -174,7 +186,7 @@ class PicoScopeSdk(Scope): # pragma: no cover
actual_frequency = high_freq // (tb - high_subtract)
else:
tb = min(floor(log2(low_freq) - log2(frequency)), timebase_bound)
- actual_frequency = low_freq // 2 ** tb
+ actual_frequency = low_freq // 2**tb
max_samples = ctypes.c_int32()
interval_nanoseconds = ctypes.c_int32()
assert_pico_ok(
@@ -186,7 +198,7 @@ class PicoScopeSdk(Scope): # pragma: no cover
ctypes.byref(interval_nanoseconds),
0,
ctypes.byref(max_samples),
- 0
+ 0,
)
)
if max_samples.value < samples:
@@ -201,29 +213,29 @@ class PicoScopeSdk(Scope): # pragma: no cover
return actual_frequency, samples
def set_frequency(
- self, frequency: int, pretrig: int, posttrig: int
+ self, frequency: int, pretrig: int, posttrig: int
) -> Tuple[int, int]:
raise NotImplementedError
def setup_trigger(
- self,
- channel: str,
- threshold: float,
- direction: str,
- delay: int,
- timeout: int,
- enable: bool,
+ self,
+ channel: str,
+ threshold: float,
+ direction: str,
+ delay: int,
+ timeout: int,
+ enable: bool,
):
self.set_trigger(direction, enable, threshold, channel, delay, timeout)
def set_trigger(
- self,
- type: str,
- enabled: bool,
- value: float,
- channel: str,
- delay: int,
- timeout: int,
+ self,
+ type: str,
+ enabled: bool,
+ value: float,
+ channel: str,
+ delay: int,
+ timeout: int,
):
assert_pico_ok(
self._dispatch_call(
@@ -304,7 +316,7 @@ class PicoScopeSdk(Scope): # pragma: no cover
return True
def retrieve(
- self, channel: str, type: SampleType, dtype=np.float32
+ self, channel: str, type: SampleType, dtype=np.float32
) -> Optional[Trace]:
if self.samples is None:
raise ValueError
@@ -365,7 +377,6 @@ if isinstance(ps3000, CannotFindPicoSDKError):
super().__init__(variant)
raise ps3000
-
else: # pragma: no cover
@public
@@ -404,7 +415,9 @@ else: # pragma: no cover
COUPLING = {"AC": ps3000.PICO_COUPLING["AC"], "DC": ps3000.PICO_COUPLING["DC"]}
def open(self) -> None:
- assert_pico_ok(self._dispatch_call("_open_unit")) # , ctypes.byref(self.handle)
+ assert_pico_ok(
+ self._dispatch_call("_open_unit")
+ ) # , ctypes.byref(self.handle)
def stop(self):
assert_pico_ok(self._dispatch_call("_stop"))
@@ -427,10 +440,11 @@ else: # pragma: no cover
return self._variant
def set_frequency(
- self, frequency: int, pretrig: int, posttrig: int
+ self, frequency: int, pretrig: int, posttrig: int
): # TODO: fix
raise NotImplementedError
+
if isinstance(ps3000a, CannotFindPicoSDKError):
@public
@@ -441,7 +455,6 @@ if isinstance(ps3000a, CannotFindPicoSDKError):
super().__init__(variant)
raise ps3000a
-
else: # pragma: no cover
@public
@@ -455,7 +468,7 @@ else: # pragma: no cover
"B": ps3000a.PS3000A_CHANNEL["PS3000A_CHANNEL_B"],
"C": ps3000a.PS3000A_CHANNEL["PS3000A_CHANNEL_C"],
"D": ps3000a.PS3000A_CHANNEL["PS3000A_CHANNEL_D"],
- "AUX": ps3000a.PS3000A_CHANNEL["PS3000A_TRIGGER_AUX"]
+ "AUX": ps3000a.PS3000A_CHANNEL["PS3000A_TRIGGER_AUX"],
}
RANGES = {
@@ -470,31 +483,40 @@ else: # pragma: no cover
5.00: ps3000a.PS3000A_RANGE["PS3000A_5V"],
10.0: ps3000a.PS3000A_RANGE["PS3000A_10V"],
20.0: ps3000a.PS3000A_RANGE["PS3000A_20V"],
- 50.0: ps3000a.PS3000A_RANGE["PS3000A_50V"]
+ 50.0: ps3000a.PS3000A_RANGE["PS3000A_50V"],
}
MAX_ADC_VALUE = 32767
MIN_ADC_VALUE = -32767
- COUPLING = {"AC": ps3000a.PICO_COUPLING["AC"], "DC": ps3000a.PICO_COUPLING["DC"]}
+ COUPLING = {
+ "AC": ps3000a.PICO_COUPLING["AC"],
+ "DC": ps3000a.PICO_COUPLING["DC"],
+ }
def open(self) -> None:
assert_pico_ok(ps3000a.ps3000aOpenUnit(ctypes.byref(self.handle), None))
def set_channel(
- self,
- channel: str,
- enabled: bool,
- coupling: str,
- range: float,
- offset: float,
+ self,
+ channel: str,
+ enabled: bool,
+ coupling: str,
+ range: float,
+ offset: float,
):
if channel not in self.CHANNELS:
- raise ValueError(f"Channel {channel} not in available channels: {self.CHANNELS.keys()}")
+ raise ValueError(
+ f"Channel {channel} not in available channels: {self.CHANNELS.keys()}"
+ )
if coupling not in self.COUPLING:
- raise ValueError(f"Coupling {coupling} not in available couplings: {self.COUPLING.keys()}")
+ raise ValueError(
+ f"Coupling {coupling} not in available couplings: {self.COUPLING.keys()}"
+ )
if range not in self.RANGES:
- raise ValueError(f"Range {range} not in available ranges: {self.RANGES.keys()}")
+ raise ValueError(
+ f"Range {range} not in available ranges: {self.RANGES.keys()}"
+ )
assert_pico_ok(
ps3000a.ps3000aSetChannel(
self.handle,
@@ -502,7 +524,7 @@ else: # pragma: no cover
enabled,
self.COUPLING[coupling],
self.RANGES[range],
- offset
+ offset,
)
)
self.ranges[channel] = range
@@ -521,15 +543,19 @@ else: # pragma: no cover
ctypes.byref(buffer),
self.samples,
0,
- ps3000a.PS3000A_RATIO_MODE["PS3000A_RATIO_MODE_NONE"]
+ ps3000a.PS3000A_RATIO_MODE["PS3000A_RATIO_MODE_NONE"],
)
)
self.buffers[channel] = buffer
else:
assert_pico_ok(
ps3000a.ps3000aSetDataBuffer(
- self.handle, self.CHANNELS[channel], None, self.samples, 0,
- ps3000a.PS3000A_RATIO_MODE["PS3000A_RATIO_MODE_NONE"]
+ self.handle,
+ self.CHANNELS[channel],
+ None,
+ self.samples,
+ 0,
+ ps3000a.PS3000A_RATIO_MODE["PS3000A_RATIO_MODE_NONE"],
)
)
del self.buffers[channel]
@@ -539,13 +565,20 @@ else: # pragma: no cover
if variant in ("3000A", "3000B"):
# This only holds for the 2-channel versions
# 4-channel versions have the settings from branch "D".
- return self._set_freq(frequency, pretrig, posttrig, 8e-9, 2, 500_000_000, 62_500_000, 2)
+ return self._set_freq(
+ frequency, pretrig, posttrig, 8e-9, 2, 500_000_000, 62_500_000, 2
+ )
elif variant == "3000":
- return self._set_freq(frequency, pretrig, posttrig, 4e-9, 1, 500_000_000, 125_000_000, 1)
+ return self._set_freq(
+ frequency, pretrig, posttrig, 4e-9, 1, 500_000_000, 125_000_000, 1
+ )
elif variant.endswith("D"):
- return self._set_freq(frequency, pretrig, posttrig, 4e-9, 2, 1_000_000_000, 125_000_000, 2)
+ return self._set_freq(
+ frequency, pretrig, posttrig, 4e-9, 2, 1_000_000_000, 125_000_000, 2
+ )
# TODO: Needs more per-device settings to be generic.
+
if isinstance(ps4000, CannotFindPicoSDKError):
@public
@@ -556,7 +589,6 @@ if isinstance(ps4000, CannotFindPicoSDKError):
super().__init__(variant)
raise ps4000
-
else: # pragma: no cover
@public
@@ -570,7 +602,7 @@ else: # pragma: no cover
"B": ps4000.PS4000_CHANNEL["PS4000_CHANNEL_B"],
"C": ps4000.PS4000_CHANNEL["PS4000_CHANNEL_C"],
"D": ps4000.PS4000_CHANNEL["PS4000_CHANNEL_D"],
- "AUX": ps4000.PS4000_CHANNEL["PS4000_TRIGGER_AUX"]
+ "AUX": ps4000.PS4000_CHANNEL["PS4000_TRIGGER_AUX"],
}
RANGES = {
@@ -611,6 +643,7 @@ else: # pragma: no cover
else:
raise ValueError(f"Unknown variant: {variant}")
+
if isinstance(ps5000, CannotFindPicoSDKError):
@public
@@ -621,7 +654,6 @@ if isinstance(ps5000, CannotFindPicoSDKError):
super().__init__(variant)
raise ps5000
-
else: # pragma: no cover
@public
@@ -635,7 +667,7 @@ else: # pragma: no cover
"B": ps5000.PS5000_CHANNEL["PS5000_CHANNEL_B"],
"C": ps5000.PS5000_CHANNEL["PS5000_CHANNEL_C"],
"D": ps5000.PS5000_CHANNEL["PS5000_CHANNEL_D"],
- "AUX": ps5000.PS5000_CHANNEL["PS5000_TRIGGER_AUX"]
+ "AUX": ps5000.PS5000_CHANNEL["PS5000_TRIGGER_AUX"],
}
RANGES = {
@@ -663,6 +695,7 @@ else: # pragma: no cover
frequency, pretrig, posttrig, 4e-9, 2, 1_000_000_000, 125_000_000, 2
)
+
if isinstance(ps6000, CannotFindPicoSDKError):
@public
@@ -673,7 +706,6 @@ if isinstance(ps6000, CannotFindPicoSDKError):
super().__init__(variant)
raise ps6000
-
else: # pragma: no cover
@public
@@ -718,19 +750,25 @@ else: # pragma: no cover
assert_pico_ok(ps6000.ps6000OpenUnit(ctypes.byref(self.handle), None))
def set_channel(
- self,
- channel: str,
- enabled: bool,
- coupling: str,
- range: float,
- offset: float,
+ self,
+ channel: str,
+ enabled: bool,
+ coupling: str,
+ range: float,
+ offset: float,
):
if channel not in self.CHANNELS:
- raise ValueError(f"Channel {channel} not in available channels: {self.CHANNELS.keys()}")
+ raise ValueError(
+ f"Channel {channel} not in available channels: {self.CHANNELS.keys()}"
+ )
if coupling not in self.COUPLING:
- raise ValueError(f"Coupling {coupling} not in available couplings: {self.COUPLING.keys()}")
+ raise ValueError(
+ f"Coupling {coupling} not in available couplings: {self.COUPLING.keys()}"
+ )
if range not in self.RANGES:
- raise ValueError(f"Range {range} not in available ranges: {self.RANGES.keys()}")
+ raise ValueError(
+ f"Range {range} not in available ranges: {self.RANGES.keys()}"
+ )
assert_pico_ok(
ps6000.ps6000SetChannel(
self.handle,
diff --git a/pyecsca/sca/stacked_traces/combine.py b/pyecsca/sca/stacked_traces/combine.py
index 3659613..33bb1a6 100644
--- a/pyecsca/sca/stacked_traces/combine.py
+++ b/pyecsca/sca/stacked_traces/combine.py
@@ -163,9 +163,11 @@ class GPUTraceManager(BaseTraceManager): # pragma: no cover
self._chunk_size = chunk_size
else:
self._chunk_size = self.chunk_size_from_ratio(
- chunk_memory_ratio
- if chunk_memory_ratio is not None
- else CHUNK_MEMORY_RATIO,
+ (
+ chunk_memory_ratio
+ if chunk_memory_ratio is not None
+ else CHUNK_MEMORY_RATIO
+ ),
item_size=self._traces.samples.itemsize,
chunk_item_count=self._traces.samples.shape[0],
)
@@ -247,7 +249,10 @@ class GPUTraceManager(BaseTraceManager): # pragma: no cover
return self._traces.samples.shape
def _gpu_combine1D(
- self, func: CUDADispatcher, inputs: Optional[List[InputType]] = None, output_count: int = 1
+ self,
+ func: CUDADispatcher,
+ inputs: Optional[List[InputType]] = None,
+ output_count: int = 1,
) -> Union[CombinedTrace, List[CombinedTrace]]:
inputs = [] if inputs is None else inputs
results = self._combine_func(func, inputs, output_count)
@@ -431,7 +436,9 @@ def _gpu_average( # pragma: no cover
@cuda.jit(cache=True)
-def gpu_average(samples: npt.NDArray[np.number], result: npt.NDArray[np.number]): # pragma: no cover
+def gpu_average(
+ samples: npt.NDArray[np.number], result: npt.NDArray[np.number]
+): # pragma: no cover
"""
Sample average of stacked traces, sample-wise.
@@ -484,7 +491,9 @@ def _gpu_variance( # pragma: no cover
@cuda.jit(cache=True)
-def gpu_std_dev(samples: npt.NDArray[np.number], result: npt.NDArray[np.number]): # pragma: no cover
+def gpu_std_dev(
+ samples: npt.NDArray[np.number], result: npt.NDArray[np.number]
+): # pragma: no cover
"""
Sample standard deviation of stacked traces, sample-wise.
@@ -502,7 +511,9 @@ def gpu_std_dev(samples: npt.NDArray[np.number], result: npt.NDArray[np.number])
@cuda.jit(cache=True)
-def gpu_variance(samples: npt.NDArray[np.number], result: npt.NDArray[np.number]): # pragma: no cover
+def gpu_variance(
+ samples: npt.NDArray[np.number], result: npt.NDArray[np.number]
+): # pragma: no cover
"""
Sample variance of stacked traces, sample-wise.
@@ -540,7 +551,9 @@ def gpu_avg_var( # pragma: no cover
@cuda.jit(cache=True)
-def gpu_add(samples: npt.NDArray[np.number], result: npt.NDArray[np.number]): # pragma: no cover
+def gpu_add(
+ samples: npt.NDArray[np.number], result: npt.NDArray[np.number]
+): # pragma: no cover
"""
Add samples of stacked traces, sample-wise.
diff --git a/pyecsca/sca/stacked_traces/stacked_traces.py b/pyecsca/sca/stacked_traces/stacked_traces.py
index 09169bd..476375e 100644
--- a/pyecsca/sca/stacked_traces/stacked_traces.py
+++ b/pyecsca/sca/stacked_traces/stacked_traces.py
@@ -16,16 +16,17 @@ class StackedTraces:
# TODO: Split metadata into common and per-trace
def __init__(
- self, samples: np.ndarray,
- meta: Mapping[str, Any] | None = None) -> None:
+ self, samples: np.ndarray, meta: Mapping[str, Any] | None = None
+ ) -> None:
if meta is None:
meta = {}
self.meta = meta
self.samples = samples
@classmethod
- def fromarray(cls, traces: Sequence[np.ndarray],
- meta: Mapping[str, Any] | None = None) -> 'StackedTraces':
+ def fromarray(
+ cls, traces: Sequence[np.ndarray], meta: Mapping[str, Any] | None = None
+ ) -> "StackedTraces":
if meta is None:
meta = {}
ts = list(traces)
@@ -36,7 +37,7 @@ class StackedTraces:
return cls(stacked, meta)
@classmethod
- def fromtraceset(cls, traceset: TraceSet) -> 'StackedTraces':
+ def fromtraceset(cls, traceset: TraceSet) -> "StackedTraces":
traces = [t.samples for t in traceset]
return cls.fromarray(traces)
diff --git a/pyecsca/sca/target/ISO7816.py b/pyecsca/sca/target/ISO7816.py
index 0af78db..950aa05 100644
--- a/pyecsca/sca/target/ISO7816.py
+++ b/pyecsca/sca/target/ISO7816.py
@@ -1,4 +1,5 @@
"""Provides classes for working with ISO7816-4 APDUs and an abstract base class for an ISO7816-4 based target."""
+
from abc import abstractmethod, ABC
from dataclasses import dataclass
from enum import IntEnum
@@ -12,12 +13,14 @@ from pyecsca.sca.target.base import Target
@public
class CardConnectionException(Exception):
"""Card could not be connected."""
+
pass
@public
class CardProtocol(IntEnum):
"""Card protocol to use/negotiate."""
+
T0 = 0
T1 = 1
@@ -59,35 +62,35 @@ class CommandAPDU: # pragma: no cover
if len(self.data) <= 255:
# Case 3s
return (
- bytes([self.cls, self.ins, self.p1, self.p2, len(self.data)])
- + self.data
+ bytes([self.cls, self.ins, self.p1, self.p2, len(self.data)])
+ + self.data
)
else:
# Case 3e
return (
- bytes([self.cls, self.ins, self.p1, self.p2, 0])
- + len(self.data).to_bytes(2, "big")
- + self.data
+ bytes([self.cls, self.ins, self.p1, self.p2, 0])
+ + len(self.data).to_bytes(2, "big")
+ + self.data
)
else:
if len(self.data) <= 255 and self.ne <= 256:
# Case 4s
return (
- bytes([self.cls, self.ins, self.p1, self.p2, len(self.data)])
- + self.data
- + bytes([self.ne if self.ne != 256 else 0])
+ bytes([self.cls, self.ins, self.p1, self.p2, len(self.data)])
+ + self.data
+ + bytes([self.ne if self.ne != 256 else 0])
)
else:
# Case 4e
return (
- bytes([self.cls, self.ins, self.p1, self.p2, 0])
- + len(self.data).to_bytes(2, "big")
- + self.data
- + (
- self.ne.to_bytes(2, "big")
- if self.ne != 65536
- else bytes([0, 0])
- )
+ bytes([self.cls, self.ins, self.p1, self.p2, 0])
+ + len(self.data).to_bytes(2, "big")
+ + self.data
+ + (
+ self.ne.to_bytes(2, "big")
+ if self.ne != 65536
+ else bytes([0, 0])
+ )
)
diff --git a/pyecsca/sca/target/PCSC.py b/pyecsca/sca/target/PCSC.py
index cd74149..53b04fa 100644
--- a/pyecsca/sca/target/PCSC.py
+++ b/pyecsca/sca/target/PCSC.py
@@ -1,4 +1,5 @@
"""Provides a smartcard target communicating via PC/SC (Personal Computer/Smart Card)."""
+
from typing import Union, Optional
from public import public
@@ -7,8 +8,14 @@ from smartcard.System import readers
from smartcard.pcsc.PCSCCardConnection import PCSCCardConnection
from smartcard.pcsc.PCSCReader import PCSCReader
-from pyecsca.sca.target.ISO7816 import ISO7816Target, CommandAPDU, ResponseAPDU, ISO7816, CardProtocol, \
- CardConnectionException
+from pyecsca.sca.target.ISO7816 import (
+ ISO7816Target,
+ CommandAPDU,
+ ResponseAPDU,
+ ISO7816,
+ CardProtocol,
+ CardConnectionException,
+)
@public
diff --git a/pyecsca/sca/target/base.py b/pyecsca/sca/target/base.py
index 53106d5..7cb1a75 100644
--- a/pyecsca/sca/target/base.py
+++ b/pyecsca/sca/target/base.py
@@ -1,4 +1,5 @@
"""Provides an abstract base class for targets."""
+
from abc import ABC, abstractmethod
from public import public
diff --git a/pyecsca/sca/target/binary.py b/pyecsca/sca/target/binary.py
index 0dd22d5..dcfe704 100644
--- a/pyecsca/sca/target/binary.py
+++ b/pyecsca/sca/target/binary.py
@@ -1,4 +1,5 @@
"""Provides a binary target class which represents a target that is a runnable binary on the host."""
+
import subprocess
from subprocess import Popen
from typing import Optional, Union, List
diff --git a/pyecsca/sca/target/chipwhisperer.py b/pyecsca/sca/target/chipwhisperer.py
index 28a2cb8..30b4a86 100644
--- a/pyecsca/sca/target/chipwhisperer.py
+++ b/pyecsca/sca/target/chipwhisperer.py
@@ -5,6 +5,7 @@ ChipWhisperer is a side-channel analysis tool and framework. A ChipWhisperer tar
that uses the ChipWhisperer's SimpleSerial communication protocol and is communicated with
using ChipWhisperer-Lite or Pro.
"""
+
from time import sleep
import chipwhisperer as cw
@@ -20,9 +21,7 @@ from pyecsca.sca.target.simpleserial import SimpleSerialTarget
class ChipWhispererTarget(Flashable, SimpleSerialTarget): # pragma: no cover
"""ChipWhisperer-based target, using the SimpleSerial-ish protocol and communicating using ChipWhisperer-Lite/Pro."""
- def __init__(
- self, target: SimpleSerial, scope: ScopeTypes, programmer, **kwargs
- ):
+ def __init__(self, target: SimpleSerial, scope: ScopeTypes, programmer, **kwargs):
super().__init__()
self.target = target
self.scope = scope
diff --git a/pyecsca/sca/target/ectester.py b/pyecsca/sca/target/ectester.py
index ec00502..5ab5d7e 100644
--- a/pyecsca/sca/target/ectester.py
+++ b/pyecsca/sca/target/ectester.py
@@ -1,4 +1,5 @@
"""Provides an `ECTester <https://github.com/crocs-muni/ECTester/>`_ target class."""
+
from abc import ABC
from binascii import hexlify
from enum import IntEnum, IntFlag
diff --git a/pyecsca/sca/target/flash.py b/pyecsca/sca/target/flash.py
index 95c078d..8ab1883 100644
--- a/pyecsca/sca/target/flash.py
+++ b/pyecsca/sca/target/flash.py
@@ -1,4 +1,5 @@
"""Provides a mix-in class of a flashable target (e.g. one where the code gets flashed to it before running)."""
+
from public import public
from abc import ABC, abstractmethod
diff --git a/pyecsca/sca/target/leakage.py b/pyecsca/sca/target/leakage.py
index 6487c56..a44f48f 100644
--- a/pyecsca/sca/target/leakage.py
+++ b/pyecsca/sca/target/leakage.py
@@ -121,9 +121,7 @@ class LeakageTarget(Target):
if self.privkey is None:
raise ValueError("Missing privkey")
with local(DefaultContext()) as ctx:
- ecdh = ECDH(
- self.mult, self.params, other_pubkey, self.privkey, hash_algo
- )
+ ecdh = ECDH(self.mult, self.params, other_pubkey, self.privkey, hash_algo)
shared_secret = ecdh.perform()
return shared_secret, self.get_trace(ctx)
diff --git a/pyecsca/sca/target/leia.py b/pyecsca/sca/target/leia.py
index 59336b6..5bd19af 100644
--- a/pyecsca/sca/target/leia.py
+++ b/pyecsca/sca/target/leia.py
@@ -1,10 +1,17 @@
"""Provides a smartcard target communicating via the LEIA board in solo mode."""
+
from typing import Optional
from smartleia import LEIA, create_APDU_from_bytes, T
-from pyecsca.sca.target.ISO7816 import ISO7816Target, CommandAPDU, ResponseAPDU, ISO7816, CardProtocol, \
- CardConnectionException
+from pyecsca.sca.target.ISO7816 import (
+ ISO7816Target,
+ CommandAPDU,
+ ResponseAPDU,
+ ISO7816,
+ CardProtocol,
+ CardConnectionException,
+)
class LEIATarget(ISO7816Target): # pragma: no cover
diff --git a/pyecsca/sca/target/serial.py b/pyecsca/sca/target/serial.py
index 62dea45..a9dbdac 100644
--- a/pyecsca/sca/target/serial.py
+++ b/pyecsca/sca/target/serial.py
@@ -1,4 +1,5 @@
"""Provides an abstract serial target, that communicates by writing and reading a stream of bytes."""
+
from abc import abstractmethod
from public import public
diff --git a/pyecsca/sca/target/simpleserial.py b/pyecsca/sca/target/simpleserial.py
index f13a0a6..d28f697 100644
--- a/pyecsca/sca/target/simpleserial.py
+++ b/pyecsca/sca/target/simpleserial.py
@@ -1,4 +1,5 @@
"""Provides an abstract target class communicating using the `ChipWhisperer's <https://github.com/newaetech/chipwhisperer/>`_ SimpleSerial protocol."""
+
from abc import ABC
from time import time_ns, sleep
from typing import Mapping, Union
diff --git a/pyecsca/sca/trace/align.py b/pyecsca/sca/trace/align.py
index e1d3669..71c84cb 100644
--- a/pyecsca/sca/trace/align.py
+++ b/pyecsca/sca/trace/align.py
@@ -1,4 +1,5 @@
"""Provides functions for aligning traces in a trace set to a reference trace within it."""
+
import numpy as np
from copy import deepcopy
from fastdtw import fastdtw, dtw
diff --git a/pyecsca/sca/trace/combine.py b/pyecsca/sca/trace/combine.py
index 9997a83..7d751e2 100644
--- a/pyecsca/sca/trace/combine.py
+++ b/pyecsca/sca/trace/combine.py
@@ -1,4 +1,5 @@
"""Provides functions for combining traces sample-wise."""
+
from typing import Callable, Tuple
import numpy as np
diff --git a/pyecsca/sca/trace/edit.py b/pyecsca/sca/trace/edit.py
index 7d50188..7c8db61 100644
--- a/pyecsca/sca/trace/edit.py
+++ b/pyecsca/sca/trace/edit.py
@@ -1,4 +1,5 @@
"""Provides functions for editing traces as if they were tapes you can trim, reverse, etc."""
+
import numpy as np
from public import public
from typing import Union, Tuple, Any, Optional
diff --git a/pyecsca/sca/trace/filter.py b/pyecsca/sca/trace/filter.py
index 17361b9..8bfe01e 100644
--- a/pyecsca/sca/trace/filter.py
+++ b/pyecsca/sca/trace/filter.py
@@ -1,4 +1,5 @@
"""Provides functions for filtering traces using digital (low/high/band)-pass and bandstop filters."""
+
from public import public
from scipy.signal import butter, lfilter
from typing import Union, Tuple
diff --git a/pyecsca/sca/trace/match.py b/pyecsca/sca/trace/match.py
index 8a1b9bb..55a93c1 100644
--- a/pyecsca/sca/trace/match.py
+++ b/pyecsca/sca/trace/match.py
@@ -1,4 +1,5 @@
"""Provides functions for matching a pattern within a trace to it."""
+
import numpy as np
from scipy.signal import find_peaks
from public import public
diff --git a/pyecsca/sca/trace/plot.py b/pyecsca/sca/trace/plot.py
index c12840b..49b6165 100644
--- a/pyecsca/sca/trace/plot.py
+++ b/pyecsca/sca/trace/plot.py
@@ -1,4 +1,5 @@
"""Provides functions for plotting traces."""
+
from functools import reduce
import holoviews as hv
diff --git a/pyecsca/sca/trace/process.py b/pyecsca/sca/trace/process.py
index 1851e10..5540e7a 100644
--- a/pyecsca/sca/trace/process.py
+++ b/pyecsca/sca/trace/process.py
@@ -1,4 +1,5 @@
"""Provides functions for sample-wise processing of single traces."""
+
from typing import Any
import numpy as np
@@ -56,7 +57,10 @@ def rolling_mean(trace: Trace, window: int) -> Trace:
:param window:
:return:
"""
- return trace.with_samples(convolve(trace.samples, np.ones(window, dtype=trace.samples.dtype), "valid") / window)
+ return trace.with_samples(
+ convolve(trace.samples, np.ones(window, dtype=trace.samples.dtype), "valid")
+ / window
+ )
@public
@@ -130,4 +134,4 @@ def transform(trace: Trace, min_value: Any = 0, max_value: Any = 1) -> Trace:
t_max = np.max(trace.samples)
t_range = t_max - t_min
d = max_value - min_value
- return trace.with_samples(((trace.samples - t_min) * (d/t_range)) + min_value)
+ return trace.with_samples(((trace.samples - t_min) * (d / t_range)) + min_value)
diff --git a/pyecsca/sca/trace/sampling.py b/pyecsca/sca/trace/sampling.py
index 2c39e4d..701d22a 100644
--- a/pyecsca/sca/trace/sampling.py
+++ b/pyecsca/sca/trace/sampling.py
@@ -1,4 +1,5 @@
"""Provides downsampling functions for traces."""
+
from typing import cast
import numpy as np
diff --git a/pyecsca/sca/trace/test.py b/pyecsca/sca/trace/test.py
index c7bbd95..8970e5b 100644
--- a/pyecsca/sca/trace/test.py
+++ b/pyecsca/sca/trace/test.py
@@ -1,4 +1,5 @@
"""Provides statistical tests usable on groups of traces sample-wise (Welch's and Student's t-test, ...)."""
+
from typing import Sequence, Tuple
import numpy as np
@@ -58,7 +59,7 @@ def welch_ttest(
result = [CombinedTrace(tval)]
if dof or p_value:
top = (varn_0 + varn_1) ** 2
- bot = (varn_0 ** 2 / (n0 - 1)) + (varn_1 ** 2 / (n1 - 1))
+ bot = (varn_0**2 / (n0 - 1)) + (varn_1**2 / (n1 - 1))
df = top / bot
del top
del bot
@@ -88,9 +89,7 @@ def student_ttest(
@public
-def ks_test(
- first_set: Sequence[Trace], second_set: Sequence[Trace]
-) -> CombinedTrace:
+def ks_test(first_set: Sequence[Trace], second_set: Sequence[Trace]) -> CombinedTrace:
"""
Perform the Kolmogorov-Smirnov two sample test on equality of distributions sample wise on two sets of traces :paramref:`~.ks_test.first_set` and :paramref:`~.ks_test.second_set`.
diff --git a/pyecsca/sca/trace/trace.py b/pyecsca/sca/trace/trace.py
index c824967..beb9247 100644
--- a/pyecsca/sca/trace/trace.py
+++ b/pyecsca/sca/trace/trace.py
@@ -1,4 +1,5 @@
"""Provides the Trace class."""
+
import weakref
from typing import Any, Mapping, Sequence, Optional
from copy import copy, deepcopy
@@ -108,9 +109,11 @@ class Trace:
def __deepcopy__(self, memodict):
return Trace(
- deepcopy(self.samples, memo=memodict)
- if isinstance(self.samples, np.ndarray)
- else np.array(self.samples),
+ (
+ deepcopy(self.samples, memo=memodict)
+ if isinstance(self.samples, np.ndarray)
+ else np.array(self.samples)
+ ),
deepcopy(self.meta, memo=memodict),
)
diff --git a/pyecsca/sca/trace_set/base.py b/pyecsca/sca/trace_set/base.py
index 0f605e4..83a3a1a 100644
--- a/pyecsca/sca/trace_set/base.py
+++ b/pyecsca/sca/trace_set/base.py
@@ -1,4 +1,5 @@
"""Provides a base traceset class."""
+
from pathlib import Path
from typing import List, Union, BinaryIO
@@ -45,7 +46,5 @@ class TraceSet:
raise NotImplementedError
def __repr__(self):
- args = ", ".join(
- [f"{key}={getattr(self, key)!r}" for key in self._keys]
- )
+ args = ", ".join([f"{key}={getattr(self, key)!r}" for key in self._keys])
return f"{self.__class__.__name__}({args})"
diff --git a/pyecsca/sca/trace_set/chipwhisperer.py b/pyecsca/sca/trace_set/chipwhisperer.py
index 564e1cd..1a66db8 100644
--- a/pyecsca/sca/trace_set/chipwhisperer.py
+++ b/pyecsca/sca/trace_set/chipwhisperer.py
@@ -16,7 +16,9 @@ class ChipWhispererTraceSet(TraceSet):
"""ChipWhisperer trace set (native) format."""
@classmethod
- def read(cls, input: Union[str, Path, bytes, BinaryIO], **kwargs) -> "ChipWhispererTraceSet":
+ def read(
+ cls, input: Union[str, Path, bytes, BinaryIO], **kwargs
+ ) -> "ChipWhispererTraceSet":
if isinstance(input, (str, Path)):
traces, kws = ChipWhispererTraceSet.__read(input)
return ChipWhispererTraceSet(*traces, **kws)
diff --git a/pyecsca/sca/trace_set/hdf5.py b/pyecsca/sca/trace_set/hdf5.py
index 62690ae..2c2594c 100644
--- a/pyecsca/sca/trace_set/hdf5.py
+++ b/pyecsca/sca/trace_set/hdf5.py
@@ -4,6 +4,7 @@ Provides a traceset implemented on top of the Hierarchical Data Format (HDF5).
This traceset can be loaded "inplace" which means that it is not fully loaded into memory, and only parts of traces that
are operated on are in memory. This is very useful for working with huge sets of traces that do not fit in memory.
"""
+
import pickle
import uuid
from collections.abc import MutableMapping
@@ -98,7 +99,9 @@ class HDF5TraceSet(TraceSet):
return HDF5TraceSet(*traces, **kws, _ordering=ordering)
@classmethod
- def inplace(cls, input: Union[str, Path, bytes, BinaryIO], **kwargs) -> "HDF5TraceSet":
+ def inplace(
+ cls, input: Union[str, Path, bytes, BinaryIO], **kwargs
+ ) -> "HDF5TraceSet":
if isinstance(input, (str, Path)):
hdf5 = h5py.File(str(input), mode="a")
elif isinstance(input, (RawIOBase, BufferedIOBase, BinaryIO)):
diff --git a/pyecsca/sca/trace_set/inspector.py b/pyecsca/sca/trace_set/inspector.py
index 3ed4e2b..71802d0 100644
--- a/pyecsca/sca/trace_set/inspector.py
+++ b/pyecsca/sca/trace_set/inspector.py
@@ -1,4 +1,5 @@
"""Provides a traceset implementation based on Riscure's Inspector traceset format (``.trs``)."""
+
import struct
from enum import IntEnum
from io import BytesIO, RawIOBase, BufferedIOBase, UnsupportedOperation
@@ -148,7 +149,9 @@ class InspectorTraceSet(TraceSet):
_scaled: bool = False
@classmethod
- def read(cls, input: Union[str, Path, bytes, BinaryIO], **kwargs) -> "InspectorTraceSet":
+ def read(
+ cls, input: Union[str, Path, bytes, BinaryIO], **kwargs
+ ) -> "InspectorTraceSet":
"""
Read Inspector trace set from file path, bytes or file-like object.
@@ -213,7 +216,9 @@ class InspectorTraceSet(TraceSet):
return result, tags
@classmethod
- def inplace(cls, input: Union[str, Path, bytes, BinaryIO], **kwargs) -> "InspectorTraceSet":
+ def inplace(
+ cls, input: Union[str, Path, bytes, BinaryIO], **kwargs
+ ) -> "InspectorTraceSet":
raise NotImplementedError
def write(self, output: Union[str, Path, BinaryIO]):
diff --git a/pyecsca/sca/trace_set/pickle.py b/pyecsca/sca/trace_set/pickle.py
index 0134c63..05bc5d7 100644
--- a/pyecsca/sca/trace_set/pickle.py
+++ b/pyecsca/sca/trace_set/pickle.py
@@ -3,6 +3,7 @@ Provides a traceset implementation based on Python's pickle format.
This implementation of the traceset is thus very generic.
"""
+
import pickle
from io import BufferedIOBase, RawIOBase
from pathlib import Path
@@ -18,7 +19,9 @@ class PickleTraceSet(TraceSet):
"""Pickle-based traceset format."""
@classmethod
- def read(cls, input: Union[str, Path, bytes, BinaryIO], **kwargs) -> "PickleTraceSet":
+ def read(
+ cls, input: Union[str, Path, bytes, BinaryIO], **kwargs
+ ) -> "PickleTraceSet":
if isinstance(input, bytes):
return pickle.loads(input) # pickle is OK here, skipcq: BAN-B301
elif isinstance(input, (str, Path)):
@@ -29,7 +32,9 @@ class PickleTraceSet(TraceSet):
raise TypeError
@classmethod
- def inplace(cls, input: Union[str, Path, bytes, BinaryIO], **kwargs) -> "PickleTraceSet":
+ def inplace(
+ cls, input: Union[str, Path, bytes, BinaryIO], **kwargs
+ ) -> "PickleTraceSet":
raise NotImplementedError
def write(self, output: Union[str, Path, BinaryIO]):
@@ -42,7 +47,5 @@ class PickleTraceSet(TraceSet):
raise TypeError
def __repr__(self):
- args = ", ".join(
- [f"{key}={getattr(self, key)!r}" for key in self._keys]
- )
+ args = ", ".join([f"{key}={getattr(self, key)!r}" for key in self._keys])
return f"PickleTraceSet(num_traces={len(self)}, {args})"