tBTC: Navigating the cross-chain conundrum

Painting by Michael Zeno Diemer

We recently conducted a security assessment of Thesis’ tBTC: a trust-minimized, redeemable, Bitcoin-backed ERC20 token. The project, which uses Keep Network to span Bitcoin and Ethereum, aims to enable a new cross-chain economy by allowing users to transact on Ethereum using Bitcoin-backed ERC20. Our report is publically available here.


It’s not often we get to review a project like tBTC. After all, tBTC spans several systems: Bitcoin, Ethereum, and the Keep Network. The smart contracts that facilitate all this interoperability are quite complex and demand an understanding of all three protocols. Although our previous work with Liquality and Atomic Loans is similar in nature, tBTC’s massive codebase puts it on another level.

During the course of our review, we learned a lot about the development of cross-chain systems. In particular, our research into Bitcoin transactions uncovered a particularly interesting limitation of Bitcoin transaction verification on Ethereum. We expand on this finding here.

What is an SPV proof?

In the context of Bitcoin, an SPV proof is used to prove the existence of a transaction within a given block. Put simply, the proof pairs a Merkle proof with a Bitcoin block’s hashMerkleRoot to show that a transaction exists within the block:

Proofs like these are often used because they are relatively computationally lightweight. This property is especially important in the context of the smart contracts that make up tBTC. Because it runs on the EVM (the Ethereum Virtual Machine), tBTC is naturally constrained by the limited computational resources of Ethereum.

Let’s say we want to prove that some transaction exists on Bitcoin. For this SPV proof, we need a few inputs:

  1. The block header of the block that contains the transaction
  2. The raw transaction itself
  3. The transaction’s index (its position in the block)
  4. A merkle proof (a list of nodes that form a “path” from the transaction to the Bitcoin block header)

Using these inputs, it’s possible to prove that a transaction exists in the block, all without needing to connect to a Bitcoin node. Provided one accepts that the provided Bitcoin block header originates from the longest proof-of-work chain, Simple Payment Verification (SPV) can take place anywhere, on any device.

The cross-chain conundrum

While researching Bitcoin transactions, we came across a fundamental limitation of SPV proofs performed on Ethereum: Bitcoin transaction size.

Bitcoin transactions are constrained primarily by the maximum Bitcoin block size of 4 MB. Additionally, because SPV proofs can exclude witness data, we can reduce the theoretical maximum Bitcoin transaction size to 1 MB. However, for our purposes, the exact upper bound isn’t actually determined by the Bitcoin block size, because it actually turns out to be limited by the Ethereum blockchain.

Why? Unlike Bitcoin, Ethereum’s transactions are constrained by the amount of computational resources their execution consumes. Each operation performed requires a certain amount of gas, and transactions cannot consume more gas than is contained in a single block. This is referred to as the gas limit, which, at the time of writing, is about 10 million gas.

To understand how this roughly equates to Bitcoin transaction size, we can use a definition from the Ethereum yellow paper, Gtxdatanonzero, which is the gas cost required for each byte of data in a transaction. Gtxdatanonzero is 16 gas per byte.

This means that each byte of a Bitcoin transaction supplied as part of an SPV proof consumes 16 gas, minimum. Note that there are additional costs associated with performing an SPV proof, but I’m ignoring those for the purposes of this rough estimation.

So, how large can a Bitcoin transaction get before it becomes impossible to perform an SPV proof on Ethereum? The answer is Ethereum’s block gas limit divided by Gtxdatanonzero:

(10,000,000 gas) / (16 gas per byte) = 625,000 bytes, or about 63% of the 1 MB maximum Bitcoin transaction size.

What does this mean for tBTC?

In tBTC, SPV proofs originally served two purposes:

  1. Deposit proofs: allowed users to prove that they had correctly made a BTC deposit, triggering the tBTC contracts to release corresponding Bitcoin-backed ERC20.
  2. Fraud proofs: allowed users to prove that a BTC deposit had been spent without authorization by the deposit’s custodial signer group, triggering signer slashing and awarding a bond to the deposit owner.

Fraud proofs

SPV fraud proofs allowed users to safeguard against malicious signers. If a signer group colludes, they are able to spend deposited BTC without explicit authorization by the user. By supplying this unauthorized transaction to tBTC’s contracts, users could prove that the spend occurred, penalize the malicious signers, and ensure they were fairly compensated for the loss of their deposit.

However, using the Bitcoin transaction size limitation described above, signers could avoid this penalty by spending the deposit in a large enough transaction.

Luckily, SPV fraud proofs were one of two fraud proof mechanisms implemented in tBTC. The alternative method, ECDSA fraud proofs, provided a much more robust alternative to SPV fraud proofs. As a result, SPV fraud proofs were removed from tBTC’s contracts.

Deposit proofs

Deposit proofs are still used in tBTC as each user enters the system. In order to release Bitcoin-backed ERC20 on Ethereum, users must provide an SPV proof of successful deposit. Although the Bitcoin transaction size issue does not provide a clear method to abuse the deposit system, it is possible that a user might fund a deposit with a valid BTC transaction, only to find their transaction is too large and cannot be validated within the tBTC contracts.

No clear path exists to remove this dependency; SPV proofs must be provided in order to validate a deposit. Fortunately, the Bitcoin transaction size limitation is not so severe as to prevent tBTC from functioning entirely; a simple spend with a single input and output is well within the bounds of Ethereum’s current block gas limit. As long as efforts are made to ensure users are sufficiently aware of this restriction, Bitcoin transaction size should not pose a significant issue when funding deposits.

What can tBTC (and other cross-chain projects) do to ensure their systems work correctly?

Understand the primitives of both chains. When using Ethereum, understand where the EVM falls short in replicating the primitives of other chains. Cross-chain applications bridge two worlds, each with its own time system, rules, and subtle gotchas.

Unit tests will never be enough. Cross-chain dapps, by nature, have moving parts at all ends of the system. In order to ensure those parts work together, developers need to go beyond simple unit testing.

Prepare for the worst. With great complexity comes great responsibility. It’s not realistic to identify every possible issue before release.

Finally, educate your users. Understanding where things may go wrong is part of the battle; the next step is to ensure your users share your understanding. To that end, Matt Luongo of Thesis recently posted a long thread describing tBTC’s security model and governance.

Update May 16, 2020: This article originally gave a gas price of 68 per byte, which has since been updated, and did not mention that witness data can be excluded from the SPV proof. Thank you to James Prestwich and Paul Vienhage for the corrections.


Thinking about smart contract security? We can provide training, ongoing advice, and smart contract auditing. Contact us.

More posts chevronRight icon