aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJ08nY2023-07-29 16:08:03 +0200
committerJ08nY2023-07-29 16:08:03 +0200
commit58b3e0f862ab13f7125d40c9360b4b348366370a (patch)
treee6dc34a67e75585ed0125e133d6c7bc8e21dc2d4
parentb003b1d2437b842beafca0f13bea368c92a422fe (diff)
downloadpyecsca-58b3e0f862ab13f7125d40c9360b4b348366370a.tar.gz
pyecsca-58b3e0f862ab13f7125d40c9360b4b348366370a.tar.zst
pyecsca-58b3e0f862ab13f7125d40c9360b4b348366370a.zip
Add ZVP formula unroll.
-rw-r--r--pyecsca/ec/formula.py1
-rw-r--r--pyecsca/ec/mod.py10
-rw-r--r--pyecsca/misc/cfg.py5
-rw-r--r--pyecsca/sca/re/zvp.py26
-rw-r--r--test/sca/test_zvp.py21
5 files changed, 55 insertions, 8 deletions
diff --git a/pyecsca/ec/formula.py b/pyecsca/ec/formula.py
index 267aba0..7855622 100644
--- a/pyecsca/ec/formula.py
+++ b/pyecsca/ec/formula.py
@@ -40,6 +40,7 @@ class OpResult:
return self.name
def __repr__(self):
+ # TODO: This repr is broken for square and neg and inv.
char = self.op.op_str
parents = char.join(str(parent) for parent in self.parents)
return f"{self.name} = {parents}"
diff --git a/pyecsca/ec/mod.py b/pyecsca/ec/mod.py
index 2d0893c..301bd70 100644
--- a/pyecsca/ec/mod.py
+++ b/pyecsca/ec/mod.py
@@ -10,7 +10,7 @@ dispatches to the implementation chosen by the runtime configuration of the libr
import random
import secrets
from functools import wraps, lru_cache
-from typing import Type, Dict, Any, Tuple, Union
+from typing import Type, Dict, Any, Tuple, Union, Optional
from public import public
from sympy import Expr, FF
@@ -564,13 +564,11 @@ class SymbolicMod(Mod):
return hash(("SymbolicMod", self.x, self.n))
def __pow__(self, n) -> "SymbolicMod":
- try:
- x = pow(self.x, n, self.n)
- except TypeError:
- x = pow(self.x, n) % self.n
- return SymbolicMod(x, self.n)
+ return self.__class__(pow(self.x, n), self.n)
+_mod_classes["symbolic"] = SymbolicMod
+
if has_gmp:
@lru_cache
diff --git a/pyecsca/misc/cfg.py b/pyecsca/misc/cfg.py
index 2affb27..ee9c95d 100644
--- a/pyecsca/misc/cfg.py
+++ b/pyecsca/misc/cfg.py
@@ -111,13 +111,14 @@ class ECConfig:
- ``"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"):
- raise ValueError("Bad Mod implementaiton, can be one of 'python' or 'gmp'.")
+ if value not in ("python", "gmp", "symbolic"):
+ raise ValueError("Bad Mod implementaiton, can be one of 'python', 'gmp' or 'symbolic'.")
self._mod_implementation = value
diff --git a/pyecsca/sca/re/zvp.py b/pyecsca/sca/re/zvp.py
new file mode 100644
index 0000000..46d4337
--- /dev/null
+++ b/pyecsca/sca/re/zvp.py
@@ -0,0 +1,26 @@
+"""
+Provides functionality inspired by the Zero-value point attack
+
+ Zero-Value Point Attacks on Elliptic Curve Cryptosystem, Toru Akishita & Tsuyoshi Takagi , ISC '03
+ `<https://doi.org/10.1007/10958513_17>`_
+"""
+
+from sympy import symbols, FF, poly
+
+from pyecsca.ec.context import DefaultContext, local
+from pyecsca.ec.formula import Formula
+from pyecsca.ec.mod import SymbolicMod
+from pyecsca.ec.point import Point
+from pyecsca.misc.cfg import TemporaryConfig
+
+
+def unroll_formula(formula: Formula, prime: int):
+ inputs = [Point(formula.coordinate_model,
+ **{var: SymbolicMod(symbols(var + str(i)), prime) for var in formula.coordinate_model.variables})
+ for i in
+ range(1, 1 + formula.num_inputs)]
+ params = {var: SymbolicMod(symbols(var), prime) for var in formula.coordinate_model.curve_model.parameter_names}
+ with local(DefaultContext()) as ctx, TemporaryConfig() as cfg:
+ cfg.ec.mod_implementation = "symbolic"
+ formula(prime, *inputs, **params)
+ return [op_result.value for op_result in ctx.actions.get_by_index([0])[0].op_results]
diff --git a/test/sca/test_zvp.py b/test/sca/test_zvp.py
new file mode 100644
index 0000000..a6ce015
--- /dev/null
+++ b/test/sca/test_zvp.py
@@ -0,0 +1,21 @@
+from unittest import TestCase
+
+from pyecsca.ec.model import ShortWeierstrassModel
+from pyecsca.sca.re.zvp import unroll_formula
+
+
+class ZVPTests(TestCase):
+ def setUp(self):
+ self.model = ShortWeierstrassModel()
+ self.coords = self.model.coordinates["projective"]
+ self.add = self.coords.formulas["add-2007-bl"]
+ self.dbl = self.coords.formulas["dbl-2007-bl"]
+ self.neg = self.coords.formulas["neg"]
+
+ def test_unroll(self):
+ results = unroll_formula(self.add, 11)
+ self.assertIsNotNone(results)
+ results = unroll_formula(self.dbl, 11)
+ self.assertIsNotNone(results)
+ results = unroll_formula(self.neg, 11)
+ self.assertIsNotNone(results)