From a39bfba2d9a2e7509bcc1638afa67b042c1b0868 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Fri, 3 Sep 2021 16:48:29 +0200 Subject: [PATCH] ecc: allow tests to disable ecdsa R-value grinding see https://github.com/spesmilo/electrum/pull/7453#issuecomment-912594926 --- electrum/ecc.py | 16 +++++++++++----- electrum/tests/test_bitcoin.py | 24 ++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/electrum/ecc.py b/electrum/ecc.py index d75a70234..f92503872 100644 --- a/electrum/ecc.py +++ b/electrum/ecc.py @@ -41,6 +41,11 @@ from .ecc_fast import _libsecp256k1, SECP256K1_EC_UNCOMPRESSED _logger = get_logger(__name__) +# Some unit tests need to create ECDSA sigs without grinding the R value (and just use RFC6979). +# see https://github.com/bitcoin/bitcoin/pull/13666 +ENABLE_ECDSA_R_VALUE_GRINDING = True + + def string_to_number(b: bytes) -> int: return int.from_bytes(b, byteorder='big', signed=False) @@ -463,11 +468,12 @@ class ECPrivkey(ECPubkey): return r, s r, s = sign_with_extra_entropy(extra_entropy=None) - counter = 0 - while r >= 2**255: # grind for low R value https://github.com/bitcoin/bitcoin/pull/13666 - counter += 1 - extra_entropy = counter.to_bytes(32, byteorder="little") - r, s = sign_with_extra_entropy(extra_entropy=extra_entropy) + if ENABLE_ECDSA_R_VALUE_GRINDING: + counter = 0 + while r >= 2**255: # grind for low R value https://github.com/bitcoin/bitcoin/pull/13666 + counter += 1 + extra_entropy = counter.to_bytes(32, byteorder="little") + r, s = sign_with_extra_entropy(extra_entropy=extra_entropy) sig_string = sig_string_from_r_and_s(r, s) self.verify_message_hash(sig_string, msg_hash) diff --git a/electrum/tests/test_bitcoin.py b/electrum/tests/test_bitcoin.py index 5f89b59e2..89cdf3e19 100644 --- a/electrum/tests/test_bitcoin.py +++ b/electrum/tests/test_bitcoin.py @@ -86,6 +86,24 @@ def needs_test_with_all_chacha20_implementations(func): return run_test +def disable_ecdsa_r_value_grinding(func): + """Function decorator to run a unit test with ecdsa R-value grinding disabled. + This is used when we want to pass test vectors that were created without R-value grinding. + (see https://github.com/bitcoin/bitcoin/pull/13666 ) + + NOTE: this is inherently sequential; + tests running in parallel would break things + """ + def run_test(*args, **kwargs): + is_grinding = ecc.ENABLE_ECDSA_R_VALUE_GRINDING + try: + ecc.ENABLE_ECDSA_R_VALUE_GRINDING = False + func(*args, **kwargs) + finally: + ecc.ENABLE_ECDSA_R_VALUE_GRINDING = is_grinding + return run_test + + class Test_bitcoin(ElectrumTestCase): def test_libsecp256k1_is_available(self): @@ -221,6 +239,12 @@ class Test_bitcoin(ElectrumTestCase): sig2 = eckey2.sign_transaction(bfh('642a2e66332f507c92bda910158dfe46fc10afbf72218764899d3af99a043fac')) self.assertEqual('30440220618513f4cfc87dde798ce5febae7634c23e7b9254a1eabf486be820f6a7c2c4702204fef459393a2b931f949e63ced06888f35e286e446dc46feb24b5b5f81c6ed52', sig2.hex()) + @disable_ecdsa_r_value_grinding + def test_sign_transaction_without_ecdsa_r_value_grinding(self): + eckey1 = ecc.ECPrivkey(bfh('7e1255fddb52db1729fc3ceb21a46f95b8d9fe94cc83425e936a6c5223bb679d')) + sig1 = eckey1.sign_transaction(bfh('5a548b12369a53faaa7e51b5081829474ebdd9c924b3a8230b69aa0be254cd94')) + self.assertEqual('3045022100902a288b98392254cd23c0e9a49ac6d7920f171b8249a48e484b998f1874a2010220723d844826828f092cf400cb210c4fa0b8cd1b9d1a7f21590e78e022ff6476b9', sig1.hex()) + @needs_test_with_all_aes_implementations def test_aes_homomorphic(self): """Make sure AES is homomorphic."""