Simplified Payment Verification (SPV) security is good enough for most Bitcoin applications. However, the impending activation of Segwit2x changes SPV’s basic security assumptions. This article explains why SPV wallet users face unique risks in the months ahead.
A different risk, known as “replay,” has received considerably more attention than the one described here. Replay occurs when a transaction broadcast to one side a hard fork becomes confirmed on the other. This causes the user to potentially lose funds on the side of the fork to be abandoned. The risk described here, however, can cause loss of funds on the side of the fork the user intends to follow.
Anatomy of a Block
The security risk to SPV nodes traces its origins to the structure of the block chain itself. A block consists of two detachable units: a header and a body. Once detached, header and body can be reassembled with perfect fidelity. This modularity allows headers and bodies to be stored and transmitted separately.
A block header encodes six fields, two of which factor into the current discussion. Both are hash values, a form of mathematically-derived unique identifier. The first hash value links a header to its parent. The second hash value links a header to its body. In this way, a block header is securely linked to both its parent and its body.
|Version||4||Bit array used to signal miner readiness for soft-fork protocol updates. Must evaluate to an integer greater than or equal to two.|
|Parent Block Hash||32||Double SHA-256 hash value of previous block.|
|Merkle Root||32||Unique identifier for an ordered list of transactions.|
|Timestamp||4||Date and time in modified Unix time format.|
|Difficulty Target||4||Maximum allowable value for block’s hash value; encoded in custom format.|
|Nonce||4||Random value used to obtain a hash value satisfying target.|
A block body consists of an ordered list of transactions identified by a Merkle root. Whereas a hash value uniquely identifies a single digital message (e.g., a parent block header), a Merkle root uniquely identifies an ordered list of them (e.g., transactions in a block). If an item in the list changes, or the list is re-ordered, the Merkle root changes as well.
The SPV Compromise
A node requests a complete chain of headers from its peers. Each header is subjected to a series of tests that ensure the validity of its fields, including:
- the version field must be greater than or equal to two when viewed as a signed integer;
- the timestamp must be no greater than two hours ahead of current time; and
- the hash value of the header must be less than the target.
Each header is then connected to its parent. Blocks without parents (orphans) are discarded, along with all of their descendants. Two or more blocks may claim the same parent. The result is a tree with the Genesis Block at its root.
Many paths through a given header tree can be traced. Each is assigned a cumulative proof-of-work by summing the implied work of all member headers. The path with the most cumulative proof-of-work constitutes the active chain. This is also known as the strongest chain, where “strength” refers to cumulative proof-of-work.
A full node complements the above analysis by downloading and validating every block body. Each transaction is checked for validity individually, and as a chain of ownership. The body as a whole is also checked. In particular the block size is computed and must be less than or equal to the current limit.
In contrast, an SPV node stops validation after identifying the active chain. No block is downloaded in its entirety. Instead, only a set of interesting transactions is downloaded. This set typically includes those transactions referencing the members of a particular key pool. This parsimony saves bandwidth, time, storage, and computational power that would otherwise be dedicated to processing complete blocks.
SPV offers users a security tradeoff. In exchange for ignoring block bodies, an SPV node can operate at a fraction of the cost of a full node. Provided that the hash rate majority never tries to publish an invalid block body, an SPV node offers security that approaches that of a full node.
The Stealth Hard Fork
SPV security relies on the honesty of the hash rate majority. In this context, “honest” means that nodes follow the Bitcoin protocol. Specifically, an honest node can be counted on to neither publish nor relay an invalid block. However, this assumption falls apart in the event of a hard fork update.
A hard fork update causes nodes that implement it to publish and relay blocks that were previously considered invalid. Invalid block features can reside in the header, the body, or both. As described above, an SPV node can only detect blocks containing invalid headers. Therefore, blocks with invalid bodies will be accepted as valid.
Any hard fork update that produces valid block headers will be invisible to SPV nodes. As shown previously, block size isn’t one of the six values encoded by a block header. Rather, block size can only be computed from a header/body combination. Because SPV nodes specifically avoid requesting block bodies, they can never reject a header based on the size of the block it represents.
This means that in the absence of a signal encoded into the block header, an SPV node will blindly accept any block size limit increase, no matter how large, provided that it is sufficiently strong.
Bitcoin Cash implemented a block size limit increase, yet Bitcoin SPV nodes will always reject Bitcoin Cash headers. How is this possible?
In addition to its block size limit increase, Bitcoin Cash implemented a feature known as Emergency Difficulty Adjustment (EDA). EDA causes Bitcoin Cash nodes to generate and relay blocks with lower difficulty than would otherwise be considered valid. This change was included to allow a hash rate minority to grow the Bitcoin Cash chain. A side-effect of EDA was to make block headers become invalid to Bitcoin SPV nodes.
When the first EDA became active, a block with an unacceptably high difficulty target field (low proof-of-work) was published by the Bitcoin Cash network. Because the difficulty target is encoded within the block header, Bitcoin SPV nodes rejected all Bitcoin Cash block headers from the moment EDA activated onward.
Unlike Bitcoin Cash, Segwit2x causes no changes to block headers. As such, SPV nodes will accept any Segwit2x header as valid, even those linked to blocks exceeding 1 MB in size. SPV nodes will blindly follow the strongest chain, regardless of the sizes of its member blocks.
By informal agreement, miners intending to implement the Segwit2x hard fork place the three letters “NYA” into the input script of their coinbase transactions. Current support for Segwit2x signaled in this way stands at over 90%. In other words, over 90% of the Bitcoin network hash rate intends to deploy Segwit2x.
Taken at face value, the Bitcoin network stands to lose over 90% of its hash power when Segwit2x activates in mid-November 2017. Block interval will increase tenfold from 10 minutes to 100 minutes or higher. Meanwhile, the Segwit2x network will generate blocks nine times faster than the Bitcoin network.
However, this initial hash rate distribution is subject to change as Segwit2x unfolds. It’s feasible that what starts as a hash rate majority could devolve into a hash rate minority. It’s even possible for relative hash rate to flip-flop several times before settling on a stable distribution.
Unfortunately, even a single switch in hash rate distribution could be disastrous for SPV nodes. Identification of a new active chain triggers a reorganization. During reorganization, confirmed transactions can either move to a new block or be evicted from the block chain altogether.
From the perspective of an SPV wallet user, a transaction with six confirmations could become a transaction with no confirmations from one minute to the next. This danger exists regardless of which chain the user intends to follow. Even so, an SPV wallet user would be powerless to choose one chain or the other because SPV itself specifically excludes the block bodies needed to distinguish the chains. Any wipeout protection would need to be hard-coded by the wallet itself in some way.
In contrast to an SPV node, a full node will never accept a block generated by a Segwit2x node. The reason is simple: Segwit2x mandates a signaling block larger than 1 MB in size. A full node will reject such a block and all of its descendants, regardless of how much hash power lies behind it. However, this weak wipeout protection is insufficient to safeguard SPV nodes from wipeout risk.
Hard Fork Bit
A 2015 proposal introduced the concept of a hard fork bit. This bit occupies index 31 of the header version field. A node unaware of a hard fork update underway will reject any block in which the hard fork bit is set (the result would yield a negative version number, which the protocol forbids). Because the hard fork bit appears in the block header, setting it will cause the block to be rejected by SPV and full nodes alike.
A hard fork using the hard fork bit would deploy a signal block, in which the hard fork bit is turned on, to notify the network of the update’s commencement. Descendants of the signal block would leave the hard fork bit unset. It could then once again be activated in a subsequent hard fork update if so desired.
The presence of a signal block in which the hard fork bit is set in the header would cause Bitcoin SPV and full nodes to reject the entire hard fork chain. Neither type of node would identify a path containing the signal block as the active chain. Likewise, nodes running the hard fork update would reject Bitcoin chains due to their exclusion of the signal block.
SPV and full nodes on either side of the hard fork would therefore be protected against wipeouts.
The presence of a signal block requires the explicit consent of both SPV and full node operators planning to follow the hard fork. However, requiring SPV wallets to update may lead to a non-viable hard fork. Users who refuse to update wouldn’t follow the hard fork, and if enough of them did so, the hard fork might find it difficult to garner economic support. The alternative option, no signal block, risks the financial security of SPV users on both sides of the fork though wipeouts.
SPV wallets in current use include:
Specific wallet vulnerability to the security threat described in this post will need to be addressed by the respective development teams.
The lack of strong wipeout protection places every SPV user, regardless of the chain they intend to follow, at risk of financial loss in the weeks following Segwit2x activation. Worse, SPV itself makes chain selection practically impossible even if a user prefers one or the other. For these reasons, the security implications of using SPV wallets during the period following Segwit2x activation should be carefully considered.
Users can protect their financial assets from mid-November onward by running a full node. Some SPV wallets such as Electrum, breadwallet, and Airbitz offer an option to connect to a trusted node or server. This feature, sometimes referred to as “node tethering” mitigates the risks of wipeout caused by an unstable hash rate majority, but does so at the risk of trusting a single node.
In broader terms, the Segwit2x project should protect its own SPV users from possible wipeout events through use of a signal block deploying the hard fork bit, or some other method invalidating the block header.