diff options
| -rw-r--r-- | docs/installation.rst | 2 | ||||
| -rw-r--r-- | pyecsca/ec/curve.py | 4 | ||||
| -rw-r--r-- | pyecsca/ec/formula/base.py | 32 | ||||
| -rw-r--r-- | pyecsca/ec/mod.py | 41 | ||||
| -rw-r--r-- | pyecsca/ec/params.py | 7 | ||||
| -rw-r--r-- | pyecsca/sca/re/zvp.py | 2 | ||||
| -rw-r--r-- | test/ec/test_formula.py | 2 | ||||
| -rw-r--r-- | test/ec/test_mod.py | 18 |
8 files changed, 28 insertions, 80 deletions
diff --git a/docs/installation.rst b/docs/installation.rst index d973a02..2396171 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -40,6 +40,7 @@ Requirements - **Faster arithmetic:** - gmpy2_ (and also GMP library) + - python-flint_ (and also Flint library) - cypari2_ (and also PARI library) *pyecsca* contains data from the `Explicit-Formulas Database`_ by Daniel J. Bernstein and Tanja Lange. @@ -92,6 +93,7 @@ Requirements .. _pyscard: https://pyscard.sourceforge.io/ .. _leia: https://pypi.org/project/smartleia/ .. _gmpy2: https://gmpy2.readthedocs.io/ +.. _python-flint: https://fredrikj.net/python-flint/ .. _cypari2: https://cypari2.readthedocs.io/ .. _pytest: https://pytest.org .. _mypy: http://mypy-lang.org/ diff --git a/pyecsca/ec/curve.py b/pyecsca/ec/curve.py index 957aafc..fb3e763 100644 --- a/pyecsca/ec/curve.py +++ b/pyecsca/ec/curve.py @@ -120,12 +120,12 @@ class EllipticCurve: lhs, rhs = assumption_string.split(" = ") expr = sympify(f"{rhs} - {lhs}") for curve_param, value in self.parameters.items(): - expr = expr.subs(curve_param, k(value)) + expr = expr.subs(curve_param, value) if len(expr.free_symbols) > 0: raise ValueError( f"Missing necessary coordinate model parameter ({assumption_string})." ) - if k(expr) != 0: + if k.from_sympy(expr) != 0: raise_unsatisified_assumption( getconfig().ec.unsatisfied_coordinate_assumption_action, f"Coordinate model {self.coordinate_model} has an unsatisifed assumption on the {param} parameter (0 = {expr})." diff --git a/pyecsca/ec/formula/base.py b/pyecsca/ec/formula/base.py index 704ba11..faccd97 100644 --- a/pyecsca/ec/formula/base.py +++ b/pyecsca/ec/formula/base.py @@ -8,7 +8,7 @@ from astunparse import unparse from typing import List, Any, ClassVar, MutableMapping, Tuple, Union, Dict from public import public -from sympy import FF, symbols, Poly, Rational +from sympy import FF, symbols, Poly, parse_expr from pyecsca.ec.context import ResultAction from pyecsca.ec import context @@ -178,22 +178,20 @@ class Formula(ABC): ) elif lhs in self.parameters and is_symbolic: # Handle a symbolic assignment to a new parameter. - k = FF(field) expr = sympify(rhs, evaluate=False) for curve_param, value in params.items(): if isinstance(value, SymbolicMod): expr = expr.subs(curve_param, value.x) else: - expr = expr.subs(curve_param, k(value)) + expr = expr.subs(curve_param, int(value)) params[lhs] = SymbolicMod(expr, field) else: - k = FF(field) expr = sympify(f"{rhs} - {lhs}", evaluate=False) for curve_param, value in params.items(): if isinstance(value, SymbolicMod): expr = expr.subs(curve_param, value.x) else: - expr = expr.subs(curve_param, k(value)) + expr = expr.subs(curve_param, int(value)) if ( len(expr.free_symbols) > 1 or (param := str(expr.free_symbols.pop())) not in self.parameters @@ -201,31 +199,17 @@ class Formula(ABC): raise ValueError( f"This formula couldn't be executed due to an unsupported assumption ({assumption_string})." ) - - def resolve(expression, k): - if not expression.args: - return expression - args = [] - for arg in expression.args: - if isinstance(arg, Rational): - a = arg.p - b = arg.q - res = k(a) / k(b) - else: - res = resolve(arg, k) - args.append(res) - return expression.func(*args) - - expr = resolve(simplify(expr), k) - poly = Poly(expr, symbols(param), domain=k) + numerator, denominator = expr.as_numer_denom() + domain = FF(field) + poly = Poly(numerator, symbols(param), domain=domain) roots = poly.ground_roots() for root in roots: - params[param] = Mod(int(root), field) + params[param] = Mod(int(domain.from_sympy(root)), field) break else: raise UnsatisfiedAssumptionError( f"Unsatisfied assumption in the formula ({assumption_string}).\n" - f"'{expr}' has no roots in the base field {k}." + f"'{expr}' has no roots in the base field GF({field})." ) def __call__(self, field: int, *points: Any, **params: Mod) -> Tuple[Any, ...]: diff --git a/pyecsca/ec/mod.py b/pyecsca/ec/mod.py index 07b2734..2aa4bdd 100644 --- a/pyecsca/ec/mod.py +++ b/pyecsca/ec/mod.py @@ -457,27 +457,6 @@ class Undefined(Mod): return NotImplemented -@lru_cache -def __ff_cache(n): - return FF(n) - - -def _symbolic_check(func): - @wraps(func) - def method(self, other): - if type(self) is not type(other): - if type(other) is int: - other = self.__class__(__ff_cache(self.n)(other), self.n) - else: - other = self.__class__(other, self.n) - else: - if self.n != other.n: - raise ValueError - return func(self, other) - - return method - - @public class SymbolicMod(Mod): """A symbolic element x of ℤₙ (implemented using sympy).""" @@ -493,19 +472,19 @@ class SymbolicMod(Mod): self.x = x self.n = n - @_symbolic_check + @_check def __add__(self, other) -> "SymbolicMod": return self.__class__((self.x + other.x), self.n) - @_symbolic_check + @_check def __radd__(self, other) -> "SymbolicMod": return self + other - @_symbolic_check + @_check def __sub__(self, other) -> "SymbolicMod": return self.__class__((self.x - other.x), self.n) - @_symbolic_check + @_check def __rsub__(self, other) -> "SymbolicMod": return -self + other @@ -527,27 +506,27 @@ class SymbolicMod(Mod): def __invert__(self) -> "SymbolicMod": return self.inverse() - @_symbolic_check + @_check def __mul__(self, other) -> "SymbolicMod": return self.__class__(self.x * other.x, self.n) - @_symbolic_check + @_check def __rmul__(self, other) -> "SymbolicMod": return self * other - @_symbolic_check + @_check def __truediv__(self, other) -> "SymbolicMod": return self * ~other - @_symbolic_check + @_check def __rtruediv__(self, other) -> "SymbolicMod": return ~self * other - @_symbolic_check + @_check def __floordiv__(self, other) -> "SymbolicMod": return self * ~other - @_symbolic_check + @_check def __rfloordiv__(self, other) -> "SymbolicMod": return ~self * other diff --git a/pyecsca/ec/params.py b/pyecsca/ec/params.py index d9e05e5..d5477b6 100644 --- a/pyecsca/ec/params.py +++ b/pyecsca/ec/params.py @@ -220,7 +220,7 @@ def _create_params(curve, coords, infty): lhs, rhs = assumption_string.split(" = ") expr = sympify(f"{rhs} - {lhs}") for curve_param, value in params.items(): - expr = expr.subs(curve_param, k(value)) + expr = expr.subs(curve_param, value) if ( len(expr.free_symbols) > 1 or (param := str(expr.free_symbols.pop())) @@ -229,10 +229,11 @@ def _create_params(curve, coords, infty): raise ValueError( f"This coordinate model couldn't be loaded due to an unsupported assumption ({assumption_string})." ) - poly = Poly(expr, symbols(param), domain=k) + numerator, denominator = expr.as_numer_denom() + poly = Poly(numerator, symbols(param), domain=k) roots = poly.ground_roots() for root in roots: - params[param] = Mod(int(root), field) + params[param] = Mod(int(k.from_sympy(root)), field) break else: raise_unsatisified_assumption( diff --git a/pyecsca/sca/re/zvp.py b/pyecsca/sca/re/zvp.py index a697388..8005382 100644 --- a/pyecsca/sca/re/zvp.py +++ b/pyecsca/sca/re/zvp.py @@ -180,7 +180,7 @@ def compute_factor_set( # Go over all the factors of the intermediate, forget the power for factor, power in factor_list: # Remove unnecessary variables from the Poly - reduced = factor.exclude() + reduced = factor.exclude() if not factor.is_univariate else factor # If there are only curve parameters, we do not care about the polynomial if set(reduced.gens).issubset(curve_params): # type: ignore[attr-defined] continue diff --git a/test/ec/test_formula.py b/test/ec/test_formula.py index 24cdc7c..f8434fd 100644 --- a/test/ec/test_formula.py +++ b/test/ec/test_formula.py @@ -139,7 +139,7 @@ def test_symbolic(secp128r1, dbl): generator_val = getattr(generator_double, outer_var).x for inner_var in coords.variables: symbolic_val = symbolic_val.subs( - inner_var, k(getattr(secp128r1.generator, inner_var).x) + inner_var, int(getattr(secp128r1.generator, inner_var).x) ) assert Mod(int(symbolic_val), p) == Mod(generator_val, p) diff --git a/test/ec/test_mod.py b/test/ec/test_mod.py index 1b9a83e..7234816 100644 --- a/test/ec/test_mod.py +++ b/test/ec/test_mod.py @@ -212,21 +212,3 @@ def test_symbolic(): r = sx * a + b assert isinstance(r, SymbolicMod) assert r.n == p - sa = SymbolicMod(a, p) - sb = SymbolicMod(b, p) - assert sa == 3 - assert sa.inverse() == SymbolicMod(k(9), p) - assert 1 / sa == SymbolicMod(k(9), p) - assert sa + sb == 8 - assert 1 + sa == 4 - assert sa - 1 == 2 - assert 1 - sa == 11 - assert sa + 1 == 4 - assert -sa == 10 - assert sa / 2 == 8 - assert 2 / sa == 5 - assert sa // 2 == 8 - assert 2 // sa == 5 - assert int(sa) == 3 - assert sa != sb - assert hash(sa) is not None |
