diff options
| author | J08nY | 2023-12-05 13:58:51 +0100 |
|---|---|---|
| committer | J08nY | 2023-12-05 14:06:07 +0100 |
| commit | 3860a7ca356e334e4a5c7419e774e49f79408905 (patch) | |
| tree | 8ebdbe1188a2c52f0a034ceacf9276d652c55dca /pyecsca/ec/formula/efd.py | |
| parent | fc610e310c649d275b43df92cf127ab07d4663b2 (diff) | |
| download | pyecsca-3860a7ca356e334e4a5c7419e774e49f79408905.tar.gz pyecsca-3860a7ca356e334e4a5c7419e774e49f79408905.tar.zst pyecsca-3860a7ca356e334e4a5c7419e774e49f79408905.zip | |
Integrate formula expansion.
- Moved into pyecsca.ec.formula subpackage.
- Unified formula metrics.
- Moved tests into tests with library_formula fixture.
- Cleaned up typing.
Diffstat (limited to 'pyecsca/ec/formula/efd.py')
| -rw-r--r-- | pyecsca/ec/formula/efd.py | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/pyecsca/ec/formula/efd.py b/pyecsca/ec/formula/efd.py new file mode 100644 index 0000000..0156fb3 --- /dev/null +++ b/pyecsca/ec/formula/efd.py @@ -0,0 +1,142 @@ +"""""" +from functools import cached_property +from itertools import product + +from public import public + +from importlib_resources.abc import Traversable +from typing import Any +from .base import ( + Formula, + CodeOp, + AdditionFormula, + DoublingFormula, + TriplingFormula, + NegationFormula, + ScalingFormula, + DifferentialAdditionFormula, + LadderFormula, +) +from ast import parse + + +class EFDFormula(Formula): + """Formula from the [EFD]_.""" + + def __init__( + self, + meta_path: Traversable, + op3_path: Traversable, + name: str, + coordinate_model: Any, + ): + self.name = name + self.coordinate_model = coordinate_model + self.meta = {} + self.parameters = [] + self.assumptions = [] + self.code = [] + self.unified = False + self.__read_meta_file(meta_path) + self.__read_op3_file(op3_path) + + def __read_meta_file(self, path: Traversable): + with path.open("rb") as f: + line = f.readline().decode("ascii").rstrip() + while line: + if line.startswith("source"): + self.meta["source"] = line[7:] + elif line.startswith("parameter"): + self.parameters.append(line[10:]) + elif line.startswith("assume"): + self.assumptions.append( + parse( + line[7:].replace("=", "==").replace("^", "**"), mode="eval" + ) + ) + elif line.startswith("unified"): + self.unified = True + line = f.readline().decode("ascii").rstrip() + + def __read_op3_file(self, path: Traversable): + with path.open("rb") as f: + for line in f.readlines(): + code_module = parse( + line.decode("ascii").replace("^", "**"), str(path), mode="exec" + ) + self.code.append(CodeOp(code_module)) + + def __str__(self): + return f"{self.coordinate_model!s}/{self.name}" + + @cached_property + def input_index(self): + return 1 + + @cached_property + def output_index(self): + return max(self.num_inputs + 1, 3) + + @cached_property + def inputs(self): + return { + var + str(i) + for var, i in product( + self.coordinate_model.variables, range(1, 1 + self.num_inputs) + ) + } + + @cached_property + def outputs(self): + return { + var + str(i) + for var, i in product( + self.coordinate_model.variables, + range(self.output_index, self.output_index + self.num_outputs), + ) + } + + def __eq__(self, other): + if not isinstance(other, EFDFormula): + return False + return ( + self.name == other.name and self.coordinate_model == other.coordinate_model + ) + + def __hash__(self): + return hash((self.coordinate_model, self.name)) + + +@public +class AdditionEFDFormula(AdditionFormula, EFDFormula): + pass + + +@public +class DoublingEFDFormula(DoublingFormula, EFDFormula): + pass + + +@public +class TriplingEFDFormula(TriplingFormula, EFDFormula): + pass + + +@public +class NegationEFDFormula(NegationFormula, EFDFormula): + pass + + +@public +class ScalingEFDFormula(ScalingFormula, EFDFormula): + pass + + +@public +class DifferentialAdditionEFDFormula(DifferentialAdditionFormula, EFDFormula): + pass + + +@public +class LadderEFDFormula(LadderFormula, EFDFormula): + pass |
