diff options
| author | J08nY | 2024-01-27 11:48:50 +0100 |
|---|---|---|
| committer | J08nY | 2024-01-27 11:48:50 +0100 |
| commit | 8f05c2a23462be44b8f22da17f36eaf07e8cf9c4 (patch) | |
| tree | 1bf7b0228f7326521651ba85e7fe7139a6127ac2 | |
| parent | c99905ad7e2e4dcc269669fb5ef92e787e5248d7 (diff) | |
| download | pyecsca-8f05c2a23462be44b8f22da17f36eaf07e8cf9c4.tar.gz pyecsca-8f05c2a23462be44b8f22da17f36eaf07e8cf9c4.tar.zst pyecsca-8f05c2a23462be44b8f22da17f36eaf07e8cf9c4.zip | |
Add EFD -> Code transformation.
| -rw-r--r-- | pyecsca/ec/formula/base.py | 10 | ||||
| -rw-r--r-- | pyecsca/ec/formula/code.py | 34 | ||||
| -rw-r--r-- | pyecsca/ec/formula/efd.py | 10 | ||||
| -rw-r--r-- | pyecsca/ec/formula/fake.py | 1 | ||||
| -rw-r--r-- | test/ec/test_formula.py | 11 |
5 files changed, 50 insertions, 16 deletions
diff --git a/pyecsca/ec/formula/base.py b/pyecsca/ec/formula/base.py index 429f4c1..5cfb425 100644 --- a/pyecsca/ec/formula/base.py +++ b/pyecsca/ec/formula/base.py @@ -16,7 +16,6 @@ from ..error import UnsatisfiedAssumptionError, raise_unsatisified_assumption from ..mod import Mod, SymbolicMod from ..op import CodeOp, OpType from ...misc.cfg import getconfig -from ...misc.utils import peval from ...misc.cache import sympify, simplify @@ -283,15 +282,6 @@ class Formula(ABC): def __repr__(self): return f"{self.__class__.__name__}({self.name} for {self.coordinate_model})" - def __getstate__(self): - state = self.__dict__.copy() - state["assumptions"] = list(map(unparse, state["assumptions"])) - return state - - def __setstate__(self, state): - state["assumptions"] = list(map(peval, state["assumptions"])) - self.__dict__.update(state) - @cached_property def input_index(self): """Return the starting index where this formula reads its inputs.""" diff --git a/pyecsca/ec/formula/code.py b/pyecsca/ec/formula/code.py index 9d36d94..307870f 100644 --- a/pyecsca/ec/formula/code.py +++ b/pyecsca/ec/formula/code.py @@ -1,4 +1,7 @@ """Provides a concrete class of a formula that has a constructor.""" +from typing import List, Any +from ast import Expression +from astunparse import unparse from .base import ( Formula, @@ -10,17 +13,29 @@ from .base import ( ScalingFormula, DifferentialAdditionFormula, ) +from ..op import CodeOp +from ...misc.utils import peval class CodeFormula(Formula): - def __init__(self, name, code, coordinate_model, parameters, assumptions): + """A basic formula class that can be directly initialized with the code and other attributes.""" + + def __init__( + self, + name: str, + code: List[CodeOp], + coordinate_model: Any, + parameters: List[str], + assumptions: List[Expression], + unified: bool = False, + ): self.name = name + self.code = code self.coordinate_model = coordinate_model self.meta = {} self.parameters = parameters self.assumptions = assumptions - self.code = code - self.unified = False + self.unified = unified def __hash__(self): return hash( @@ -30,6 +45,7 @@ class CodeFormula(Formula): tuple(self.code), tuple(self.parameters), tuple(self.assumptions), + self.unified, ) ) @@ -40,8 +56,20 @@ class CodeFormula(Formula): self.name == other.name and self.coordinate_model == other.coordinate_model and self.code == other.code + and self.parameters == other.parameters + and self.assumptions_str == other.assumptions_str + and self.unified == other.unified ) + def __getstate__(self): + state = self.__dict__.copy() + state["assumptions"] = list(map(unparse, state["assumptions"])) + return state + + def __setstate__(self, state): + state["assumptions"] = list(map(peval, state["assumptions"])) + self.__dict__.update(state) + class CodeAdditionFormula(AdditionFormula, CodeFormula): pass diff --git a/pyecsca/ec/formula/efd.py b/pyecsca/ec/formula/efd.py index c2ec49a..edf64de 100644 --- a/pyecsca/ec/formula/efd.py +++ b/pyecsca/ec/formula/efd.py @@ -1,8 +1,12 @@ """""" +from copy import copy + from public import public from importlib_resources.abc import Traversable from typing import Any + +from . import CodeFormula from .base import ( Formula, CodeOp, @@ -66,6 +70,12 @@ class EFDFormula(Formula): code_module = pexec(line.decode("ascii").replace("^", "**")) self.code.append(CodeOp(code_module)) + def to_code(self) -> CodeFormula: + for klass in CodeFormula.__subclasses__(): + if self.shortname == klass.shortname: + return klass(self.name, copy(self.code), self.coordinate_model, copy(self.parameters), copy(self.assumptions), self.unified) + raise TypeError(f"CodeFormula not found for {self.__class__}.") + def __getnewargs__(self): return None, None, self.name, self.coordinate_model diff --git a/pyecsca/ec/formula/fake.py b/pyecsca/ec/formula/fake.py index 837e2d8..cc52740 100644 --- a/pyecsca/ec/formula/fake.py +++ b/pyecsca/ec/formula/fake.py @@ -26,6 +26,7 @@ class FakeFormula(Formula, ABC): and points (for example to get the addition chain via the MultipleContext). """ def __init__(self, coordinate_model): + # TODO: This is missing all of the other attributes self.coordinate_model = coordinate_model self.code = [] diff --git a/test/ec/test_formula.py b/test/ec/test_formula.py index ed437a5..e0fd6fe 100644 --- a/test/ec/test_formula.py +++ b/test/ec/test_formula.py @@ -33,7 +33,12 @@ from pyecsca.ec.formula.efd import ( LadderEFDFormula, EFDFormula, ) -from pyecsca.ec.formula import AdditionFormula, DoublingFormula, LadderFormula +from pyecsca.ec.formula import ( + AdditionFormula, + DoublingFormula, + LadderFormula, + CodeFormula, +) @pytest.fixture() @@ -390,14 +395,14 @@ LIBRARY_FORMULAS = [ @pytest.fixture(params=LIBRARY_FORMULAS, ids=list(map(itemgetter(0), LIBRARY_FORMULAS))) -def library_formula_params(request) -> Tuple[EFDFormula, DomainParameters]: +def library_formula_params(request) -> Tuple[CodeFormula, DomainParameters]: name, model, coords_name, param_spec, formula_type = request.param model = model() coordinate_model = model.coordinates[coords_name] with as_file(files(test.data.formulas).joinpath(name)) as meta_path, as_file( files(test.data.formulas).joinpath(name + ".op3") ) as op3_path: - formula = formula_type(meta_path, op3_path, name, coordinate_model) + formula = formula_type(meta_path, op3_path, name, coordinate_model).to_code() params = get_params(*param_spec, coords_name) return formula, params |
