aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ08nY2019-04-24 19:26:11 +0200
committerJ08nY2019-04-24 19:26:11 +0200
commit2a109ad4502bc7983c9fd4fc29a62b6f028762b0 (patch)
treeab0074015d3e2008fa0071efbfb49f2c224e78c7
parentf4bcb085cfc9ddac71fe8bb82e8f6719309b2637 (diff)
downloadpyecsca-2a109ad4502bc7983c9fd4fc29a62b6f028762b0.tar.gz
pyecsca-2a109ad4502bc7983c9fd4fc29a62b6f028762b0.tar.zst
pyecsca-2a109ad4502bc7983c9fd4fc29a62b6f028762b0.zip
-rw-r--r--pyecsca/ec/context.py48
-rw-r--r--pyecsca/ec/coordinates.py8
-rw-r--r--pyecsca/ec/curve.py5
-rw-r--r--pyecsca/ec/formula.py7
-rw-r--r--pyecsca/ec/group.py6
-rw-r--r--pyecsca/ec/key_agreement.py30
-rw-r--r--pyecsca/ec/mod.py6
-rw-r--r--pyecsca/ec/model.py2
-rw-r--r--pyecsca/ec/naf.py10
-rw-r--r--pyecsca/ec/op.py5
-rw-r--r--pyecsca/ec/point.py25
-rw-r--r--pyecsca/ec/signature.py45
-rw-r--r--test/ec/test_context.py8
-rw-r--r--test/ec/test_point.py18
-rw-r--r--test/ec/test_signature.py23
-rw-r--r--test/sca/test_traceset.py5
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):