diff options
| author | J08nY | 2020-02-10 20:39:53 +0100 |
|---|---|---|
| committer | J08nY | 2020-02-10 20:39:53 +0100 |
| commit | 4e2bd346baf2db39391deb49e9bdb9d89f94101a (patch) | |
| tree | f72098033d15ba5ce2e5848a4f744b0a8b6d9c82 | |
| parent | 16c93caa5762158999abdcb00ed5e4ddac12cafb (diff) | |
| download | pyecsca-4e2bd346baf2db39391deb49e9bdb9d89f94101a.tar.gz pyecsca-4e2bd346baf2db39391deb49e9bdb9d89f94101a.tar.zst pyecsca-4e2bd346baf2db39391deb49e9bdb9d89f94101a.zip | |
| -rw-r--r-- | .gitmodules | 4 | ||||
| -rw-r--r-- | MANIFEST.in | 3 | ||||
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | pyecsca/ec/coordinates.py | 7 | ||||
| -rw-r--r-- | pyecsca/ec/curves.py | 92 | ||||
| -rw-r--r-- | pyecsca/ec/model.py | 5 | ||||
| m--------- | pyecsca/ec/std | 0 | ||||
| -rw-r--r-- | setup.py | 2 | ||||
| -rw-r--r-- | test/ec/test_context.py | 4 | ||||
| -rw-r--r-- | test/ec/test_curve.py | 23 | ||||
| -rw-r--r-- | test/ec/test_curves.py | 33 | ||||
| -rw-r--r-- | test/ec/test_key_agreement.py | 10 | ||||
| -rw-r--r-- | test/ec/test_mult.py | 20 | ||||
| -rw-r--r-- | test/ec/test_params.py | 6 | ||||
| -rw-r--r-- | test/ec/test_point.py | 4 | ||||
| -rw-r--r-- | test/ec/test_signature.py | 4 |
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 @@ -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 @@ -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) |
