URI: 
       tMerge pull request #5820 from SomberNight/201912_ecdsa_sig_r_grinding - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit a6aa97c3e3a248f24a3e0c5d85f1f48bac230af2
   DIR parent 2e4cfd07445bc3f38090fdb3cd52612a55470469
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Fri,  6 Dec 2019 20:38:46 +0100
       
       Merge pull request #5820 from SomberNight/201912_ecdsa_sig_r_grinding
       
       ECDSA signatures: grind low R to match with Bitcoin Core (take 2)
       Diffstat:
         M contrib/requirements/requirements.… |       2 +-
         M electrum/ecc.py                     |      10 +++++++++-
         M electrum/ecc_fast.py                |      26 ++++++++++++++++++--------
         M electrum/tests/test_bitcoin.py      |       8 ++++----
         M electrum/tests/test_commands.py     |       2 +-
         M electrum/tests/test_lnutil.py       |       4 ++--
         M electrum/tests/test_wallet_vertica… |      96 ++++++++++++++++----------------
         M electrum/transaction.py             |       9 +++++++--
       
       8 files changed, 90 insertions(+), 67 deletions(-)
       ---
   DIR diff --git a/contrib/requirements/requirements.txt b/contrib/requirements/requirements.txt
       t@@ -1,5 +1,5 @@
        pyaes>=0.1a1
       -ecdsa>=0.13.3
       +ecdsa>=0.14
        qrcode
        protobuf
        dnspython
   DIR diff --git a/electrum/ecc.py b/electrum/ecc.py
       t@@ -414,7 +414,15 @@ class ECPrivkey(ECPubkey):
                if sigdecode is None:
                    sigdecode = get_r_and_s_from_sig_string
                private_key = _MySigningKey.from_secret_exponent(self.secret_scalar, curve=SECP256k1)
       -        sig = private_key.sign_digest_deterministic(data, hashfunc=hashlib.sha256, sigencode=sigencode)
       +        def sig_encode_r_s(r, s, order):
       +            return r, s
       +        r, s = private_key.sign_digest_deterministic(data, hashfunc=hashlib.sha256, sigencode=sig_encode_r_s)
       +        counter = 0
       +        while r >= 2**255:  # grind for low R value https://github.com/bitcoin/bitcoin/pull/13666
       +            counter += 1
       +            extra_entropy = int.to_bytes(counter, 32, 'little')
       +            r, s = private_key.sign_digest_deterministic(data, hashfunc=hashlib.sha256, sigencode=sig_encode_r_s, extra_entropy=extra_entropy)
       +        sig = sigencode(r, s, CURVE_ORDER)
                public_key = private_key.get_verifying_key()
                if not public_key.verify_digest(sig, data, sigdecode=sigdecode):
                    raise Exception('Sanity check verifying our own signature failed.')
   DIR diff --git a/electrum/ecc_fast.py b/electrum/ecc_fast.py
       t@@ -179,14 +179,24 @@ def _prepare_monkey_patching_of_python_ecdsa_internals_with_libsecp256k1():
                nonce_function = None
                sig = create_string_buffer(64)
                sig_hash_bytes = hash.to_bytes(32, byteorder="big")
       -        r = _libsecp256k1.secp256k1_ecdsa_sign(
       -            _libsecp256k1.ctx, sig, sig_hash_bytes, secret_exponent.to_bytes(32, byteorder="big"), nonce_function, None)
       -        if not r:
       -            raise Exception('the nonce generation function failed, or the private key was invalid')
       -        compact_signature = create_string_buffer(64)
       -        _libsecp256k1.secp256k1_ecdsa_signature_serialize_compact(_libsecp256k1.ctx, compact_signature, sig)
       -        r = int.from_bytes(compact_signature[:32], byteorder="big")
       -        s = int.from_bytes(compact_signature[32:], byteorder="big")
       +        def sign_with_extra_entropy(extra_entropy):
       +            ret = _libsecp256k1.secp256k1_ecdsa_sign(
       +                _libsecp256k1.ctx, sig, sig_hash_bytes, secret_exponent.to_bytes(32, byteorder="big"),
       +                nonce_function, extra_entropy)
       +            if not ret:
       +                raise Exception('the nonce generation function failed, or the private key was invalid')
       +            compact_signature = create_string_buffer(64)
       +            _libsecp256k1.secp256k1_ecdsa_signature_serialize_compact(_libsecp256k1.ctx, compact_signature, sig)
       +            r = int.from_bytes(compact_signature[:32], byteorder="big")
       +            s = int.from_bytes(compact_signature[32:], byteorder="big")
       +            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)
                return ecdsa.ecdsa.Signature(r, s)
        
            def verify(self: ecdsa.ecdsa.Public_key, hash: int, signature: ecdsa.ecdsa.Signature) -> bool:
   DIR diff --git a/electrum/tests/test_bitcoin.py b/electrum/tests/test_bitcoin.py
       t@@ -175,8 +175,8 @@ class Test_bitcoin(ElectrumTestCase):
                sig1_b64 = base64.b64encode(sig1)
                sig2_b64 = base64.b64encode(sig2)
        
       -        self.assertEqual(sig1_b64, b'H/9jMOnj4MFbH3d7t4yCQ9i7DgZU/VZ278w3+ySv2F4yIsdqjsc5ng3kmN8OZAThgyfCZOQxZCWza9V5XzlVY0Y=')
       -        self.assertEqual(sig2_b64, b'G84dmJ8TKIDKMT9qBRhpX2sNmR0y5t+POcYnFFJCs66lJmAs3T8A6Sbpx7KA6yTQ9djQMabwQXRrDomOkIKGn18=')
       +        self.assertEqual(sig1_b64, b'Hzsu0U/THAsPz/MSuXGBKSULz2dTfmrg1NsAhFp+wH5aKfmX4Db7ExLGa7FGn0m6Mf43KsbEOWpvUUUBTM3Uusw=')
       +        self.assertEqual(sig2_b64, b'HBQdYfv7kOrxmRewLJnG7sV6KlU71O04hUnE4tai97p7Pg+D+yKaWXsdGgHTrKw90caQMo/D6b//qX50ge9P9iI=')
        
                self.assertTrue(ecc.verify_message_with_address(addr1, sig1, msg1))
                self.assertTrue(ecc.verify_message_with_address(addr2, sig2, msg2))
       t@@ -211,11 +211,11 @@ class Test_bitcoin(ElectrumTestCase):
            def test_sign_transaction(self):
                eckey1 = ecc.ECPrivkey(bfh('7e1255fddb52db1729fc3ceb21a46f95b8d9fe94cc83425e936a6c5223bb679d'))
                sig1 = eckey1.sign_transaction(bfh('5a548b12369a53faaa7e51b5081829474ebdd9c924b3a8230b69aa0be254cd94'))
       -        self.assertEqual(bfh('3045022100902a288b98392254cd23c0e9a49ac6d7920f171b8249a48e484b998f1874a2010220723d844826828f092cf400cb210c4fa0b8cd1b9d1a7f21590e78e022ff6476b9'), sig1)
       +        self.assertEqual('3044022066e7d6a954006cce78a223f5edece8aaedcf3607142e9677acef1cfcb91cfdde022065cb0b5401bf16959ce7b785ea7fd408be5e4cb7d8f1b1a32c78eac6f73678d9', sig1.hex())
        
                eckey2 = ecc.ECPrivkey(bfh('c7ce8c1462c311eec24dff9e2532ac6241e50ae57e7d1833af21942136972f23'))
                sig2 = eckey2.sign_transaction(bfh('642a2e66332f507c92bda910158dfe46fc10afbf72218764899d3af99a043fac'))
       -        self.assertEqual(bfh('30440220618513f4cfc87dde798ce5febae7634c23e7b9254a1eabf486be820f6a7c2c4702204fef459393a2b931f949e63ced06888f35e286e446dc46feb24b5b5f81c6ed52'), sig2)
       +        self.assertEqual('30440220618513f4cfc87dde798ce5febae7634c23e7b9254a1eabf486be820f6a7c2c4702204fef459393a2b931f949e63ced06888f35e286e446dc46feb24b5b5f81c6ed52', sig2.hex())
        
            @needs_test_with_all_aes_implementations
            def test_aes_homomorphic(self):
   DIR diff --git a/electrum/tests/test_commands.py b/electrum/tests/test_commands.py
       t@@ -178,5 +178,5 @@ class TestCommandsTestnet(TestCaseForTestnet):
                        }
                    ]
                }
       -        self.assertEqual("0200000000010139c5375fe9da7bd377c1783002b129f8c57d3e724d62f5eacb9739ca691a229d0100000000feffffff01301b0f0000000000160014ac0e2d229200bffb2167ed6fd196aef9d687d8bb02483045022100fa88a9e7930b2af269fd0a5cb7fbbc3d0a05606f3ac6ea8a40686ebf02fdd85802203dd19603b4ee8fdb81d40185572027686f70ea299c6a3e22bc2545e1396398b20121021f110909ded653828a254515b58498a6bafc96799fb0851554463ed44ca7d9da00000000",
       +        self.assertEqual("0200000000010139c5375fe9da7bd377c1783002b129f8c57d3e724d62f5eacb9739ca691a229d0100000000feffffff01301b0f0000000000160014ac0e2d229200bffb2167ed6fd196aef9d687d8bb0247304402206367fb2ddd723985f5f51e0f2435084c0a66f5c26f4403a75d3dd417b71a20450220545dc3637bcb49beedbbdf5063e05cad63be91af4f839886451c30ecd6edf1d20121021f110909ded653828a254515b58498a6bafc96799fb0851554463ed44ca7d9da00000000",
                                 cmds._run('serialize', (jsontx,)))
   DIR diff --git a/electrum/tests/test_lnutil.py b/electrum/tests/test_lnutil.py
       t@@ -526,9 +526,9 @@ class TestLNUtil(ElectrumTestCase):
                TIMEOUT = False
                output_htlc_tx[0] = (SUCCESS, "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219700000000000000000001e8030000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402206a6e59f18764a5bf8d4fa45eebc591566689441229c918b480fb2af8cc6a4aeb02205248f273be447684b33e3c8d1d85a8e0ca9fa0bae9ae33f0527ada9c162919a60147304402207cb324fa0de88f452ffa9389678127ebcf4cabe1dd848b8e076c1a1962bf34720220116ed922b12311bd602d67e60d2529917f21c5b82f25ff6506c0f87886b4dfd5012000000000000000000000000000000000000000000000000000000000000000008a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f401b175ac686800000000")
        
       -        output_htlc_tx[2] = (TIMEOUT, "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219701000000000000000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d5275b3619953cb0c3b5aa577f04bc512380e60fa551762ce3d7a1bb7401cff9022037237ab0dac3fe100cde094e82e2bed9ba0ed1bb40154b48e56aa70f259e608b01483045022100c89172099507ff50f4c925e6c5150e871fb6e83dd73ff9fbb72f6ce829a9633f02203a63821d9162e99f9be712a68f9e589483994feae2661e4546cd5b6cec007be501008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000")
       +        output_htlc_tx[2] = (TIMEOUT, "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219701000000000000000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100d5275b3619953cb0c3b5aa577f04bc512380e60fa551762ce3d7a1bb7401cff9022037237ab0dac3fe100cde094e82e2bed9ba0ed1bb40154b48e56aa70f259e608b0147304402205735e9f335dfd123f730ac5bf184fd7d5b672e4d84c51a3f0478cc229bb44936022018b1cec3e3b29e5cc335d7e326bc29d75a7e063216427d081cb83ebdbd828b4d01008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868f6010000")
        
       -        output_htlc_tx[1] = (SUCCESS, "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219702000000000000000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402201b63ec807771baf4fdff523c644080de17f1da478989308ad13a58b51db91d360220568939d38c9ce295adba15665fa68f51d967e8ed14a007b751540a80b325f20201483045022100def389deab09cee69eaa1ec14d9428770e45bcbe9feb46468ecf481371165c2f022015d2e3c46600b2ebba8dcc899768874cc6851fd1ecb3fffd15db1cc3de7e10da012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000")
       +        output_htlc_tx[1] = (SUCCESS, "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219702000000000000000001d0070000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e050047304402201b63ec807771baf4fdff523c644080de17f1da478989308ad13a58b51db91d360220568939d38c9ce295adba15665fa68f51d967e8ed14a007b751540a80b325f202014730440220481a48f83c358ae0f220e37f88e56b3d434cefaded82065b8e7a9fd78fee7a26022022674ab37a4c39e6efba302f760ca05931d8add8d65231c5bf34a6c2a76b15bf012001010101010101010101010101010101010101010101010101010101010101018a76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a9144b6b2e5444c2639cc0fb7bcea5afba3f3cdce23988527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f501b175ac686800000000")
        
                output_htlc_tx[3] = (TIMEOUT, "020000000001018154ecccf11a5fb56c39654c4deb4d2296f83c69268280b94d021370c94e219703000000000000000001b80b0000000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e0500483045022100daee1808f9861b6c3ecd14f7b707eca02dd6bdfc714ba2f33bc8cdba507bb182022026654bf8863af77d74f51f4e0b62d461a019561bb12acb120d3f7195d148a554014730440220643aacb19bbb72bd2b635bc3f7375481f5981bace78cdd8319b2988ffcc6704202203d27784ec8ad51ed3bd517a05525a5139bb0b755dd719e0054332d186ac0872701008576a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a9148a486ff2e31d6158bf39e2608864d63fefd09d5b88ac6868f7010000")
        
   DIR diff --git a/electrum/tests/test_wallet_vertical.py b/electrum/tests/test_wallet_vertical.py
       t@@ -603,10 +603,10 @@ class TestWalletSending(TestCaseForTestnet):
                tx_copy = tx_from_any(tx.serialize())
                self.assertTrue(wallet2.is_mine(wallet2.get_txin_address(tx_copy.inputs()[0])))
        
       -        self.assertEqual('0100000001e228327e4c0bb80661d258d625f516307e7c127c7f3e2b476a22e89b4dae063c000000006b483045022100d3895b31e7c9766987c6f53794c7394f534f4acecefda5479d963236f9703d0b022026dd4e40700ceb788f136faf54bf85b966648dc7c2a608d8110604f2d22d59070121030b482838721a38d94847699fed8818b5c5f56500ef72f13489e365b65e5749cffeffffff02a0860100000000001600148a28bddb7f61864bdcf58b2ad13d5aeb3abc3c4268360200000000001976a914ca4c60999c46c2108326590b125aefd476dcb11888ac00000000',
       +        self.assertEqual('0100000001e228327e4c0bb80661d258d625f516307e7c127c7f3e2b476a22e89b4dae063c000000006a47304402207d352950df94d1243917abe4fa5c4f74e0ad7eb47ee02232a2939f52d87d6e57022047603b9ffb32a200d530f5c54eed5245f1034e6ed77462d23e3417b8e763f25c0121030b482838721a38d94847699fed8818b5c5f56500ef72f13489e365b65e5749cffeffffff02a0860100000000001600148a28bddb7f61864bdcf58b2ad13d5aeb3abc3c4268360200000000001976a914ca4c60999c46c2108326590b125aefd476dcb11888ac00000000',
                                 str(tx_copy))
       -        self.assertEqual('5f25707571eb776bdf14142f9966bf2a681906e0a79501edbb99a972c2ceb972', tx_copy.txid())
       -        self.assertEqual('5f25707571eb776bdf14142f9966bf2a681906e0a79501edbb99a972c2ceb972', tx_copy.wtxid())
       +        self.assertEqual('d0e40c8a8586f7faf33505269df64ebad317e8188f008649faaf48cbeb49dae8', tx_copy.txid())
       +        self.assertEqual('d0e40c8a8586f7faf33505269df64ebad317e8188f008649faaf48cbeb49dae8', tx_copy.wtxid())
                self.assertEqual(tx.wtxid(), tx_copy.wtxid())
        
                wallet1.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
       t@@ -651,7 +651,7 @@ class TestWalletSending(TestCaseForTestnet):
                outputs = [PartialTxOutput.from_address_and_value(wallet2.get_receiving_address(), 370000)]
                tx = wallet1a.mktx(outputs=outputs, password=None, fee=5000, tx_version=1)
                partial_tx = tx.serialize_as_bytes().hex()
parazyd.org:70 /git/electrum/commit/a6aa97c3e3a248f24a3e0c5d85f1f48bac230af2.gph:154: line too long