aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ08nY2024-07-11 15:45:54 +0200
committerJ08nY2024-07-11 15:45:54 +0200
commit43e105655bd2de6b64ddb3c4ddf4b965bc196e6b (patch)
tree0cdb44eba00cad7d2e87a41e6c202f33578ae92a
parentb85ebefb35e2661e87a8c1be16a222bb6eae6a1f (diff)
downloadpyecsca-43e105655bd2de6b64ddb3c4ddf4b965bc196e6b.tar.gz
pyecsca-43e105655bd2de6b64ddb3c4ddf4b965bc196e6b.tar.zst
pyecsca-43e105655bd2de6b64ddb3c4ddf4b965bc196e6b.zip
-rw-r--r--docs/installation.rst2
-rw-r--r--pyecsca/ec/curve.py4
-rw-r--r--pyecsca/ec/formula/base.py32
-rw-r--r--pyecsca/ec/mod.py41
-rw-r--r--pyecsca/ec/params.py7
-rw-r--r--pyecsca/sca/re/zvp.py2
-rw-r--r--test/ec/test_formula.py2
-rw-r--r--test/ec/test_mod.py18
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