Skip to content

Commit 8ab416b

Browse files
committed
use curve cofactor for point verification
since multiplying a point by the order is farily expensive, skipping it (when safe to do so) greatly increases performance does not increase the speed.py numbers as point verification happens outside the signing and verifying operations
1 parent b8fdfbe commit 8ab416b

File tree

2 files changed

+39
-19
lines changed

2 files changed

+39
-19
lines changed

src/ecdsa/ecdsa.py

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,11 @@ def __init__(self, generator, point, verify=True):
131131
raise InvalidPointError("Point does not lie on the curve")
132132
if not n:
133133
raise InvalidPointError("Generator point must have order.")
134-
if verify and not n * point == ellipticcurve.INFINITY:
134+
# for curve parameters with base point with cofactor 1, all points
135+
# that are on the curve are scalar multiples of the base point, so
136+
# verifying that is not necessary. See Section 3.2.2.1 of SEC 1 v2
137+
if verify and self.curve.cofactor() != 1 and \
138+
not n * point == ellipticcurve.INFINITY:
135139
raise InvalidPointError("Generator point order is bad.")
136140

137141
def __eq__(self, other):
@@ -272,7 +276,8 @@ def point_is_valid(generator, x, y):
272276
return False
273277
if not curve.contains_point(x, y):
274278
return False
275-
if not n * ellipticcurve.PointJacobi(curve, x, y, 1)\
279+
if curve.cofactor() != 1 and \
280+
not n * ellipticcurve.PointJacobi(curve, x, y, 1)\
276281
== ellipticcurve.INFINITY:
277282
return False
278283
return True
@@ -287,7 +292,7 @@ def point_is_valid(generator, x, y):
287292
_Gx = 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012
288293
_Gy = 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811
289294

290-
curve_192 = ellipticcurve.CurveFp(_p, -3, _b)
295+
curve_192 = ellipticcurve.CurveFp(_p, -3, _b, 1)
291296
generator_192 = ellipticcurve.PointJacobi(
292297
curve_192, _Gx, _Gy, 1, _r, generator=True)
293298

@@ -301,7 +306,7 @@ def point_is_valid(generator, x, y):
301306
_Gx = 0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21
302307
_Gy = 0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34
303308

304-
curve_224 = ellipticcurve.CurveFp(_p, -3, _b)
309+
curve_224 = ellipticcurve.CurveFp(_p, -3, _b, 1)
305310
generator_224 = ellipticcurve.PointJacobi(
306311
curve_224, _Gx, _Gy, 1, _r, generator=True)
307312

@@ -314,7 +319,7 @@ def point_is_valid(generator, x, y):
314319
_Gx = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296
315320
_Gy = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5
316321

317-
curve_256 = ellipticcurve.CurveFp(_p, -3, _b)
322+
curve_256 = ellipticcurve.CurveFp(_p, -3, _b, 1)
318323
generator_256 = ellipticcurve.PointJacobi(
319324
curve_256, _Gx, _Gy, 1, _r, generator=True)
320325

@@ -327,7 +332,7 @@ def point_is_valid(generator, x, y):
327332
_Gx = 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7
328333
_Gy = 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f
329334

330-
curve_384 = ellipticcurve.CurveFp(_p, -3, _b)
335+
curve_384 = ellipticcurve.CurveFp(_p, -3, _b, 1)
331336
generator_384 = ellipticcurve.PointJacobi(
332337
curve_384, _Gx, _Gy, 1, _r, generator=True)
333338

@@ -340,7 +345,7 @@ def point_is_valid(generator, x, y):
340345
_Gx = 0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66
341346
_Gy = 0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650
342347

343-
curve_521 = ellipticcurve.CurveFp(_p, -3, _b)
348+
curve_521 = ellipticcurve.CurveFp(_p, -3, _b, 1)
344349
generator_521 = ellipticcurve.PointJacobi(
345350
curve_521, _Gx, _Gy, 1, _r, generator=True)
346351

@@ -352,7 +357,7 @@ def point_is_valid(generator, x, y):
352357
_Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
353358
_r = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
354359

355-
curve_secp256k1 = ellipticcurve.CurveFp(_p, _a, _b)
360+
curve_secp256k1 = ellipticcurve.CurveFp(_p, _a, _b, 1)
356361
generator_secp256k1 = ellipticcurve.PointJacobi(
357362
curve_secp256k1, _Gx, _Gy, 1, _r, generator=True)
358363

@@ -364,7 +369,7 @@ def point_is_valid(generator, x, y):
364369
_Gy = 0x1667CB477A1A8EC338F94741669C976316DA6321
365370
_q = 0xE95E4A5F737059DC60DF5991D45029409E60FC09
366371

367-
curve_brainpoolp160r1 = ellipticcurve.CurveFp(_p, _a, _b)
372+
curve_brainpoolp160r1 = ellipticcurve.CurveFp(_p, _a, _b, 1)
368373
generator_brainpoolp160r1 = ellipticcurve.PointJacobi(
369374
curve_brainpoolp160r1, _Gx, _Gy, 1, _q, generator=True)
370375

@@ -376,7 +381,7 @@ def point_is_valid(generator, x, y):
376381
_Gy = 0x14B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F
377382
_q = 0xC302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1
378383

379-
curve_brainpoolp192r1 = ellipticcurve.CurveFp(_p, _a, _b)
384+
curve_brainpoolp192r1 = ellipticcurve.CurveFp(_p, _a, _b, 1)
380385
generator_brainpoolp192r1 = ellipticcurve.PointJacobi(
381386
curve_brainpoolp192r1, _Gx, _Gy, 1, _q, generator=True)
382387

@@ -388,7 +393,7 @@ def point_is_valid(generator, x, y):
388393
_Gy = 0x58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD
389394
_q = 0xD7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F
390395

391-
curve_brainpoolp224r1 = ellipticcurve.CurveFp(_p, _a, _b)
396+
curve_brainpoolp224r1 = ellipticcurve.CurveFp(_p, _a, _b, 1)
392397
generator_brainpoolp224r1 = ellipticcurve.PointJacobi(
393398
curve_brainpoolp224r1, _Gx, _Gy, 1, _q, generator=True)
394399

@@ -400,7 +405,7 @@ def point_is_valid(generator, x, y):
400405
_Gy = 0x547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997
401406
_q = 0xA9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7
402407

403-
curve_brainpoolp256r1 = ellipticcurve.CurveFp(_p, _a, _b)
408+
curve_brainpoolp256r1 = ellipticcurve.CurveFp(_p, _a, _b, 1)
404409
generator_brainpoolp256r1 = ellipticcurve.PointJacobi(
405410
curve_brainpoolp256r1, _Gx, _Gy, 1, _q, generator=True)
406411

@@ -412,7 +417,7 @@ def point_is_valid(generator, x, y):
412417
_Gy = 0x14FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1
413418
_q = 0xD35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311
414419

415-
curve_brainpoolp320r1 = ellipticcurve.CurveFp(_p, _a, _b)
420+
curve_brainpoolp320r1 = ellipticcurve.CurveFp(_p, _a, _b, 1)
416421
generator_brainpoolp320r1 = ellipticcurve.PointJacobi(
417422
curve_brainpoolp320r1, _Gx, _Gy, 1, _q, generator=True)
418423

@@ -424,7 +429,7 @@ def point_is_valid(generator, x, y):
424429
_Gy = 0x8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315
425430
_q = 0x8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565
426431

427-
curve_brainpoolp384r1 = ellipticcurve.CurveFp(_p, _a, _b)
432+
curve_brainpoolp384r1 = ellipticcurve.CurveFp(_p, _a, _b, 1)
428433
generator_brainpoolp384r1 = ellipticcurve.PointJacobi(
429434
curve_brainpoolp384r1, _Gx, _Gy, 1, _q, generator=True)
430435

@@ -436,6 +441,6 @@ def point_is_valid(generator, x, y):
436441
_Gy = 0x7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892
437442
_q = 0xAADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069
438443

439-
curve_brainpoolp512r1 = ellipticcurve.CurveFp(_p, _a, _b)
444+
curve_brainpoolp512r1 = ellipticcurve.CurveFp(_p, _a, _b, 1)
440445
generator_brainpoolp512r1 = ellipticcurve.PointJacobi(
441446
curve_brainpoolp512r1, _Gx, _Gy, 1, _q, generator=True)

src/ecdsa/ellipticcurve.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,19 @@
4141
@python_2_unicode_compatible
4242
class CurveFp(object):
4343
"""Elliptic Curve over the field of integers modulo a prime."""
44-
def __init__(self, p, a, b):
45-
"""The curve of points satisfying y^2 = x^3 + a*x + b (mod p)."""
44+
def __init__(self, p, a, b, h=None):
45+
"""
46+
The curve of points satisfying y^2 = x^3 + a*x + b (mod p).
47+
48+
h is an integer that is the cofactor of the elliptic curve domain
49+
parameters; it is the number of points satisfying the elliptic curve
50+
equation divided by the order of the base point. It is used for selection
51+
of efficient algorithm for public point verification.
52+
"""
4653
self.__p = p
4754
self.__a = a
4855
self.__b = b
56+
self.__h = h
4957

5058
def __eq__(self, other):
5159
if isinstance(other, CurveFp):
@@ -64,12 +72,16 @@ def a(self):
6472
def b(self):
6573
return self.__b
6674

75+
def cofactor(self):
76+
return self.__h
77+
6778
def contains_point(self, x, y):
6879
"""Is the point (x,y) on this curve?"""
6980
return (y * y - ((x * x + self.__a) * x + self.__b)) % self.__p == 0
7081

7182
def __str__(self):
72-
return "CurveFp(p=%d, a=%d, b=%d)" % (self.__p, self.__a, self.__b)
83+
return "CurveFp(p=%d, a=%d, b=%d, h=%d)" % (
84+
self.__p, self.__a, self.__b, self.__h)
7385

7486

7587
class PointJacobi(object):
@@ -536,7 +548,10 @@ def __init__(self, curve, x, y, order=None):
536548
# self.curve is allowed to be None only for INFINITY:
537549
if self.__curve:
538550
assert self.__curve.contains_point(x, y)
539-
if order:
551+
# for curves with cofactor 1, all points that are on the curve are scalar
552+
# multiples of the base point, so performing multiplication is not
553+
# necessary to verify that. See Section 3.2.2.1 of SEC 1 v2
554+
if curve and curve.cofactor() != 1 and order:
540555
assert self * order == INFINITY
541556

542557
def __eq__(self, other):

0 commit comments

Comments
 (0)