diff options
| -rw-r--r-- | .coveragerc | 4 | ||||
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | pyecsca/ec/curves.py | 238 | ||||
| -rw-r--r-- | test/ec/curves.py | 29 | ||||
| -rw-r--r-- | test/ec/test_context.py | 9 | ||||
| -rw-r--r-- | test/ec/test_curve.py | 28 | ||||
| -rw-r--r-- | test/ec/test_group.py | 7 | ||||
| -rw-r--r-- | test/ec/test_key_agreement.py | 4 | ||||
| -rw-r--r-- | test/ec/test_mult.py | 140 | ||||
| -rw-r--r-- | test/ec/test_op.py | 32 | ||||
| -rw-r--r-- | test/ec/test_point.py | 13 | ||||
| -rw-r--r-- | test/ec/test_signature.py | 4 | ||||
| -rw-r--r-- | test/sca/test_traceset.py | 1 |
13 files changed, 404 insertions, 107 deletions
diff --git a/.coveragerc b/.coveragerc index 014d16f..fedfb33 100644 --- a/.coveragerc +++ b/.coveragerc @@ -6,8 +6,10 @@ omit = [report] exclude_lines = + __repr__ pragma: no cover raise AssertionError raise NotImplementedError if 0: - if __name__ == .__main__.:
\ No newline at end of file + if __name__ == .__main__.: + \.\.\.$
\ No newline at end of file @@ -1,5 +1,5 @@ EC_TESTS = ec.test_context ec.test_curve ec.test_group ec.test_key_agreement ec.test_mod ec.test_model \ -ec.test_mult ec.test_naf ec.test_point ec.test_signature +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 \ sca.test_sampling sca.test_test sca.test_trace sca.test_traceset diff --git a/pyecsca/ec/curves.py b/pyecsca/ec/curves.py new file mode 100644 index 0000000..de919b8 --- /dev/null +++ b/pyecsca/ec/curves.py @@ -0,0 +1,238 @@ +from public import public +from typing import Mapping, Any + +from pyecsca.ec.coordinates import AffineCoordinateModel +from pyecsca.ec.curve import EllipticCurve +from pyecsca.ec.group import AbelianGroup +from pyecsca.ec.mod import Mod +from pyecsca.ec.model import (ShortWeierstrassModel, MontgomeryModel, TwistedEdwardsModel, + EdwardsModel) +from pyecsca.ec.point import Point, InfinityPoint + + +SHORT_WEIERSTRASS: Mapping[str, Mapping[str, Any]] = { + "brainpoolP160r1": { + "p": 0xE95E4A5F737059DC60DFC7AD95B3D8139515620F, + "a": 0x340E7BE2A280EB74E2BE61BADA745D97E8F7C300, + "b": 0x1E589A8595423412134FAA2DBDEC95C8D8675E58, + "g": (0xBED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC3, + 0x1667CB477A1A8EC338F94741669C976316DA6321), + "n": 0xE95E4A5F737059DC60DF5991D45029409E60FC09, + "h": 0x1}, + "brainpoolP192r1": { + "p": 0xC302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297, + "a": 0x6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF, + "b": 0x469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9, + "g": (0xC0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD6, + 0x14B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F), + "n": 0xC302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1, + "h": 0x1}, + "brainpoolP224r1": { + "p": 0xD7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF, + "a": 0x68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43, + "b": 0x2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B, + "g": (0x0D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D, + 0x58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD), + "n": 0xD7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F, + "h": 0x1}, + "brainpoolP256r1": { + "p": 0xA9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377, + "a": 0x7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9, + "b": 0x26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6, + "g": (0x8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262, + 0x547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997), + "n": 0xA9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7, + "h": 0x1}, + "brainpoolP320r1": { + "p": 0xD35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27, + "a": 0x3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4, + "b": 0x520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6, + "g": ( + 0x43BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E20611, + 0x14FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1), + "n": 0xD35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311, + "h": 0x1}, + "brainpoolP384r1": { + "p": 0x8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53, + "a": 0x7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826, + "b": 0x04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11, + "g": ( + 0x1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E, + 0x8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315), + "n": 0x8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565, + "h": 0x1}, + "brainpoolP512r1": { + "p": 0xAADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3, + "a": 0x7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA, + "b": 0x3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723, + "g": ( + 0x81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822, + 0x7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892), + "n": 0xAADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069, + "h": 0x1}, + "secp128r1": { + "p": 0xfffffffdffffffffffffffffffffffff, + "a": 0xfffffffdfffffffffffffffffffffffc, + "b": 0xe87579c11079f43dd824993c2cee5ed3, + "g": (0x161ff7528b899b2d0c28607ca52c5b86, + 0xcf5ac8395bafeb13c02da292dded7a83), + "n": 0xfffffffe0000000075a30d1b9038a115, + "h": 0x1}, + "secp128r2": { + "p": 0xfffffffdffffffffffffffffffffffff, + "a": 0xd6031998d1b3bbfebf59cc9bbff9aee1, + "b": 0x5eeefca380d02919dc2c6558bb6d8a5d, + "g": (0x7b6aa5d85e572983e6fb32a7cdebc140, + 0x27b6916a894d3aee7106fe805fc34b44), + "n": 0x3fffffff7fffffffbe0024720613b5a3, + "h":0x4}, + "secp160k1": { + "p": 0xfffffffffffffffffffffffffffffffeffffac73, + "a": 0x0000000000000000000000000000000000000000, + "b": 0x0000000000000000000000000000000000000007, + "g": (0x3b4c382ce37aa192a4019e763036f4f5dd4d7ebb, + 0x938cf935318fdced6bc28286531733c3f03c4fee), + "n": 0x0100000000000000000001b8fa16dfab9aca16b6b3, + "h": 0x1}, + "secp160r1": { + "p": 0xffffffffffffffffffffffffffffffff7fffffff, + "a": 0xffffffffffffffffffffffffffffffff7ffffffc, + "b": 0x1c97befc54bd7a8b65acf89f81d4d4adc565fa45, + "g": (0x4a96b5688ef573284664698968c38bb913cbfc82, + 0x23a628553168947d59dcc912042351377ac5fb32), + "n": 0x0100000000000000000001f4c8f927aed3ca752257, + "h": 0x1}, + "secp160r2": { + "p": 0xfffffffffffffffffffffffffffffffeffffac73, + "a": 0xfffffffffffffffffffffffffffffffeffffac70, + "b": 0xb4e134d3fb59eb8bab57274904664d5af50388ba, + "g": (0x52dcb034293a117e1f4ff11b30f7199d3144ce6d, + 0xfeaffef2e331f296e071fa0df9982cfea7d43f2e), + "n": 0x0100000000000000000000351ee786a818f3a1a16b, + "h": 0x1}, + "secp192r1": { + "p": 0xfffffffffffffffffffffffffffffffeffffffffffffffff, + "a": 0xfffffffffffffffffffffffffffffffefffffffffffffffc, + "b": 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1, + "g": (0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012, + 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811), + "n": 0xffffffffffffffffffffffff99def836146bc9b1b4d22831, + "h": 0x1}, + "secp224r1": { + "p": 0xffffffffffffffffffffffffffffffff000000000000000000000001, + "a": 0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe, + "b": 0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4, + "g": (0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21, + 0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34), + "n": 0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d, + "h": 0x1}, + "secp256r1": { + "p": 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff, + "a": 0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc, + "b": 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b, + "g": (0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296, + 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5), + "n": 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551, + "h": 0x1}, + "secp384r1": { + "p": 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff, + "a": 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc, + "b": 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef, + "g": ( + 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7, + 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f), + "n": 0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973, + "h": 0x1}, + "secp521r1": { + "p": 0x000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, + "a": 0x000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc, + "b": 0x00000051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00, + "g": ( + 0x000000c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66, + 0x0000011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650), + "n": 0x000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409, + "h": 0x1}} + +MONTGOMERY: Mapping[str, Mapping[str, Any]] = { + "curve25519": { + "p": 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed, + "a": 486662, + "b": 1, + "x": 9, + "z": 1, + "n": 0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED, + "h": 2 + } +} + +EDWARDS: Mapping[str, Mapping[str, Any]] = { + "ed448": { + "p": 2**448 - 2**224 - 1, + "c": 1, + "d": 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffff6756, + "g": (0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa955555555555555555555555555555555555555555555555555555555, + 0xae05e9634ad7048db359d6205086c2b0036ed7a035884dd7b7e36d728ad8c4b80d6565833a2a3098bbbcb2bed1cda06bdaeafbcdea9386ed), + "n": 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3, + "h": 4 + } +} + +TWISTED_EDWARDS: Mapping[str, Mapping[str, Any]] = { + "ed25519": { + "p": 2 ** 255 - 19, + "d": 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3, + "a": -1, + "g": (0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a, + 0x6666666666666666666666666666666666666666666666666666666666666658), + "n": 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed, + "h": 2 + } +} + + +@public +def get_curve(name: str, coords: str) -> AbelianGroup: + """ + Retrieve a curve from a set of stored parameters. + + :param name: The name of the curve. + :param coords: The name of the coordinate system to use. + :return: The curve. + """ + if name in SHORT_WEIERSTRASS: + params = SHORT_WEIERSTRASS[name] + 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 AbelianGroup(curve, generator, InfinityPoint(coord_model), params["n"], params["h"]) + elif name in MONTGOMERY: + params = MONTGOMERY[name] + 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 AbelianGroup(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 AbelianGroup(curve, generator, InfinityPoint(coord_model), params["n"], params["h"]) + elif name in EDWARDS: + params = EDWARDS[name] + 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 AbelianGroup(curve, generator, InfinityPoint(coord_model), params["n"], params["h"]) + else: + raise ValueError("Unknown curve: {}".format(name)) diff --git a/test/ec/curves.py b/test/ec/curves.py deleted file mode 100644 index c7453c7..0000000 --- a/test/ec/curves.py +++ /dev/null @@ -1,29 +0,0 @@ -from pyecsca.ec.curve import EllipticCurve -from pyecsca.ec.group import AbelianGroup -from pyecsca.ec.mod import Mod -from pyecsca.ec.model import ShortWeierstrassModel, MontgomeryModel -from pyecsca.ec.point import Point, InfinityPoint - - -def get_secp128r1(): - prime = 0xfffffffdffffffffffffffffffffffff - model = ShortWeierstrassModel() - coords = model.coordinates["projective"] - curve = EllipticCurve(model, coords, prime, dict(a=0xfffffffdfffffffffffffffffffffffc, - b=0xe87579c11079f43dd824993c2cee5ed3)) - return AbelianGroup(curve, Point(coords, X=Mod(0x161ff7528b899b2d0c28607ca52c5b86, prime), - Y=Mod(0xcf5ac8395bafeb13c02da292dded7a83, prime), - Z=Mod(1, prime)), InfinityPoint(coords), - order=0xfffffffe0000000075a30d1b9038a115, cofactor=1) - - -def get_curve25519(): - prime = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed - model = MontgomeryModel() - coords = model.coordinates["xz"] - curve = EllipticCurve(model, coords, prime, - dict(a=486662, b=1)) - return AbelianGroup(curve, Point(coords, X=Mod(9, prime), Z=Mod(1, prime)), - InfinityPoint(coords), - order=0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED, - cofactor=2) diff --git a/test/ec/test_context.py b/test/ec/test_context.py index 1073fc0..77160cb 100644 --- a/test/ec/test_context.py +++ b/test/ec/test_context.py @@ -5,25 +5,24 @@ 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.mod import Mod from pyecsca.ec.mult import LTRMultiplier from pyecsca.ec.point import Point -from .curves import get_secp128r1 class OpResultTests(TestCase): - def test_repr(self): + def test_str(self): for op, char in zip((ast.Add(), ast.Sub(), ast.Mult(), ast.Div()), "+-*/"): res = OpResult("X1", Mod(0, 5), op, Mod(2, 5), Mod(3, 5)) self.assertEqual(str(res), "X1") - self.assertEqual(repr(res), "X1 = 2{}3".format(char)) class ContextTests(TestCase): def setUp(self): - self.secp128r1 = get_secp128r1() + self.secp128r1 = get_curve("secp128r1", "projective") self.base = self.secp128r1.generator self.coords = self.secp128r1.curve.coordinate_model self.mult = LTRMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], @@ -51,7 +50,7 @@ class ContextTests(TestCase): Point(AffineCoordinateModel(self.secp128r1.curve.model), x=Mod(1, 5), y=Mod(2, 5))) - def test_repr(self): + def test_str(self): with local(DefaultContext()) as default: self.mult.multiply(59, self.base) str(default) diff --git a/test/ec/test_curve.py b/test/ec/test_curve.py index 1adaf47..1f2ca1f 100644 --- a/test/ec/test_curve.py +++ b/test/ec/test_curve.py @@ -1,17 +1,19 @@ from unittest import TestCase +from parameterized import parameterized + from pyecsca.ec.curve import EllipticCurve +from pyecsca.ec.curves import get_curve from pyecsca.ec.mod import Mod from pyecsca.ec.model import MontgomeryModel from pyecsca.ec.point import Point -from .curves import get_secp128r1, get_curve25519 class CurveTests(TestCase): def setUp(self): - self.secp128r1 = get_secp128r1() + self.secp128r1 = get_curve("secp128r1", "projective") self.base = self.secp128r1.generator - self.curve25519 = get_curve25519() + self.curve25519 = get_curve("curve25519", "xz") def test_init(self): with self.assertRaises(ValueError): @@ -39,10 +41,22 @@ 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) - - def test_repr(self): - self.assertEqual(repr(self.secp128r1.curve), - "EllipticCurve([a=340282366762482138434845932244680310780, b=308990863222245658030922601041482374867] on ShortWeierstrassModel() using EFDCoordinateModel(\"projective\" on short Weierstrass curves))") + self.assertNotEqual(self.secp128r1.curve, None) diff --git a/test/ec/test_group.py b/test/ec/test_group.py index e3b3a72..ca0ea91 100644 --- a/test/ec/test_group.py +++ b/test/ec/test_group.py @@ -1,14 +1,14 @@ from unittest import TestCase +from pyecsca.ec.curves import get_curve from pyecsca.ec.point import InfinityPoint -from .curves import get_secp128r1, get_curve25519 class AbelianGroupTests(TestCase): def setUp(self): - self.secp128r1 = get_secp128r1() - self.curve25519 = get_curve25519() + self.secp128r1 = get_curve("secp128r1", "projective") + self.curve25519 = get_curve("curve25519", "xz") def test_is_neutral(self): assert self.secp128r1.is_neutral(InfinityPoint(self.secp128r1.curve.coordinate_model)) @@ -16,3 +16,4 @@ class AbelianGroupTests(TestCase): def test_eq(self): self.assertEqual(self.secp128r1, self.secp128r1) self.assertNotEqual(self.secp128r1, self.curve25519) + self.assertNotEqual(self.secp128r1, None) diff --git a/test/ec/test_key_agreement.py b/test/ec/test_key_agreement.py index f22ee75..ab009e3 100644 --- a/test/ec/test_key_agreement.py +++ b/test/ec/test_key_agreement.py @@ -1,14 +1,14 @@ from unittest import TestCase +from pyecsca.ec.curves import get_curve from pyecsca.ec.key_agreement import * from pyecsca.ec.mult import LTRMultiplier -from .curves import get_secp128r1 class KeyAgreementTests(TestCase): def setUp(self): - self.secp128r1 = get_secp128r1() + self.secp128r1 = get_curve("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.secp128r1, self.add, self.dbl) diff --git a/test/ec/test_mult.py b/test/ec/test_mult.py index c72f370..3abc72c 100644 --- a/test/ec/test_mult.py +++ b/test/ec/test_mult.py @@ -1,47 +1,67 @@ from unittest import TestCase +from parameterized import parameterized + +from pyecsca.ec.curves import get_curve from pyecsca.ec.mult import (LTRMultiplier, RTLMultiplier, LadderMultiplier, BinaryNAFMultiplier, WindowNAFMultiplier, SimpleLadderMultiplier, CoronMultiplier) from pyecsca.ec.point import InfinityPoint -from .curves import get_secp128r1, get_curve25519 class ScalarMultiplierTests(TestCase): def setUp(self): - self.secp128r1 = get_secp128r1() + self.secp128r1 = get_curve("secp128r1", "projective") self.base = self.secp128r1.generator self.coords = self.secp128r1.curve.coordinate_model - self.curve25519 = get_curve25519() + self.curve25519 = get_curve("curve25519", "xz") self.base25519 = self.curve25519.generator self.coords25519 = self.curve25519.curve.coordinate_model - def test_rtl(self): - mult = RTLMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], - self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["z"]) + def get_formulas(self, coords, *names): + return [coords.formulas[name] for name in names if name is not None] + + def assertPointEquality(self, one, other, scale): + if scale: + self.assertEqual(one, other) + else: + assert one.equals(other) + + @parameterized.expand([ + ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"), + ("none", "add-1998-cmo", "dbl-1998-cmo", None) + ]) + def test_rtl(self, name, add, dbl, scale): + mult = RTLMultiplier(self.secp128r1, *self.get_formulas(self.coords, add, dbl, scale)) res = mult.multiply(10, self.base) other = mult.multiply(5, self.base) other = mult.multiply(2, other) - self.assertEqual(res, other) + self.assertPointEquality(res, other, scale) self.assertEqual(InfinityPoint(self.coords), mult.multiply(0, self.base)) - def test_ltr(self): - mult = LTRMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], - self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["z"]) + @parameterized.expand([ + ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"), + ("none", "add-1998-cmo", "dbl-1998-cmo", None) + ]) + def test_ltr(self, name, add, dbl, scale): + mult = LTRMultiplier(self.secp128r1, *self.get_formulas(self.coords, add, dbl, scale)) res = mult.multiply(10, self.base) other = mult.multiply(5, self.base) other = mult.multiply(2, other) - self.assertEqual(res, other) + self.assertPointEquality(res, other, scale) self.assertEqual(InfinityPoint(self.coords), mult.multiply(0, self.base)) - def test_coron(self): - mult = CoronMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], - self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["z"]) + @parameterized.expand([ + ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"), + ("none", "add-1998-cmo", "dbl-1998-cmo", None) + ]) + def test_coron(self, name, add, dbl, scale): + mult = CoronMultiplier(self.secp128r1, *self.get_formulas(self.coords, add, dbl, scale)) res = mult.multiply(10, self.base) other = mult.multiply(5, self.base) other = mult.multiply(2, other) - self.assertEqual(res, other) + self.assertPointEquality(res, other, scale) self.assertEqual(InfinityPoint(self.coords), mult.multiply(0, self.base)) def test_ladder(self): @@ -54,17 +74,24 @@ class ScalarMultiplierTests(TestCase): self.assertEqual(res, other) self.assertEqual(InfinityPoint(self.coords25519), mult.multiply(0, self.base25519)) - def test_simple_ladder(self): - mult = SimpleLadderMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], - self.coords.formulas["dbl-1998-cmo"], - self.coords.formulas["z"]) + @parameterized.expand([ + ("scaled", "add-1998-cmo", "dbl-1998-cmo", "z"), + ("none", "add-1998-cmo", "dbl-1998-cmo", None) + ]) + def test_simple_ladder(self, name, add, dbl, scale): + mult = SimpleLadderMultiplier(self.secp128r1, + *self.get_formulas(self.coords, add, dbl, scale)) res = mult.multiply(10, self.base) other = mult.multiply(5, self.base) other = mult.multiply(2, other) - self.assertEqual(res, other) + self.assertPointEquality(res, other, scale) self.assertEqual(InfinityPoint(self.coords), mult.multiply(0, self.base)) - def test_ladder_differential(self): + @parameterized.expand([ + ("10", 15), + ("2355498743", 2355498743,) + ]) + def test_ladder_differential(self, name, num): ladder = LadderMultiplier(self.curve25519, self.coords25519.formulas["ladd-1987-m"], self.coords25519.formulas["dbl-1987-m"], self.coords25519.formulas["scale"]) @@ -72,45 +99,53 @@ class ScalarMultiplierTests(TestCase): self.coords25519.formulas["dadd-1987-m"], self.coords25519.formulas["dbl-1987-m"], self.coords25519.formulas["scale"]) - res_ladder = ladder.multiply(15, self.base25519) - res_differential = differential.multiply(15, self.base25519) + res_ladder = ladder.multiply(num, self.base25519) + res_differential = differential.multiply(num, self.base25519) self.assertEqual(res_ladder, res_differential) self.assertEqual(InfinityPoint(self.coords25519), differential.multiply(0, self.base25519)) - def test_binary_naf(self): - mult = BinaryNAFMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], - self.coords.formulas["dbl-1998-cmo"], - self.coords.formulas["neg"], self.coords.formulas["z"]) + @parameterized.expand([ + ("scaled", "add-1998-cmo", "dbl-1998-cmo", "neg", "z"), + ("none", "add-1998-cmo", "dbl-1998-cmo", "neg", None) + ]) + def test_binary_naf(self, name, add, dbl, neg, scale): + mult = BinaryNAFMultiplier(self.secp128r1, + *self.get_formulas(self.coords, add, dbl, neg, scale)) res = mult.multiply(10, self.base) other = mult.multiply(5, self.base) other = mult.multiply(2, other) - self.assertEqual(res, other) + self.assertPointEquality(res, other, scale) self.assertEqual(InfinityPoint(self.coords), mult.multiply(0, self.base)) - def test_window_naf(self): - mult = WindowNAFMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], - self.coords.formulas["dbl-1998-cmo"], - self.coords.formulas["neg"], 3, self.coords.formulas["z"]) + @parameterized.expand([ + ("scaled3", "add-1998-cmo", "dbl-1998-cmo", "neg", 3, "z"), + ("none3", "add-1998-cmo", "dbl-1998-cmo", "neg", 3, None) + ]) + def test_window_naf(self, name, add, dbl, neg, width, scale): + formulas = self.get_formulas(self.coords, add, dbl, neg, scale) + mult = WindowNAFMultiplier(self.secp128r1, *formulas[:3], width, *formulas[3:]) res = mult.multiply(10, self.base) other = mult.multiply(5, self.base) other = mult.multiply(2, other) - self.assertEqual(res, other) + self.assertPointEquality(res, other, scale) self.assertEqual(InfinityPoint(self.coords), mult.multiply(0, self.base)) - mult = WindowNAFMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], - self.coords.formulas["dbl-1998-cmo"], - self.coords.formulas["neg"], 3, self.coords.formulas["z"], + mult = WindowNAFMultiplier(self.secp128r1, *formulas[:3], width, *formulas[3:], precompute_negation=True) res_precompute = mult.multiply(10, self.base) - self.assertEqual(res_precompute, res) + self.assertPointEquality(res_precompute, res, scale) - def test_basic_multipliers(self): + @parameterized.expand([ + ("10", 10), + ("2355498743", 2355498743,) + ]) + def test_basic_multipliers(self, name, num): ltr = LTRMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["z"]) - res_ltr = ltr.multiply(10, self.base) + res_ltr = ltr.multiply(num, self.base) rtl = RTLMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["z"]) - res_rtl = rtl.multiply(10, self.base) + res_rtl = rtl.multiply(num, self.base) self.assertEqual(res_ltr, res_rtl) ltr_always = LTRMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], @@ -119,31 +154,44 @@ class ScalarMultiplierTests(TestCase): rtl_always = RTLMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["z"], always=True) - res_ltr_always = ltr_always.multiply(10, self.base) - res_rtl_always = rtl_always.multiply(10, self.base) + res_ltr_always = ltr_always.multiply(num, self.base) + res_rtl_always = rtl_always.multiply(num, self.base) self.assertEqual(res_ltr, res_ltr_always) self.assertEqual(res_rtl, res_rtl_always) bnaf = BinaryNAFMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["neg"], self.coords.formulas["z"]) - res_bnaf = bnaf.multiply(10, self.base) + res_bnaf = bnaf.multiply(num, self.base) self.assertEqual(res_bnaf, res_ltr) wnaf = WindowNAFMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["neg"], 3, self.coords.formulas["z"]) - res_wnaf = wnaf.multiply(10, self.base) + res_wnaf = wnaf.multiply(num, self.base) self.assertEqual(res_wnaf, res_ltr) ladder = SimpleLadderMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["z"]) - res_ladder = ladder.multiply(10, self.base) + res_ladder = ladder.multiply(num, self.base) self.assertEqual(res_ladder, res_ltr) coron = CoronMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["z"]) - res_coron = coron.multiply(10, self.base) + res_coron = coron.multiply(num, self.base) self.assertEqual(res_coron, res_ltr) + + def test_init_fail(self): + with self.assertRaises(ValueError): + SimpleLadderMultiplier(self.secp128r1, + self.coords25519.formulas["dadd-1987-m"], + self.coords25519.formulas["dbl-1987-m"], + self.coords25519.formulas["scale"]) + + def test_mult_fail(self): + mult = LTRMultiplier(self.secp128r1, self.coords.formulas["add-1998-cmo"], + self.coords.formulas["dbl-1998-cmo"], self.coords.formulas["z"]) + with self.assertRaises(ValueError): + mult.multiply(15) diff --git a/test/ec/test_op.py b/test/ec/test_op.py new file mode 100644 index 0000000..13efc53 --- /dev/null +++ b/test/ec/test_op.py @@ -0,0 +1,32 @@ +from ast import parse +from unittest import TestCase + +from parameterized import parameterized + +from pyecsca.ec.mod import Mod +from pyecsca.ec.op import CodeOp + + +class OpTests(TestCase): + + @parameterized.expand([ + ("add", "x = a+b", "x = a+b"), + ("sub", "x = a-b", "x = a-b"), + ("mul", "y = a*b", "y = a*b"), + ("div", "z = a/b", "z = a/b"), + ("pow", "b = a**d", "b = a^d") + ]) + def test_str(self, name, module, result): + code = parse(module, mode="exec") + op = CodeOp(code) + self.assertEqual(str(op), result) + + @parameterized.expand([ + ("add", "x = a+b", {"a": Mod(5, 21), "b": Mod(7, 21)}, Mod(12, 21)), + ("sub", "x = a-b", {"a": Mod(7, 21), "b": Mod(5, 21)}, Mod(2, 21)) + ]) + def test_call(self, name, module, locals, result): + code = parse(module, mode="exec") + op = CodeOp(code) + res = op(**locals) + self.assertEqual(res, result) diff --git a/test/ec/test_point.py b/test/ec/test_point.py index c80d4cc..0809edc 100644 --- a/test/ec/test_point.py +++ b/test/ec/test_point.py @@ -1,15 +1,15 @@ from unittest import TestCase from pyecsca.ec.coordinates import AffineCoordinateModel +from pyecsca.ec.curves import get_curve from pyecsca.ec.mod import Mod from pyecsca.ec.model import ShortWeierstrassModel, MontgomeryModel from pyecsca.ec.point import Point, InfinityPoint -from .curves import get_secp128r1 class PointTests(TestCase): def setUp(self): - self.secp128r1 = get_secp128r1() + self.secp128r1 = get_curve("secp128r1", "projective") self.base = self.secp128r1.generator self.coords = self.secp128r1.curve.coordinate_model self.affine = AffineCoordinateModel(ShortWeierstrassModel()) @@ -81,12 +81,3 @@ class PointTests(TestCase): Z=Mod(1, 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)) assert not pt.equals(different) self.assertNotEqual(pt, different) - - def test_repr(self): - self.assertEqual(str(self.base), - "[X=29408993404948928992877151431649155974, Y=275621562871047521857442314737465260675, Z=1]") - self.assertEqual(repr(self.base), - "Point([[X=29408993404948928992877151431649155974, Y=275621562871047521857442314737465260675, Z=1]] in EFDCoordinateModel(\"projective\" on short Weierstrass curves))") - self.assertEqual(str(InfinityPoint(self.coords)), "Infinity") - self.assertEqual(repr(InfinityPoint(self.coords)), - "InfinityPoint(EFDCoordinateModel(\"projective\" on short Weierstrass curves))") diff --git a/test/ec/test_signature.py b/test/ec/test_signature.py index d9b306a..06b6123 100644 --- a/test/ec/test_signature.py +++ b/test/ec/test_signature.py @@ -1,15 +1,15 @@ from hashlib import sha1 from unittest import TestCase +from pyecsca.ec.curves import get_curve from pyecsca.ec.mult import LTRMultiplier from pyecsca.ec.signature import * -from .curves import get_secp128r1 class SignatureTests(TestCase): def setUp(self): - self.secp128r1 = get_secp128r1() + self.secp128r1 = get_curve("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.secp128r1, self.add, self.dbl) diff --git a/test/sca/test_traceset.py b/test/sca/test_traceset.py index f12f205..6d48707 100644 --- a/test/sca/test_traceset.py +++ b/test/sca/test_traceset.py @@ -20,6 +20,7 @@ class InspectorTraceSetTests(TestCase): self.assertIsNotNone(result) self.assertEqual(result.global_title, "Example trace set") self.assertEqual(len(result), 10) + self.assertEqual(len(list(result)), 10) self.assertIn("InspectorTraceSet", str(result)) self.assertIs(result[0].trace_set, result) self.assertEqual(result.sampling_frequency, 12500000) |
