aboutsummaryrefslogtreecommitdiffhomepage
path: root/pyecsca/ec
diff options
context:
space:
mode:
authorJ08nY2023-08-31 18:14:16 +0200
committerJ08nY2023-08-31 18:14:16 +0200
commitc341419b7a67fe2ac1367f56e0c5a91ab551fe05 (patch)
treed53d0060ad862dabfaae9c43461c4e8ee85f19f0 /pyecsca/ec
parentb01f37d1dfaa447f53f44fb9ced1e7c39251d7de (diff)
downloadpyecsca-c341419b7a67fe2ac1367f56e0c5a91ab551fe05.tar.gz
pyecsca-c341419b7a67fe2ac1367f56e0c5a91ab551fe05.tar.zst
pyecsca-c341419b7a67fe2ac1367f56e0c5a91ab551fe05.zip
Add more curve model transformaations.
Thanks @vojtechsu.
Diffstat (limited to 'pyecsca/ec')
-rw-r--r--pyecsca/ec/configuration.py2
-rw-r--r--pyecsca/ec/params.py2
-rw-r--r--pyecsca/ec/transformations.py171
3 files changed, 137 insertions, 38 deletions
diff --git a/pyecsca/ec/configuration.py b/pyecsca/ec/configuration.py
index eb70ddc..7e90102 100644
--- a/pyecsca/ec/configuration.py
+++ b/pyecsca/ec/configuration.py
@@ -113,7 +113,7 @@ class Configuration:
@public
-def all_configurations(**kwargs) -> Generator[Configuration, Configuration, None]:
+def all_configurations(**kwargs) -> Generator[Configuration, None, None]:
"""
Get all implementation configurations that match the given `kwargs`.
diff --git a/pyecsca/ec/params.py b/pyecsca/ec/params.py
index 19ed974..54656d4 100644
--- a/pyecsca/ec/params.py
+++ b/pyecsca/ec/params.py
@@ -238,6 +238,8 @@ def _create_params(curve, coords, infty):
infinity_coords[coordinate] = value
infinity = Point(coord_model, **infinity_coords)
elliptic_curve = EllipticCurve(model, coord_model, field, infinity, params) # type: ignore[arg-type]
+ if "generator" not in curve:
+ raise ValueError("Cannot construct curve, missing generator.")
affine = Point(
AffineCoordinateModel(model),
x=Mod(int(curve["generator"]["x"]["raw"], 16), field),
diff --git a/pyecsca/ec/transformations.py b/pyecsca/ec/transformations.py
index 894421f..de1915c 100644
--- a/pyecsca/ec/transformations.py
+++ b/pyecsca/ec/transformations.py
@@ -1,16 +1,18 @@
"""Provides functions for transforming curves to different models."""
+from typing import Tuple, Generator
+
from public import public
from sympy import FF, symbols, Poly
from .coordinates import AffineCoordinateModel
from .curve import EllipticCurve
from .mod import Mod
-from .model import ShortWeierstrassModel, MontgomeryModel, TwistedEdwardsModel
+from .model import ShortWeierstrassModel, MontgomeryModel, TwistedEdwardsModel, EdwardsModel
from .params import DomainParameters
from .point import InfinityPoint, Point
-def __M_map(params, param_names, map_parameters, map_point, model):
+def __map(params, param_names, map_parameters, map_point, model):
param_one = params.curve.parameters[param_names[0]]
param_other = params.curve.parameters[param_names[1]]
parameters = map_parameters(param_one, param_other)
@@ -19,10 +21,11 @@ def __M_map(params, param_names, map_parameters, map_point, model):
neutral = InfinityPoint(aff)
else:
neutral = map_point(param_one, param_other, params.curve.neutral, aff)
+ generator = map_point(param_one, param_other, params.generator, aff)
curve = EllipticCurve(model, aff, params.curve.prime, neutral, parameters)
return DomainParameters(
curve,
- map_point(param_one, param_other, params.generator, aff),
+ generator,
params.order,
params.cofactor,
)
@@ -37,7 +40,7 @@ def M2SW(params: DomainParameters) -> DomainParameters:
:return: The converted domain parameters.
"""
if not isinstance(params.curve.model, MontgomeryModel) or not isinstance(
- params.curve.coordinate_model, AffineCoordinateModel
+ params.curve.coordinate_model, AffineCoordinateModel
):
raise ValueError
@@ -51,7 +54,7 @@ def M2SW(params: DomainParameters) -> DomainParameters:
v = pt.y / B
return Point(aff, x=u, y=v)
- return __M_map(
+ return __map(
params, ("a", "b"), map_parameters, map_point, ShortWeierstrassModel()
)
@@ -65,7 +68,7 @@ def M2TE(params: DomainParameters) -> DomainParameters:
:return: The converted domain parameters.
"""
if not isinstance(params.curve.model, MontgomeryModel) or not isinstance(
- params.curve.coordinate_model, AffineCoordinateModel
+ params.curve.coordinate_model, AffineCoordinateModel
):
raise ValueError
@@ -79,7 +82,33 @@ def M2TE(params: DomainParameters) -> DomainParameters:
v = (pt.x - 1) / (pt.x + 1)
return Point(aff, x=u, y=v)
- return __M_map(params, ("a", "b"), map_parameters, map_point, TwistedEdwardsModel())
+ return __map(params, ("a", "b"), map_parameters, map_point, TwistedEdwardsModel())
+
+
+@public
+def M2E(params: DomainParameters) -> DomainParameters:
+ """
+ Convert a Montgomery curve to Edwards.
+
+ :param params: The domain parameters to convert.
+ :return: The converted domain parameters.
+ """
+ if not isinstance(params.curve.model, MontgomeryModel) or not isinstance(
+ params.curve.coordinate_model, AffineCoordinateModel
+ ):
+ raise ValueError
+
+ def map_parameters(A, B):
+ c = (B / (A + 2)).sqrt()
+ d = (A ** 2 - 4) / (B ** 2)
+ return {"c": c, "d": d}
+
+ def map_point(A, B, pt, aff):
+ u = pt.x / pt.y
+ v = ((pt.x - 1) / (pt.x + 1)) * (B / (A + 2)).sqrt()
+ return Point(aff, x=u, y=v)
+
+ return __map(params, ("a", "b"), map_parameters, map_point, EdwardsModel())
@public
@@ -91,7 +120,7 @@ def TE2M(params: DomainParameters) -> DomainParameters:
:return: The converted domain parameters.
"""
if not isinstance(params.curve.model, TwistedEdwardsModel) or not isinstance(
- params.curve.coordinate_model, AffineCoordinateModel
+ params.curve.coordinate_model, AffineCoordinateModel
):
raise ValueError
@@ -105,19 +134,64 @@ def TE2M(params: DomainParameters) -> DomainParameters:
v = (1 + pt.y) / ((1 - pt.y) * pt.x)
return Point(aff, x=u, y=v)
- return __M_map(params, ("a", "d"), map_parameters, map_point, MontgomeryModel())
+ return __map(params, ("a", "d"), map_parameters, map_point, MontgomeryModel())
@public
-def SW2M(params: DomainParameters) -> DomainParameters:
+def TE2E(params: DomainParameters) -> DomainParameters:
"""
- Convert a ShortWeierstrass curve to Montgomery.
+ Convert a TwistedEdwards curve to Edwards.
:param params: The domain parameters to convert.
:return: The converted domain parameters.
"""
+ if not isinstance(params.curve.model, TwistedEdwardsModel) or not isinstance(
+ params.curve.coordinate_model, AffineCoordinateModel
+ ):
+ raise ValueError
+
+ def map_parameters(a, d):
+ c = a.sqrt().inverse()
+ d = a * d
+ return {"c": c, "d": d}
+
+ def map_point(a, d, pt, aff):
+ u = pt.x
+ v = pt.y / a.sqrt().inverse()
+ return Point(aff, x=u, y=v)
+
+ return __map(params, ("a", "d"), map_parameters, map_point, EdwardsModel())
+
+
+@public
+def TE2SW(params: DomainParameters) -> DomainParameters:
+ """
+ Convert a TwistedEdwards curve to ShortWeierstrass.
+
+ :param params: The domain parameters to convert.
+ :return: The converted domain parameters.
+ """
+ if not isinstance(params.curve.model, TwistedEdwardsModel) or not isinstance(
+ params.curve.coordinate_model, AffineCoordinateModel
+ ):
+ raise ValueError
+
+ def map_parameters(A, D):
+ a = -(A ** 2 + 14 * D * A + D ** 2) / 48
+ b = (A + D) * (-A ** 2 + 34 * A * D - D ** 2) / 864
+ return {"a": a, "b": b}
+
+ def map_point(A, D, pt, aff):
+ u = (5 * A + A * pt.y - 5 * D * pt.y - D) / (12 - 12 * pt.y)
+ v = (A + A * pt.y - D * pt.y - D) / (4 * pt.x - 4 * pt.x * pt.y)
+ return Point(aff, x=u, y=v)
+
+ return __map(params, ("a", "d"), map_parameters, map_point, ShortWeierstrassModel())
+
+
+def __sw_ab(params: DomainParameters) -> Generator[Tuple[Mod, Mod], None, None]:
if not isinstance(params.curve.model, ShortWeierstrassModel) or not isinstance(
- params.curve.coordinate_model, AffineCoordinateModel
+ params.curve.coordinate_model, AffineCoordinateModel
):
raise ValueError
ax = symbols("α")
@@ -132,10 +206,23 @@ def SW2M(params: DomainParameters) -> DomainParameters:
roots = rhs.ground_roots()
if not roots:
raise ValueError(
- "Curve cannot be transformed to Montgomery model (x^3 + ax + b has no root)."
+ "Curve cannot be transformed (x^3 + ax + b has no root)."
)
- alpha = Mod(int(next(iter(roots.keys()))), params.curve.prime)
- beta = (3 * alpha ** 2 + params.curve.parameters["a"]).sqrt()
+ for root in roots:
+ alpha = Mod(int(root), params.curve.prime)
+ beta = (3 * alpha ** 2 + params.curve.parameters["a"]).sqrt()
+ yield alpha, beta
+
+
+@public
+def SW2M(params: DomainParameters) -> DomainParameters:
+ """
+ Convert a ShortWeierstrass curve to Montgomery.
+
+ :param params: The domain parameters to convert.
+ :return: The converted domain parameters.
+ """
+ alpha, beta = next(iter(__sw_ab(params)))
def map_parameters(a, b):
A = (3 * alpha) / beta
@@ -147,7 +234,7 @@ def SW2M(params: DomainParameters) -> DomainParameters:
v = pt.y / beta
return Point(aff, x=u, y=v)
- return __M_map(params, ("a", "b"), map_parameters, map_point, MontgomeryModel())
+ return __map(params, ("a", "b"), map_parameters, map_point, MontgomeryModel())
@public
@@ -158,26 +245,7 @@ def SW2TE(params: DomainParameters) -> DomainParameters:
:param params: The domain parameters to convert.
:return: The converted domain parameters.
"""
- if not isinstance(params.curve.model, ShortWeierstrassModel) or not isinstance(
- params.curve.coordinate_model, AffineCoordinateModel
- ):
- raise ValueError
- ax = symbols("α")
- field = FF(params.curve.prime)
- rhs = Poly(
- ax ** 3
- + field(int(params.curve.parameters["a"])) * ax
- + field(int(params.curve.parameters["b"])),
- ax,
- domain=field,
- )
- roots = rhs.ground_roots()
- if not roots:
- raise ValueError(
- "Curve cannot be transformed to Montgomery model (x^3 + ax + b has no root)."
- )
- alpha = Mod(int(next(iter(roots.keys()))), params.curve.prime)
- beta = (3 * alpha ** 2 + params.curve.parameters["a"]).sqrt()
+ alpha, beta = next(iter(__sw_ab(params)))
def map_parameters(a, b):
a = 3 * alpha + 2 * beta
@@ -196,4 +264,33 @@ def SW2TE(params: DomainParameters) -> DomainParameters:
v = (pt.x - alpha - beta) / (pt.x - alpha + beta)
return Point(aff, x=u, y=v)
- return __M_map(params, ("a", "b"), map_parameters, map_point, TwistedEdwardsModel())
+ return __map(params, ("a", "b"), map_parameters, map_point, TwistedEdwardsModel())
+
+
+@public
+def SW2E(params: DomainParameters) -> DomainParameters:
+ """
+ Convert a ShortWeierstrass curve to Edwards.
+
+ :param params: The domain parameters to convert.
+ :return: The converted domain parameters.
+ """
+ for alpha, beta in __sw_ab(params):
+ s = beta.inverse()
+ t = (s / (3 * s * alpha + 2))
+ if not t.is_residue():
+ continue
+ t = t.sqrt()
+
+ def map_parameters(a, b):
+ c = t
+ d = -4 * a - 3 * alpha ** 2
+ return {"c": c, "d": d}
+
+ def map_point(a, b, pt, aff):
+ u = (pt.x - alpha) / pt.y
+ v = (s * (pt.x - alpha) - 1) / (s * (pt.x - alpha) + 1) * t
+ return Point(aff, x=u, y=v)
+
+ return __map(params, ("a", "b"), map_parameters, map_point, EdwardsModel())
+ raise ValueError("Cannot convert.")