Skip to content

Commit b6d43c6

Browse files
committedMar 13, 2025·
use integer division for canonicalization of signatures
fixes #353
1 parent aa81ba3 commit b6d43c6

File tree

2 files changed

+37
-6
lines changed

2 files changed

+37
-6
lines changed
 

‎src/ecdsa/test_pyecdsa.py

+17
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,23 @@ def test_sigencode_der_canonize(self):
520520
self.assertEqual(r, new_r)
521521
self.assertEqual(order - s, new_s)
522522

523+
def test_sigencode_der_canonize_with_close_to_half_order(self):
524+
r = 13
525+
order = SECP112r1.order
526+
s = order // 2 + 1
527+
528+
regular_encode = sigencode_der(r, s, order)
529+
canonical_encode = sigencode_der_canonize(r, s, order)
530+
531+
self.assertNotEqual(regular_encode, canonical_encode)
532+
533+
new_r, new_s = sigdecode_der(
534+
sigencode_der_canonize(r, s, order), order
535+
)
536+
537+
self.assertEqual(r, new_r)
538+
self.assertEqual(order - s, new_s)
539+
523540
def test_sig_decode_strings_with_invalid_count(self):
524541
with self.assertRaises(MalformedSignature):
525542
sigdecode_strings([b"one", b"two", b"three"], 0xFF)

‎src/ecdsa/util.py

+20-6
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,23 @@ def sigencode_der(r, s, order):
304304
return der.encode_sequence(der.encode_integer(r), der.encode_integer(s))
305305

306306

307+
def _canonize(s, order):
308+
"""
309+
Internal function for ensuring that the ``s`` value of a signature is in
310+
the "canonical" format.
311+
312+
:param int s: the second parameter of ECDSA signature
313+
:param int order: the order of the curve over which the signatures was
314+
computed
315+
316+
:return: canonical value of s
317+
:rtype: int
318+
"""
319+
if s > order // 2:
320+
s = order - s
321+
return s
322+
323+
307324
def sigencode_strings_canonize(r, s, order):
308325
"""
309326
Encode the signature to a pair of strings in a tuple
@@ -326,8 +343,7 @@ def sigencode_strings_canonize(r, s, order):
326343
:return: raw encoding of ECDSA signature
327344
:rtype: tuple(bytes, bytes)
328345
"""
329-
if s > order / 2:
330-
s = order - s
346+
s = _canonize(s, order)
331347
return sigencode_strings(r, s, order)
332348

333349

@@ -350,8 +366,7 @@ def sigencode_string_canonize(r, s, order):
350366
:return: raw encoding of ECDSA signature
351367
:rtype: bytes
352368
"""
353-
if s > order / 2:
354-
s = order - s
369+
s = _canonize(s, order)
355370
return sigencode_string(r, s, order)
356371

357372

@@ -381,8 +396,7 @@ def sigencode_der_canonize(r, s, order):
381396
:return: DER encoding of ECDSA signature
382397
:rtype: bytes
383398
"""
384-
if s > order / 2:
385-
s = order - s
399+
s = _canonize(s, order)
386400
return sigencode_der(r, s, order)
387401

388402

0 commit comments

Comments
 (0)
Please sign in to comment.