Source code for pyecsca.misc.cfg

"""
Provides functions for runtime configuration of the toolkit.

This includes how errors are handled, or which :py:class:`~pyecsca.ec.mod.Mod` implementation is used.
"""
from copy import deepcopy
from contextvars import ContextVar, Token
from typing import Optional

from public import public


[docs] @public class ECConfig: """Configuration for the :py:mod:`pyecsca.ec` package.""" _no_inverse_action: str = "error" _non_residue_action: str = "error" _unsatisfied_formula_assumption_action: str = "error" _unsatisfied_coordinate_assumption_action: str = "error" _mod_implementation: str = "gmp" @property def no_inverse_action(self) -> str: """ Return or set the action to take when a non-invertible element is to be inverted. One of: - ``"error"``: Raise :py:class:`pyecsca.ec.error.NonInvertibleError`. - ``"warning"``: Raise :py:class:`pyecsca.ec.error.NonInvertibleWarning`. - ``"ignore"``: Ignore the event and compute as if nothing happened. """ return self._no_inverse_action @no_inverse_action.setter def no_inverse_action(self, value: str): if value not in ("error", "warning", "ignore"): raise ValueError("Action has to be one of 'error', 'warning', 'ignore'.") self._no_inverse_action = value @property def non_residue_action(self) -> str: """ Return or set the action to take when a the square-root of a non-residue is to be computed. One of: - ``"error"``: Raise :py:class:`pyecsca.ec.error.NonResidueError`. - ``"warning"``: Raise :py:class:`pyecsca.ec.error.NonResidueWarning`. - ``"ignore"``: Ignore the event and compute as if nothing happened. """ return self._non_residue_action @non_residue_action.setter def non_residue_action(self, value: str): if value not in ("error", "warning", "ignore"): raise ValueError("Action has to be one of 'error', 'warning', 'ignore'.") self._non_residue_action = value @property def unsatisfied_formula_assumption_action(self) -> str: """ Return or set the action to take when a formula assumption is unsatisfied during execution. This works for assumption that can be ignored without a fatal error, which are those that are not used to compute a value of an undefined parameter. For example, things of the form ``Z1 = 1``. One of: - ``"error"``: Raise :py:class:`pyecsca.ec.error.UnsatisfiedAssumptionError`. - ``"warning"``: Raise :py:class:`pyecsca.ec.error.UnsatisfiedAssumptionWarning`. - ``"ignore"``: Ignore the event and compute as if nothing happened. """ return self._unsatisfied_formula_assumption_action @unsatisfied_formula_assumption_action.setter def unsatisfied_formula_assumption_action(self, value: str): if value not in ("error", "warning", "ignore"): raise ValueError("Action has to be one of 'error', 'warning', 'ignore'.") self._unsatisfied_formula_assumption_action = value @property def unsatisfied_coordinate_assumption_action(self) -> str: """ Return or set the action to take when a coordinate assumption is unsatisfied during curve creation. This works for assumption that can be ignored without a fatal error, which are those that are not used to compute a value of an undefined parameter. For example, things of the form ``a = -1``. One of: - ``"error"``: Raise :py:class:`pyecsca.ec.error.UnsatisfiedAssumptionError`. - ``"warning"``: Raise :py:class:`pyecsca.ec.error.UnsatisfiedAssumptionWarning`. - ``"ignore"``: Ignore the event and compute as if nothing happened. """ return self._unsatisfied_coordinate_assumption_action @unsatisfied_coordinate_assumption_action.setter def unsatisfied_coordinate_assumption_action(self, value: str): if value not in ("error", "warning", "ignore"): raise ValueError("Action has to be one of 'error', 'warning', 'ignore'.") self._unsatisfied_coordinate_assumption_action = value @property def mod_implementation(self) -> str: """ Return or set the selected :py:class:`pyecsca.ec.mod.Mod` implementation. One of: - ``"gmp"``: Requires the GMP library and `gmpy2` package. - ``"python"``: Doesn't require anything. - ``"symbolic"``: Requires sympy. """ return self._mod_implementation @mod_implementation.setter def mod_implementation(self, value: str): if value not in ("python", "gmp", "symbolic"): raise ValueError("Bad Mod implementaiton, can be one of 'python', 'gmp' or 'symbolic'.") self._mod_implementation = value
[docs] @public class LoggingConfig: """Logging configuration.""" enabled: bool = True """Whether logging is enabled."""
[docs] @public class Config: """Runtime configuration for the library.""" ec: ECConfig """Configuration for the :py:mod:`pyecsca.ec` package.""" log: LoggingConfig """Logging configuration.""" def __init__(self): self.ec = ECConfig() self.log = LoggingConfig()
_config: ContextVar[Config] = ContextVar("config", default=Config())
[docs] @public def getconfig() -> Config: """ Get the current config. :return: The current config. """ return _config.get()
[docs] @public def setconfig(cfg: Config) -> Token: """ Set the current config. :param cfg: The config to set. :return: A token that can be used to reset the config to the previous one. """ return _config.set(cfg)
[docs] @public def resetconfig(token: Token) -> None: """ Reset the config to the previous one. :param token: A token from :py:func:`setconfig()`. """ _config.reset(token)
[docs] @public class TemporaryConfig: """ Temporary config context manager. Can be entered as follows: .. code-block:: python with TemporaryConfig() as cfg: cfg.some_property = some_value ... """ token: Optional[Token] def __init__(self): self.token = None self.new_config = deepcopy(getconfig()) def __enter__(self) -> Config: self.token = setconfig(self.new_config) return self.new_config def __exit__(self, t, v, tb): if self.token: resetconfig(self.token)