Browse Source

Merge pull request #5494 from SomberNight/tx_signing_perf_20190708

transaction: segwit input signing was doing quadratic hashing
dependabot/pip/contrib/deterministic-build/ecdsa-0.13.3
ThomasV 6 years ago
committed by GitHub
parent
commit
261c492c37
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 35
      electrum/transaction.py

35
electrum/transaction.py

@ -86,6 +86,12 @@ class TxOutputHwInfo(NamedTuple):
script_type: str script_type: str
class BIP143SharedTxDigestFields(NamedTuple):
hashPrevouts: str
hashSequence: str
hashOutputs: str
class BCDataStream(object): class BCDataStream(object):
"""Workalike python implementation of Bitcoin's CDataStream class.""" """Workalike python implementation of Bitcoin's CDataStream class."""
@ -958,7 +964,18 @@ class Transaction:
s += script s += script
return s 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) nVersion = int_to_hex(self.version, 4)
nHashType = int_to_hex(1, 4) # SIGHASH_ALL nHashType = int_to_hex(1, 4) # SIGHASH_ALL
nLocktime = int_to_hex(self.locktime, 4) nLocktime = int_to_hex(self.locktime, 4)
@ -966,9 +983,11 @@ class Transaction:
outputs = self.outputs() outputs = self.outputs()
txin = inputs[txin_index] txin = inputs[txin_index]
if self.is_segwit_input(txin): if self.is_segwit_input(txin):
hashPrevouts = bh2u(sha256d(bfh(''.join(self.serialize_outpoint(txin) for txin in inputs)))) if bip143_shared_txdigest_fields is None:
hashSequence = bh2u(sha256d(bfh(''.join(int_to_hex(txin.get('sequence', 0xffffffff - 1), 4) for txin in inputs)))) bip143_shared_txdigest_fields = self._calc_bip143_shared_txdigest_fields()
hashOutputs = bh2u(sha256d(bfh(''.join(self.serialize_output(o) for o in outputs)))) hashPrevouts = bip143_shared_txdigest_fields.hashPrevouts
hashSequence = bip143_shared_txdigest_fields.hashSequence
hashOutputs = bip143_shared_txdigest_fields.hashOutputs
outpoint = self.serialize_outpoint(txin) outpoint = self.serialize_outpoint(txin)
preimage_script = self.get_preimage_script(txin) preimage_script = self.get_preimage_script(txin)
scriptCode = var_int(len(preimage_script) // 2) + preimage_script scriptCode = var_int(len(preimage_script) // 2) + preimage_script
@ -1129,6 +1148,7 @@ class Transaction:
def sign(self, keypairs) -> None: def sign(self, keypairs) -> None:
# keypairs: (x_)pubkey -> secret_bytes # keypairs: (x_)pubkey -> secret_bytes
bip143_shared_txdigest_fields = self._calc_bip143_shared_txdigest_fields()
for i, txin in enumerate(self.inputs()): for i, txin in enumerate(self.inputs()):
pubkeys, x_pubkeys = self.get_sorted_pubkeys(txin) pubkeys, x_pubkeys = self.get_sorted_pubkeys(txin)
for j, (pubkey, x_pubkey) in enumerate(zip(pubkeys, x_pubkeys)): for j, (pubkey, x_pubkey) in enumerate(zip(pubkeys, x_pubkeys)):
@ -1142,14 +1162,15 @@ class Transaction:
continue continue
_logger.info(f"adding signature for {_pubkey}") _logger.info(f"adding signature for {_pubkey}")
sec, compressed = keypairs.get(_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) self.add_signature_to_txin(i, j, sig)
_logger.info(f"is_complete {self.is_complete()}") _logger.info(f"is_complete {self.is_complete()}")
self.raw = self.serialize() self.raw = self.serialize()
def sign_txin(self, txin_index, privkey_bytes) -> str: def sign_txin(self, txin_index, privkey_bytes, *, bip143_shared_txdigest_fields=None) -> str:
pre_hash = sha256d(bfh(self.serialize_preimage(txin_index))) pre_hash = sha256d(bfh(self.serialize_preimage(txin_index,
bip143_shared_txdigest_fields=bip143_shared_txdigest_fields)))
privkey = ecc.ECPrivkey(privkey_bytes) privkey = ecc.ECPrivkey(privkey_bytes)
sig = privkey.sign_transaction(pre_hash) sig = privkey.sign_transaction(pre_hash)
sig = bh2u(sig) + '01' sig = bh2u(sig) + '01'

Loading…
Cancel
Save