Suppose you have a 3 of 5 multi-signature wallet (there are many possibilities, but 3 or 5 is my preference which I will explain in a different article).
The goal is never to have a computer holding enough keys to spend. If that computer is compromised, your bitcoin are lost. Splitting the keys across multiple computers in different locations is much safer, and requires an attacker to access multiple computers in different locations simultaneously. If you notice one computer is compromised, you have time to move your funds before the second is taken (if its presence is even known about). Basically, NO SINGLE POINT OF FAILURE.
It is also important that two computers (with a sum of keys enough to spend) never touch. This means, don’t put a USB drive in one of these computers and then in the other, because malicious software potentially has access to all keys from the USB. I have no idea how an attacker could do this, but that doesn’t mean they can’t. So be safe. This leaves the problem of sharing a transaction between these computers so you can spend funds when you need to. This will be explained later.
This is one possible way to achieve the above goals:
Create a multisignature wallet. This example uses a 3 of 5 multisig, and shows how to spread out the keys:
Computer 1 has an Electrum Wallet with private key 1, and public keys 2, 3, 4 and 5 (can’t spend).
Computer 2 has an Electrum Wallet (3 of 5 multisig) with private keys 2 & 3 (Zpriv), and 3 public keys (Zpubs) 1, 4, and 5 (so it also can’t spend). Ideally, this computer is air-gapped. (A third private key on this computer would defeat the whole purpose of the plan explained at the start. Keep a maximum of 2 keys here.) How to set up an air-gapped Electrum wallet is tricky. I have explained it here.
Neither computer, if compromised, can lead to your funds being stolen; both computers need to be compromised simultaneously. This adds extra safety but makes spending more cumbersome. If one computer is stolen/compromised, then move all your funds to a new wallet, and start again.
It might seem counterintuitive to have two keys on a single computer. There is a reason for this. Even if you had a 5 of 7 multisig wallet, for example, you can keep 4 keys on Computer 2, and 1 key on computer 1. This is safe enough and doesn’t add too much inconvenience when you want to spend. But then the question naturally arises, “Isn’t this just reducing the safety of your system to a 2 of 2 multisig wallet with 1 key on each computer? This is correct, partly.
Note, there are other reasons to have more than 2 keys, not just reducing single points of failure. For example in bequeathment plans, you may wish to pass 5 keys to 5 trusted individuals who do not know each other, and can not collude to spend your funds until you die (Article coming one day).
Also note: Seed phrases for 4 and 5 are NEVER required to be entered into a computer. (But the PUBLIC keys are ALWAYS required to generate the wallet at least. This is further explained in my multisignature article). These are your backup keys in case you lose one or two private keys. You can also use these keys for sharing with 3rd parties. The extra keys in a 3 of 5 system add flexibility compared to a 3 of 3 multisig.
Keep in mind that the more keys you need to spend, the larger, and more costly, any transaction becomes. This is magnified if you have say 2 UTXOs in one address and you want to spend the whole balance of that address. In that case, you have 3 keys signing for each UTXO, a total of 6 signatures! That would be close to six times the expense of a single key spending a single UTXO. Note that a 3 of 10 multisig is not more expensive to spend from than a 3 of 5 — it’s the signing keys that add to the cost. (I could be completely or slightly wrong about this last statement though. I have not tested it, and I’m making some assumptions about the comparison)
PSBTs (Partially Signed Bitcoin Transactions)
On Computer 1’s Electrum Wallet, go through the process of signing a transaction. You CAN’T do it on an air-gapped (no internet) computer (Computer 2) because that wallet does not have any knowledge of UTXOs, it only has keys and addresses. The balance on Computer 2 always shows zero.
You need to start with the computer that is connected to your node (or, not ideal, but to a public Electrum node works too). Then, you can take some coins in your wallet and generate a transaction (see part 2 below). You can sign the transaction, but you won’t be able to broadcast it (because it is only signed by 1 of 5 keys so it’s not valid yet).
Instead, when you get to this stage, export the transaction to a file on a USB stick and load that transaction to Computer 2 (see Part 2). You’ll see it is 1 of 5 signed. You then sign it with THAT wallet, and it becomes 3 of 5 signed, ready to broadcast. Because Computer 2 is air-gapped, you actually can’t broadcast it from that computer, even though it’s signed. You need to first export the transaction (now fully signed) back to Computer 1, which has access to your node. From there, you load it and broadcast it.
One very tiny risk with this setup, which can be eliminated, is that malicious code invisible to you can be transmitted through any USB stick you use to move a partially signed transaction from one computer to another, and this malicious code could theoretically have access to all 3 keys needed to steal your funds. To mitigate this risk, instead of exporting a partially signed transaction to a USB, you can export it to a QR code which is displayed on the screen (see Part 2 below).
You can take a photo with your phone, and show that image to the camera connected to Computer 1, to import the transaction to the wallet. This way, there is no physical connection ever between the two computers. (As long as there is no malicious code transmitted in the QR codes which is super unlikely, maybe even impossible I’m not sure of that).
I have found this method works, but only for small transactions. (It is not at all about the size of the transaction in Bitcoin, but the size of the transaction in bytes, which increases with signature data). When there are multiple UTXOs being spent from an address to another address, the QR code becomes so big, it becomes unreadable (QR codes are not designed for large amounts of data).In this situation, you could accept the tiny risk of your USB being compromised, but there is a better way:
Add Computer 3 to the system (Electrum wallet, 5 public keys, zero private keys, connected to the internet, connection to a node is optional)
This computer can be the “middle man”, communicating with one of the computers only via email, but can safely accept a USB stick.
For example, I can generate a partially signed transaction from the computer with one seed (Computer 1), email it to Computer 3, then put it on the USB from there, take the USB to Computer 2 (air-gapped), and then load the transaction.
As long as the transaction being emailed has no malicious code, it is safe. (Remember the transaction is public knowledge anyway, so no need to encrypt it).
This way, if there is hidden malicious code on the USB stick, it never touches the computer with the final “spending seed.” In other words, the USB stick never touches both Computer 1 AND Computer 2.
Generating a transaction…
Start at Computer 1, and make a transaction.
On the screen above, click “pay”
Then click sign. The status “unsigned” shown above, should change to something like 3/9 signed, indicating 1 key has signed 3 UTXOs, which is why there are 3 signatures.
If you click “export”, you have the option to generate a QR code like this…
Take a photo of it with your camera. Don’t scan it, just take the photo. (Note this particular QR code is too big, and won’t work)
If the QR code is going to be too big, you need to use a USB stick. In that case, select export to a file…
Now you can save this to your USB, or to your computer and email it to yourself…
Next, go to Computer 3 (no private keys), and open your email, and download the transaction to the computer from your email. Then load the transaction in Electrum:
When the next screen loads, click sign, and this will be the result:
Notice it is still 3/9 signed, and there is no option to sign. That is because this computer holds no private keys.
The next step is to export again to the USB and load it on Computer 2. Then sign. The status will show “signed”.
You then export to USB, and load to Computer 3 (middle man). From here, you can broadcast it if the computer is connected to a node. If not, email it to yourself, download it on Computer 1, load it to Electrum, and broadcast it. Done.
On-chain or Lightning