Segwit, PSBT Vulnerability
Speakers: Luke Dashjr
Date: June 18, 2020
Transcript By: Michael Folkson
SegWit/PSBT vulnerability (CVE-2020-14199)
Location: LA BitDevs (online)
Trezor blog post on the vulnerability: https://blog.trezor.io/latest-firmware-updates-correct-possible-segwit-transaction-vulnerability-266df0d2860
Greg Sanders Bitcoin dev mailing list post in April 2017: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-August/014843.html
The way Bitcoin transactions are encoded in the software is there is a list of coins essentially and then there is a list of destinations and the amount being sent to each destination. The destinations do not include the fee. Nothing in the transaction tells you what the fee of the transaction is. The inputs do not tell you the amount of each input, they are just identifiers that are resolved by a full node. There is no way to tell how many Bitcoin are going into a transaction itself, just in total how many are going out. Without knowing how many are going in you cannot know the fee of the transaction. You need a full node to know the fee of the transaction normally. The way hardware wallets have dealt with this, they need to provide the user with information to confirm, is for each of the inputs your computer over the USB or whatever would send every transaction that created those inputs. That transaction has the amount and the output because it created what is now being used as the input. That was a lot of data. If you are sending a transaction you would not only have to send the hardware wallet the transaction you want to send but also a transaction behind every coin you were spending in that transaction. A few years ago for SegWit the idea was the signature includes the amount of the input in it. If you sign the input is 1 Bitcoin but the input is really 2 Bitcoin the signature is invalid. The idea being the hardware wallet can trust what the computer is telling it for the amount and if the computer is lying the signature won’t matter anyway. The transaction won’t go through. The problem with this turned out to be if you can lie to the hardware wallet in different ways you can trick it into giving you signatures. If it is 30 Bitcoin and then 20 Bitcoin, the example Trezor used. You have got a 30 Bitcoin coin and a 20 Bitcoin coin. You tell the hardware wallet that one of those coins is much smaller than it is and the other coin is bigger than it is. 20 and 30 may not be the best examples for reasons I will get into later. The hardware wallet will then sign for both inputs, each input has its own signature. That transaction is invalid because the computer lied about the amount of the input. But if you trick the user. The computer says “This signature failed. Try again.” Your hardware wallet will then again ask you and you confirm it a second time, the computer is also lying the second time. It is saying the other input is the wrong size. Now you have two different invalid transactions but the signatures on each input in those are valid. The opposite one is invalid. You throw away the invalid signatures and you take the valid signatures and combine them into a new transaction. Now you have a valid transaction with signatures on both inputs and the outputs are what it told you but the fee is completely different because you have the true value of both inputs in there. The one reason this isn’t as concerning necessarily is that the user has to be socially engineered to sign the transaction twice. They have to approve the transaction twice. If the computer is malicious anyway it can make them both be valid transactions and send the transaction twice. The reason that doesn’t negate it entirely is that the hardware wallet could be telling you that it is 0.01 Bitcoin for each of the transactions. You could be thinking “That’s no big deal. If I send it twice, I send it twice.” But that 0.01 may not be the fee you are being tricked into sending. The fee you are being tricked into sending could very well be your whole wallet balance. It is not entirely harmless either.
Q - The worst case scenario is that your funds could be drained from your hardware wallet. Is that correct?
A - Pretty much. That is a pretty bad scenario.
Q - The fee goes to whichever miner picks it up and mines it?
A - Potentially. If the attacker is a miner they can just not broadcast it until it is mined in their own block. I don’t know how probable that is with mining being as centralized as it is. It would be pretty obvious, maybe not. The miner could claim that it was broadcast. There are only so many miners that could pull it off.
Q - Different hardware wallets chose to solve this problem in different ways. Trezor, they did something that broke backward compatibility. Coldcard made you opt in to it.
A - The solution Trezor went with which is pretty straightforward was they just treated a SegWit transaction as a non-SegWit transaction. They sent over the transactions behind every input just like they did before. Not using that feature of SegWit.
Q - People were saying that now you can’t use Trezor with BTCPay Server anymore.
A - The software on the computer has to know that you are treating it as non-SegWit even though it is SegWit. Previously the software assumed if it is a SegWit they don’t need to send the transaction for that because the signature will be signed anyway. Now that they have changed this the software has to send the input transactions for everything even if it is SegWit.
Q - Could you talk through from your perspective if you developed a hardware wallet how would you roll out a fix for this bug? What kind of things would you keep in mind while still maintaining security as your number one feature in your hardware wallet?
A - If security is the number one feature then you would compromise with compatibility with old software. You’d break compatibility with all the software out there but that’s just temporary until that software gets updated. In the meantime you at least have the security of knowing that you are not vulnerable to this attack. You could also tell people “If you don’t want to upgrade until your software is ready simply be aware of this problem and don’t sign multiple times no matter how small the amount may appear.”
Q - For whatever reason you might be signing a transaction you didn’t intend?
A - The transaction will be more or less the same, the same amount being sent but the fee would be a lot larger than what you intended to send. It could be a tiny amount but the fee may be wrong and it may be your entire wallet being sent to fee.
Q - An attacker, they wouldn’t get the funds, all of that would go to the miner?
A - Unless the attacker was the miner. Or had some agreement with the miner.
Q - You said this was a feature of SegWit. Was this an intended feature? Obviously the bug is unintended, to try to make the hardware wallet interface send less data was that an intention?
A - That was a planned feature. If you go to bitcoincore.org and see the SegWit FAQ it has a whole section on how it works.
Q - This was an unforeseen consequence?
A - Yes. Before this exploit was announced it was in Taproot that it was going to sign the amounts of all the inputs to prevent this.
Q - Taproot would have addressed this also in that case?
A - Right. Taproot was going to address this when deployed.
Q - For another reason or due to recognizing this sort of problem?
A - I think it was recognizing it but not necessarily recognizing the security implication.
Q - Were people aware of this problem for a long time and it has just recently come to light or was this is a recent discovery?
A - I didn’t hear about it before Trezor announced it. But I think Trezor said that it was revealed to them a few months previously. Other hardware wallets I guess had asked for more time to fix it.
Q - We have SegWit and that has been deployed for over a year now.
A - Three years now almost.
Q - Just now we are finding out a vulnerability like this. It is crazy to me that on other blockchains people are developing new technologies, new formats and new languages and yet they slap a security audit on it and say you can trust it. Bitcoin Core tech is so rigorously scrutinized and yet three years later we find a bug like this.
A - The review process is definitely a good idea. I don’t know if it provides as much security as people assume it does. Things that slip past one person may very well slip past ten people or whatever.
Q - Will HWI get changed here?
A - Bitcoin Core is going to probably need updates to handle this as well. Right now it will also not provide the transactions if there is a SegWit input. That is being changed. It also actually used to reject PSBT (partially signed Bitcoin transactions) as invalid or another phrase that was used. It would reject those if they had the input transaction for a SegWit input. That is probably a compatibility issue that will have to be addressed. That may get backported into 0.21. I put that fix into Bitcoin Knots 0.20 so if it does become an issue there are options.
Q - There is a fix in 0.20?
A - Bitcoin Knots, my derivative of Bitcoin Core that has a bunch of enhancements and sometimes fixes. It is still in the review process for Core (PR 19215). It may take a few months.
Q - Do you have a general sense of how long it will take for something like Taproot to get reviewed and then implemented in Core?
A - Not really. It really depends on how much time people put into it. There are some bug fixes that have sat for years before finally being merged. Hopefully Taproot won’t be like those. It has a lot of enthusiasm than some other pull requests so hopefully it will get reviewed quicker.
Q - I feel like there are not a lot of people against it if any.
A - I haven’t heard of anyone against it. What I think might be an issue is the activation method. There is some disagreement about what the best approach at this point is. With SegWit we tried to do miner activation but obviously that didn’t work out and we had to switch to user activated. It has never quite clarified in everyone’s mind what the best way to do user activated soft fork is going forward.
Q - Can you lay out the different options people are currently considering?
A - The main two ideas are to do a miner activated soft fork but if the miners don’t do it within a certain amount of time then it becomes active on its own as if it had never been inactive. It is similar to what BIP 149 was that did not get used for SegWit where suddenly the rule starts applying one day and we hope that there are enough people enforcing it. There is no real way to tell. The other approach which we used for SegWit and I think we should probably continue to use is similar to BIP 148 where you have a month or whatever of blocks that explicitly say “This is activating.” You have the signaling for several months before the final activation but that last block before it is locked in should require the miners to explicitly say “Yes I have upgraded. We understand these rules that are coming into effect.” This way everyone can be sure that when it is activated it is actually activated. The rule is expected to be enforced. There is no question of whether Taproot is active or maybe not active and working by chance.
Q - The first one kind of sounds like you are almost forcing the miners. Do this by this time or else you are off the network.
A - Miners never have a choice in the matter. It is all about what the users want. Miners either go along with it or they are mining in an altcoin. The difference lies in whether the blockchain itself is committing to the new rules. Whether the chain says “These are the rules that are now in effect” or whether it is just an assumption that the rules are in effect but nobody really knows until they try to attack it. Usually nobody does try to attack it so it leaves an open question. We wouldn’t know today if SegWit was active or not because there would be no clear indication if we hadn’t done this with SegWit. We would be able to say “No one has attacked my SegWit coins” but there would be no way to know for sure if someone did attack those SegWIt coins whether they would succeed or not.
Q - Is there a fail option? The second option sounds like it is based on percentage. A certain amount of miners have to start signaling that they are going to implement this new fork. Is there a fail option to that?
A - Both options allow miners to indicate that they are ready to protect old nodes early. It could be a month or two months and miners can trigger to activate it early. The question is what happens if the miners don’t do that and it goes on for a year or two or maybe a little shorter? That is another question that needs to be addressed, the timeframe. What happens if it has been a year and the miners haven’t bothered to upgrade yet? If the community is going to activate it anyway do we explicitly have the chain signal that it is going to be upgraded or do we just assume that it has upgraded and hope for the best?
Q - Taproot when it goes into production will it be limited to opcodes or will it look more like Ethereum’s Solidity? More open to different development?
A - One of the main ideas behind Taproot is that in most cases you can have this script that says “These are the rules. Who can spend it. Who can’t spend it.” In most of the cases if both parties in the transaction agree then you don’t need to bother evaluating the rules. You can just have both people sign. In most cases it will short circuit to a multisig. The only time it would have a program run in the script would be if one of the parties is refusing to cooperate. Hopefully the fact that you can fallback to running that script will be an incentive to always cooperate because it is not going to stop anything from happening.
Q - How about creating a complex multisig wallet for example? A 2-of-2 wallet where one of the signers is actually a multisig. Would that become possible?
A - I believe the Schnorr signatures that are included in Taproot make that possible but that script is over my head.