aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ08nY2020-02-10 20:39:53 +0100
committerJ08nY2020-02-10 20:39:53 +0100
commit4e2bd346baf2db39391deb49e9bdb9d89f94101a (patch)
treef72098033d15ba5ce2e5848a4f744b0a8b6d9c82
parent16c93caa5762158999abdcb00ed5e4ddac12cafb (diff)
downloadpyecsca-4e2bd346baf2db39391deb49e9bdb9d89f94101a.tar.gz
pyecsca-4e2bd346baf2db39391deb49e9bdb9d89f94101a.tar.bz2
pyecsca-4e2bd346baf2db39391deb49e9bdb9d89f94101a.zip
Use std-curves database submodule instead of hard-coding standard curves.
-rw-r--r--.gitmodules4
-rw-r--r--MANIFEST.in3
-rw-r--r--Makefile2
-rw-r--r--pyecsca/ec/coordinates.py7
-rw-r--r--pyecsca/ec/curves.py92
-rw-r--r--pyecsca/ec/model.py5
m---------pyecsca/ec/std0
-rw-r--r--setup.py2
-rw-r--r--test/ec/test_context.py4
-rw-r--r--test/ec/test_curve.py23
-rw-r--r--test/ec/test_curves.py33
-rw-r--r--test/ec/test_key_agreement.py10
-rw-r--r--test/ec/test_mult.py20
-rw-r--r--test/ec/test_params.py6
-rw-r--r--test/ec/test_point.py4
-rw-r--r--test/ec/test_signature.py4
16 files changed, 130 insertions, 89 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..f5b2455
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,4 @@
+[submodule "pyecsca/ec/std"]
+ path = pyecsca/ec/std
+ url = https://github.com/J08nY/std-curves
+ branch = data
diff --git a/MANIFEST.in b/MANIFEST.in
index 50b7161..b3ff14f 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,2 +1,3 @@
include README.md
-graft pyecsca/ec/efd/ \ No newline at end of file
+graft pyecsca/ec/efd/
+graft pyecsca/ec/std/ \ No newline at end of file
diff --git a/Makefile b/Makefile
index 691556c..ad8fd0f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-EC_TESTS = ec.test_context ec.test_curve ec.test_params ec.test_key_agreement ec.test_mod ec.test_model \
+EC_TESTS = ec.test_context ec.test_curve ec.test_curves ec.test_params ec.test_key_agreement ec.test_mod ec.test_model \
ec.test_mult ec.test_naf ec.test_op ec.test_point ec.test_signature
SCA_TESTS = sca.test_align sca.test_combine sca.test_edit sca.test_filter sca.test_match sca.test_process \
diff --git a/pyecsca/ec/coordinates.py b/pyecsca/ec/coordinates.py
index 89452c9..cfb65e2 100644
--- a/pyecsca/ec/coordinates.py
+++ b/pyecsca/ec/coordinates.py
@@ -1,5 +1,6 @@
from ast import parse, Expression, Module
-from typing import List, Any, MutableMapping, Union
+from typing import List, Any, MutableMapping
+from os.path import join
from pkg_resources import resource_listdir, resource_isdir, resource_stream
@@ -52,7 +53,7 @@ class EFDCoordinateModel(CoordinateModel):
self.assumptions = []
self.formulas = {}
for fname in resource_listdir(__name__, dir_path):
- file_path = dir_path + "/" + fname
+ file_path = join(dir_path, fname)
if resource_isdir(__name__, file_path):
self.__read_formula_dir(file_path, fname)
else:
@@ -72,7 +73,7 @@ class EFDCoordinateModel(CoordinateModel):
"negation": NegationEFDFormula
}
cls = formula_types.get(formula_type, EFDFormula)
- self.formulas[fname] = cls(dir_path + "/" + fname, fname, self)
+ self.formulas[fname] = cls(join(dir_path, fname), fname, self)
def __read_coordinates_file(self, file_path):
with resource_stream(__name__, file_path) as f:
diff --git a/pyecsca/ec/curves.py b/pyecsca/ec/curves.py
index 1bb2161..d490b74 100644
--- a/pyecsca/ec/curves.py
+++ b/pyecsca/ec/curves.py
@@ -1,15 +1,18 @@
-from public import public
+import json
+from os.path import join
from typing import Mapping, Any
+from pkg_resources import resource_listdir, resource_isdir, resource_stream
+from public import public
+
from .coordinates import AffineCoordinateModel
from .curve import EllipticCurve
-from .params import DomainParameters
from .mod import Mod
from .model import (ShortWeierstrassModel, MontgomeryModel, TwistedEdwardsModel,
EdwardsModel, CurveModel)
+from .params import DomainParameters
from .point import Point, InfinityPoint
-
SHORT_WEIERSTRASS: Mapping[str, Mapping[str, Any]] = {
"brainpoolP160r1": {
"p": 0xE95E4A5F737059DC60DFC7AD95B3D8139515620F,
@@ -167,11 +170,12 @@ MONTGOMERY: Mapping[str, Mapping[str, Any]] = {
EDWARDS: Mapping[str, Mapping[str, Any]] = {
"ed448": {
- "p": 2**448 - 2**224 - 1,
+ "p": 2 ** 448 - 2 ** 224 - 1,
"c": 1,
"d": 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffff6756,
- "g": (0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa955555555555555555555555555555555555555555555555555555555,
- 0xae05e9634ad7048db359d6205086c2b0036ed7a035884dd7b7e36d728ad8c4b80d6565833a2a3098bbbcb2bed1cda06bdaeafbcdea9386ed),
+ "g": (
+ 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa955555555555555555555555555555555555555555555555555555555,
+ 0xae05e9634ad7048db359d6205086c2b0036ed7a035884dd7b7e36d728ad8c4b80d6565833a2a3098bbbcb2bed1cda06bdaeafbcdea9386ed),
"n": 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3,
"h": 4
}
@@ -191,49 +195,55 @@ TWISTED_EDWARDS: Mapping[str, Mapping[str, Any]] = {
@public
-def get_curve(name: str, coords: str) -> DomainParameters:
+def get_params(category: str, name: str, coords: str) -> DomainParameters:
"""
- Retrieve a curve from a set of stored parameters.
+ Retrieve a curve from a set of stored parameters. Uses the std-curves database at
+ https://github.com/J08nY/std-curves.
+ :param category: The category of the curve.
:param name: The name of the curve.
:param coords: The name of the coordinate system to use.
:return: The curve.
"""
+ listing = resource_listdir(__name__, "std")
+ categories = list(entry for entry in listing if resource_isdir(__name__, join("std", entry)))
+ if category not in categories:
+ raise ValueError("Category {} not found.".format(category))
+ json_path = join("std", category, "curves.json")
+ with resource_stream(__name__, json_path) as f:
+ category_json = json.load(f)
+ for curve in category_json["curves"]:
+ if curve["name"] == name:
+ break
+ else:
+ raise ValueError("Curve {} not found in category {}.".format(name, category))
+ if curve["field"]["type"] == "Binary":
+ raise ValueError("Binary field curves are currently not supported.")
+
model: CurveModel
- if name in SHORT_WEIERSTRASS:
- params = SHORT_WEIERSTRASS[name]
+ field = int(curve["field"]["p"], 16)
+ order = int(curve["order"], 16)
+ cofactor = int(curve["cofactor"], 16)
+ if curve["form"] == "Weierstrass":
model = ShortWeierstrassModel()
- coord_model = model.coordinates[coords]
- curve = EllipticCurve(model, coord_model, params["p"], dict(a=params["a"], b=params["b"]))
- affine = Point(AffineCoordinateModel(model), x=Mod(params["g"][0], params["p"]),
- y=Mod(params["g"][1], params["p"]))
- generator = Point.from_affine(coord_model, affine)
- return DomainParameters(curve, generator, InfinityPoint(coord_model), params["n"], params["h"])
- elif name in MONTGOMERY:
- params = MONTGOMERY[name]
+ param_names = ["a", "b"]
+ elif curve["form"] == "Montgomery":
model = MontgomeryModel()
- coord_model = model.coordinates[coords]
- curve = EllipticCurve(model, coord_model, params["p"], dict(a=params["a"], b=params["b"]))
- generator = Point(coord_model, X=Mod(params["x"], params["p"]),
- Z=Mod(params["z"], params["p"]))
- return DomainParameters(curve, generator, InfinityPoint(coord_model), params["n"], params["h"])
- elif name in TWISTED_EDWARDS:
- params = TWISTED_EDWARDS[name]
- model = TwistedEdwardsModel()
- coord_model = model.coordinates[coords]
- curve = EllipticCurve(model, coord_model, params["p"], dict(a=params["a"], d=params["d"]))
- affine = Point(AffineCoordinateModel(model), x=Mod(params["g"][0], params["p"]),
- y=Mod(params["g"][1], params["p"]))
- generator = Point.from_affine(coord_model, affine)
- return DomainParameters(curve, generator, InfinityPoint(coord_model), params["n"], params["h"])
- elif name in EDWARDS:
- params = EDWARDS[name]
+ param_names = ["a", "b"]
+ elif curve["form"] == "Edwards":
model = EdwardsModel()
- coord_model = model.coordinates[coords]
- curve = EllipticCurve(model, coord_model, params["p"], dict(c=params["c"], d=params["d"]))
- affine = Point(AffineCoordinateModel(model), x=Mod(params["g"][0], params["p"]),
- y=Mod(params["g"][1], params["p"]))
- generator = Point.from_affine(coord_model, affine)
- return DomainParameters(curve, generator, InfinityPoint(coord_model), params["n"], params["h"])
+ param_names = ["c", "d"]
+ elif curve["form"] == "TwistedEdwards":
+ model = TwistedEdwardsModel()
+ param_names = ["a", "d"]
else:
- raise ValueError("Unknown curve: {}".format(name))
+ raise ValueError("Unknown curve model.")
+ if coords not in model.coordinates:
+ raise ValueError("Coordinate model not supported for curve.")
+ coord_model = model.coordinates[coords]
+ params = {name: int(curve["params"][name], 16) for name in param_names}
+ elliptic_curve = EllipticCurve(model, coord_model, field, params)
+ affine = Point(AffineCoordinateModel(model), x=Mod(int(curve["generator"]["x"], 16), field),
+ y=Mod(int(curve["generator"]["y"], 16), field))
+ generator = Point.from_affine(coord_model, affine)
+ return DomainParameters(elliptic_curve, generator, InfinityPoint(coord_model), order, cofactor)
diff --git a/pyecsca/ec/model.py b/pyecsca/ec/model.py
index a313a00..dba083e 100644
--- a/pyecsca/ec/model.py
+++ b/pyecsca/ec/model.py
@@ -1,4 +1,5 @@
from ast import parse, Expression, Module
+from os.path import join
from pkg_resources import resource_listdir, resource_isdir, resource_stream
from public import public
from typing import List, MutableMapping
@@ -46,9 +47,9 @@ class EFDCurveModel(CurveModel):
self.__class__.to_weierstrass = []
self.__class__.from_weierstrass = []
- files = resource_listdir(__name__, "efd/" + efd_name)
+ files = resource_listdir(__name__, join("efd", efd_name))
for fname in files:
- file_path = "efd/" + efd_name + "/" + fname
+ file_path = join("efd", efd_name, fname)
if resource_isdir(__name__, file_path):
self.__read_coordinate_dir(self.__class__, file_path, fname)
else:
diff --git a/pyecsca/ec/std b/pyecsca/ec/std
new file mode 160000
+Subproject 1d6b91fba61c791b5371b003800f3849d5aaae2
diff --git a/setup.py b/setup.py
index dbb4d49..1f1bffa 100644
--- a/setup.py
+++ b/setup.py
@@ -21,7 +21,7 @@ setup(
"Intended Audience :: Science/Research"
],
package_data={
- "pyecsca.ec" : ["efd/*/*", "efd/*/*/*", "efd/*/*/*/*"]
+ "pyecsca.ec" : ["efd/*/*", "efd/*/*/*", "efd/*/*/*/*", "std/*", "std/*/*"]
},
#install_package_data=True,
python_requires='>=3.8',
diff --git a/test/ec/test_context.py b/test/ec/test_context.py
index ceecf2c..6b9c526 100644
--- a/test/ec/test_context.py
+++ b/test/ec/test_context.py
@@ -5,7 +5,7 @@ from pyecsca.ec.context import (local, DefaultContext, OpResult, NullContext, ge
setcontext,
resetcontext)
from pyecsca.ec.coordinates import AffineCoordinateModel
-from pyecsca.ec.curves import get_curve
+from pyecsca.ec.curves import get_params
from pyecsca.ec.mod import Mod
from pyecsca.ec.mult import LTRMultiplier
from pyecsca.ec.point import Point
@@ -22,7 +22,7 @@ class OpResultTests(TestCase):
class ContextTests(TestCase):
def setUp(self):
- self.secp128r1 = get_curve("secp128r1", "projective")
+ self.secp128r1 = get_params("secg", "secp128r1", "projective")
self.base = self.secp128r1.generator
self.coords = self.secp128r1.curve.coordinate_model
self.mult = LTRMultiplier(self.coords.formulas["add-1998-cmo"],
diff --git a/test/ec/test_curve.py b/test/ec/test_curve.py
index 1f2ca1f..a68edcf 100644
--- a/test/ec/test_curve.py
+++ b/test/ec/test_curve.py
@@ -1,9 +1,7 @@
from unittest import TestCase
-from parameterized import parameterized
-
from pyecsca.ec.curve import EllipticCurve
-from pyecsca.ec.curves import get_curve
+from pyecsca.ec.curves import get_params
from pyecsca.ec.mod import Mod
from pyecsca.ec.model import MontgomeryModel
from pyecsca.ec.point import Point
@@ -11,9 +9,9 @@ from pyecsca.ec.point import Point
class CurveTests(TestCase):
def setUp(self):
- self.secp128r1 = get_curve("secp128r1", "projective")
+ self.secp128r1 = get_params("secg", "secp128r1", "projective")
self.base = self.secp128r1.generator
- self.curve25519 = get_curve("curve25519", "xz")
+ self.curve25519 = get_params("other", "Curve25519", "xz")
def test_init(self):
with self.assertRaises(ValueError):
@@ -41,21 +39,6 @@ class CurveTests(TestCase):
Z=Mod(1, self.secp128r1.curve.prime))
assert not self.secp128r1.curve.is_on_curve(other)
- @parameterized.expand([
- ("secp128r1","projective"),
- ("secp256r1", "projective"),
- ("secp521r1", "projective"),
- ("curve25519", "xz"),
- ("ed25519", "projective"),
- ("ed448", "projective")
- ])
- def test_curve_utils(self, name, coords):
- group = get_curve(name, coords)
- try:
- assert group.curve.is_on_curve(group.generator)
- except NotImplementedError:
- pass
-
def test_eq(self):
self.assertEqual(self.secp128r1.curve, self.secp128r1.curve)
self.assertNotEqual(self.secp128r1.curve, self.curve25519.curve)
diff --git a/test/ec/test_curves.py b/test/ec/test_curves.py
new file mode 100644
index 0000000..1f6a117
--- /dev/null
+++ b/test/ec/test_curves.py
@@ -0,0 +1,33 @@
+from unittest import TestCase
+
+from parameterized import parameterized
+
+from pyecsca.ec.curves import get_params
+
+
+class CurvesTests(TestCase):
+
+ @parameterized.expand([
+ ("secg/secp128r1", "projective"),
+ ("secg/secp256r1", "projective"),
+ ("secg/secp521r1", "projective"),
+ ("other/Curve25519", "xz"),
+ ("other/Ed25519", "projective"),
+ ("other/Ed448", "projective"),
+ ("other/E-222", "projective")
+ ])
+ def test_get_params(self, name, coords):
+ group = get_params(*name.split("/"), coords)
+ try:
+ assert group.curve.is_on_curve(group.generator)
+ except NotImplementedError:
+ pass
+
+ @parameterized.expand([
+ ("no_category/some", "else"),
+ ("secg/no_curve", "else"),
+ ("secg/secp128r1", "some")
+ ])
+ def test_unknown(self, name, coords):
+ with self.assertRaises(ValueError):
+ get_params(*name.split("/"), coords) \ No newline at end of file
diff --git a/test/ec/test_key_agreement.py b/test/ec/test_key_agreement.py
index 3acb070..b771863 100644
--- a/test/ec/test_key_agreement.py
+++ b/test/ec/test_key_agreement.py
@@ -1,14 +1,16 @@
from unittest import TestCase
-from pyecsca.ec.curves import get_curve
+from parameterized import parameterized
+
+from pyecsca.ec.curves import get_params
from pyecsca.ec.key_agreement import *
from pyecsca.ec.mult import LTRMultiplier
-from parameterized import parameterized
+
class KeyAgreementTests(TestCase):
def setUp(self):
- self.secp128r1 = get_curve("secp128r1", "projective")
+ self.secp128r1 = get_params("secg", "secp128r1", "projective")
self.add = self.secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
self.dbl = self.secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
self.mult = LTRMultiplier(self.add, self.dbl)
@@ -30,3 +32,5 @@ class KeyAgreementTests(TestCase):
result_ab = algo(self.mult, self.secp128r1, self.pub_a, self.priv_b).perform()
result_ba = algo(self.mult, self.secp128r1, self.pub_b, self.priv_a).perform()
self.assertEqual(result_ab, result_ba)
+
+ # TODO: Add KAT-based tests here.
diff --git a/test/ec/test_mult.py b/test/ec/test_mult.py
index 6d6b3ec..2f4308e 100644
--- a/test/ec/test_mult.py
+++ b/test/ec/test_mult.py
@@ -1,7 +1,8 @@
from unittest import TestCase
from parameterized import parameterized
-from pyecsca.ec.curves import get_curve
+
+from pyecsca.ec.curves import get_params
from pyecsca.ec.mult import (LTRMultiplier, RTLMultiplier, LadderMultiplier, BinaryNAFMultiplier,
WindowNAFMultiplier, SimpleLadderMultiplier,
DifferentialLadderMultiplier,
@@ -12,11 +13,11 @@ from pyecsca.ec.point import InfinityPoint
class ScalarMultiplierTests(TestCase):
def setUp(self):
- self.secp128r1 = get_curve("secp128r1", "projective")
+ self.secp128r1 = get_params("secg", "secp128r1", "projective")
self.base = self.secp128r1.generator
self.coords = self.secp128r1.curve.coordinate_model
- self.curve25519 = get_curve("curve25519", "xz")
+ self.curve25519 = get_params("other", "Curve25519", "xz")
self.base25519 = self.curve25519.generator
self.coords25519 = self.curve25519.curve.coordinate_model
@@ -30,7 +31,8 @@ class ScalarMultiplierTests(TestCase):
assert one.equals(other)
def do_basic_test(self, mult_class, group, base, add, dbl, scale, neg=None, **kwargs):
- mult = mult_class(*self.get_formulas(group.curve.coordinate_model, add, dbl, neg, scale), **kwargs)
+ mult = mult_class(*self.get_formulas(group.curve.coordinate_model, add, dbl, neg, scale),
+ **kwargs)
mult.init(group, base)
res = mult.multiply(314)
other = mult.multiply(157)
@@ -54,8 +56,10 @@ class ScalarMultiplierTests(TestCase):
def test_ltr(self, name, add, dbl, scale):
self.do_basic_test(LTRMultiplier, self.secp128r1, self.base, add, dbl, scale)
self.do_basic_test(LTRMultiplier, self.secp128r1, self.base, add, dbl, scale, always=True)
- self.do_basic_test(LTRMultiplier, self.secp128r1, self.base, add, dbl, scale, complete=False)
- self.do_basic_test(LTRMultiplier, self.secp128r1, self.base, add, dbl, scale, always=True, complete=False)
+ self.do_basic_test(LTRMultiplier, self.secp128r1, self.base, add, dbl, scale,
+ complete=False)
+ self.do_basic_test(LTRMultiplier, self.secp128r1, self.base, add, dbl, scale, always=True,
+ complete=False)
@parameterized.expand([
("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"),
@@ -86,8 +90,8 @@ class ScalarMultiplierTests(TestCase):
self.coords25519.formulas["dbl-1987-m"],
self.coords25519.formulas["scale"])
differential = DifferentialLadderMultiplier(self.coords25519.formulas["dadd-1987-m"],
- self.coords25519.formulas["dbl-1987-m"],
- self.coords25519.formulas["scale"])
+ self.coords25519.formulas["dbl-1987-m"],
+ self.coords25519.formulas["scale"])
ladder.init(self.curve25519, self.base25519)
res_ladder = ladder.multiply(num)
differential.init(self.curve25519, self.base25519)
diff --git a/test/ec/test_params.py b/test/ec/test_params.py
index 222698d..da293f4 100644
--- a/test/ec/test_params.py
+++ b/test/ec/test_params.py
@@ -1,14 +1,14 @@
from unittest import TestCase
-from pyecsca.ec.curves import get_curve
+from pyecsca.ec.curves import get_params
from pyecsca.ec.point import InfinityPoint
class DomainParameterTests(TestCase):
def setUp(self):
- self.secp128r1 = get_curve("secp128r1", "projective")
- self.curve25519 = get_curve("curve25519", "xz")
+ self.secp128r1 = get_params("secg", "secp128r1", "projective")
+ self.curve25519 = get_params("other", "Curve25519", "xz")
def test_is_neutral(self):
assert self.secp128r1.is_neutral(InfinityPoint(self.secp128r1.curve.coordinate_model))
diff --git a/test/ec/test_point.py b/test/ec/test_point.py
index 0809edc..76e1103 100644
--- a/test/ec/test_point.py
+++ b/test/ec/test_point.py
@@ -1,7 +1,7 @@
from unittest import TestCase
from pyecsca.ec.coordinates import AffineCoordinateModel
-from pyecsca.ec.curves import get_curve
+from pyecsca.ec.curves import get_params
from pyecsca.ec.mod import Mod
from pyecsca.ec.model import ShortWeierstrassModel, MontgomeryModel
from pyecsca.ec.point import Point, InfinityPoint
@@ -9,7 +9,7 @@ from pyecsca.ec.point import Point, InfinityPoint
class PointTests(TestCase):
def setUp(self):
- self.secp128r1 = get_curve("secp128r1", "projective")
+ self.secp128r1 = get_params("secg", "secp128r1", "projective")
self.base = self.secp128r1.generator
self.coords = self.secp128r1.curve.coordinate_model
self.affine = AffineCoordinateModel(ShortWeierstrassModel())
diff --git a/test/ec/test_signature.py b/test/ec/test_signature.py
index b7cccec..41e9df2 100644
--- a/test/ec/test_signature.py
+++ b/test/ec/test_signature.py
@@ -1,7 +1,7 @@
from hashlib import sha1
from unittest import TestCase
-from pyecsca.ec.curves import get_curve
+from pyecsca.ec.curves import get_params
from pyecsca.ec.mult import LTRMultiplier
from pyecsca.ec.signature import *
from parameterized import parameterized
@@ -9,7 +9,7 @@ from parameterized import parameterized
class SignatureTests(TestCase):
def setUp(self):
- self.secp128r1 = get_curve("secp128r1", "projective")
+ self.secp128r1 = get_params("secg", "secp128r1", "projective")
self.add = self.secp128r1.curve.coordinate_model.formulas["add-2007-bl"]
self.dbl = self.secp128r1.curve.coordinate_model.formulas["dbl-2007-bl"]
self.mult = LTRMultiplier(self.add, self.dbl)