Skip to content

Commit 5bbf735

Browse files
committed
Merge bitcoin/bitcoin#27653: test: add unit test coverage for Python ECDSA implementation
96b3f2d test: add unit test coverage for Python ECDSA implementation (Sebastian Falbesoner) Pull request description: This PR adds missing unit test coverage for the Python ECDSA implementation, which should be useful for detecting potential problems early whenever changes in the test framework's Python implementation of secp256k1 are made (e.g. #26222). Note that right now we don't call `ECPubKey.verify_ecdsa` anywhere in our tests, so we wouldn't notice if it is broken at some point. To keep it simple, the already existing unit test for Schnorr signatures is extended to also check ECDSA signatures. For that purpose, the dictionary storing private-key/public-key entries use their legacy types `ECKey/ECPubKey` instead of bare byte-arrays, and for Schnorr signing/verification the necessary conversions (ECKey -> bare private key, ECPubKey -> x-only pubkey) is done later when needed. To avoid code duplication, a helper function `random_bitflip` for damaging signatures is introduced. The unit test can be run by either calling it for this single module: `$ python3 -m unittest ./test/functional/test_framework/key.py` or simply running `$ ./test/functional/test_runner.py` which calls all test framework module's unit tests at the start (see TEST_FRAMEWORK_MODULES list). ACKs for top commit: achow101: ACK 96b3f2d sipa: utACK 96b3f2d stratospher: tested ACK 96b3f2d. Tree-SHA512: b993f25b843fa047376addda4ce4b0f15750ffba926528b5cca4c5f99b9af456206f4e8af885d25a017dddddf382ddebf38765819b3d16a3f28810d03b010808
2 parents f562856 + 96b3f2d commit 5bbf735

File tree

1 file changed

+21
-12
lines changed
  • test/functional/test_framework

1 file changed

+21
-12
lines changed

test/functional/test_framework/key.py

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -290,24 +290,33 @@ def sign_schnorr(key, msg, aux=None, flip_p=False, flip_r=False):
290290

291291

292292
class TestFrameworkKey(unittest.TestCase):
293-
def test_schnorr(self):
294-
"""Test the Python Schnorr implementation."""
293+
def test_ecdsa_and_schnorr(self):
294+
"""Test the Python ECDSA and Schnorr implementations."""
295+
def random_bitflip(sig):
296+
sig = list(sig)
297+
sig[random.randrange(len(sig))] ^= (1 << (random.randrange(8)))
298+
return bytes(sig)
299+
295300
byte_arrays = [generate_privkey() for _ in range(3)] + [v.to_bytes(32, 'big') for v in [0, ORDER - 1, ORDER, 2**256 - 1]]
296301
keys = {}
297-
for privkey in byte_arrays: # build array of key/pubkey pairs
298-
pubkey, _ = compute_xonly_pubkey(privkey)
299-
if pubkey is not None:
300-
keys[privkey] = pubkey
302+
for privkey_bytes in byte_arrays: # build array of key/pubkey pairs
303+
privkey = ECKey()
304+
privkey.set(privkey_bytes, compressed=True)
305+
if privkey.is_valid:
306+
keys[privkey] = privkey.get_pubkey()
301307
for msg in byte_arrays: # test every combination of message, signing key, verification key
302308
for sign_privkey, _ in keys.items():
303-
sig = sign_schnorr(sign_privkey, msg)
309+
sig_ecdsa = sign_privkey.sign_ecdsa(msg)
310+
sig_schnorr = sign_schnorr(sign_privkey.get_bytes(), msg)
304311
for verify_privkey, verify_pubkey in keys.items():
312+
verify_xonly_pubkey = verify_pubkey.get_bytes()[1:]
305313
if verify_privkey == sign_privkey:
306-
self.assertTrue(verify_schnorr(verify_pubkey, sig, msg))
307-
sig = list(sig)
308-
sig[random.randrange(64)] ^= (1 << (random.randrange(8))) # damaging signature should break things
309-
sig = bytes(sig)
310-
self.assertFalse(verify_schnorr(verify_pubkey, sig, msg))
314+
self.assertTrue(verify_pubkey.verify_ecdsa(sig_ecdsa, msg))
315+
self.assertTrue(verify_schnorr(verify_xonly_pubkey, sig_schnorr, msg))
316+
sig_ecdsa = random_bitflip(sig_ecdsa) # damaging signature should break things
317+
sig_schnorr = random_bitflip(sig_schnorr)
318+
self.assertFalse(verify_pubkey.verify_ecdsa(sig_ecdsa, msg))
319+
self.assertFalse(verify_schnorr(verify_xonly_pubkey, sig_schnorr, msg))
311320

312321
def test_schnorr_testvectors(self):
313322
"""Implement the BIP340 test vectors (read from bip340_test_vectors.csv)."""

0 commit comments

Comments
 (0)