diff options
| -rw-r--r-- | pyecsca/ec/context.py | 48 | ||||
| -rw-r--r-- | pyecsca/ec/coordinates.py | 8 | ||||
| -rw-r--r-- | pyecsca/ec/curve.py | 5 | ||||
| -rw-r--r-- | pyecsca/ec/formula.py | 7 | ||||
| -rw-r--r-- | pyecsca/ec/group.py | 6 | ||||
| -rw-r--r-- | pyecsca/ec/key_agreement.py | 30 | ||||
| -rw-r--r-- | pyecsca/ec/mod.py | 6 | ||||
| -rw-r--r-- | pyecsca/ec/model.py | 2 | ||||
| -rw-r--r-- | pyecsca/ec/naf.py | 10 | ||||
| -rw-r--r-- | pyecsca/ec/op.py | 5 | ||||
| -rw-r--r-- | pyecsca/ec/point.py | 25 | ||||
| -rw-r--r-- | pyecsca/ec/signature.py | 45 | ||||
| -rw-r--r-- | test/ec/test_context.py | 8 | ||||
| -rw-r--r-- | test/ec/test_point.py | 18 | ||||
| -rw-r--r-- | test/ec/test_signature.py | 23 | ||||
| -rw-r--r-- | test/sca/test_traceset.py | 5 |
16 files changed, 206 insertions, 45 deletions
diff --git a/pyecsca/ec/context.py b/pyecsca/ec/context.py index 48dcc1d..2abc7ff 100644 --- a/pyecsca/ec/context.py +++ b/pyecsca/ec/context.py @@ -1,7 +1,7 @@ import ast from contextvars import ContextVar, Token from copy import deepcopy -from typing import List, Tuple, Optional, Union, MutableMapping, Any, Mapping +from typing import List, Tuple, Optional, Union, MutableMapping, Any, ContextManager from public import public @@ -13,6 +13,7 @@ from .point import Point @public class OpResult(object): + """A result of an operation.""" parents: Tuple op: ast.operator name: str @@ -43,6 +44,7 @@ class OpResult(object): @public class Action(object): + """An execution of a formula, on some input points and parameters, with some outputs.""" formula: Formula input_points: List[Point] inputs: MutableMapping[str, Mod] @@ -118,6 +120,14 @@ class Context(object): return tuple(result) def execute(self, formula: Formula, *points: Point, **params: Mod) -> Tuple[Point, ...]: + """ + Execute a formula. + + :param formula: Formula to execute. + :param points: Points to pass into the formula. + :param params: Parameters of the curve. + :return: The resulting point(s). + """ return self._execute(formula, *points, **params) def __str__(self): @@ -126,6 +136,7 @@ class Context(object): @public class NullContext(Context): + """A context that does not trace any operations.""" def _log_action(self, formula: Formula, *points: Point, **inputs: Mod): pass @@ -139,6 +150,7 @@ class NullContext(Context): @public class DefaultContext(Context): + """A context that traces executions of formulas.""" actions: List[Action] def __init__(self): @@ -157,31 +169,53 @@ class DefaultContext(Context): _actual_context: ContextVar[Context] = ContextVar("operational_context", default=NullContext()) -class ContextManager(object): +class _ContextManager(object): def __init__(self, new_context): self.new_context = deepcopy(new_context) def __enter__(self) -> Context: - self.saved_context = getcontext() - setcontext(self.new_context) + self.token = setcontext(self.new_context) return self.new_context def __exit__(self, t, v, tb): - setcontext(self.saved_context) + resetcontext(self.token) @public -def getcontext(): +def getcontext() -> Context: + """Get the current thread/task context.""" return _actual_context.get() @public def setcontext(ctx: Context) -> Token: + """ + Set the current thread/task context. + + :param ctx: A context to set. + :return: A token to restore previous context. + """ return _actual_context.set(ctx) @public +def resetcontext(token: Token): + """ + Reset the context to a previous value. + + :param token: A token to restore. + """ + _actual_context.reset(token) + + +@public def local(ctx: Optional[Context] = None) -> ContextManager: + """ + Use a local context. + + :param ctx: If none, current context is copied. + :return: A context manager. + """ if ctx is None: ctx = getcontext() - return ContextManager(ctx) + return _ContextManager(ctx) diff --git a/pyecsca/ec/coordinates.py b/pyecsca/ec/coordinates.py index 817bff9..585fb28 100644 --- a/pyecsca/ec/coordinates.py +++ b/pyecsca/ec/coordinates.py @@ -1,7 +1,8 @@ from ast import parse, Expression, Module -from pkg_resources import resource_listdir, resource_isdir, resource_stream from typing import List, Any, MutableMapping, Union +from pkg_resources import resource_listdir, resource_isdir, resource_stream + from .formula import (Formula, EFDFormula, AdditionEFDFormula, DoublingEFDFormula, TriplingEFDFormula, DifferentialAdditionEFDFormula, LadderEFDFormula, ScalingEFDFormula, @@ -94,3 +95,8 @@ class EFDCoordinateModel(CoordinateModel): self.assumptions.append( parse(line[7:].replace("=", "==").replace("^", "**"), mode="eval")) line = f.readline().decode("ascii") + + def __eq__(self, other): + if not isinstance(other, EFDCoordinateModel): + return False + return self.curve_model == other.curve_model and self.name == other.name diff --git a/pyecsca/ec/curve.py b/pyecsca/ec/curve.py index 3c0b200..85081ea 100644 --- a/pyecsca/ec/curve.py +++ b/pyecsca/ec/curve.py @@ -39,6 +39,11 @@ class EllipticCurve(object): loc = {**self.parameters, **point.to_affine().coords} return eval(compile(self.model.equation, "", mode="eval"), loc) + def __eq__(self, other): + 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 + def __repr__(self): params = ", ".join((f"{key}={val}" for key, val in self.parameters.items())) return f"EllipticCurve([{params}] on {self.model} using {self.coordinate_model})" diff --git a/pyecsca/ec/formula.py b/pyecsca/ec/formula.py index 441953e..f80e9fa 100644 --- a/pyecsca/ec/formula.py +++ b/pyecsca/ec/formula.py @@ -8,6 +8,7 @@ from .op import Op, CodeOp class Formula(object): + """A formula operating on points.""" name: str coordinate_model: Any meta: MutableMapping[str, Any] @@ -22,6 +23,7 @@ class Formula(object): @property def output_index(cls): + """The starting index where this formula stores its outputs.""" raise NotImplementedError @@ -61,6 +63,11 @@ class EFDFormula(Formula): def output_index(cls): return max(cls.num_inputs + 1, 3) + def __eq__(self, other): + if not isinstance(other, EFDFormula): + return False + return self.name == other.name and self.coordinate_model == other.coordinate_model + @public class AdditionFormula(Formula): diff --git a/pyecsca/ec/group.py b/pyecsca/ec/group.py index af0dae2..6d8694d 100644 --- a/pyecsca/ec/group.py +++ b/pyecsca/ec/group.py @@ -6,6 +6,7 @@ from .point import Point @public class AbelianGroup(object): + """A (sub)group of an elliptic curve.""" curve: EllipticCurve generator: Point neutral: Point @@ -22,3 +23,8 @@ class AbelianGroup(object): def is_neutral(self, point: Point) -> bool: return self.neutral == point + + def __eq__(self, other): + if not isinstance(other, AbelianGroup): + return False + return self.curve == other.curve and self.generator == other.generator and self.neutral == other.neutral and self.order == other.order and self.cofactor == other.cofactor diff --git a/pyecsca/ec/key_agreement.py b/pyecsca/ec/key_agreement.py index 5bd2edd..018b177 100644 --- a/pyecsca/ec/key_agreement.py +++ b/pyecsca/ec/key_agreement.py @@ -9,6 +9,7 @@ from .point import Point @public class KeyAgreement(object): + """An EC based key agreement primitive. (ECDH)""" mult: ScalarMultiplier pubkey: Point privkey: int @@ -21,9 +22,22 @@ class KeyAgreement(object): self.privkey = privkey self.hash_algo = hash_algo - def perform(self): + def perform_raw(self) -> Point: + """ + Perform the scalar-multiplication of the key agreement. + + :return: The shared point. + """ point = self.mult.multiply(self.privkey, self.pubkey) - affine_point = point.to_affine() # TODO: This conversion should be somehow added to the context + return point.to_affine() # TODO: This conversion should be somehow added to the context + + def perform(self) -> bytes: + """ + Perform the key agreement operation. + + :return: The shared secret. + """ + affine_point = self.perform_raw() x = int(affine_point.x) p = self.mult.group.curve.prime n = (p.bit_length() + 7) // 8 @@ -35,35 +49,47 @@ class KeyAgreement(object): @public class ECDH_NONE(KeyAgreement): + """Raw x-coordinate ECDH.""" + def __init__(self, mult: ScalarMultiplier, pubkey: Point, privkey: int): super().__init__(mult, pubkey, privkey) @public class ECDH_SHA1(KeyAgreement): + """ECDH with SHA1 of x-coordinate.""" + def __init__(self, mult: ScalarMultiplier, pubkey: Point, privkey: int): super().__init__(mult, pubkey, privkey, hashlib.sha1) @public class ECDH_SHA224(KeyAgreement): + """ECDH with SHA224 of x-coordinate.""" + def __init__(self, mult: ScalarMultiplier, pubkey: Point, privkey: int): super().__init__(mult, pubkey, privkey, hashlib.sha224) @public class ECDH_SHA256(KeyAgreement): + """ECDH with SHA256 of x-coordinate.""" + def __init__(self, mult: ScalarMultiplier, pubkey: Point, privkey: int): super().__init__(mult, pubkey, privkey, hashlib.sha256) @public class ECDH_SHA384(KeyAgreement): + """ECDH with SHA384 of x-coordinate.""" + def __init__(self, mult: ScalarMultiplier, pubkey: Point, privkey: int): super().__init__(mult, pubkey, privkey, hashlib.sha384) @public class ECDH_SHA512(KeyAgreement): + """ECDH with SHA512 of x-coordinate.""" + def __init__(self, mult: ScalarMultiplier, pubkey: Point, privkey: int): super().__init__(mult, pubkey, privkey, hashlib.sha512) diff --git a/pyecsca/ec/mod.py b/pyecsca/ec/mod.py index e9c5657..dd09847 100644 --- a/pyecsca/ec/mod.py +++ b/pyecsca/ec/mod.py @@ -1,9 +1,11 @@ from functools import wraps + from public import public @public def gcd(a, b): + """Euclid's greatest common denominator algorithm.""" if abs(a) < abs(b): return gcd(b, a) @@ -16,6 +18,7 @@ def gcd(a, b): @public def extgcd(a, b): + """Extended Euclid's greatest common denominator algorithm.""" if abs(b) > abs(a): (x, y, d) = extgcd(b, a) return y, x, d @@ -48,6 +51,7 @@ def check(func): @public class Mod(object): + """An element x of ℤₙ.""" def __init__(self, x: int, n: int): self.x: int = x % n @@ -150,7 +154,7 @@ class Mod(object): class Undefined(Mod): def __init__(self): - pass + object.__init__(self) def __add__(self, other): raise NotImplementedError diff --git a/pyecsca/ec/model.py b/pyecsca/ec/model.py index 53d530a..6e79c9b 100644 --- a/pyecsca/ec/model.py +++ b/pyecsca/ec/model.py @@ -23,6 +23,8 @@ class CurveModel(object): #TODO: move the base_formulas into methods, operatin on affine points? # Also to_weierstrass anf from_weierstrass. + # TODO: __eq__ + class EFDCurveModel(CurveModel): _efd_name: str diff --git a/pyecsca/ec/naf.py b/pyecsca/ec/naf.py index 8f07c9f..fe4f24c 100644 --- a/pyecsca/ec/naf.py +++ b/pyecsca/ec/naf.py @@ -7,9 +7,9 @@ def wnaf(k: int, w: int) -> List[int]: """ Compute width `w` NAF (Non-Adjacent Form) of the scalar `k`. - :param k: - :param w: - :return: + :param k: The scalar. + :param w: The width. + :return: The NAF. """ half_width = 2 ** (w - 1) full_width = half_width * 2 @@ -37,7 +37,7 @@ def naf(k: int) -> List[int]: """ Compute the NAF (Non-Adjacent Form) of the scalar `k`. - :param k: - :return: + :param k: The scalar. + :return: The NAF. """ return wnaf(k, 2) diff --git a/pyecsca/ec/op.py b/pyecsca/ec/op.py index 6a057fe..169f3bb 100644 --- a/pyecsca/ec/op.py +++ b/pyecsca/ec/op.py @@ -10,7 +10,8 @@ class Op(object): parameters: FrozenSet[str] variables: FrozenSet[str] - def __call__(self, *args, **kwargs) -> Mod: + def __call__(self, *args, **kwargs: Mod) -> Mod: + """Execute this operation with kwargs.""" raise NotImplementedError @@ -43,7 +44,7 @@ class CodeOp(Op): def __repr__(self): return f"CodeOp({self.result} = f(params={self.parameters}, vars={self.variables}))" - def __call__(self, *args, **kwargs) -> Mod: + def __call__(self, *args, **kwargs: Mod) -> Mod: loc = dict(kwargs) exec(self.compiled, {}, loc) return loc[self.result] diff --git a/pyecsca/ec/point.py b/pyecsca/ec/point.py index 75b4a1e..3b0b970 100644 --- a/pyecsca/ec/point.py +++ b/pyecsca/ec/point.py @@ -1,5 +1,5 @@ from copy import copy -from typing import Mapping,Any +from typing import Mapping, Any from public import public @@ -10,6 +10,7 @@ from .op import CodeOp @public class Point(object): + """A point with coordinates in a coordinate model.""" coordinate_model: CoordinateModel coords: Mapping[str, Mod] @@ -19,14 +20,15 @@ class Point(object): self.coordinate_model = model self.coords = coords - def __getattribute__(self, name: Any): + def __getattribute__(self, name): if "coords" in super().__getattribute__("__dict__"): coords = super().__getattribute__("coords") if name in coords: return coords[name] return super().__getattribute__(name) - def to_affine(self): + def to_affine(self) -> "Point": + """Convert this point into the affine coordinate model, if possible.""" if isinstance(self.coordinate_model, AffineCoordinateModel): return copy(self) ops = set() @@ -47,12 +49,13 @@ class Point(object): return Point(affine_model, **result) @staticmethod - def from_affine(coordinate_model, affine_point): + def from_affine(coordinate_model: CoordinateModel, affine_point: "Point") -> "Point": + """Convert an affine point into a given coordinate model, if possible.""" if not isinstance(affine_point.coordinate_model, AffineCoordinateModel): - return ValueError + raise ValueError result = {} n = affine_point.coords["x"].n - for var in coordinate_model.variables: + for var in coordinate_model.variables: # XXX: This just works for the stuff currently in EFD. if var == "X": result[var] = affine_point.coords["x"] elif var == "Y": @@ -65,7 +68,8 @@ class Point(object): raise NotImplementedError return Point(coordinate_model, **result) - def equals(self, other): + def equals(self, other: Any) -> bool: + """Test whether this point is equal to `other` irrespective of the coordinate model (in the affine sense).""" if not isinstance(other, Point): return False if self.coordinate_model.curve_model != other.coordinate_model.curve_model: @@ -89,19 +93,20 @@ class Point(object): @public class InfinityPoint(Point): + """A point at infinity.""" def __init__(self, model: CoordinateModel): coords = {key: Undefined() for key in model.variables} super().__init__(model, **coords) - def to_affine(self): + def to_affine(self) -> "InfinityPoint": return InfinityPoint(AffineCoordinateModel(self.coordinate_model.curve_model)) @staticmethod - def from_affine(coordinate_model, affine_point): + def from_affine(coordinate_model: CoordinateModel, affine_point: "Point") -> "InfinityPoint": raise NotImplementedError - def equals(self, other): + def equals(self, other) -> bool: return self == other def __eq__(self, other): diff --git a/pyecsca/ec/signature.py b/pyecsca/ec/signature.py index 857d5a2..4d1e43b 100644 --- a/pyecsca/ec/signature.py +++ b/pyecsca/ec/signature.py @@ -14,6 +14,7 @@ from .point import Point @public class SignatureResult(object): + """An ECDSA signature result (r, s).""" r: int s: int @@ -24,11 +25,13 @@ class SignatureResult(object): self.s = s @staticmethod - def from_DER(data: bytes): + def from_DER(data: bytes) -> "SignatureResult": + """Load an ECDSA signature from ASN.1 DER data.""" r, s = Sequence.load(data).native.values() return SignatureResult(r, s) def to_DER(self) -> bytes: + """Output this signature into ASN.1 DER.""" obj = SequenceOf(spec=Integer) obj.append(self.r) obj.append(self.s) @@ -39,9 +42,6 @@ class SignatureResult(object): return False return self.r == other.r and self.s == other.s - def __ne__(self, other): - return not self == other - def __str__(self): return f"(r={self.r}, s={self.s})" @@ -51,6 +51,7 @@ class SignatureResult(object): @public class Signature(object): + """An EC based signature primitive. (ECDSA)""" mult: ScalarMultiplier add: Optional[AdditionFormula] pubkey: Optional[Point] @@ -75,11 +76,13 @@ class Signature(object): @property def can_sign(self) -> bool: + """Whether this instance can sign (has a private key).""" return self.privkey is not None @property def can_verify(self) -> bool: - return self.pubkey is not None + """Whether this instance can verify (has a public key and add formula).""" + return self.pubkey is not None and self.add is not None def _get_nonce(self, nonce: Optional[int]) -> Mod: if nonce is None: @@ -97,10 +100,16 @@ class Signature(object): privkey=self.privkey) def sign_hash(self, digest: bytes, nonce: Optional[int] = None) -> SignatureResult: + """Sign already hashed data.""" + if not self.can_sign: + raise RuntimeError("This instance cannot sign.") k = self._get_nonce(nonce) return self._do_sign(k, digest) def sign_data(self, data: bytes, nonce: Optional[int] = None) -> SignatureResult: + """Sign data.""" + if not self.can_sign: + raise RuntimeError("This instance cannot sign.") k = self._get_nonce(nonce) if self.hash_algo is None: digest = data @@ -108,9 +117,9 @@ class Signature(object): digest = self.hash_algo(data).digest() return self._do_sign(k, digest) - def _do_verify(self, signature: SignatureResult, e: int) -> bool: + def _do_verify(self, signature: SignatureResult, digest: bytes) -> bool: c = Mod(signature.s, self.mult.group.order).inverse() - u1 = Mod(e, self.mult.group.order) * c + u1 = Mod(int.from_bytes(digest, byteorder="big"), self.mult.group.order) * c u2 = Mod(signature.r, self.mult.group.order) * c p1 = self.mult.multiply(int(u1), self.mult.group.generator) p2 = self.mult.multiply(int(u2), self.pubkey) @@ -120,18 +129,26 @@ class Signature(object): return signature.r == int(v) def verify_hash(self, signature: SignatureResult, digest: bytes) -> bool: - return self._do_verify(signature, int.from_bytes(digest, byteorder="big")) + """Verify already hashed data.""" + if not self.can_verify: + raise RuntimeError("This instance cannot verify.") + return self._do_verify(signature, digest) def verify_data(self, signature: SignatureResult, data: bytes) -> bool: + """Verify data.""" + if not self.can_verify: + raise RuntimeError("This instance cannot verify.") if self.hash_algo is None: digest = data else: digest = self.hash_algo(data).digest() - return self._do_verify(signature, int.from_bytes(digest, byteorder="big")) + return self._do_verify(signature, digest) @public class ECDSA_NONE(Signature): + """ECDSA with raw message input.""" + def __init__(self, mult: ScalarMultiplier, add: Optional[AdditionFormula] = None, pubkey: Optional[Point] = None, privkey: Optional[int] = None): super().__init__(mult, add, pubkey, privkey) @@ -139,6 +156,8 @@ class ECDSA_NONE(Signature): @public class ECDSA_SHA1(Signature): + """ECDSA with SHA1.""" + def __init__(self, mult: ScalarMultiplier, add: Optional[AdditionFormula] = None, pubkey: Optional[Point] = None, privkey: Optional[int] = None): super().__init__(mult, add, pubkey, privkey, hashlib.sha1) @@ -146,6 +165,8 @@ class ECDSA_SHA1(Signature): @public class ECDSA_SHA224(Signature): + """ECDSA with SHA224.""" + def __init__(self, mult: ScalarMultiplier, add: Optional[AdditionFormula] = None, pubkey: Optional[Point] = None, privkey: Optional[int] = None): super().__init__(mult, add, pubkey, privkey, hashlib.sha224) @@ -153,6 +174,8 @@ class ECDSA_SHA224(Signature): @public class ECDSA_SHA256(Signature): + """ECDSA with SHA256.""" + def __init__(self, mult: ScalarMultiplier, add: Optional[AdditionFormula] = None, pubkey: Optional[Point] = None, privkey: Optional[int] = None): super().__init__(mult, add, pubkey, privkey, hashlib.sha256) @@ -160,6 +183,8 @@ class ECDSA_SHA256(Signature): @public class ECDSA_SHA384(Signature): + """ECDSA with SHA384.""" + def __init__(self, mult: ScalarMultiplier, add: Optional[AdditionFormula] = None, pubkey: Optional[Point] = None, privkey: Optional[int] = None): super().__init__(mult, add, pubkey, privkey, hashlib.sha384) @@ -167,6 +192,8 @@ class ECDSA_SHA384(Signature): @public class ECDSA_SHA512(Signature): + """ECDSA with SHA512.""" + def __init__(self, mult: ScalarMultiplier, add: Optional[AdditionFormula] = None, pubkey: Optional[Point] = None, privkey: Optional[int] = None): super().__init__(mult, add, pubkey, privkey, hashlib.sha512) diff --git a/test/ec/test_context.py b/test/ec/test_context.py index 9e56afb..1073fc0 100644 --- a/test/ec/test_context.py +++ b/test/ec/test_context.py @@ -1,7 +1,9 @@ import ast from unittest import TestCase -from pyecsca.ec.context import local, DefaultContext, OpResult, NullContext, getcontext +from pyecsca.ec.context import (local, DefaultContext, OpResult, NullContext, getcontext, + setcontext, + resetcontext) from pyecsca.ec.coordinates import AffineCoordinateModel from pyecsca.ec.mod import Mod from pyecsca.ec.mult import LTRMultiplier @@ -33,9 +35,13 @@ class ContextTests(TestCase): self.assertIsInstance(ctx, NullContext) def test_default(self): + token = setcontext(DefaultContext()) + self.addCleanup(resetcontext, token) + with local(DefaultContext()) as ctx: self.mult.multiply(59, self.base) self.assertEqual(len(ctx.actions), 10) + self.assertEqual(len(getcontext().actions), 0) def test_execute(self): with self.assertRaises(ValueError): diff --git a/test/ec/test_point.py b/test/ec/test_point.py index f6f53c8..d85ed4a 100644 --- a/test/ec/test_point.py +++ b/test/ec/test_point.py @@ -2,7 +2,7 @@ from unittest import TestCase from pyecsca.ec.coordinates import AffineCoordinateModel from pyecsca.ec.mod import Mod -from pyecsca.ec.model import ShortWeierstrassModel +from pyecsca.ec.model import ShortWeierstrassModel, MontgomeryModel from pyecsca.ec.point import Point, InfinityPoint from test.ec.curves import get_secp128r1 @@ -44,6 +44,8 @@ class PointTests(TestCase): with self.assertRaises(NotImplementedError): InfinityPoint.from_affine(self.coords, affine) + with self.assertRaises(ValueError): + Point.from_affine(self.coords, self.base) def test_to_from_affine(self): pt = Point(self.coords, @@ -63,14 +65,22 @@ class PointTests(TestCase): Y=Mod(0x3, self.secp128r1.curve.prime), Z=Mod(1, self.secp128r1.curve.prime)) assert pt.equals(other) - self.assertNotEquals(pt, other) + self.assertNotEqual(pt, other) assert not pt.equals(2) - self.assertNotEquals(pt, 2) + self.assertNotEqual(pt, 2) infty_one = InfinityPoint(self.coords) infty_other = InfinityPoint(self.coords) assert infty_one.equals(infty_other) - self.assertEquals(infty_one, infty_other) + self.assertEqual(infty_one, infty_other) + + mont = MontgomeryModel() + different = Point(mont.coordinates["xz"], + X=Mod(0x64daccd2656420216545e5f65221eb, + 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa), + Z=Mod(1, 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)) + assert not pt.equals(different) + self.assertNotEqual(pt, different) def test_repr(self): self.assertEqual(str(self.base), diff --git a/test/ec/test_signature.py b/test/ec/test_signature.py index 6dc6d9f..d9b306a 100644 --- a/test/ec/test_signature.py +++ b/test/ec/test_signature.py @@ -1,8 +1,8 @@ +from hashlib import sha1 from unittest import TestCase -from hashlib import sha1 -from pyecsca.ec.signature import * from pyecsca.ec.mult import LTRMultiplier +from pyecsca.ec.signature import * from .curves import get_secp128r1 @@ -33,6 +33,25 @@ class SignatureTests(TestCase): sig = none.sign_data(digest) assert none.verify_data(sig, digest) + def test_cannot(self): + ok = ECDSA_NONE(self.mult, add=self.add, pubkey=self.pub, privkey=self.priv) + data = b"aaaa" + sig = ok.sign_data(data) + + no_priv = ECDSA_NONE(self.mult, 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, privkey=self.priv) + with self.assertRaises(RuntimeError): + no_pubadd.verify_data(sig, data) + with self.assertRaises(RuntimeError): + no_pubadd.verify_hash(sig, data) + + with self.assertRaises(ValueError): + Signature(self.mult) + def test_fixed_nonce(self): for algo in self.algos: signer = algo(self.mult, privkey=self.priv) diff --git a/test/sca/test_traceset.py b/test/sca/test_traceset.py index 90768c2..f12f205 100644 --- a/test/sca/test_traceset.py +++ b/test/sca/test_traceset.py @@ -1,6 +1,6 @@ -from unittest import TestCase import os.path import tempfile +from unittest import TestCase from pyecsca.sca import TraceSet, InspectorTraceSet, ChipWhispererTraceSet @@ -49,6 +49,9 @@ class InspectorTraceSetTests(TestCase): self.assertTrue(os.path.exists(path)) self.assertIsNotNone(InspectorTraceSet(path)) + with self.assertRaises(ValueError): + trace_set.save(None) + class ChipWhispererTraceSetTest(TestCase): |
