aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ08nY2020-02-12 21:00:20 +0100
committerJ08nY2020-02-12 21:00:20 +0100
commit85afbe7548d59d5ca5a8d17b32926f99235f5211 (patch)
tree5645730f38ff87bcbdfe76539dee2e7961df4901
parent11bd56b296f1620932f098a6037f0807e7f6616f (diff)
downloadpyecsca-85afbe7548d59d5ca5a8d17b32926f99235f5211.tar.gz
pyecsca-85afbe7548d59d5ca5a8d17b32926f99235f5211.tar.bz2
pyecsca-85afbe7548d59d5ca5a8d17b32926f99235f5211.zip
Add the concept of a configuration. Add enumeration of configurations.
-rw-r--r--Makefile5
-rw-r--r--docs/Makefile2
-rw-r--r--pyecsca/ec/configuration.py179
-rw-r--r--pyecsca/ec/context.py88
-rw-r--r--pyecsca/ec/coordinates.py5
-rw-r--r--pyecsca/ec/curves.py181
-rw-r--r--pyecsca/ec/formula.py15
-rw-r--r--pyecsca/ec/mult.py6
-rw-r--r--pyecsca/sca/target/ISO7816.py12
-rw-r--r--pyecsca/sca/target/base.py10
-rw-r--r--test/ec/test_configuration.py53
-rw-r--r--test/ec/test_context.py39
-rw-r--r--test/ec/test_formula.py4
13 files changed, 379 insertions, 220 deletions
diff --git a/Makefile b/Makefile
index 369a065..0f52507 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,6 @@
-EC_TESTS = ec.test_context ec.test_curve ec.test_curves ec.test_formula ec.test_params ec.test_key_agreement ec.test_key_generation \
-ec.test_mod ec.test_model ec.test_mult ec.test_naf ec.test_op ec.test_point ec.test_signature
+EC_TESTS = ec.test_context ec.test_configuration ec.test_curve ec.test_curves ec.test_formula \
+ec.test_params ec.test_key_agreement ec.test_key_generation ec.test_mod ec.test_model \
+ec.test_mult ec.test_naf ec.test_op ec.test_point ec.test_signature
SCA_TESTS = sca.test_align sca.test_combine sca.test_edit sca.test_filter sca.test_match sca.test_process \
sca.test_sampling sca.test_test sca.test_trace sca.test_traceset
diff --git a/docs/Makefile b/docs/Makefile
index 4f2a169..eac584d 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -15,7 +15,7 @@ help:
apidoc:
mkdir -p api/codegen/
sphinx-apidoc ../pyecsca/ --implicit-namespaces --ext-autodoc -M -f -e -o api/
- sphinx-apidoc ../../pyecsca-codegen/pyecsca/ --implicit-namespaces --ext-autodoc -M -no-toc -f -e -o api/codegen/
+ sphinx-apidoc ../../pyecsca-codegen/pyecsca/ --implicit-namespaces --ext-autodoc -M --no-toc -f -e -o api/codegen/
echo " codegen/pyecsca.codegen" >> api/modules.rst
.PHONY: help apidoc Makefile
diff --git a/pyecsca/ec/configuration.py b/pyecsca/ec/configuration.py
new file mode 100644
index 0000000..25bd4f9
--- /dev/null
+++ b/pyecsca/ec/configuration.py
@@ -0,0 +1,179 @@
+from dataclasses import dataclass
+from enum import Enum
+from itertools import product
+from typing import Set, get_type_hints, Union, get_origin, get_args, Generator
+
+from public import public
+
+from .coordinates import CoordinateModel
+from .formula import Formula
+from .model import CurveModel
+from .mult import ScalarMultiplier
+
+
+@public
+class EnumDefine(Enum):
+ def __str__(self):
+ return self.value
+
+ def __repr__(self):
+ return self.value
+
+ @classmethod
+ def names(cls):
+ return list(e.name for e in cls)
+
+
+@public
+class Multiplication(EnumDefine):
+ """Base multiplication algorithm to use."""
+ TOOM_COOK = "MUL_TOOM_COOK"
+ KARATSUBA = "MUL_KARATSUBA"
+ COMBA = "MUL_COMBA"
+ BASE = "MUL_BASE"
+
+
+@public
+class Squaring(EnumDefine):
+ """Base squaring algorithm to use."""
+ TOOM_COOK = "SQR_TOOM_COOK"
+ KARATSUBA = "SQR_KARATSUBA"
+ COMBA = "SQR_COMBA"
+ BASE = "SQR_BASE"
+
+
+@public
+class Reduction(EnumDefine):
+ """Modular reduction method used."""
+ BARRETT = "RED_BARRETT"
+ MONTGOMERY = "RED_MONTGOMERY"
+ BASE = "RED_BASE"
+
+
+@public
+class HashType(EnumDefine):
+ """Hash algorithm used in ECDH and ECDSA."""
+ NONE = "HASH_NONE"
+ SHA1 = "HASH_SHA1"
+ SHA224 = "HASH_SHA224"
+ SHA256 = "HASH_SHA256"
+ SHA384 = "HASH_SHA384"
+ SHA512 = "HASH_SHA512"
+
+
+@public
+class RandomMod(EnumDefine):
+ """Method of sampling a uniform integer modulo order."""
+ SAMPLE = "MOD_RAND_SAMPLE"
+ REDUCE = "MOD_RAND_REDUCE"
+
+
+@public
+@dataclass(frozen=True)
+class Configuration(object):
+ """An ECC implementation."""
+ model: CurveModel
+ coords: CoordinateModel
+ formulas: Set[Formula]
+ scalarmult: ScalarMultiplier
+ hash_type: HashType
+ mod_rand: RandomMod
+ mult: Multiplication
+ sqr: Squaring
+ red: Reduction
+
+
+@public
+def all_configurations(**kwargs) -> Generator[Configuration, Configuration, None]:
+ def is_optional(arg_type):
+ return get_origin(arg_type) == Union and len(get_args(arg_type)) == 2 and \
+ get_args(arg_type)[1] == type(None)
+
+ def leaf_subclasses(cls):
+ subs = cls.__subclasses__()
+ result = []
+ for subclass in subs:
+ if subclass.__subclasses__():
+ result.extend(leaf_subclasses(subclass))
+ else:
+ result.append(subclass)
+ return result
+
+ def independents(kwargs):
+ options = {
+ "hash_type": HashType,
+ "mod_rand": RandomMod,
+ "mult": Multiplication,
+ "sqr": Squaring,
+ "red": Reduction
+ }
+ keys = list(filter(lambda key: key not in kwargs, options.keys()))
+ values = [options[key] for key in keys]
+ fixed_args = {key: kwargs[key] for key in kwargs if key in options}
+ for value_choice in product(*values):
+ yield dict(zip(keys, value_choice), **fixed_args)
+
+ def multipliers(mult_classes, coords_formulas, fixed_args=None):
+ for mult_cls in mult_classes:
+ if fixed_args is not None and "cls" in fixed_args and mult_cls != fixed_args["cls"]:
+ continue
+ arg_options = {}
+ for name, required_type in get_type_hints(mult_cls.__init__).items():
+ if fixed_args is not None and name in fixed_args:
+ arg_options[name] = [fixed_args[name]]
+ continue
+ if is_optional(required_type):
+ opt_type = get_args(required_type)[0]
+ if issubclass(opt_type, Formula):
+ options = [formula for formula in coords_formulas if
+ isinstance(formula, opt_type)] + [None]
+ else:
+ options = [None] # TODO: anything here?
+ elif get_origin(required_type) == None and issubclass(required_type, Formula):
+ options = [formula for formula in coords_formulas if
+ isinstance(formula, required_type)]
+ elif get_origin(required_type) == None and issubclass(required_type, bool):
+ options = [True, False]
+ elif get_origin(required_type) == None and issubclass(required_type,
+ int) and name == "width":
+ options = [3, 5]
+ else:
+ options = []
+ arg_options[name] = options
+ keys = arg_options.keys()
+ values = arg_options.values()
+ for combination in product(*values):
+ try:
+ mult = mult_cls(**dict(zip(keys, combination)))
+ except Exception:
+ continue
+ yield mult
+
+ for model_cls in leaf_subclasses(CurveModel):
+ model = model_cls()
+ if "model" in kwargs:
+ if model != kwargs["model"]:
+ continue
+ for coords_name, coords in model.coordinates.items():
+ if "coords" in kwargs:
+ if coords != kwargs["coords"]:
+ continue
+ coords_formulas = coords.formulas.values()
+ mult_classes = leaf_subclasses(ScalarMultiplier)
+ if "scalarmult" in kwargs:
+ if isinstance(kwargs["scalarmult"], ScalarMultiplier):
+ mults = [kwargs["scalarmult"]]
+ elif isinstance(kwargs["scalarmult"], type) and issubclass(kwargs["scalarmult"],
+ ScalarMultiplier):
+ mult_classes = list(
+ filter(lambda mult: issubclass(mult, kwargs["scalarmult"]),
+ mult_classes))
+ mults = multipliers(mult_classes, coords_formulas)
+ else:
+ mults = multipliers(mult_classes, coords_formulas, kwargs["scalarmult"])
+ else:
+ mults = multipliers(mult_classes, coords_formulas)
+ for mult in mults:
+ formulas = frozenset(mult.formulas.values())
+ for independent_args in independents(kwargs):
+ yield Configuration(model, coords, formulas, mult, **independent_args)
diff --git a/pyecsca/ec/context.py b/pyecsca/ec/context.py
index d6f56af..c4e1a3c 100644
--- a/pyecsca/ec/context.py
+++ b/pyecsca/ec/context.py
@@ -1,8 +1,8 @@
-from abc import ABCMeta, abstractmethod
+from abc import ABCMeta, abstractmethod, ABC
from collections import OrderedDict
from contextvars import ContextVar, Token
from copy import deepcopy
-from typing import List, Optional, ContextManager, Any
+from typing import List, Optional, ContextManager, Any, Tuple
from public import public
@@ -25,33 +25,87 @@ class Action(object):
self.inside = False
-
-
-
+@public
class Tree(OrderedDict):
- def walk_get(self, path: List) -> Any:
+ def get_by_key(self, path: List) -> Any:
+ """
+ Get the value in the tree at a position given by the path.
+
+ :param path: The path to get.
+ :return: The value in the tree.
+ """
if len(path) == 0:
return self
value = self[path[0]]
if isinstance(value, Tree):
- return value.walk_get(path[1:])
+ return value.get_by_key(path[1:])
elif len(path) == 1:
return value
else:
raise ValueError
+ def get_by_index(self, path: List[int]) -> Tuple[Any, Any]:
+ """
+ Get the key and value in the tree at a position given by the path of indices
+ (the nodes inside a level of a tree are ordered by insertion order).
+
+ :param path: The path to get.
+ :return: The key and value.
+ """
+ if len(path) == 0:
+ raise ValueError
+ key = list(self.keys())[path[0]]
+ value = self[key]
+ if len(path) == 1:
+ return key, value
+ elif isinstance(value, Tree):
+ return value.get_by_index(path[1:])
+ else:
+ raise ValueError
+
+ def repr(self, depth: int = 0) -> str:
+ """
+ Construct a textual representation of the tree. Useful for visualization and debugging.
+
+ :param depth:
+ :return: The resulting textual representation.
+ """
+ result = ""
+ for key, value in self.items():
+ if isinstance(value, Tree):
+ result += "\t" * depth + str(key) + "\n"
+ result += value.repr(depth + 1)
+ else:
+ result += "\t" * depth + str(key) + ":" + str(value) + "\n"
+ return result
+
+ def __repr__(self):
+ return self.repr()
+
@public
-class Context(object):
- __metaclass__ = ABCMeta
+class Context(ABC):
+ """A context is an object that traces actions which happen. There is always one
+ context active, see functions :py:func:`getcontext`, :py:func:`setcontext` and :py:func:`resetcontext`.
+ """
@abstractmethod
- def enter_action(self, action: Action):
+ def enter_action(self, action: Action) -> None:
+ """
+ Enter into an action (i.e. start executing it).
+
+ :param action: The action.
+ """
...
@abstractmethod
- def exit_action(self, action: Action):
+ def exit_action(self, action: Action) -> None:
+ """
+ Exit from an action (i.e. stop executing it).
+
+ :param action: The action.
+ """
...
def __str__(self):
@@ -62,24 +116,24 @@ class Context(object):
class NullContext(Context):
"""A context that does not trace any actions."""
- def enter_action(self, action: Action):
+ def enter_action(self, action: Action) -> None:
pass
- def exit_action(self, action: Action):
+ def exit_action(self, action: Action) -> None:
pass
@public
class DefaultContext(Context):
- """A context that traces executions of actions."""
+ """A context that traces executions of actions in a tree."""
actions: Tree
current: List[Action]
- def enter_action(self, action: Action):
- self.actions.walk_get(self.current)[action] = Tree()
+ def enter_action(self, action: Action) -> None:
+ self.actions.get_by_key(self.current)[action] = Tree()
self.current.append(action)
- def exit_action(self, action: Action):
+ def exit_action(self, action: Action) -> None:
if self.current[-1] != action:
raise ValueError
self.current.pop()
diff --git a/pyecsca/ec/coordinates.py b/pyecsca/ec/coordinates.py
index cfb65e2..922cbcb 100644
--- a/pyecsca/ec/coordinates.py
+++ b/pyecsca/ec/coordinates.py
@@ -1,8 +1,9 @@
from ast import parse, Expression, Module
-from typing import List, Any, MutableMapping
from os.path import join
+from typing import List, Any, MutableMapping
from pkg_resources import resource_listdir, resource_isdir, resource_stream
+from public import public
from .formula import (Formula, EFDFormula, AdditionEFDFormula, DoublingEFDFormula,
TriplingEFDFormula,
@@ -10,6 +11,7 @@ from .formula import (Formula, EFDFormula, AdditionEFDFormula, DoublingEFDFormul
NegationEFDFormula)
+@public
class CoordinateModel(object):
name: str
full_name: str
@@ -24,6 +26,7 @@ class CoordinateModel(object):
return f"{self.__class__.__name__}(\"{self.name}\" on {self.curve_model.name})"
+@public
class AffineCoordinateModel(CoordinateModel):
name = "affine"
full_name = "Affine coordinates"
diff --git a/pyecsca/ec/curves.py b/pyecsca/ec/curves.py
index d490b74..4ae1d5c 100644
--- a/pyecsca/ec/curves.py
+++ b/pyecsca/ec/curves.py
@@ -13,187 +13,6 @@ from .model import (ShortWeierstrassModel, MontgomeryModel, TwistedEdwardsModel,
from .params import DomainParameters
from .point import Point, InfinityPoint
-SHORT_WEIERSTRASS: Mapping[str, Mapping[str, Any]] = {
- "brainpoolP160r1": {
- "p": 0xE95E4A5F737059DC60DFC7AD95B3D8139515620F,
- "a": 0x340E7BE2A280EB74E2BE61BADA745D97E8F7C300,
- "b": 0x1E589A8595423412134FAA2DBDEC95C8D8675E58,
- "g": (0xBED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC3,
- 0x1667CB477A1A8EC338F94741669C976316DA6321),
- "n": 0xE95E4A5F737059DC60DF5991D45029409E60FC09,
- "h": 0x1},
- "brainpoolP192r1": {
- "p": 0xC302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297,
- "a": 0x6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF,
- "b": 0x469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9,
- "g": (0xC0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD6,
- 0x14B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F),
- "n": 0xC302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1,
- "h": 0x1},
- "brainpoolP224r1": {
- "p": 0xD7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF,
- "a": 0x68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43,
- "b": 0x2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B,
- "g": (0x0D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D,
- 0x58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD),
- "n": 0xD7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F,
- "h": 0x1},
- "brainpoolP256r1": {
- "p": 0xA9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377,
- "a": 0x7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9,
- "b": 0x26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6,
- "g": (0x8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262,
- 0x547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997),
- "n": 0xA9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7,
- "h": 0x1},
- "brainpoolP320r1": {
- "p": 0xD35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27,
- "a": 0x3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4,
- "b": 0x520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6,
- "g": (
- 0x43BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E20611,
- 0x14FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1),
- "n": 0xD35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311,
- "h": 0x1},
- "brainpoolP384r1": {
- "p": 0x8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53,
- "a": 0x7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826,
- "b": 0x04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11,
- "g": (
- 0x1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E,
- 0x8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315),
- "n": 0x8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565,
- "h": 0x1},
- "brainpoolP512r1": {
- "p": 0xAADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3,
- "a": 0x7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA,
- "b": 0x3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723,
- "g": (
- 0x81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822,
- 0x7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892),
- "n": 0xAADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069,
- "h": 0x1},
- "secp128r1": {
- "p": 0xfffffffdffffffffffffffffffffffff,
- "a": 0xfffffffdfffffffffffffffffffffffc,
- "b": 0xe87579c11079f43dd824993c2cee5ed3,
- "g": (0x161ff7528b899b2d0c28607ca52c5b86,
- 0xcf5ac8395bafeb13c02da292dded7a83),
- "n": 0xfffffffe0000000075a30d1b9038a115,
- "h": 0x1},
- "secp128r2": {
- "p": 0xfffffffdffffffffffffffffffffffff,
- "a": 0xd6031998d1b3bbfebf59cc9bbff9aee1,
- "b": 0x5eeefca380d02919dc2c6558bb6d8a5d,
- "g": (0x7b6aa5d85e572983e6fb32a7cdebc140,
- 0x27b6916a894d3aee7106fe805fc34b44),
- "n": 0x3fffffff7fffffffbe0024720613b5a3,
- "h": 0x4},
- "secp160k1": {
- "p": 0xfffffffffffffffffffffffffffffffeffffac73,
- "a": 0x0000000000000000000000000000000000000000,
- "b": 0x0000000000000000000000000000000000000007,
- "g": (0x3b4c382ce37aa192a4019e763036f4f5dd4d7ebb,
- 0x938cf935318fdced6bc28286531733c3f03c4fee),
- "n": 0x0100000000000000000001b8fa16dfab9aca16b6b3,
- "h": 0x1},
- "secp160r1": {
- "p": 0xffffffffffffffffffffffffffffffff7fffffff,
- "a": 0xffffffffffffffffffffffffffffffff7ffffffc,
- "b": 0x1c97befc54bd7a8b65acf89f81d4d4adc565fa45,
- "g": (0x4a96b5688ef573284664698968c38bb913cbfc82,
- 0x23a628553168947d59dcc912042351377ac5fb32),
- "n": 0x0100000000000000000001f4c8f927aed3ca752257,
- "h": 0x1},
- "secp160r2": {
- "p": 0xfffffffffffffffffffffffffffffffeffffac73,
- "a": 0xfffffffffffffffffffffffffffffffeffffac70,
- "b": 0xb4e134d3fb59eb8bab57274904664d5af50388ba,
- "g": (0x52dcb034293a117e1f4ff11b30f7199d3144ce6d,
- 0xfeaffef2e331f296e071fa0df9982cfea7d43f2e),
- "n": 0x0100000000000000000000351ee786a818f3a1a16b,
- "h": 0x1},
- "secp192r1": {
- "p": 0xfffffffffffffffffffffffffffffffeffffffffffffffff,
- "a": 0xfffffffffffffffffffffffffffffffefffffffffffffffc,
- "b": 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1,
- "g": (0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012,
- 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811),
- "n": 0xffffffffffffffffffffffff99def836146bc9b1b4d22831,
- "h": 0x1},
- "secp224r1": {
- "p": 0xffffffffffffffffffffffffffffffff000000000000000000000001,
- "a": 0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe,
- "b": 0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4,
- "g": (0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21,
- 0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34),
- "n": 0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d,
- "h": 0x1},
- "secp256r1": {
- "p": 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff,
- "a": 0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc,
- "b": 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b,
- "g": (0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296,
- 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5),
- "n": 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551,
- "h": 0x1},
- "secp384r1": {
- "p": 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff,
- "a": 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc,
- "b": 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef,
- "g": (
- 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7,
- 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f),
- "n": 0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973,
- "h": 0x1},
- "secp521r1": {
- "p": 0x000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff,
- "a": 0x000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc,
- "b": 0x00000051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00,
- "g": (
- 0x000000c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66,
- 0x0000011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650),
- "n": 0x000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409,
- "h": 0x1}}
-
-MONTGOMERY: Mapping[str, Mapping[str, Any]] = {
- "curve25519": {
- "p": 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed,
- "a": 486662,
- "b": 1,
- "x": 9,
- "z": 1,
- "n": 0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED,
- "h": 2
- }
-}
-
-EDWARDS: Mapping[str, Mapping[str, Any]] = {
- "ed448": {
- "p": 2 ** 448 - 2 ** 224 - 1,
- "c": 1,
- "d": 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffff6756,
- "g": (
- 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa955555555555555555555555555555555555555555555555555555555,
- 0xae05e9634ad7048db359d6205086c2b0036ed7a035884dd7b7e36d728ad8c4b80d6565833a2a3098bbbcb2bed1cda06bdaeafbcdea9386ed),
- "n": 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3,
- "h": 4
- }
-}
-
-TWISTED_EDWARDS: Mapping[str, Mapping[str, Any]] = {
- "ed25519": {
- "p": 2 ** 255 - 19,
- "d": 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3,
- "a": -1,
- "g": (0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a,
- 0x6666666666666666666666666666666666666666666666666666666666666658),
- "n": 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed,
- "h": 2
- }
-}
-
-
@public
def get_params(category: str, name: str, coords: str) -> DomainParameters:
"""
diff --git a/pyecsca/ec/formula.py b/pyecsca/ec/formula.py
index a3875ec..95ca246 100644
--- a/pyecsca/ec/formula.py
+++ b/pyecsca/ec/formula.py
@@ -1,3 +1,4 @@
+from abc import ABC, abstractmethod
from ast import parse, Expression, Mult, Add, Sub, Pow, Div
from itertools import product
from typing import List, Set, Any, ClassVar, MutableMapping, Tuple, Union
@@ -71,7 +72,7 @@ class FormulaAction(Action):
return f"{self.__class__.__name__}({self.formula}, {self.input_points}) = {self.output_points}"
-class Formula(object):
+class Formula(ABC):
"""A formula operating on points."""
name: str
coordinate_model: Any
@@ -125,24 +126,28 @@ class Formula(object):
return f"{self.__class__.__name__}({self.name} for {self.coordinate_model})"
@property
+ @abstractmethod
def input_index(self):
"""The starting index where this formula reads its inputs."""
- raise NotImplementedError
+ ...
@property
+ @abstractmethod
def output_index(self) -> int:
"""The starting index where this formula stores its outputs."""
- raise NotImplementedError
+ ...
@property
+ @abstractmethod
def inputs(self) -> Set[str]:
"""The input variables of the formula."""
- raise NotImplementedError
+ ...
@property
+ @abstractmethod
def outputs(self) -> Set[str]:
"""The output variables of the formula."""
- raise NotImplementedError
+ ...
@property
def num_operations(self) -> int:
diff --git a/pyecsca/ec/mult.py b/pyecsca/ec/mult.py
index 4c5b6d9..35cb6fe 100644
--- a/pyecsca/ec/mult.py
+++ b/pyecsca/ec/mult.py
@@ -1,3 +1,4 @@
+from abc import ABC, abstractmethod
from copy import copy
from typing import Mapping, Tuple, Optional, MutableMapping, ClassVar, Set, Type
@@ -26,7 +27,7 @@ class ScalarMultiplicationAction(Action):
return f"{self.__class__.__name__}({self.point}, {self.scalar})"
-class ScalarMultiplier(object):
+class ScalarMultiplier(ABC):
"""
A scalar multiplication algorithm.
@@ -106,9 +107,10 @@ class ScalarMultiplier(object):
self._point = point
self._initialized = True
+ @abstractmethod
def multiply(self, scalar: int) -> Point:
"""Multiply the point with the scalar."""
- raise NotImplementedError
+ ...
@public
diff --git a/pyecsca/sca/target/ISO7816.py b/pyecsca/sca/target/ISO7816.py
index afa75c5..b5790e6 100644
--- a/pyecsca/sca/target/ISO7816.py
+++ b/pyecsca/sca/target/ISO7816.py
@@ -1,3 +1,4 @@
+from abc import abstractmethod, ABC
from dataclasses import dataclass
from typing import Optional
@@ -36,14 +37,16 @@ class ResponseAPDU(object):
@public
-class ISO7816Target(Target):
+class ISO7816Target(Target, ABC):
"""An ISO7816-4 target."""
@property
+ @abstractmethod
def atr(self) -> bytes:
"""The ATR (Answer To Reset) of the target."""
- raise NotImplementedError
+ ...
+ @abstractmethod
def select(self, aid: bytes) -> bool:
"""
Select an applet with `aid`.
@@ -51,8 +54,9 @@ class ISO7816Target(Target):
:param aid: The AID of the applet to select.
:return: Whether the selection was successful.
"""
- raise NotImplementedError
+ ...
+ @abstractmethod
def send_apdu(self, apdu: CommandAPDU) -> ResponseAPDU:
"""
Send an APDU to the selected applet.
@@ -60,4 +64,4 @@ class ISO7816Target(Target):
:param apdu: The APDU to send.
:return: The response.
"""
- raise NotImplementedError
+ ...
diff --git a/pyecsca/sca/target/base.py b/pyecsca/sca/target/base.py
index ed51c02..cc0436c 100644
--- a/pyecsca/sca/target/base.py
+++ b/pyecsca/sca/target/base.py
@@ -1,14 +1,18 @@
+from abc import ABC, abstractmethod
+
from public import public
@public
-class Target(object):
+class Target(ABC):
"""A target."""
+ @abstractmethod
def connect(self):
"""Connect to the target device."""
- raise NotImplementedError
+ ...
+ @abstractmethod
def disconnect(self):
"""Disconnect from the target device."""
- raise NotImplementedError
+ ...
diff --git a/test/ec/test_configuration.py b/test/ec/test_configuration.py
new file mode 100644
index 0000000..560074b
--- /dev/null
+++ b/test/ec/test_configuration.py
@@ -0,0 +1,53 @@
+from unittest import TestCase
+
+from pyecsca.ec.configuration import (all_configurations, HashType, RandomMod, Multiplication,
+ Squaring, Reduction)
+from pyecsca.ec.model import ShortWeierstrassModel
+from pyecsca.ec.mult import LTRMultiplier
+from test.sca.utils import slow
+
+
+class ConfigurationTests(TestCase):
+
+ @slow
+ def test_all(self):
+ j = 0
+ for _ in all_configurations(model=ShortWeierstrassModel()):
+ j += 1
+ print(j)
+
+ def test_mult_class(self):
+ model = ShortWeierstrassModel()
+ coords = model.coordinates["projective"]
+ scalarmult = LTRMultiplier
+ hash_type = HashType.SHA1
+ mod_rand = RandomMod.SAMPLE
+ mult = Multiplication.BASE
+ sqr = Squaring.BASE
+ red = Reduction.BASE
+ configs = list(all_configurations(model=model, coords=coords, scalarmult=scalarmult,
+ hash_type=hash_type, mod_rand=mod_rand, mult=mult,
+ sqr=sqr, red=red))
+ self.assertEqual(len(configs), 384)
+
+ def test_one(self):
+ model = ShortWeierstrassModel()
+ coords = model.coordinates["projective"]
+ scalarmult = {
+ "cls": LTRMultiplier,
+ "add": coords.formulas["add-1998-cmo"],
+ "dbl": coords.formulas["dbl-1998-cmo"],
+ "scl": None,
+ "always": True,
+ "complete": False,
+ "short_circuit": True
+ }
+ hash_type = HashType.SHA1
+ mod_rand = RandomMod.SAMPLE
+ mult = Multiplication.BASE
+ sqr = Squaring.BASE
+ red = Reduction.BASE
+ configs = list(all_configurations(model=model, coords=coords, scalarmult=scalarmult,
+ hash_type=hash_type, mod_rand=mod_rand, mult=mult,
+ sqr=sqr, red=red))
+ self.assertEqual(len(configs), 1)
diff --git a/test/ec/test_context.py b/test/ec/test_context.py
index 3f46c9d..ea87b7f 100644
--- a/test/ec/test_context.py
+++ b/test/ec/test_context.py
@@ -1,11 +1,48 @@
from unittest import TestCase
from pyecsca.ec.context import (local, DefaultContext, NullContext, getcontext,
- setcontext, resetcontext)
+ setcontext, resetcontext, Tree)
from pyecsca.ec.curves import get_params
from pyecsca.ec.mult import LTRMultiplier, ScalarMultiplicationAction
+class TreeTests(TestCase):
+
+ def test_walk_by_key(self):
+ tree = Tree()
+ tree["a"] = Tree()
+ tree["a"]["1"] = Tree()
+ tree["a"]["2"] = Tree()
+ self.assertIn("a", tree)
+ self.assertIsInstance(tree.get_by_key([]), Tree)
+ self.assertIsInstance(tree.get_by_key(["a"]), Tree)
+ self.assertIsInstance(tree.get_by_key(["a", "1"]), Tree)
+
+ def test_walk_by_index(self):
+ tree = Tree()
+ a = Tree()
+ tree["a"] = a
+ d = Tree()
+ b = Tree()
+ tree["a"]["d"] = d
+ tree["a"]["b"] = b
+ self.assertIn("a", tree)
+ with self.assertRaises(ValueError):
+ tree.get_by_index([])
+
+ self.assertEqual(tree.get_by_index([0]), ("a", a))
+ self.assertEqual(tree.get_by_index([0, 0]), ("d", d))
+
+ def test_repr(self):
+ tree = Tree()
+ tree["a"] = Tree()
+ tree["a"]["1"] = Tree()
+ tree["a"]["2"] = Tree()
+ txt = tree.repr()
+ self.assertEqual(txt.count("\t"), 2)
+ self.assertEqual(txt.count("\n"), 3)
+
+
class ContextTests(TestCase):
def setUp(self):
diff --git a/test/ec/test_formula.py b/test/ec/test_formula.py
index cedbe1f..6f8037a 100644
--- a/test/ec/test_formula.py
+++ b/test/ec/test_formula.py
@@ -1,8 +1,6 @@
from unittest import TestCase
from pyecsca.ec.curves import get_params
-from pyecsca.ec.key_generation import KeyGeneration
-from pyecsca.ec.mult import LTRMultiplier
class FormulaTests(TestCase):
@@ -32,4 +30,4 @@ class FormulaTests(TestCase):
self.assertEqual(self.add.num_inversions, 0)
self.assertEqual(self.add.num_powers, 0)
self.assertEqual(self.add.num_squarings, 6)
- self.assertEqual(self.add.num_addsubs, 10) \ No newline at end of file
+ self.assertEqual(self.add.num_addsubs, 10)