URI: 
       tMerge pull request #5494 from SomberNight/tx_signing_perf_20190708 - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 261c492c37d45193b808b9c91c6b3e5549dc9c42
   DIR parent a14016275b028bb53e9a2151bb27bdb84d063d07
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Tue,  9 Jul 2019 17:41:56 +0200
       
       Merge pull request #5494 from SomberNight/tx_signing_perf_20190708
       
       ttransaction: segwit input signing was doing quadratic hashing
       Diffstat:
         M electrum/transaction.py             |      35 +++++++++++++++++++++++++-------
       
       1 file changed, 28 insertions(+), 7 deletions(-)
       ---
   DIR diff --git a/electrum/transaction.py b/electrum/transaction.py
       t@@ -86,6 +86,12 @@ class TxOutputHwInfo(NamedTuple):
            script_type: str
        
        
       +class BIP143SharedTxDigestFields(NamedTuple):
       +    hashPrevouts: str
       +    hashSequence: str
       +    hashOutputs: str
       +
       +
        class BCDataStream(object):
            """Workalike python implementation of Bitcoin's CDataStream class."""
        
       t@@ -958,7 +964,18 @@ class Transaction:
                s += script
                return s
        
       -    def serialize_preimage(self, txin_index: int) -> str:
       +    def _calc_bip143_shared_txdigest_fields(self) -> BIP143SharedTxDigestFields:
       +        inputs = self.inputs()
       +        outputs = self.outputs()
       +        hashPrevouts = bh2u(sha256d(bfh(''.join(self.serialize_outpoint(txin) for txin in inputs))))
       +        hashSequence = bh2u(sha256d(bfh(''.join(int_to_hex(txin.get('sequence', 0xffffffff - 1), 4) for txin in inputs))))
       +        hashOutputs = bh2u(sha256d(bfh(''.join(self.serialize_output(o) for o in outputs))))
       +        return BIP143SharedTxDigestFields(hashPrevouts=hashPrevouts,
       +                                          hashSequence=hashSequence,
       +                                          hashOutputs=hashOutputs)
       +
       +    def serialize_preimage(self, txin_index: int, *,
       +                           bip143_shared_txdigest_fields: BIP143SharedTxDigestFields = None) -> str:
                nVersion = int_to_hex(self.version, 4)
                nHashType = int_to_hex(1, 4)  # SIGHASH_ALL
                nLocktime = int_to_hex(self.locktime, 4)
       t@@ -966,9 +983,11 @@ class Transaction:
                outputs = self.outputs()
                txin = inputs[txin_index]
                if self.is_segwit_input(txin):
       -            hashPrevouts = bh2u(sha256d(bfh(''.join(self.serialize_outpoint(txin) for txin in inputs))))
       -            hashSequence = bh2u(sha256d(bfh(''.join(int_to_hex(txin.get('sequence', 0xffffffff - 1), 4) for txin in inputs))))
       -            hashOutputs = bh2u(sha256d(bfh(''.join(self.serialize_output(o) for o in outputs))))
       +            if bip143_shared_txdigest_fields is None:
       +                bip143_shared_txdigest_fields = self._calc_bip143_shared_txdigest_fields()
       +            hashPrevouts = bip143_shared_txdigest_fields.hashPrevouts
       +            hashSequence = bip143_shared_txdigest_fields.hashSequence
       +            hashOutputs = bip143_shared_txdigest_fields.hashOutputs
                    outpoint = self.serialize_outpoint(txin)
                    preimage_script = self.get_preimage_script(txin)
                    scriptCode = var_int(len(preimage_script) // 2) + preimage_script
       t@@ -1129,6 +1148,7 @@ class Transaction:
        
            def sign(self, keypairs) -> None:
                # keypairs:  (x_)pubkey -> secret_bytes
       +        bip143_shared_txdigest_fields = self._calc_bip143_shared_txdigest_fields()
                for i, txin in enumerate(self.inputs()):
                    pubkeys, x_pubkeys = self.get_sorted_pubkeys(txin)
                    for j, (pubkey, x_pubkey) in enumerate(zip(pubkeys, x_pubkeys)):
       t@@ -1142,14 +1162,15 @@ class Transaction:
                            continue
                        _logger.info(f"adding signature for {_pubkey}")
                        sec, compressed = keypairs.get(_pubkey)
       -                sig = self.sign_txin(i, sec)
       +                sig = self.sign_txin(i, sec, bip143_shared_txdigest_fields=bip143_shared_txdigest_fields)
                        self.add_signature_to_txin(i, j, sig)
        
                _logger.info(f"is_complete {self.is_complete()}")
                self.raw = self.serialize()
        
       -    def sign_txin(self, txin_index, privkey_bytes) -> str:
       -        pre_hash = sha256d(bfh(self.serialize_preimage(txin_index)))
       +    def sign_txin(self, txin_index, privkey_bytes, *, bip143_shared_txdigest_fields=None) -> str:
       +        pre_hash = sha256d(bfh(self.serialize_preimage(txin_index,
       +                                                       bip143_shared_txdigest_fields=bip143_shared_txdigest_fields)))
                privkey = ecc.ECPrivkey(privkey_bytes)
                sig = privkey.sign_transaction(pre_hash)
                sig = bh2u(sig) + '01'