There is No Security Trade-off Running a Thin Client Instead of a Full Node

Sam Armstrong
8 min readApr 3, 2018

It’s been said “Not your private key, not your Bitcoin. Not your node, not Bitcoin”. The theory goes like this. If you aren’t running a fully validating node to verify your own transactions, then you can’t know if you are transacting on the chain you intend to. Running a full node “guarantees” that you are securely transacting according to the exact rules that you desire.

Let’s see how close we can get to the security of a full node without running one. Without running a full node, supposedly an attacker can fool your not-full node into accepting a block which has one or more of the following 3 properties.

  1. Contains invalid transactions.
  2. Contains transactions which were never broadcast to miners, and further blocks won’t be built upon.
  3. Is an invalid block according to other consensus rules not surrounding transactions.

So then, without a fully validating node, what types of blocks are you able to accept or reject? That depends on what information you record. But let’s start with…

  1. Record only transactions related to your own addresses.

In this situation you’re trusting the full nodes you’ve connected your wallet to. For example, if you’re running an Electrum wallet on a Tails OS, you have zero storage because the operating system is amnesiac. But because Tails routes through TOR, your traffic should remain untraceable, and any attacker would have to control all the exit nodes you selected or the full nodes you’ve connected to for any chance of fooling you. And if you can’t connect through TOR, just assume you’re under direct attack.

If any one of them deviates from the others when reporting blocks or transaction history, cutting them off and replacing them with a different full node would be applicable. As I’ve stated before, merchants can be relied upon to run full nodes so long as they can accept 0-confirmation transactions, because that’s the only way to verify a transaction before miners have done so. Paying a fee for access to these nodes would make such access to nodes infeasible.

But we can do better than simply making nodes fight it out between each other and accepting the blocks of the majority if you…

2. Record the hash difficulty and the last 100 block headers.

Now we can verify that any block given to us by N-number of nodes not only match each-other, but that the hash of the block matches the requirements of the block difficulty algorithm. This allows us to verify that any transaction sent to our address is included in a such a block at the tip of the blockchain, and that the miner thinks such a transaction would be built upon by other miners, so it’s likely a valid transaction.

But we can do even better than a simple Keynesian Beauty Contest if you…

3. Record every block header and coinbase in the chain with the most proof of work.

How to calculate the Merkle Branch (H = hashing function)

Now we’re getting somewhere. This is where we can validate that any transaction output sent to us has been included somewhere in the blockchain. Whenever a transaction is sent to you and it gets included in the blockchain, if you don’t trust the fully validating nodes you’re connected to, and you don’t trust that the Keynesian Beauty Contest would lead miners to orphan blocks with invalid transactions, and therefore strive never to create them, then you simply require that the sender specify the Merkle Branch with the utxo from which they received the transaction. Nobody can trick you into thinking a transaction is in a block that it isn’t part of because the Merkle Branch will always lead to the root hash.

With these components, a thin client can validate…

  1. The hash power validity
  2. Block reward validity
  3. A host of other validity rules that don’t affect transactions

There’s only one rule which thin clients can’t verify directly because they don’t have the transaction history. Double-spending. But for this, thin clients have a solution. Remember those merchants accepting 0-confirmations running full nodes. Now that you have all the block headers, you have a way to verify all information given to you. At worst, if merchants are unwilling to provide an honest transaction lookup service for you in a show of good will (as if they wouldn’t freely prove a double-spend to everybody on a network they’re using to prevent double-spends), all you need to do is create a bounty.

“Hear ye, hear ye, I have 1 Bitcoin for the first person who can provide proof of a block, built on top of block X which is buried by 6 or more blocks at the current hashing difficulty, is the longest proof of work chain from block X, and contains a transaction with an input that was already spent in a previous block.”

Just… you know, write that into a smart contract or something, maybe on a competing chain, uncontrolled by the miners you don’t trust… maybe crowdfunded.

Any selfish node runner, including said 0-confirmation merchants, would be perfectly able to provide such proof, and you don’t need to trust anybody to verify the data they give to you to prove it. Just verify the hashes.

But more than this, with just the headers, you can know exactly which chain you are transacting on. If you keep track of the headers of any significant fork of the blockchain, your thin client can tell you which side of a fork a transaction was sent or received on. If you wish to only keep track of a single branch, you will know if any transaction sent to you is on that chain when the miners include those transactions on that block. So now you can simply ignore any branch where the reward for a proven double-spend is claimed.

You’ll notice that we aren’t keeping anything other than the block header, which means the we can have a secure node without caring about a block size limit at all. This isn’t even necessarily a security trade off. Your full node running on your own hardware is directly link-able to yourself. Since we’re on the subject of things incredibly unlikely to happen, if a government ever raids you, it can prove you were tracking a collection of addresses by determining how frequently your computer read certain disk space of your hard drive where your transactions were stored.

If Ross Ulbricht used TAILS OS with a memorized Mnemonic, saved only the block headers on a thumb drive, and temporarily downloaded his transactions which he could verify with the block headers, would they even have been able to verify he owned those Bitcoin? Though it’s true they caught him with the private keys, finding his full node would have been good enough to determine which addresses were his. That smoking gun cost him his life. Even if TOR is compromised and they have your full request history, that has to be submitted to evidence, something the government is highly unlikely to admit for a single criminal case (also possibly making the evidence inadmissible). Full nodes are bad OpSec. In contrast, the block headers can be downloaded over TOR in a couple minutes and never stored on a hard drive.

To recap, here is the perfectly secure protocol with no opportunity for anybody other than your counter party to identify your transactions and addresses

  1. Have anybody who sends you a transaction provide the Merkle Branch for it.
  2. When you send a transaction, download every new block until your transaction is included, and send that Merkle Branch to your recipients doing the same thing.
  3. Wait for more block headers built on those blocks.
  4. Wait for the double-spend proof reward to be claimed.
  5. If not claimed, transaction complete.

Sure, you might miss out on transactions that senders don’t tell you about… But now you have perfect security even when your hardware is confiscated.

But even if you’re not worried about OpSec, SHA-256 is an incredibly easy snip-it of code to audit, and there are vast numbers of input/output examples with which to verify the code you’re running. In Full Node software, there’s a few orders of magnitude more code to audit.

When you installed the full node, did you even bother the check that the software hashes matched the published hashes? Did you audit the code of your full node? No? Then you’re trusting someone. At absolute best, you’re trusting in your own ability to detect software defects and malicious code. If you’re not a committed open source software engineer, then you’re trusting a server from which you downloaded your installer, a software developer who wrote it, and the open source community to keep an eye on things for you… and that’s only if your node even runs open source software.

I know, I know, the likelihood of these things being compromised are minuscule, but we’re talking about a world where you can’t even depend on independent selfish full node runners to provide proof of miners including a double spend in a block to claim a 1 Bitcoin reward at no added cost to them-self. If that’s fair game to deny, then so is the government forensically determining your transactions. This the level of security that Small Block Bitcoin advocates are talking about.

“The archive nodes will be mutated and we can’t possibly stop it if the block size gets too big! (even though you’ll be able to tell it was mutated because the hashes don’t match the headers of your thin client) Increasing it will lead to centralization and the inability of users to securely verify their own transactions. No, we can’t even require them to set a crowdfund bounty (like it would ever come to that) for information that they can verify the correctness of!”

When the “increase” in security is on the order of “Make sure you only run open source software, where the installer matches the published hash, and go audit the code yourself”, the marginal utility of the added security you’re talking about is near infinitesimal.

Your protecting yourself from x-rays hitting you in the head by wearing a tinfoil hat. But whatever man… you do you. Have some tinfoil.

--

--