diff options
| author | J08nY | 2019-12-22 02:39:49 +0100 |
|---|---|---|
| committer | J08nY | 2019-12-22 02:39:49 +0100 |
| commit | 67fa43ddd53325a6318076356e8ab8c4d76917bc (patch) | |
| tree | fa345f71ea3b226b1dde0d9c538becf9cf9af116 | |
| parent | 77c3141139be0c3f851dff92f8da6f463e29d57c (diff) | |
| download | pyecsca-67fa43ddd53325a6318076356e8ab8c4d76917bc.tar.gz pyecsca-67fa43ddd53325a6318076356e8ab8c4d76917bc.tar.zst pyecsca-67fa43ddd53325a6318076356e8ab8c4d76917bc.zip | |
| -rw-r--r-- | docs/Makefile | 8 | ||||
| -rw-r--r-- | docs/conf.py | 9 | ||||
| -rw-r--r-- | pyecsca/ec/coordinates.py | 3 | ||||
| -rw-r--r-- | pyecsca/ec/formula.py | 6 | ||||
| -rw-r--r-- | pyecsca/ec/key_agreement.py | 34 | ||||
| -rw-r--r-- | pyecsca/ec/model.py | 3 | ||||
| -rw-r--r-- | pyecsca/ec/mult.py | 163 | ||||
| -rw-r--r-- | pyecsca/ec/op.py | 10 | ||||
| -rw-r--r-- | pyecsca/ec/point.py | 3 | ||||
| -rw-r--r-- | pyecsca/ec/signature.py | 64 | ||||
| -rw-r--r-- | test/ec/test_context.py | 11 | ||||
| -rw-r--r-- | test/ec/test_key_agreement.py | 27 | ||||
| -rw-r--r-- | test/ec/test_mult.py | 143 | ||||
| -rw-r--r-- | test/ec/test_signature.py | 74 |
14 files changed, 292 insertions, 266 deletions
diff --git a/docs/Makefile b/docs/Makefile index c12361e..689e069 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -14,11 +14,9 @@ help: apidoc: mkdir -p api/codegen/ - sphinx-apidoc ../pyecsca/ --ext-autodoc -f -e -o api/ - sed -i "s/automodule:: /automodule:: pyecsca./g" api/*.rst - sphinx-apidoc ../../pyecsca-codegen/pyecsca/ --ext-autodoc -f -e -o api/codegen/ - sed -i "s/automodule:: /automodule:: pyecsca./g" api/codegen/*.rst - echo " codegen/codegen" >> api/modules.rst + sphinx-apidoc ../pyecsca/ --implicit-namespaces --ext-autodoc -f -e -o api/ + sphinx-apidoc ../../pyecsca-codegen/pyecsca/ --implicit-namespaces --ext-autodoc --no-toc -f -e -o api/codegen/ + echo " codegen/pyecsca.codegen" >> api/modules.rst .PHONY: help apidoc Makefile diff --git a/docs/conf.py b/docs/conf.py index f219c17..2b1ee9c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -199,4 +199,11 @@ epub_exclude_files = ['search.html'] # -- Extension configuration ------------------------------------------------- -todo_include_todos = True
\ No newline at end of file +todo_include_todos = True + +autodoc_default_options = { + "members": True, + "undoc-members": True, + "inherited-members": True, + "show-inheritance": True +}
\ No newline at end of file diff --git a/pyecsca/ec/coordinates.py b/pyecsca/ec/coordinates.py index 585fb28..285e54b 100644 --- a/pyecsca/ec/coordinates.py +++ b/pyecsca/ec/coordinates.py @@ -100,3 +100,6 @@ class EFDCoordinateModel(CoordinateModel): if not isinstance(other, EFDCoordinateModel): return False return self.curve_model == other.curve_model and self.name == other.name + + def __hash__(self): + return hash(self.curve_model) + hash(self.name) diff --git a/pyecsca/ec/formula.py b/pyecsca/ec/formula.py index 5f4c7cb..6c9feba 100644 --- a/pyecsca/ec/formula.py +++ b/pyecsca/ec/formula.py @@ -5,7 +5,7 @@ from itertools import product from pkg_resources import resource_stream from public import public -from .op import Op, CodeOp +from .op import CodeOp class Formula(object): @@ -15,7 +15,7 @@ class Formula(object): meta: MutableMapping[str, Any] parameters: List[str] assumptions: List[Expression] - code: List[Op] + code: List[CodeOp] num_inputs: ClassVar[int] num_outputs: ClassVar[int] @@ -95,6 +95,8 @@ class EFDFormula(Formula): return False return self.name == other.name and self.coordinate_model == other.coordinate_model + def __hash__(self): + return hash(self.name) + hash(self.coordinate_model) @public class AdditionFormula(Formula): diff --git a/pyecsca/ec/key_agreement.py b/pyecsca/ec/key_agreement.py index 018b177..4b9a99e 100644 --- a/pyecsca/ec/key_agreement.py +++ b/pyecsca/ec/key_agreement.py @@ -3,6 +3,7 @@ from typing import Optional, Any from public import public +from .group import AbelianGroup from .mult import ScalarMultiplier from .point import Point @@ -11,16 +12,19 @@ from .point import Point class KeyAgreement(object): """An EC based key agreement primitive. (ECDH)""" mult: ScalarMultiplier + group: AbelianGroup pubkey: Point privkey: int hash_algo: Optional[Any] - def __init__(self, mult: ScalarMultiplier, pubkey: Point, privkey: int, + def __init__(self, mult: ScalarMultiplier, group: AbelianGroup, pubkey: Point, privkey: int, hash_algo: Optional[Any] = None): self.mult = mult + self.group = group self.pubkey = pubkey self.privkey = privkey self.hash_algo = hash_algo + self.mult.init(self.group, self.pubkey) def perform_raw(self) -> Point: """ @@ -28,7 +32,7 @@ class KeyAgreement(object): :return: The shared point. """ - point = self.mult.multiply(self.privkey, self.pubkey) + point = self.mult.multiply(self.privkey) return point.to_affine() # TODO: This conversion should be somehow added to the context def perform(self) -> bytes: @@ -39,7 +43,7 @@ class KeyAgreement(object): """ affine_point = self.perform_raw() x = int(affine_point.x) - p = self.mult.group.curve.prime + p = self.group.curve.prime n = (p.bit_length() + 7) // 8 result = x.to_bytes(n, byteorder="big") if self.hash_algo is not None: @@ -51,45 +55,45 @@ class KeyAgreement(object): class ECDH_NONE(KeyAgreement): """Raw x-coordinate ECDH.""" - def __init__(self, mult: ScalarMultiplier, pubkey: Point, privkey: int): - super().__init__(mult, pubkey, privkey) + def __init__(self, mult: ScalarMultiplier, group: AbelianGroup, pubkey: Point, privkey: int): + super().__init__(mult, group, 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) + def __init__(self, mult: ScalarMultiplier, group: AbelianGroup, pubkey: Point, privkey: int): + super().__init__(mult, group, 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) + def __init__(self, mult: ScalarMultiplier, group: AbelianGroup, pubkey: Point, privkey: int): + super().__init__(mult, group, 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) + def __init__(self, mult: ScalarMultiplier, group: AbelianGroup, pubkey: Point, privkey: int): + super().__init__(mult, group, 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) + def __init__(self, mult: ScalarMultiplier, group: AbelianGroup, pubkey: Point, privkey: int): + super().__init__(mult, group, 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) + def __init__(self, mult: ScalarMultiplier, group: AbelianGroup, pubkey: Point, privkey: int): + super().__init__(mult, group, pubkey, privkey, hashlib.sha512) diff --git a/pyecsca/ec/model.py b/pyecsca/ec/model.py index 6e79c9b..c8a9b46 100644 --- a/pyecsca/ec/model.py +++ b/pyecsca/ec/model.py @@ -94,6 +94,9 @@ class EFDCurveModel(CurveModel): return False return self._efd_name == other._efd_name + def __hash__(self): + return hash(self._efd_name) + 1 + def __repr__(self): return f"{self.__class__.__name__}()" diff --git a/pyecsca/ec/mult.py b/pyecsca/ec/mult.py index ab6cf7b..c766ff0 100644 --- a/pyecsca/ec/mult.py +++ b/pyecsca/ec/mult.py @@ -12,73 +12,79 @@ from .point import Point class ScalarMultiplier(object): - group: AbelianGroup + """ + A scalar multiplication algorithm. + + :param short_circuit: Whether the use of formulas will be guarded by short-circuit on inputs + of the point at infinity. + :param formulas: Formulas this instance will use. + """ + short_circuit: bool formulas: Mapping[str, Formula] + _group: AbelianGroup _point: Point = None - def __init__(self, group: AbelianGroup, **formulas: Optional[Formula]): - for formula in formulas.values(): - if formula is not None and formula.coordinate_model is not group.curve.coordinate_model: - raise ValueError - self.group = group + def __init__(self, short_circuit=True, **formulas: Optional[Formula]): + if len(set(formula.coordinate_model for formula in formulas.values() if + formula is not None)) != 1: + raise ValueError + self.short_circuit = short_circuit self.formulas = dict(filter(lambda pair: pair[1] is not None, formulas.items())) def _add(self, one: Point, other: Point) -> Point: if "add" not in self.formulas: raise NotImplementedError - if one == self.group.neutral: - return copy(other) - if other == self.group.neutral: - return copy(one) + if self.short_circuit: + if one == self._group.neutral: + return copy(other) + if other == self._group.neutral: + return copy(one) return \ - getcontext().execute(self.formulas["add"], one, other, **self.group.curve.parameters)[0] + getcontext().execute(self.formulas["add"], one, other, **self._group.curve.parameters)[0] def _dbl(self, point: Point) -> Point: if "dbl" not in self.formulas: raise NotImplementedError - if point == self.group.neutral: - return copy(point) - return getcontext().execute(self.formulas["dbl"], point, **self.group.curve.parameters)[0] + if self.short_circuit: + if point == self._group.neutral: + return copy(point) + return getcontext().execute(self.formulas["dbl"], point, **self._group.curve.parameters)[0] def _scl(self, point: Point) -> Point: if "scl" not in self.formulas: raise NotImplementedError - return getcontext().execute(self.formulas["scl"], point, **self.group.curve.parameters)[0] + return getcontext().execute(self.formulas["scl"], point, **self._group.curve.parameters)[0] def _ladd(self, start: Point, to_dbl: Point, to_add: Point) -> Tuple[Point, ...]: if "ladd" not in self.formulas: raise NotImplementedError return getcontext().execute(self.formulas["ladd"], start, to_dbl, to_add, - **self.group.curve.parameters) + **self._group.curve.parameters) def _dadd(self, start: Point, one: Point, other: Point) -> Point: if "dadd" not in self.formulas: raise NotImplementedError - if one == self.group.neutral: - return copy(other) - if other == self.group.neutral: - return copy(one) + if self.short_circuit: + if one == self._group.neutral: + return copy(other) + if other == self._group.neutral: + return copy(one) return getcontext().execute(self.formulas["dadd"], start, one, other, - **self.group.curve.parameters)[0] + **self._group.curve.parameters)[0] def _neg(self, point: Point) -> Point: if "neg" not in self.formulas: raise NotImplementedError - return getcontext().execute(self.formulas["neg"], point, **self.group.curve.parameters)[0] + return getcontext().execute(self.formulas["neg"], point, **self._group.curve.parameters)[0] - def init(self, point: Point): + def init(self, group: AbelianGroup, point: Point): + coord_model = set(self.formulas.values()).pop().coordinate_model + if group.curve.coordinate_model != coord_model or point.coordinate_model != coord_model: + raise ValueError + self._group = group self._point = point - def _init_multiply(self, point: Optional[Point]) -> Point: - if point is None: - if self._point is None: - raise ValueError - else: - if self._point != point: - self.init(point) - return self._point - - def multiply(self, scalar: int, point: Optional[Point] = None) -> Point: + def multiply(self, scalar: int) -> Point: raise NotImplementedError @@ -91,16 +97,16 @@ class LTRMultiplier(ScalarMultiplier): """ always: bool - def __init__(self, group: AbelianGroup, add: AdditionFormula, dbl: DoublingFormula, + def __init__(self, add: AdditionFormula, dbl: DoublingFormula, scl: ScalingFormula = None, always: bool = False): - super().__init__(group, add=add, dbl=dbl, scl=scl) + super().__init__(add=add, dbl=dbl, scl=scl) self.always = always - def multiply(self, scalar: int, point: Optional[Point] = None) -> Point: + def multiply(self, scalar: int) -> Point: if scalar == 0: - return copy(self.group.neutral) - q = self._init_multiply(point) - r = copy(self.group.neutral) + return copy(self._group.neutral) + q = self._point + r = copy(self._group.neutral) for i in range(scalar.bit_length() - 1, -1, -1): r = self._dbl(r) if scalar & (1 << i) != 0: @@ -121,16 +127,16 @@ class RTLMultiplier(ScalarMultiplier): """ always: bool - def __init__(self, group: AbelianGroup, add: AdditionFormula, dbl: DoublingFormula, + def __init__(self, add: AdditionFormula, dbl: DoublingFormula, scl: ScalingFormula = None, always: bool = False): - super().__init__(group, add=add, dbl=dbl, scl=scl) + super().__init__(add=add, dbl=dbl, scl=scl) self.always = always - def multiply(self, scalar: int, point: Optional[Point] = None) -> Point: + def multiply(self, scalar: int) -> Point: if scalar == 0: - return copy(self.group.neutral) - q = self._init_multiply(point) - r = copy(self.group.neutral) + return copy(self._group.neutral) + q = self._point + r = copy(self._group.neutral) while scalar > 0: if scalar & 1 != 0: r = self._add(r, q) @@ -152,14 +158,13 @@ class CoronMultiplier(ScalarMultiplier): https://link.springer.com/content/pdf/10.1007/3-540-48059-5_25.pdf """ - def __init__(self, group: AbelianGroup, add: AdditionFormula, dbl: DoublingFormula, - scl: ScalingFormula = None): - super().__init__(group, add=add, dbl=dbl, scl=scl) + def __init__(self, add: AdditionFormula, dbl: DoublingFormula, scl: ScalingFormula = None): + super().__init__(add=add, dbl=dbl, scl=scl) - def multiply(self, scalar: int, point: Optional[Point] = None): + def multiply(self, scalar: int) -> Point: if scalar == 0: - return copy(self.group.neutral) - q = self._init_multiply(point) + return copy(self._group.neutral) + q = self._point p0 = copy(q) for i in range(scalar.bit_length() - 2, -1, -1): p0 = self._dbl(p0) @@ -177,14 +182,13 @@ class LadderMultiplier(ScalarMultiplier): Montgomery ladder multiplier, using a three input, two output ladder formula. """ - def __init__(self, group: AbelianGroup, ladd: LadderFormula, dbl: DoublingFormula, - scl: ScalingFormula = None): - super().__init__(group, ladd=ladd, dbl=dbl, scl=scl) + def __init__(self, ladd: LadderFormula, dbl: DoublingFormula, scl: ScalingFormula = None): + super().__init__(ladd=ladd, dbl=dbl, scl=scl) - def multiply(self, scalar: int, point: Optional[Point] = None) -> Point: + def multiply(self, scalar: int) -> Point: if scalar == 0: - return copy(self.group.neutral) - q = self._init_multiply(point) + return copy(self._group.neutral) + q = self._point p0 = copy(q) p1 = self._dbl(q) for i in range(scalar.bit_length() - 2, -1, -1): @@ -204,22 +208,21 @@ class SimpleLadderMultiplier(ScalarMultiplier): """ _differential: bool = False - def __init__(self, group: AbelianGroup, - add: Union[AdditionFormula, DifferentialAdditionFormula], dbl: DoublingFormula, + def __init__(self, add: Union[AdditionFormula, DifferentialAdditionFormula], dbl: DoublingFormula, scl: ScalingFormula = None): if isinstance(add, AdditionFormula): - super().__init__(group, add=add, dbl=dbl, scl=scl) + super().__init__(add=add, dbl=dbl, scl=scl) elif isinstance(add, DifferentialAdditionFormula): - super().__init__(group, dadd=add, dbl=dbl, scl=scl) + super().__init__(dadd=add, dbl=dbl, scl=scl) self._differential = True else: raise ValueError - def multiply(self, scalar: int, point: Optional[Point] = None) -> Point: + def multiply(self, scalar: int) -> Point: if scalar == 0: - return copy(self.group.neutral) - q = self._init_multiply(point) - p0 = copy(self.group.neutral) + return copy(self._group.neutral) + q = self._point + p0 = copy(self._group.neutral) p1 = copy(q) for i in range(scalar.bit_length() - 1, -1, -1): if scalar & (1 << i) == 0: @@ -246,20 +249,19 @@ class BinaryNAFMultiplier(ScalarMultiplier): """ _point_neg: Point - def __init__(self, group: AbelianGroup, add: AdditionFormula, dbl: DoublingFormula, + def __init__(self, add: AdditionFormula, dbl: DoublingFormula, neg: NegationFormula, scl: ScalingFormula = None): - super().__init__(group, add=add, dbl=dbl, neg=neg, scl=scl) + super().__init__(add=add, dbl=dbl, neg=neg, scl=scl) - def init(self, point: Point): - super().init(point) + def init(self, group: AbelianGroup, point: Point): + super().init(group, point) self._point_neg = self._neg(point) - def multiply(self, scalar: int, point: Optional[Point] = None) -> Point: + def multiply(self, scalar: int) -> Point: if scalar == 0: - return copy(self.group.neutral) - self._init_multiply(point) + return copy(self._group.neutral) bnaf = naf(scalar) - q = copy(self.group.neutral) + q = copy(self._group.neutral) for val in bnaf: q = self._dbl(q) if val == 1: @@ -281,15 +283,15 @@ class WindowNAFMultiplier(ScalarMultiplier): _precompute_neg: bool = False _width: int - def __init__(self, group: AbelianGroup, add: AdditionFormula, dbl: DoublingFormula, + def __init__(self, add: AdditionFormula, dbl: DoublingFormula, neg: NegationFormula, width: int, scl: ScalingFormula = None, precompute_negation: bool = False): - super().__init__(group, add=add, dbl=dbl, neg=neg, scl=scl) + super().__init__(add=add, dbl=dbl, neg=neg, scl=scl) self._width = width self._precompute_neg = precompute_negation - def init(self, point: Point): - self._point = point + def init(self, group: AbelianGroup, point: Point): + super().init(group, point) self._points = {} self._points_neg = {} current_point = point @@ -300,12 +302,11 @@ class WindowNAFMultiplier(ScalarMultiplier): self._points_neg[2 ** i - 1] = self._neg(current_point) current_point = self._add(current_point, double_point) - def multiply(self, scalar: int, point: Optional[Point] = None): + def multiply(self, scalar: int) -> Point: if scalar == 0: - return copy(self.group.neutral) - self._init_multiply(point) + return copy(self._group.neutral) naf = wnaf(scalar, self._width) - q = copy(self.group.neutral) + q = copy(self._group.neutral) for val in naf: q = self._dbl(q) if val > 0: diff --git a/pyecsca/ec/op.py b/pyecsca/ec/op.py index 11c3079..cb186e1 100644 --- a/pyecsca/ec/op.py +++ b/pyecsca/ec/op.py @@ -5,17 +5,10 @@ from typing import FrozenSet, Optional from .mod import Mod -class Op(object): +class CodeOp(object): result: str parameters: FrozenSet[str] variables: FrozenSet[str] - - def __call__(self, *args, **kwargs: Mod) -> Mod: - """Execute this operation with kwargs.""" - raise NotImplementedError - - -class CodeOp(Op): code: Module operator: Optional[operator] compiled: CodeType @@ -75,6 +68,7 @@ class CodeOp(Op): return f"CodeOp({self.result} = f(params={self.parameters}, vars={self.variables}, consts={self.constants}))" def __call__(self, *args, **kwargs: Mod) -> Mod: + """Execute this operation with kwargs.""" loc = dict(kwargs) exec(self.compiled, {}, loc) return loc[self.result] diff --git a/pyecsca/ec/point.py b/pyecsca/ec/point.py index 3b0b970..368dd0d 100644 --- a/pyecsca/ec/point.py +++ b/pyecsca/ec/point.py @@ -83,6 +83,9 @@ class Point(object): return False return self.coords == other.coords + def __hash__(self): + return hash(self.coords) + 1 + def __str__(self): args = ", ".join([f"{key}={val}" for key, val in self.coords.items()]) return f"[{args}]" diff --git a/pyecsca/ec/signature.py b/pyecsca/ec/signature.py index dbfb30d..8c8630b 100644 --- a/pyecsca/ec/signature.py +++ b/pyecsca/ec/signature.py @@ -7,6 +7,7 @@ from public import public from .context import getcontext from .formula import AdditionFormula +from .group import AbelianGroup from .mod import Mod from .mult import ScalarMultiplier from .point import Point @@ -53,12 +54,13 @@ class SignatureResult(object): class Signature(object): """An EC based signature primitive. (ECDSA)""" mult: ScalarMultiplier + group: AbelianGroup add: Optional[AdditionFormula] pubkey: Optional[Point] privkey: Optional[int] hash_algo: Optional[Any] - def __init__(self, mult: ScalarMultiplier, add: Optional[AdditionFormula] = None, + def __init__(self, mult: ScalarMultiplier, group: AbelianGroup, add: Optional[AdditionFormula] = None, pubkey: Optional[Point] = None, privkey: Optional[int] = None, hash_algo: Optional[Any] = None): if pubkey is None and privkey is None: @@ -69,6 +71,7 @@ class Signature(object): else: add = mult.formulas["add"] self.mult = mult + self.group = group self.add = add self.pubkey = pubkey self.privkey = privkey @@ -86,18 +89,19 @@ class Signature(object): def _get_nonce(self, nonce: Optional[int]) -> Mod: if nonce is None: - return Mod(secrets.randbelow(self.mult.group.order), self.mult.group.order) + return Mod(secrets.randbelow(self.group.order), self.group.order) else: - return Mod(nonce, self.mult.group.order) + return Mod(nonce, self.group.order) def _do_sign(self, nonce: Mod, digest: bytes) -> SignatureResult: z = int.from_bytes(digest, byteorder="big") - if len(digest) * 8 > self.mult.group.order.bit_length(): - z >>= len(digest) * 8 - self.mult.group.order.bit_length() - point = self.mult.multiply(int(nonce), self.mult.group.generator) + if len(digest) * 8 > self.group.order.bit_length(): + z >>= len(digest) * 8 - self.group.order.bit_length() + self.mult.init(self.group, self.group.generator) + point = self.mult.multiply(int(nonce)) affine_point = point.to_affine() # TODO: add to context - r = Mod(int(affine_point.x), self.mult.group.order) - s = nonce.inverse() * (Mod(z, self.mult.group.order) + r * self.privkey) + r = Mod(int(affine_point.x), self.group.order) + s = nonce.inverse() * (Mod(z, self.group.order) + r * self.privkey) return SignatureResult(int(r), int(s), digest=digest, nonce=int(nonce), privkey=self.privkey) @@ -121,16 +125,18 @@ class Signature(object): def _do_verify(self, signature: SignatureResult, digest: bytes) -> bool: z = int.from_bytes(digest, byteorder="big") - if len(digest) * 8 > self.mult.group.order.bit_length(): - z >>= len(digest) * 8 - self.mult.group.order.bit_length() - c = Mod(signature.s, self.mult.group.order).inverse() - u1 = Mod(z, 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) - p = getcontext().execute(self.add, p1, p2, **self.mult.group.curve.parameters)[0] + if len(digest) * 8 > self.group.order.bit_length(): + z >>= len(digest) * 8 - self.group.order.bit_length() + c = Mod(signature.s, self.group.order).inverse() + u1 = Mod(z, self.group.order) * c + u2 = Mod(signature.r, self.group.order) * c + self.mult.init(self.group, self.group.generator) + p1 = self.mult.multiply(int(u1)) + self.mult.init(self.group, self.pubkey) + p2 = self.mult.multiply(int(u2)) + p = getcontext().execute(self.add, p1, p2, **self.group.curve.parameters)[0] affine = p.to_affine() # TODO: add to context - v = Mod(int(affine.x), self.mult.group.order) + v = Mod(int(affine.x), self.group.order) return signature.r == int(v) def verify_hash(self, signature: SignatureResult, digest: bytes) -> bool: @@ -154,51 +160,51 @@ class Signature(object): class ECDSA_NONE(Signature): """ECDSA with raw message input.""" - def __init__(self, mult: ScalarMultiplier, add: Optional[AdditionFormula] = None, + def __init__(self, mult: ScalarMultiplier, group: AbelianGroup, add: Optional[AdditionFormula] = None, pubkey: Optional[Point] = None, privkey: Optional[int] = None): - super().__init__(mult, add, pubkey, privkey) + super().__init__(mult, group, add, pubkey, privkey) @public class ECDSA_SHA1(Signature): """ECDSA with SHA1.""" - def __init__(self, mult: ScalarMultiplier, add: Optional[AdditionFormula] = None, + def __init__(self, mult: ScalarMultiplier, group: AbelianGroup, add: Optional[AdditionFormula] = None, pubkey: Optional[Point] = None, privkey: Optional[int] = None): - super().__init__(mult, add, pubkey, privkey, hashlib.sha1) + super().__init__(mult, group, add, pubkey, privkey, hashlib.sha1) @public class ECDSA_SHA224(Signature): """ECDSA with SHA224.""" - def __init__(self, mult: ScalarMultiplier, add: Optional[AdditionFormula] = None, + def __init__(self, mult: ScalarMultiplier, group: AbelianGroup, add: Optional[AdditionFormula] = None, pubkey: Optional[Point] = None, privkey: Optional[int] = None): - super().__init__(mult, add, pubkey, privkey, hashlib.sha224) + super().__init__(mult, group, add, pubkey, privkey, hashlib.sha224) @public class ECDSA_SHA256(Signature): """ECDSA with SHA256.""" - def __init__(self, mult: ScalarMultiplier, add: Optional[AdditionFormula] = None, + def __init__(self, mult: ScalarMultiplier, group: AbelianGroup, add: Optional[AdditionFormula] = None, pubkey: Optional[Point] = None, privkey: Optional[int] = None): - super().__init__(mult, add, pubkey, privkey, hashlib.sha256) + super().__init__(mult, group, add, pubkey, privkey, hashlib.sha256) @public class ECDSA_SHA384(Signature): """ECDSA with SHA384.""" - def __init__(self, mult: ScalarMultiplier, add: Optional[AdditionFormula] = None, + def __init__(self, mult: ScalarMultiplier, group: AbelianGroup, add: Optional[AdditionFormula] = None, pubkey: Optional[Point] = None, privkey: Optional[int] = None): - super().__init__(mult, add, pubkey, privkey, hashlib.sha384) + super().__init__(mult, group, add, pubkey, privkey, hashlib.sha384) @public class ECDSA_SHA512(Signature): """ECDSA with SHA512.""" - def __init__(self, mult: ScalarMultiplier, add: Optional[AdditionFormula] = None, + def __init__(self, mult: ScalarMultiplier, group: AbelianGroup, add: Optional[AdditionFormula] = None, pubkey: Optional[Point] = None, privkey: Optional[int] = None): - super().__init__(mult, add, pubkey, privkey, hashlib.sha512) + super().__init__(mult, group, add, pubkey, privkey, hashlib.sha512) diff --git a/test/ec/test_context.py b/test/ec/test_context.py index 77160cb..ceecf2c 100644 --- a/test/ec/test_context.py +++ b/test/ec/test_context.py @@ -25,12 +25,13 @@ class ContextTests(TestCase): self.secp128r1 = get_curve("secp128r1", "projective") self.base = self.secp128r1.generator self.coords = self.secp128r1.curve.coordinate_model - self.mult = LTRMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], + self.mult = LTRMultiplier(self.coords.formulas["add-1998-cmo"], self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["z"]) + self.mult.init(self.secp128r1, self.base) def test_null(self): with local() as ctx: - self.mult.multiply(59, self.base) + self.mult.multiply(59) self.assertIsInstance(ctx, NullContext) def test_default(self): @@ -38,7 +39,7 @@ class ContextTests(TestCase): self.addCleanup(resetcontext, token) with local(DefaultContext()) as ctx: - self.mult.multiply(59, self.base) + self.mult.multiply(59) self.assertEqual(len(ctx.actions), 10) self.assertEqual(len(getcontext().actions), 0) @@ -52,9 +53,9 @@ class ContextTests(TestCase): def test_str(self): with local(DefaultContext()) as default: - self.mult.multiply(59, self.base) + self.mult.multiply(59) str(default) str(default.actions) with local(NullContext()) as null: - self.mult.multiply(59, self.base) + self.mult.multiply(59) str(null) diff --git a/test/ec/test_key_agreement.py b/test/ec/test_key_agreement.py index ab009e3..3acb070 100644 --- a/test/ec/test_key_agreement.py +++ b/test/ec/test_key_agreement.py @@ -3,7 +3,7 @@ from unittest import TestCase from pyecsca.ec.curves import get_curve from pyecsca.ec.key_agreement import * from pyecsca.ec.mult import LTRMultiplier - +from parameterized import parameterized class KeyAgreementTests(TestCase): @@ -11,15 +11,22 @@ class KeyAgreementTests(TestCase): self.secp128r1 = get_curve("secp128r1", "projective") self.add = self.secp128r1.curve.coordinate_model.formulas["add-2007-bl"] self.dbl = self.secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"] - self.mult = LTRMultiplier(self.secp128r1, self.add, self.dbl) + self.mult = LTRMultiplier(self.add, self.dbl) self.priv_a = 0xdeadbeef - self.pub_a = self.mult.multiply(self.priv_a, self.secp128r1.generator) + self.mult.init(self.secp128r1, self.secp128r1.generator) + self.pub_a = self.mult.multiply(self.priv_a) self.priv_b = 0xcafebabe - self.pub_b = self.mult.multiply(self.priv_b, self.secp128r1.generator) - self.algos = [ECDH_NONE, ECDH_SHA1, ECDH_SHA224, ECDH_SHA256, ECDH_SHA384, ECDH_SHA512] + self.pub_b = self.mult.multiply(self.priv_b) - def test_all(self): - for algo in self.algos: - result_ab = algo(self.mult, self.pub_a, self.priv_b).perform() - result_ba = algo(self.mult, self.pub_b, self.priv_a).perform() - self.assertEqual(result_ab, result_ba) + @parameterized.expand([ + ("NONE", ECDH_NONE), + ("SHA1", ECDH_SHA1), + ("SHA224", ECDH_SHA224), + ("SHA256", ECDH_SHA256), + ("SHA384", ECDH_SHA384), + ("SHA512", ECDH_SHA512) + ]) + def test_all(self, name, algo): + result_ab = algo(self.mult, self.secp128r1, self.pub_a, self.priv_b).perform() + result_ba = algo(self.mult, self.secp128r1, self.pub_b, self.priv_a).perform() + self.assertEqual(result_ab, result_ba) diff --git a/test/ec/test_mult.py b/test/ec/test_mult.py index 3abc72c..ffdbf7f 100644 --- a/test/ec/test_mult.py +++ b/test/ec/test_mult.py @@ -28,94 +28,73 @@ class ScalarMultiplierTests(TestCase): else: assert one.equals(other) + def do_basic_test(self, mult_class, group, base, add, dbl, scale, neg=None): + mult = mult_class(*self.get_formulas(group.curve.coordinate_model, add, dbl, neg, scale)) + mult.init(group, base) + res = mult.multiply(314) + other = mult.multiply(157) + mult.init(group, other) + other = mult.multiply(2) + self.assertPointEquality(res, other, scale) + mult.init(group, base) + self.assertEqual(InfinityPoint(group.curve.coordinate_model), mult.multiply(0)) + @parameterized.expand([ ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"), ("none", "add-1998-cmo", "dbl-1998-cmo", None) ]) def test_rtl(self, name, add, dbl, scale): - mult = RTLMultiplier(self.secp128r1, *self.get_formulas(self.coords, add, dbl, scale)) - res = mult.multiply(10, self.base) - other = mult.multiply(5, self.base) - other = mult.multiply(2, other) - self.assertPointEquality(res, other, scale) - self.assertEqual(InfinityPoint(self.coords), mult.multiply(0, self.base)) + self.do_basic_test(RTLMultiplier, self.secp128r1, self.base, add, dbl, scale) @parameterized.expand([ ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"), ("none", "add-1998-cmo", "dbl-1998-cmo", None) ]) def test_ltr(self, name, add, dbl, scale): - mult = LTRMultiplier(self.secp128r1, *self.get_formulas(self.coords, add, dbl, scale)) - res = mult.multiply(10, self.base) - other = mult.multiply(5, self.base) - other = mult.multiply(2, other) - self.assertPointEquality(res, other, scale) - self.assertEqual(InfinityPoint(self.coords), mult.multiply(0, self.base)) + self.do_basic_test(LTRMultiplier, self.secp128r1, self.base, add, dbl, scale) @parameterized.expand([ ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"), ("none", "add-1998-cmo", "dbl-1998-cmo", None) ]) def test_coron(self, name, add, dbl, scale): - mult = CoronMultiplier(self.secp128r1, *self.get_formulas(self.coords, add, dbl, scale)) - res = mult.multiply(10, self.base) - other = mult.multiply(5, self.base) - other = mult.multiply(2, other) - self.assertPointEquality(res, other, scale) - self.assertEqual(InfinityPoint(self.coords), mult.multiply(0, self.base)) + self.do_basic_test(CoronMultiplier, self.secp128r1, self.base, add, dbl, scale) def test_ladder(self): - mult = LadderMultiplier(self.curve25519, self.coords25519.formulas["ladd-1987-m"], - self.coords25519.formulas["dbl-1987-m"], - self.coords25519.formulas["scale"]) - res = mult.multiply(15, self.base25519) - other = mult.multiply(5, self.base25519) - other = mult.multiply(3, other) - self.assertEqual(res, other) - self.assertEqual(InfinityPoint(self.coords25519), mult.multiply(0, self.base25519)) + self.do_basic_test(LadderMultiplier, self.curve25519, self.base25519, "ladd-1987-m", + "dbl-1987-m", "scale") @parameterized.expand([ ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"), ("none", "add-1998-cmo", "dbl-1998-cmo", None) ]) def test_simple_ladder(self, name, add, dbl, scale): - mult = SimpleLadderMultiplier(self.secp128r1, - *self.get_formulas(self.coords, add, dbl, scale)) - res = mult.multiply(10, self.base) - other = mult.multiply(5, self.base) - other = mult.multiply(2, other) - self.assertPointEquality(res, other, scale) - self.assertEqual(InfinityPoint(self.coords), mult.multiply(0, self.base)) + self.do_basic_test(SimpleLadderMultiplier, self.secp128r1, self.base, add, dbl, scale) @parameterized.expand([ ("10", 15), ("2355498743", 2355498743,) ]) def test_ladder_differential(self, name, num): - ladder = LadderMultiplier(self.curve25519, self.coords25519.formulas["ladd-1987-m"], + ladder = LadderMultiplier(self.coords25519.formulas["ladd-1987-m"], self.coords25519.formulas["dbl-1987-m"], self.coords25519.formulas["scale"]) - differential = SimpleLadderMultiplier(self.curve25519, - self.coords25519.formulas["dadd-1987-m"], + differential = SimpleLadderMultiplier(self.coords25519.formulas["dadd-1987-m"], self.coords25519.formulas["dbl-1987-m"], self.coords25519.formulas["scale"]) - res_ladder = ladder.multiply(num, self.base25519) - res_differential = differential.multiply(num, self.base25519) + ladder.init(self.curve25519, self.base25519) + res_ladder = ladder.multiply(num) + differential.init(self.curve25519, self.base25519) + res_differential = differential.multiply(num) self.assertEqual(res_ladder, res_differential) - self.assertEqual(InfinityPoint(self.coords25519), differential.multiply(0, self.base25519)) + self.assertEqual(InfinityPoint(self.coords25519), differential.multiply(0)) @parameterized.expand([ ("scaled", "add-1998-cmo", "dbl-1998-cmo", "neg", "z"), ("none", "add-1998-cmo", "dbl-1998-cmo", "neg", None) ]) def test_binary_naf(self, name, add, dbl, neg, scale): - mult = BinaryNAFMultiplier(self.secp128r1, - *self.get_formulas(self.coords, add, dbl, neg, scale)) - res = mult.multiply(10, self.base) - other = mult.multiply(5, self.base) - other = mult.multiply(2, other) - self.assertPointEquality(res, other, scale) - self.assertEqual(InfinityPoint(self.coords), mult.multiply(0, self.base)) + self.do_basic_test(BinaryNAFMultiplier, self.secp128r1, self.base, add, dbl, scale, neg) @parameterized.expand([ ("scaled3", "add-1998-cmo", "dbl-1998-cmo", "neg", 3, "z"), @@ -123,16 +102,20 @@ class ScalarMultiplierTests(TestCase): ]) def test_window_naf(self, name, add, dbl, neg, width, scale): formulas = self.get_formulas(self.coords, add, dbl, neg, scale) - mult = WindowNAFMultiplier(self.secp128r1, *formulas[:3], width, *formulas[3:]) - res = mult.multiply(10, self.base) - other = mult.multiply(5, self.base) - other = mult.multiply(2, other) + mult = WindowNAFMultiplier(*formulas[:3], width, *formulas[3:]) + mult.init(self.secp128r1, self.base) + res = mult.multiply(10) + other = mult.multiply(5) + mult.init(self.secp128r1, other) + other = mult.multiply(2) self.assertPointEquality(res, other, scale) - self.assertEqual(InfinityPoint(self.coords), mult.multiply(0, self.base)) + mult.init(self.secp128r1, self.base) + self.assertEqual(InfinityPoint(self.coords), mult.multiply(0)) - mult = WindowNAFMultiplier(self.secp128r1, *formulas[:3], width, *formulas[3:], + mult = WindowNAFMultiplier(*formulas[:3], width, *formulas[3:], precompute_negation=True) - res_precompute = mult.multiply(10, self.base) + mult.init(self.secp128r1, self.base) + res_precompute = mult.multiply(10) self.assertPointEquality(res_precompute, res, scale) @parameterized.expand([ @@ -140,58 +123,60 @@ class ScalarMultiplierTests(TestCase): ("2355498743", 2355498743,) ]) def test_basic_multipliers(self, name, num): - ltr = LTRMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], + ltr = LTRMultiplier(self.coords.formulas["add-1998-cmo"], self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["z"]) - res_ltr = ltr.multiply(num, self.base) - rtl = RTLMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], + ltr.init(self.secp128r1, self.base) + res_ltr = ltr.multiply(num) + rtl = RTLMultiplier(self.coords.formulas["add-1998-cmo"], self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["z"]) - res_rtl = rtl.multiply(num, self.base) + rtl.init(self.secp128r1, self.base) + res_rtl = rtl.multiply(num) self.assertEqual(res_ltr, res_rtl) - ltr_always = LTRMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], + ltr_always = LTRMultiplier(self.coords.formulas["add-1998-cmo"], self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["z"], always=True) - rtl_always = RTLMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], + rtl_always = RTLMultiplier(self.coords.formulas["add-1998-cmo"], self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["z"], always=True) - res_ltr_always = ltr_always.multiply(num, self.base) - res_rtl_always = rtl_always.multiply(num, self.base) + ltr_always.init(self.secp128r1, self.base) + rtl_always.init(self.secp128r1, self.base) + res_ltr_always = ltr_always.multiply(num) + res_rtl_always = rtl_always.multiply(num) self.assertEqual(res_ltr, res_ltr_always) self.assertEqual(res_rtl, res_rtl_always) - bnaf = BinaryNAFMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], + bnaf = BinaryNAFMultiplier(self.coords.formulas["add-1998-cmo"], self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["neg"], self.coords.formulas["z"]) - res_bnaf = bnaf.multiply(num, self.base) + bnaf.init(self.secp128r1, self.base) + res_bnaf = bnaf.multiply(num) self.assertEqual(res_bnaf, res_ltr) - wnaf = WindowNAFMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], + wnaf = WindowNAFMultiplier(self.coords.formulas["add-1998-cmo"], self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["neg"], 3, self.coords.formulas["z"]) - res_wnaf = wnaf.multiply(num, self.base) + wnaf.init(self.secp128r1, self.base) + res_wnaf = wnaf.multiply(num) self.assertEqual(res_wnaf, res_ltr) - ladder = SimpleLadderMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], + ladder = SimpleLadderMultiplier(self.coords.formulas["add-1998-cmo"], self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["z"]) - res_ladder = ladder.multiply(num, self.base) + ladder.init(self.secp128r1, self.base) + res_ladder = ladder.multiply(num) self.assertEqual(res_ladder, res_ltr) - coron = CoronMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], + coron = CoronMultiplier(self.coords.formulas["add-1998-cmo"], self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["z"]) - res_coron = coron.multiply(num, self.base) + coron.init(self.secp128r1, self.base) + res_coron = coron.multiply(num) self.assertEqual(res_coron, res_ltr) def test_init_fail(self): + mult = SimpleLadderMultiplier(self.coords25519.formulas["dadd-1987-m"], + self.coords25519.formulas["dbl-1987-m"], + self.coords25519.formulas["scale"]) with self.assertRaises(ValueError): - SimpleLadderMultiplier(self.secp128r1, - self.coords25519.formulas["dadd-1987-m"], - self.coords25519.formulas["dbl-1987-m"], - self.coords25519.formulas["scale"]) - - def test_mult_fail(self): - mult = LTRMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], - self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["z"]) - with self.assertRaises(ValueError): - mult.multiply(15) + mult.init(self.secp128r1, self.base) diff --git a/test/ec/test_signature.py b/test/ec/test_signature.py index 06b6123..b7cccec 100644 --- a/test/ec/test_signature.py +++ b/test/ec/test_signature.py @@ -4,7 +4,7 @@ from unittest import TestCase from pyecsca.ec.curves import get_curve from pyecsca.ec.mult import LTRMultiplier from pyecsca.ec.signature import * - +from parameterized import parameterized class SignatureTests(TestCase): @@ -12,55 +12,67 @@ class SignatureTests(TestCase): self.secp128r1 = get_curve("secp128r1", "projective") self.add = self.secp128r1.curve.coordinate_model.formulas["add-2007-bl"] self.dbl = self.secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"] - self.mult = LTRMultiplier(self.secp128r1, self.add, self.dbl) + self.mult = LTRMultiplier(self.add, self.dbl) self.msg = 0xcafebabe.to_bytes(4, byteorder="big") self.priv = 0xdeadbeef - self.pub = self.mult.multiply(self.priv, self.secp128r1.generator) - self.algos = [ECDSA_SHA1, ECDSA_SHA224, ECDSA_SHA256, ECDSA_SHA384, ECDSA_SHA512] + self.mult.init(self.secp128r1, self.secp128r1.generator) + self.pub = self.mult.multiply(self.priv) - def test_all(self): - for algo in self.algos: - signer = algo(self.mult, privkey=self.priv) - assert signer.can_sign - sig = signer.sign_data(self.msg) - verifier = algo(self.mult, add=self.add, pubkey=self.pub) - assert verifier.can_verify - assert verifier.verify_data(sig, self.msg) - none = ECDSA_NONE(self.mult, add=self.add, pubkey=self.pub, privkey=self.priv) - digest = sha1(self.msg).digest() - sig = none.sign_hash(digest) - assert none.verify_hash(sig, digest) - sig = none.sign_data(digest) - assert none.verify_data(sig, digest) + @parameterized.expand([ + ("SHA1", ECDSA_SHA1), + ("SHA224", ECDSA_SHA224), + ("SHA256", ECDSA_SHA256), + ("SHA384", ECDSA_SHA384), + ("SHA512", ECDSA_SHA512) + ]) + def test_all(self, name, algo): + signer = algo(self.mult, self.secp128r1, privkey=self.priv) + assert signer.can_sign + sig = signer.sign_data(self.msg) + verifier = algo(self.mult, self.secp128r1, add=self.add, pubkey=self.pub) + assert verifier.can_verify + assert verifier.verify_data(sig, self.msg) + # none = ECDSA_NONE(self.mult, add=self.add, pubkey=self.pub, privkey=self.priv) + # digest = sha1(self.msg).digest() + # sig = none.sign_hash(digest) + # assert none.verify_hash(sig, digest) + # 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) + ok = ECDSA_NONE(self.mult, self.secp128r1, add=self.add, pubkey=self.pub, privkey=self.priv) data = b"aaaa" sig = ok.sign_data(data) - no_priv = ECDSA_NONE(self.mult, pubkey=self.pub) + no_priv = ECDSA_NONE(self.mult, self.secp128r1, pubkey=self.pub) with self.assertRaises(RuntimeError): no_priv.sign_data(data) with self.assertRaises(RuntimeError): no_priv.sign_hash(data) - no_pubadd = ECDSA_NONE(self.mult, privkey=self.priv) + no_pubadd = ECDSA_NONE(self.mult, self.secp128r1, privkey=self.priv) with self.assertRaises(RuntimeError): no_pubadd.verify_data(sig, data) with self.assertRaises(RuntimeError): no_pubadd.verify_hash(sig, data) with self.assertRaises(ValueError): - Signature(self.mult) + Signature(self.mult, self.secp128r1) - def test_fixed_nonce(self): - for algo in self.algos: - signer = algo(self.mult, privkey=self.priv) - sig_one = signer.sign_data(self.msg, nonce=0xabcdef) - sig_other = signer.sign_data(self.msg, nonce=0xabcdef) - verifier = algo(self.mult, add=self.add, pubkey=self.pub) - assert verifier.verify_data(sig_one, self.msg) - assert verifier.verify_data(sig_other, self.msg) - self.assertEqual(sig_one, sig_other) + @parameterized.expand([ + ("SHA1", ECDSA_SHA1), + ("SHA224", ECDSA_SHA224), + ("SHA256", ECDSA_SHA256), + ("SHA384", ECDSA_SHA384), + ("SHA512", ECDSA_SHA512) + ]) + def test_fixed_nonce(self, name, algo): + signer = algo(self.mult, self.secp128r1, privkey=self.priv) + sig_one = signer.sign_data(self.msg, nonce=0xabcdef) + sig_other = signer.sign_data(self.msg, nonce=0xabcdef) + verifier = algo(self.mult, self.secp128r1, add=self.add, pubkey=self.pub) + assert verifier.verify_data(sig_one, self.msg) + assert verifier.verify_data(sig_other, self.msg) + self.assertEqual(sig_one, sig_other) def test_der(self): sig = SignatureResult(0xaaaaa, 0xbbbbb) |
