You can fix it this way, and someone is in the process of doing so.
The problem with hashing the entire transaction is that in order to create a transaction hash, you must know the signature. However, in order to create the signature, you need to know the transaction hash. To make this work, you need to avoid hashing the scriptSig. This is what Bitcoin does, but the way it's implemented prevents you from taking the hash for one output and using it for another.
BIP143 (part of segregated witness) proposes a system where data is (mostly) hashed once.
A new transaction digest algorithm is defined, but only applicable to
sigops in version 0 witness program:
Double SHA256 of the serialization of:
- nVersion of the transaction (4-byte little endian)
- hashPrevouts (32-byte hash)
- hashSequence (32-byte hash)
- outpoint (32-byte hash + 4-byte little endian)
- scriptCode of the input (serialized as scripts inside CTxOuts)
- value of the output spent by this input (8-byte little endian)
- nSequence of the input (4-byte little endian)
- hashOutputs (32-byte hash)
- nLocktime of the transaction (4-byte little endian)
- sighash type of the signature (4-byte little endian)
This gets run for each input. Every part of this is fixed length, except for scriptCode, but there's no way to make one scriptCode be hashed by multiple inputs. There are three inputs based on variable-length information, hashPrevouts, hashSequence, and hashOutputs, but there's limited potential for mischief there. All methods of computing them either hash one input/output, or are shared by the entire transaction, or are all zeroes.
Validating very large BIP143 transactions will take linear time, and be dominated by signature verification. However, BIP143 transactions cannot be made right now, as segregated witness has not been accepted by the miners.
I understand that signatures can't be signed, I guess I don't know why the hash for each input Sig is different? If all sigs are removed prior to hashing, why isn't the whole blob hashed just once for the entire transaction? – pinhead – 2017-02-09T21:47:22.783
Because each hash is hashing something slightly different. The references of BIP143 go into more detail about this, but you should especially look at https://en.bitcoin.it/wiki/OP_CHECKSIG TL;DR: the input you're signing for has a part of the scriptPubKey of the previous transaction in it. This is consensus-critical; changing it requires a hardfork or the creation of a new way of signing transactions.
– Nick ODell – 2017-02-09T22:28:02.137But it's only critical to consensus for
OP_CHECKSIGright? What if there was just a new op code that signed differently? – pinhead – 2017-02-09T22:31:57.973That's only for OP_CHECKSIG, correct. The new opcode is a data push of one byte of 0 to 16. – Nick ODell – 2017-02-09T22:36:30.693
Right so why not add a
OP_CHECKSIG2and new tx/address type as a soft fork that hashes the whole tx minus sigs one time and uses that hash for each input? – pinhead – 2017-02-09T22:43:29.983That would be a reasonable solution, and it would work well in most cases. However, 143 allows ANYONECANPAY and SINGLE, which wouldn't work if only hashing once. – Nick ODell – 2017-02-09T22:53:17.953