I bring this up, because as long as we've committed ourself to a [potential] hardfork in the next month, I think the following should be seriously considered. Why? Because "cold storage" is becoming a major force in the Bitcoin world. More and more people
and companies are looking at the benefits and trying to get it setup. More people are finding themselves wealthy and want to protect it. It
is the holy grail of wallet security (multi-sig, too, but that will probably include offline wallets, instead of replacing it). But implementation suffers from one extraordinary hurdle.
Example:Let's say I want to create a $10 offline signing device. I will put 32 kB of RAM and a small screen and a tiny embedded chip that is just powerful enough for ECDSA signing. It will sign transactions for me after asking me to physically confirm with a button press. But the device has so little RAM, it can't support arbitrary transactions. So, I'll just make sure my online computer software never produces transactions bigger than 10 kB, and just do multiple transactions if necessary. In Armory, I'll happily make that a configurable parameter.
But there's a serious problem here:
this isn't possible (and the Trezor ran into this). Because of a tiny little oversight by Satoshi, nothing about the 10kB transaction indicates what the transaction fee is. Without access to the blockchain, my tiny little device doesn't know whether it's signing 1 BTC input, or 1000 BTC input. To accommodate this, you must supply
all supporting transactions along with the one to be signed (and
BIP 10 does this). By doing this, the offline device can hash the supporting transaction, verify it matches the TxIn it is signing, and then record the 8-byte amount/value from that transaction. It's a lot of work to verify those 8 bytes...
Worse, I don't have control over this. I can choose never to create transactions bigger than X kB, and pick X based on my HW. But if my wallet contains a UTXO that comes from a 100 kB transaction, I have to upload 100 kB to my offline device, just to verify those 8 bytes. This forces devices like the Trezor, to implement streaming calculations, complicating the protocol 10-fold.
If you don't do this, an attacker compromising the online computer could trick your offline computer into signing away your entire wallet to transaction fee. While it's not the most direct way for the attacker to make money, it's the most direct way to ruin you by sending your life savings to some lucky miner (and they may have a way to benefit from it, like owning some mining power).
EDIT: I shouldn't focus entirely on the signing hardware. Another major problem is bandwidth: there's a lot of good ways to transfer a few kB securely between an online and offline computer, but not on the order of megabytes. QR codes are such a method that I keep shooting down, because I have no idea how to make it work with MB of data.
Raw Technical Solution:All this because Satoshi made one little oversight in the
OP_CHECKSIG procedure: the TxOut script is copied into the input being signed,
but not the value. If the value was copied prepended to the TxOut script, then the offline system only needs to be given the 8 bytes, and it could securely present the correct fee to the user and sign it. If an attacker compromises the online computer and puts incorrect values into there to trick the offline computer, the offline signature will be invalid (because full nodes verifying the transaction will use the correct value the signature won't match).
So the technical solution is simple: Add a new SIGHASH type, which I dub SIGHASH_WITHINPUTVALUE. This would have hashcode 0x10. This would be OR'd with the existing hash types. i.e. Currently all "regular" transactions are signed with (SIGHASH_ALL), now anyone who wants the benefit would sign with (SIGHASH_ALL | SIGHASH_WITHINPUTVALUE). It is compatible with the existing hash types.
Analogy:Right Now: "I, the offline computer, sign this input to be sent to this address, no matter how much this input is worth"
Proposal: "I, the offline computer, have been told this input is worth 13.28 BTC. This signature is only valid if that's how much it's actually worth"
Considerations:This solution has some nice properties:
- Simple! For the signing and verification procedures, it's probably only a few lines of code.
- I have full control over data sizes to be exchanged with the offline device, down to the minimum of being able to sign a one-input-one-output transaction. Currently, there's no way to avoid having to deal with 100kB-200kB of transaction data transfer (and if you want to be able to sign multi-input tx, you need to be able to handle megabytes)
- Also makes it resistent to changes at the network level: we plan to allow only 100 kB transactions right now. So without this new SIGHASH, I design my device to handle up to 100kB. But in two years, the limit is raised and people start mining 1 MB transactions, and I find that one of my inputs was from a 1 MB transaction. Hardware upgrade? Remember, the offline wallet needs to handle 100.0% of all transactions!
- No problems with backwards compatibility: Once the change goes into effect, new devices can be made and wallet software updated, to only use the new SIGHASH type. It can be used even on wallets that already contain coins... because it only changes what is being signed.
- Should be completely non-controversial (technically): this adds an optional restriction to transaction validity. It doesn't change overall network topology or philosophy at all. It's like asking the network to confirm, for the signer, that they were given the right value when signing. That's all.
Downsides:- Hardfork (of course). But we've committed ourselves to a hard-fork next month, anyway. And the extra hashtype would simply be "present" next month, but not become usable for 6-12 months, to allow time for upgrades. I think this change has the right combination of simplicity and benefit to be worth throwing in
- Other clients would break if they're not paying attention and they are in the habit of verifying their own transactions. Oblivious nodes would still be able to sign transactions, just not verify them. Not so important for nodes that already trust the network to verify validity of transactions, but I'm sure things would break.
Anyone who has worked on offline wallets knows what a PITA it is to have to deal with supporting transactions. Most of the ideas proposed in the
Improving Offline Tx thread, were shot down because the solution needs to support multi-megabyte transfers. This solution would eliminate that necessity.