2

Legacy transactions only include transaction components in the SignatureHash, but segwit transactions also add the amounts of inputs in the SignatureHash.

Quoting from the Mastering Bitcoin Book:

Segregated Witness signatures incorporate the value (amount) referenced by each input in the hash that is signed. Previously, an offline signing device, such as a hardware wallet, would have to verify the amount of each input before signing a transaction. This was usually accomplished by streaming a large amount of data about the previous transactions referenced as inputs. Since the amount is now part of the commitment hash that is signed, an offline device does not need the previous transactions. If the amounts do not match (are misrepresented by a compromised online system), the signature will be invalid.

Quoting from that paragraph:

If the amounts do not match

What amounts? In what context?

What I don't understand here is that a transaction doesn't have the input amount anyway. It's hashed only post-segwit. But then if it's hashed, that doesn't add any value in transaction verification, because the previous output is signed in the previous transaction, and we either have the value from that previous transaction to check that no "money printing" happened, or we don't have it. It's not available in clear text anyway to add to verification.

What are the possible attacks or bottlenecks that could've been possible if the amount in the input is not part of the SignatureHash? Can someone explain the scenario in detail because I'm failing to see the full picture.

1

1 Answer 1

5

Consider a transaction that has 2 inputs and 1 output. Let's say that the inputs are both 1 BTC and the output is 1.5 BTC. This would mean that the transaction pays a 0.5 BTC fee, which is ridiculous.

Consider a hardware signer which has no idea of the blockchain's state, but it still needs to know those input values in order to display to the user before it signs the transaction. Let's suppose the hardware signer has a more efficient protocol where the host provides the transaction and just the UTXOs (the scripts and amounts) that are being spent.

If the host were honest, it would provide the transcation and the UTXOs spent with their correct amounts. The user would see that they are spending 2 BTC and throwing away 0.5 BTC as fee, so they would reject the transaction.

But what if the host were malicious? Suppose the host instead provided 1 UTXO correctly, but the second UTXO has the wrong amount - 1.500001 BTC instead of 2 BTC. Now when the hardware signer shows the user that they are sending 1.5 BTC with a fee of 0.000001. This would be a reasonable transaction so the user approve the transaction and it would be signed and sent. But what they actually signed was a transaction that sent 0.5 BTC to transaction fees.

With non-segwit scripts, the above scenario is possible, so in order to protect against it, hardware signers require that non-segwit inputs provide the entire previous transaction so that the transaction id can be calculated and compared against the transaction id given in the spending transaction. This guarantees that the amount is correct as if it were not, the transaction id would be different. But this can be a lot of data, and so it is not efficient.

However with segwit, the amount for a given input is signed, so it is not necessary to provide the full previous transaction. In the malicious case, the user accepts the transaction and the hardware signer signs it. However when it signs it, it commits to the amount of the input, and so it would commit to the wrong input amount of 1.500001 instead of 2. When this transaction is broadcast, nodes will validate the signature and find it to be invalid as they would be using the correct input amount of 2. Thus segwit prevents this attack from working.

...Except not completely. After segwit was deployed, we discovered there is a way bypass this. Suppose the malicious host is able to convince the user to sign the same transaction twice - perhaps after the first time it claims there was some error and the user needs to try again.

In this scenario, the host can provide the correct amount for the first input and the incorrect amount for the second input for the first signing attempt. This would produce a valid signature for the first input, and an invalid one for the second input. Then it prompts the user to sign again, and this time it provides the incorrect amount for the first input, and the correct amount for the second input. Now the malicious host has a valid signature for the second input too. It can combine those two signatures and produce a valid transaction which has the transaction fee of 0.5 BTC.

With this new attack scenario, some hardware vendors decided to require the entire previous transaction when signing segwit inputs as they do with legacy inputs.

But there is a solution for this second issue which Taproot solves. The solution is to commit to the amounts for all of the UTXOs being spent. Instead of just the amount for the particular UTXO that the signature will be in the scriptSig for, the amounts of all other UTXOs will be included in the signature. This means that changing one amount will result in all of the signatures in the transaction becoming invalid, so this new attack cannot work. Just for good measure, Taproot also commits to all of the scripts of all UTXOs as well.

4
  • 2
    The difference is really that with segwit, the input amounts are signed directly. They were already signed through the fact that the the prevout txids are signed, and these commit to the output amounts. But if signing software/hardware wants to observe those values, it needs to be provided with the preimages of those txids, which is a lot of data. By additionally including the input amounts directly in the signature message, we know signatures will be invalid if the amount provided to the signer mismatches the actual UTXO spent. May 19 at 15:37
  • Thank you for the answer; I appreciate it. The Optech link in my question's comment gave me the answer, but the Taproot part from you is extra-helpful. If I understand correctly, the solution from Taproot is considered the default new way of doing things. If, however, someone wants to create an "Anyone can pay" commitment, the new solution wouldn't work, and then verification would require the old route of downloading the whole transaction of the inputs. Am I getting this right? May 24 at 12:03
  • @TheQuantumPhysicist Yes, if you signed with anyone can pay, then the amounts are not directly committed to, because otherwise it wouldn't allow anyone to pay. The point of anyone can pay is that inputs can be added and removed by anyone, unless at least one input uses SIGHASH_ALL. However anyone can pay is almost never used in practice, and hardware signers (for which the protection is largely targeted towards) won't sign with anything other than SIGHASH_ALL.
    – Andrew Chow
    May 24 at 16:35
  • @AndrewChow actually it is. More than a couple thousands input per day contain an ACP signature. (transactionfee.info/charts/…, transactionfee.info/charts/…, transactionfee.info/charts/…) The Specter supports signing using ACP. However it it's an "advanced" thing. Jun 20 at 9:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.