LIP: 0020
Title: Use full SHA-256 hash of block header as blockID
Author: Andreas Kendziorra <[email protected]>
Discussions-To: https://research.lisk.com/t/use-full-sha-256-hash-of-block-header-as-blockid/188
Status: Active
Type: Standards Track
Created: 2019-09-06
Updated: 2020-07-21
This LIP proposes to take the full SHA-256 hash of the block header as the blockID of a block. This implies an increase of the blockID length. The motivation of the proposal is to increase the security of the Lisk blockchain.
This LIP is licensed under the Creative Commons Zero 1.0 Universal.
In the current Lisk protocol, a blockID consists of 8 bytes of the SHA-256 digest of the block header. This small length comes with some advantages, such as less stored data or better visualisation on small displays. However, it comes at the price of providing low resistance to collisions and pre-images. More precisely, the low resistance could be exploited in the following scenario: An attacker could try to find another block with the same blockID for a given block in the blockchain. In the successful case, other community members may be convinced by this altered history, as the altered chain might appear valid. We will see that this kind of attack is limited to delegates and currently economically unattractive. However, the length of the blockID shall be increased to prevent this kind of attack also in the future.
Let blockBytesForId
denote the function that maps every block to the byte array that is used as the input for computing the blockID. In Lisk SDK 2.0.0, for instance, this function is implemented in Block.getBytes. In the proposed protocol, the blockID of a block B
is computed as follows:
blockID = SHA-256(blockBytesForId(B)).
Moreover, let blockBytesForSignature
denote the function that maps every block to the byte array that is used as the input for the block signature (also implemented in Block.getBytes in Lisk SDK 2.0.0). Then, the new definition of blockID implies a change for the specification of blockBytesForId
and blockBytesForSignature
: The encoding of the property previousBlock
requires 32 bytes instead of 8 bytes. Big endian encoding has to be used. As in the current protocol, the bytes for the previousBlock
property have to follow the bytes of the timestamp
property in the byte array of the whole block.
If H
is the height from which on the proposed protocol is used, then the blockID of the block forged at height H
-1 is a 64-bit integer, n
. Nevertheless, 32 bytes are used to encode the previousBlock
property of the block at height H
, i.e., n
is encoded as a 256-bit integer in big endian format.
During the block validation, it should not be checked anymore if the blockID is unique.
In a JSON object representing a block, the property previousBlock
, containing a blockID, has to be represented as a hexadecimal string.
As mentioned before, an attacker could try to find another block with the same blockID for a given block in the past. If the attacker succeeds, other community members may be convinced by this altered history, as the altered chain might appear valid. Such an attack would, however, only be possible if the attacker possesses the private key of the delegate associated with the time slot of the block. Otherwise, the signature or the time slot would be recognised as invalid during the block validation. Therefore, such an attack would be limited to delegates that have been in the top 101 at some point. Moreover, finding a new block with the same blockID requires currently 264 tries on average. In each try, the attacker creates a block which includes creating the payload, signing the block header and computing the blockID. The signing step is the computationally most expensive step. According to the designers of the signature scheme used in Lisk (Ed25519), a quad-core 2.4 GHz Westmere is able to sign 109,000 messages per second. Therefore, one would require 5.4 million years on average to find a new block with this hardware. This makes the attack economically very unattractive, even with more advanced hardware. Furthermore, the attack requires that users synchronise their chain with the faked chain where they copy at least the new block. If the attacker wants to double spend money by deleting a transaction from a block and spending the funds again, then even many delegates have to synchronise their chain with the faked chain in order to get the new transfer verified.
Although the success probability is very low, we want to increase the resistance against such an attack to provide sufficient security also for the future. The resistance against such an attack is determined by the bit length of the blockIDs. I.e., n-bit blockIDs yield n-bit resistance against such an attack. With a blockID length of 256 bit, we choose a security level that makes the mentioned attack infeasible for probably several decades.
Since it is safe to assume that blockID collisions will not occur with the proposed length, the blockID uniqueness check is not required anymore during block validation and will be removed for this reason.
The change introduces a hard fork, because of the following: Blocks forged by nodes following the proposed protocol get rejected by nodes following the current protocol and vice versa since the format of the previousBlock
property changes.