aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJ08nY2020-06-13 19:34:26 +0200
committerJ08nY2020-06-13 19:36:00 +0200
commit7e51c6546d369ec46a6ae8978147e79f2f0195a3 (patch)
treec34c825cbb7dfbeb167a75961e8d9c4f5ddba4d8
parentbec7fbe0996481bbebab80b18d781f408d96aae6 (diff)
downloadpyecsca-7e51c6546d369ec46a6ae8978147e79f2f0195a3.tar.gz
pyecsca-7e51c6546d369ec46a6ae8978147e79f2f0195a3.tar.zst
pyecsca-7e51c6546d369ec46a6ae8978147e79f2f0195a3.zip
Add a way for actions to have a result.
-rw-r--r--pyecsca/ec/context.py27
-rw-r--r--pyecsca/ec/formula.py11
-rw-r--r--pyecsca/ec/key_agreement.py8
-rw-r--r--pyecsca/ec/key_generation.py8
-rw-r--r--pyecsca/ec/mod.py8
-rw-r--r--pyecsca/ec/mult.py52
-rw-r--r--pyecsca/ec/op.py4
-rw-r--r--pyecsca/ec/point.py14
-rw-r--r--pyecsca/sca/target/ectester.py62
-rw-r--r--test/ec/test_context.py6
10 files changed, 115 insertions, 85 deletions
diff --git a/pyecsca/ec/context.py b/pyecsca/ec/context.py
index d01f40e..6a267e6 100644
--- a/pyecsca/ec/context.py
+++ b/pyecsca/ec/context.py
@@ -26,6 +26,33 @@ class Action(object):
@public
+class ResultAction(Action):
+ """An action that has a result."""
+ _result: Any = None
+ _has_result: bool = False
+
+ @property
+ def result(self) -> Any:
+ if not self._has_result:
+ raise AttributeError("No result set")
+ return self._result
+
+ def exit(self, result: Any):
+ if not self.inside:
+ raise RuntimeError("Result set outside of action scope")
+ if self._has_result:
+ return
+ self._has_result = True
+ self._result = result
+ return result
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ if not self._has_result and exc_type is None and exc_val is None and exc_tb is None:
+ raise RuntimeError("Result unset on action exit")
+ super().__exit__(exc_type, exc_val, exc_tb)
+
+
+@public
class Tree(OrderedDict):
def get_by_key(self, path: List) -> Any:
diff --git a/pyecsca/ec/formula.py b/pyecsca/ec/formula.py
index f380ebc..c10c79e 100644
--- a/pyecsca/ec/formula.py
+++ b/pyecsca/ec/formula.py
@@ -1,12 +1,12 @@
from abc import ABC, abstractmethod
-from ast import parse, Expression, Mult, Add, Sub, Pow, Div
+from ast import parse, Expression
from itertools import product
from typing import List, Set, Any, ClassVar, MutableMapping, Tuple, Union
from pkg_resources import resource_stream
from public import public
-from .context import Action
+from .context import ResultAction
from .mod import Mod
from .op import CodeOp, OpType
@@ -35,7 +35,7 @@ class OpResult(object):
@public
-class FormulaAction(Action):
+class FormulaAction(ResultAction):
"""An execution of a formula, on some input points and parameters, with some outputs."""
formula: "Formula"
inputs: MutableMapping[str, Mod]
@@ -124,7 +124,7 @@ class Formula(ABC):
action.add_result(point, **full_resulting)
result.append(point)
- return tuple(result)
+ return action.exit(tuple(result))
def __str__(self):
return f"{self.shortname}[{self.name}]"
@@ -189,7 +189,8 @@ class Formula(ABC):
@property
def num_addsubs(self) -> int:
"""Number of additions and subtractions."""
- return len(list(filter(lambda op: op.operator == OpType.Add or op.operator == OpType.Sub, self.code)))
+ return len(list(
+ filter(lambda op: op.operator == OpType.Add or op.operator == OpType.Sub, self.code)))
class EFDFormula(Formula):
diff --git a/pyecsca/ec/key_agreement.py b/pyecsca/ec/key_agreement.py
index 6d6728f..7d139fe 100644
--- a/pyecsca/ec/key_agreement.py
+++ b/pyecsca/ec/key_agreement.py
@@ -3,7 +3,7 @@ from typing import Optional, Any
from public import public
-from .context import Action
+from .context import ResultAction
from .mod import Mod
from .mult import ScalarMultiplier
from .params import DomainParameters
@@ -11,7 +11,7 @@ from .point import Point
@public
-class ECDHAction(Action):
+class ECDHAction(ResultAction):
"""An ECDH key exchange."""
params: DomainParameters
hash_algo: Optional[Any]
@@ -64,7 +64,7 @@ class KeyAgreement(object):
:return: The shared secret.
"""
- with ECDHAction(self.params, self.hash_algo, self.privkey, self.pubkey):
+ with ECDHAction(self.params, self.hash_algo, self.privkey, self.pubkey) as action:
affine_point = self.perform_raw()
x = int(affine_point.x)
p = self.params.curve.prime
@@ -72,7 +72,7 @@ class KeyAgreement(object):
result = x.to_bytes(n, byteorder="big")
if self.hash_algo is not None:
result = self.hash_algo(result).digest()
- return result
+ return action.exit(result)
@public
diff --git a/pyecsca/ec/key_generation.py b/pyecsca/ec/key_generation.py
index 0813dbd..6476cac 100644
--- a/pyecsca/ec/key_generation.py
+++ b/pyecsca/ec/key_generation.py
@@ -2,7 +2,7 @@ from typing import Tuple
from public import public
-from .context import Action
+from .context import ResultAction
from .mod import Mod
from .mult import ScalarMultiplier
from .params import DomainParameters
@@ -10,7 +10,7 @@ from .point import Point
@public
-class KeygenAction(Action):
+class KeygenAction(ResultAction):
"""A key generation."""
params: DomainParameters
@@ -36,9 +36,9 @@ class KeyGeneration(object):
self.affine = affine
def generate(self) -> Tuple[Mod, Point]:
- with KeygenAction(self.params):
+ with KeygenAction(self.params) as action:
privkey = Mod.random(self.params.order)
pubkey = self.mult.multiply(privkey.x)
if self.affine:
pubkey = pubkey.to_affine()
- return privkey, pubkey
+ return action.exit((privkey, pubkey))
diff --git a/pyecsca/ec/mod.py b/pyecsca/ec/mod.py
index 421f521..f59fcf4 100644
--- a/pyecsca/ec/mod.py
+++ b/pyecsca/ec/mod.py
@@ -4,7 +4,7 @@ from functools import wraps, lru_cache
from public import public
-from .context import Action
+from .context import ResultAction
@public
@@ -82,7 +82,7 @@ def check(func):
@public
-class RandomModAction(Action):
+class RandomModAction(ResultAction):
"""A random sampling from Z_n."""
order: int
@@ -217,8 +217,8 @@ class Mod(object):
@staticmethod
def random(n: int):
- with RandomModAction(n):
- return Mod(secrets.randbelow(n), n)
+ with RandomModAction(n) as action:
+ return action.exit(Mod(secrets.randbelow(n), n))
def __int__(self):
return self.x
diff --git a/pyecsca/ec/mult.py b/pyecsca/ec/mult.py
index 57c034a..6dfd5cd 100644
--- a/pyecsca/ec/mult.py
+++ b/pyecsca/ec/mult.py
@@ -4,7 +4,7 @@ from typing import Mapping, Tuple, Optional, MutableMapping, ClassVar, Set, Type
from public import public
-from .context import Action
+from .context import ResultAction
from .formula import (Formula, AdditionFormula, DoublingFormula, DifferentialAdditionFormula,
ScalingFormula, LadderFormula, NegationFormula)
from .naf import naf, wnaf
@@ -13,7 +13,7 @@ from .point import Point
@public
-class ScalarMultiplicationAction(Action):
+class ScalarMultiplicationAction(ResultAction):
"""A scalar multiplication of a point on a curve by a scalar."""
point: Point
scalar: int
@@ -135,9 +135,9 @@ class LTRMultiplier(ScalarMultiplier):
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalaMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar):
+ with ScalarMultiplicationAction(self._point, scalar) as action:
if scalar == 0:
- return copy(self._params.curve.neutral)
+ return action.exit(copy(self._params.curve.neutral))
if self.complete:
q = self._point
r = copy(self._params.curve.neutral)
@@ -155,7 +155,7 @@ class LTRMultiplier(ScalarMultiplier):
self._add(r, q)
if "scl" in self.formulas:
r = self._scl(r)
- return r
+ return action.exit(r)
@public
@@ -177,9 +177,9 @@ class RTLMultiplier(ScalarMultiplier):
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalaMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar):
+ with ScalarMultiplicationAction(self._point, scalar) as action:
if scalar == 0:
- return copy(self._params.curve.neutral)
+ return action.exit(copy(self._params.curve.neutral))
q = self._point
r = copy(self._params.curve.neutral)
while scalar > 0:
@@ -192,7 +192,7 @@ class RTLMultiplier(ScalarMultiplier):
scalar >>= 1
if "scl" in self.formulas:
r = self._scl(r)
- return r
+ return action.exit(r)
class CoronMultiplier(ScalarMultiplier):
@@ -213,9 +213,9 @@ class CoronMultiplier(ScalarMultiplier):
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalaMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar):
+ with ScalarMultiplicationAction(self._point, scalar) as action:
if scalar == 0:
- return copy(self._params.curve.neutral)
+ return action.exit(copy(self._params.curve.neutral))
q = self._point
p0 = copy(q)
for i in range(scalar.bit_length() - 2, -1, -1):
@@ -225,7 +225,7 @@ class CoronMultiplier(ScalarMultiplier):
p0 = p1
if "scl" in self.formulas:
p0 = self._scl(p0)
- return p0
+ return action.exit(p0)
@public
@@ -247,9 +247,9 @@ class LadderMultiplier(ScalarMultiplier):
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalaMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar):
+ with ScalarMultiplicationAction(self._point, scalar) as action:
if scalar == 0:
- return copy(self._params.curve.neutral)
+ return action.exit(copy(self._params.curve.neutral))
q = self._point
if self.complete:
p0 = copy(self._params.curve.neutral)
@@ -266,7 +266,7 @@ class LadderMultiplier(ScalarMultiplier):
p1, p0 = self._ladd(q, p1, p0)
if "scl" in self.formulas:
p0 = self._scl(p0)
- return p0
+ return action.exit(p0)
@public
@@ -286,9 +286,9 @@ class SimpleLadderMultiplier(ScalarMultiplier):
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalaMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar):
+ with ScalarMultiplicationAction(self._point, scalar) as action:
if scalar == 0:
- return copy(self._params.curve.neutral)
+ return action.exit(copy(self._params.curve.neutral))
if self.complete:
top = self._params.order.bit_length() - 1
else:
@@ -304,7 +304,7 @@ class SimpleLadderMultiplier(ScalarMultiplier):
p1 = self._dbl(p1)
if "scl" in self.formulas:
p0 = self._scl(p0)
- return p0
+ return action.exit(p0)
@public
@@ -324,9 +324,9 @@ class DifferentialLadderMultiplier(ScalarMultiplier):
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalaMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar):
+ with ScalarMultiplicationAction(self._point, scalar) as action:
if scalar == 0:
- return copy(self._params.curve.neutral)
+ return action.exit(copy(self._params.curve.neutral))
if self.complete:
top = self._params.order.bit_length() - 1
else:
@@ -343,7 +343,7 @@ class DifferentialLadderMultiplier(ScalarMultiplier):
p1 = self._dbl(p1)
if "scl" in self.formulas:
p0 = self._scl(p0)
- return p0
+ return action.exit(p0)
@public
@@ -366,9 +366,9 @@ class BinaryNAFMultiplier(ScalarMultiplier):
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalaMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar):
+ with ScalarMultiplicationAction(self._point, scalar) as action:
if scalar == 0:
- return copy(self._params.curve.neutral)
+ return action.exit(copy(self._params.curve.neutral))
bnaf = naf(scalar)
q = copy(self._params.curve.neutral)
for val in bnaf:
@@ -379,7 +379,7 @@ class BinaryNAFMultiplier(ScalarMultiplier):
q = self._add(q, self._point_neg)
if "scl" in self.formulas:
q = self._scl(q)
- return q
+ return action.exit(q)
@public
@@ -416,9 +416,9 @@ class WindowNAFMultiplier(ScalarMultiplier):
def multiply(self, scalar: int) -> Point:
if not self._initialized:
raise ValueError("ScalaMultiplier not initialized.")
- with ScalarMultiplicationAction(self._point, scalar):
+ with ScalarMultiplicationAction(self._point, scalar) as action:
if scalar == 0:
- return copy(self._params.curve.neutral)
+ return action.exit(copy(self._params.curve.neutral))
naf = wnaf(scalar, self.width)
q = copy(self._params.curve.neutral)
for val in naf:
@@ -433,4 +433,4 @@ class WindowNAFMultiplier(ScalarMultiplier):
q = self._add(q, neg)
if "scl" in self.formulas:
q = self._scl(q)
- return q
+ return action.exit(q)
diff --git a/pyecsca/ec/op.py b/pyecsca/ec/op.py
index 637b627..ea0c1ad 100644
--- a/pyecsca/ec/op.py
+++ b/pyecsca/ec/op.py
@@ -6,7 +6,7 @@ from typing import FrozenSet, cast, Any, Optional
from public import public
-from .context import Action
+from .context import ResultAction
from .mod import Mod
@@ -113,7 +113,7 @@ class CodeOp(object):
@public
-class OperationAction(Action):
+class OperationAction(ResultAction):
"""An operation."""
operation: CodeOp
diff --git a/pyecsca/ec/point.py b/pyecsca/ec/point.py
index fe515ae..268f6f4 100644
--- a/pyecsca/ec/point.py
+++ b/pyecsca/ec/point.py
@@ -3,14 +3,14 @@ from typing import Mapping, Any
from public import public
-from .context import Action
+from .context import ResultAction
from .coordinates import AffineCoordinateModel, CoordinateModel
from .mod import Mod, Undefined
from .op import CodeOp
@public
-class CoordinateMappingAction(Action):
+class CoordinateMappingAction(ResultAction):
"""A mapping of a point from one coordinate system to another one, usually one is an affine one."""
model_from: CoordinateModel
model_to: CoordinateModel
@@ -48,9 +48,9 @@ class Point(object):
def to_affine(self) -> "Point":
"""Convert this point into the affine coordinate model, if possible."""
affine_model = AffineCoordinateModel(self.coordinate_model.curve_model)
- with CoordinateMappingAction(self.coordinate_model, affine_model, self):
+ with CoordinateMappingAction(self.coordinate_model, affine_model, self) as action:
if isinstance(self.coordinate_model, AffineCoordinateModel):
- return copy(self)
+ return action.exit(copy(self))
ops = list()
for s in self.coordinate_model.satisfying:
try:
@@ -66,12 +66,12 @@ class Point(object):
locals[op.result] = op(**locals)
if op.result in affine_model.variables:
result[op.result] = locals[op.result]
- return Point(affine_model, **result)
+ return action.exit(Point(affine_model, **result))
@staticmethod
def from_affine(coordinate_model: CoordinateModel, affine_point: "Point") -> "Point":
"""Convert an affine point into a given coordinate model, if possible."""
- with CoordinateMappingAction(affine_point.coordinate_model, coordinate_model, affine_point):
+ with CoordinateMappingAction(affine_point.coordinate_model, coordinate_model, affine_point) as action:
if not isinstance(affine_point.coordinate_model, AffineCoordinateModel):
raise ValueError
result = {}
@@ -87,7 +87,7 @@ class Point(object):
result[var] = Mod(affine_point.coords["x"] * affine_point.coords["y"], n)
else:
raise NotImplementedError
- return Point(coordinate_model, **result)
+ return action.exit(Point(coordinate_model, **result))
def equals(self, other: Any) -> bool:
"""Test whether this point is equal to `other` irrespective of the coordinate model (in the affine sense)."""
diff --git a/pyecsca/sca/target/ectester.py b/pyecsca/sca/target/ectester.py
index e69695a..05028b4 100644
--- a/pyecsca/sca/target/ectester.py
+++ b/pyecsca/sca/target/ectester.py
@@ -17,7 +17,7 @@ from ...ec.params import DomainParameters
from ...ec.point import Point
-class ShiftableFlag(IntFlag):
+class ShiftableFlag(IntFlag): # pragma: no cover
def __lshift__(self, other):
val = int(self) << other
for e in self.__class__:
@@ -44,14 +44,14 @@ class ShiftableFlag(IntFlag):
@public
-class KeypairEnum(ShiftableFlag):
+class KeypairEnum(ShiftableFlag): # pragma: no cover
KEYPAIR_LOCAL = 0x01
KEYPAIR_REMOTE = 0x02
KEYPAIR_BOTH = KEYPAIR_LOCAL | KEYPAIR_REMOTE
@public
-class InstructionEnum(IntEnum):
+class InstructionEnum(IntEnum): # pragma: no cover
INS_ALLOCATE = 0x5a
INS_CLEAR = 0x5b
INS_SET = 0x5c
@@ -73,13 +73,13 @@ class InstructionEnum(IntEnum):
@public
-class KeyBuildEnum(IntEnum):
+class KeyBuildEnum(IntEnum): # pragma: no cover
BUILD_KEYPAIR = 0x01
BUILD_KEYBUILDER = 0x02
@public
-class ExportEnum(IntEnum):
+class ExportEnum(IntEnum): # pragma: no cover
EXPORT_TRUE = 0xff
EXPORT_FALSE = 0x00
@@ -89,32 +89,32 @@ class ExportEnum(IntEnum):
@public
-class RunModeEnum(IntEnum):
+class RunModeEnum(IntEnum): # pragma: no cover
MODE_NORMAL = 0xaa
MODE_DRY_RUN = 0xbb
@public
-class KeyEnum(ShiftableFlag):
+class KeyEnum(ShiftableFlag): # pragma: no cover
PUBLIC = 0x01
PRIVATE = 0x02
BOTH = PRIVATE | PUBLIC
@public
-class AppletBaseEnum(IntEnum):
+class AppletBaseEnum(IntEnum): # pragma: no cover
BASE_221 = 0x0221
BASE_222 = 0x0222
@public
-class KeyClassEnum(IntEnum):
+class KeyClassEnum(IntEnum): # pragma: no cover
ALG_EC_F2M = 4
ALG_EC_FP = 5
@public
-class KeyAgreementEnum(IntEnum):
+class KeyAgreementEnum(IntEnum): # pragma: no cover
ALG_EC_SVDP_DH = 1
ALG_EC_SVDP_DH_KDF = 1
ALG_EC_SVDP_DHC = 2
@@ -126,7 +126,7 @@ class KeyAgreementEnum(IntEnum):
@public
-class SignatureEnum(IntEnum):
+class SignatureEnum(IntEnum): # pragma: no cover
ALG_ECDSA_SHA = 17
ALG_ECDSA_SHA_224 = 37
ALG_ECDSA_SHA_256 = 33
@@ -135,7 +135,7 @@ class SignatureEnum(IntEnum):
@public
-class TransformationEnum(ShiftableFlag):
+class TransformationEnum(ShiftableFlag): # pragma: no cover
NONE = 0x00
FIXED = 0x01
FULLRANDOM = 0x02
@@ -151,14 +151,14 @@ class TransformationEnum(ShiftableFlag):
@public
-class FormatEnum(IntEnum):
+class FormatEnum(IntEnum): # pragma: no cover
UNCOMPRESSED = 0
COMPRESSED = 1
HYBRID = 2
@public
-class CurveEnum(IntEnum):
+class CurveEnum(IntEnum): # pragma: no cover
default = 0x00
external = 0xff
secp112r1 = 0x01
@@ -177,7 +177,7 @@ class CurveEnum(IntEnum):
@public
-class ParameterEnum(ShiftableFlag):
+class ParameterEnum(ShiftableFlag): # pragma: no cover
NONE = 0x00
FP = 0x01
F2M = 0x02
@@ -195,11 +195,11 @@ class ParameterEnum(ShiftableFlag):
@public
-class ChunkingException(Exception):
+class ChunkingException(Exception): # pragma: no cover
pass
-class Response(ABC):
+class Response(ABC): # pragma: no cover
resp: ResponseAPDU
sws: List[int]
params: List[bytes]
@@ -245,7 +245,7 @@ class Response(ABC):
@public
-class AllocateKaResponse(Response):
+class AllocateKaResponse(Response): # pragma: no cover
"""A response to the KeyAgreement allocation command."""
def __init__(self, resp: ResponseAPDU):
@@ -253,7 +253,7 @@ class AllocateKaResponse(Response):
@public
-class AllocateSigResponse(Response):
+class AllocateSigResponse(Response): # pragma: no cover
"""A response to the Signature allocation command."""
def __init__(self, resp: ResponseAPDU):
@@ -261,7 +261,7 @@ class AllocateSigResponse(Response):
@public
-class AllocateResponse(Response):
+class AllocateResponse(Response): # pragma: no cover
"""A response to the KeyPair allocation command."""
def __init__(self, resp: ResponseAPDU, keypair: KeypairEnum):
@@ -269,7 +269,7 @@ class AllocateResponse(Response):
@public
-class ClearResponse(Response):
+class ClearResponse(Response): # pragma: no cover
"""A response to the Clear key command."""
def __init__(self, resp: ResponseAPDU, keypair: KeypairEnum):
@@ -277,7 +277,7 @@ class ClearResponse(Response):
@public
-class SetResponse(Response):
+class SetResponse(Response): # pragma: no cover
"""A response to the Set command."""
def __init__(self, resp: ResponseAPDU, keypair: KeypairEnum):
@@ -285,7 +285,7 @@ class SetResponse(Response):
@public
-class TransformResponse(Response):
+class TransformResponse(Response): # pragma: no cover
"""A response to the Transform command."""
def __init__(self, resp: ResponseAPDU, keypair: KeypairEnum):
@@ -293,7 +293,7 @@ class TransformResponse(Response):
@public
-class GenerateResponse(Response):
+class GenerateResponse(Response): # pragma: no cover
"""A response to the Generate command."""
def __init__(self, resp: ResponseAPDU, keypair: KeypairEnum):
@@ -301,7 +301,7 @@ class GenerateResponse(Response):
@public
-class ExportResponse(Response):
+class ExportResponse(Response): # pragma: no cover
"""A response to the Export command, contains the exported parameters/values."""
keypair: KeypairEnum
key: KeyEnum
@@ -364,7 +364,7 @@ class ExportResponse(Response):
@public
-class ECDHResponse(Response):
+class ECDHResponse(Response): # pragma: no cover
"""A response to the ECDH and ECDH_direct KeyAgreement commands."""
def __init__(self, resp: ResponseAPDU, export: bool):
@@ -381,7 +381,7 @@ class ECDHResponse(Response):
@public
-class ECDSAResponse(Response):
+class ECDSAResponse(Response): # pragma: no cover
"""A response to the ECDSA and ECDSA sign and ECDSA verify commands."""
def __init__(self, resp: ResponseAPDU, export: bool):
@@ -398,7 +398,7 @@ class ECDSAResponse(Response):
@public
-class CleanupResponse(Response):
+class CleanupResponse(Response): # pragma: no cover
"""A response to the Cleanup command."""
def __init__(self, resp: ResponseAPDU):
@@ -406,14 +406,14 @@ class CleanupResponse(Response):
@public
-class RunModeResponse(Response):
+class RunModeResponse(Response): # pragma: no cover
"""A response to the Set run mode command."""
def __init__(self, resp: ResponseAPDU):
super().__init__(resp, 1, 0)
-class InfoResponse(Response):
+class InfoResponse(Response): # pragma: no cover
"""A response to the Info command, contains all information about the applet version/environment."""
version: str
base: AppletBaseEnum
@@ -458,7 +458,7 @@ class InfoResponse(Response):
@public
-class ECTesterTarget(PCSCTarget):
+class ECTesterTarget(PCSCTarget): # pragma: no cover
"""
A smartcard target which communicates with the `ECTester <https://github.com/crocs-muni/ECTester>`_
applet on smartcards of the JavaCard platform using PCSC.
diff --git a/test/ec/test_context.py b/test/ec/test_context.py
index 20fcb7e..be84eb2 100644
--- a/test/ec/test_context.py
+++ b/test/ec/test_context.py
@@ -64,10 +64,12 @@ class ContextTests(TestCase):
self.addCleanup(resetcontext, token)
with local(DefaultContext()) as ctx:
- self.mult.multiply(59)
+ result = self.mult.multiply(59)
self.assertEqual(len(ctx.actions), 1)
- self.assertIsInstance(next(iter(ctx.actions.keys())), ScalarMultiplicationAction)
+ action = next(iter(ctx.actions.keys()))
+ self.assertIsInstance(action, ScalarMultiplicationAction)
self.assertEqual(len(getcontext().actions), 0)
+ self.assertEqual(result, action.result)
def test_default_no_enter(self):
with local(DefaultContext()) as default: