Why is it difficult to modify records in a blockchain
Table of contents
Blockchain works in a peer to peer network and every new transaction is broadcast to all the nodes so that any one of the nodes could mine it. The process of mining a block involves predicting a nonce value that could satisfy the difficulty level.
What does ‘difficulty’ mean in blockchain ?
Difficulty
is the relative measure of how difficult it is to find a new block. The difficulty is adjusted periodically as a function of how much hashing power has been deployed by the network of miners.
How is a blockchain validated ?
- Every block must satisfy the difficulty criteria (proof of work).
- Every block must contain the hash value of the previous block and it should match with the previous block’s hash.
An example could help better understand this,
Let’s say we have the blockchain of length 6
, where the hashing algorithm used is SHA-256 and a difficulty
of 5
(hash beginning with 5 zeros as a proof of work)
Previous Block's hash | Timestamp | Nonce | Transaction Data |
---|---|---|---|
5FECEB66FFC86F38D952786C6D696C79C2DBC239DD4E91B46729D73A27FB57E9 | 1527990931106 | 0525170 | Block 1 |
00000F7500C1AACC0A1316BDA465407D15A0177231929C15FCE54DE944B65742 | 1527990931107 | 0070121 | Block 2 |
000001DF83C3C9BA681A89DA3D2F3D346895109E7B4E6E9767E04BA19996BE3F | 1527990931107 | 3632550 | Block 3 |
000009A057133D6F8DD724B712C31C25EF0703E87C825EACCB01122D4FF1842E | 1527990931107 | 0820089 | Block 4 |
00000D7EEE3583BA18D68990281069C76381DA9B5475EB41E872796A13FBB384 | 1527990931107 | 0660226 | Block 5 |
000003AA70B03F4F25D468C8A7B13ED8483B419BB6503BE8B25CB14DCC2855F8 | 1527990931107 | 0031723 | Block 6 |
let’s try changing the transaction data for the 3rd block from Block 3
to Block 33
. Now that the block data has been modified, the chain becomes invalid because when the validation check is performed, the hash generated by this block will not satisfy the difficulty and will not match with the next block’s previousHash value.
Previous Block's hash | Timestamp | Nonce | Transaction Data |
---|---|---|---|
5FECEB66FFC86F38D952786C6D696C79C2DBC239DD4E91B46729D73A27FB57E9 | 1527990931106 | 0525170 | Block 1 |
00000F7500C1AACC0A1316BDA465407D15A0177231929C15FCE54DE944B65742 | 1527990931107 | 0070121 | Block 2 |
000001DF83C3C9BA681A89DA3D2F3D346895109E7B4E6E9767E04BA19996BE3F | 1527990931107 | 3632550 | Block 33 |
000009A057133D6F8DD724B712C31C25EF0703E87C825EACCB01122D4FF1842E | 1527990931107 | 0820089 | Block 4 |
00000D7EEE3583BA18D68990281069C76381DA9B5475EB41E872796A13FBB384 | 1527990931107 | 0660226 | Block 5 |
000003AA70B03F4F25D468C8A7B13ED8483B419BB6503BE8B25CB14DCC2855F8 | 1527990931107 | 0031723 | Block 6 |
The following method is used to calculate the hash
public String getHash() throws NoSuchAlgorithmException {
return CryptoHelper.sha256(transactionData + String.valueOf(timestamp)
+ String.valueOf(previousBlockHash)
+ String.valueOf(nonce));
}
The hash is calculated by appending transactionData
, timestamp
, previousBlockHash
, nonce
and applying SHA-256 on the resultant string
This is the resultant string if we append the data for block 3
Block 331527990931107000001DF83C3C9BA681A89DA3D2F3D346895109E7B4E6E9767E04BA19996BE3F3632550
and the SHA-256 hash for the above string is
BD5370EB390348AA71C25C65E700E36E81BA370C665C6398BAEF7C8843C0A1C2
Obviously it doesn’t satisfy the difficulty criteria as it doesn’t start with 5 zeros, hence the nonce value needs to be recalculated. Let’s try to calculate the nonce
value by bruteforce
public class HashBreaker {
public static void main(String[] args) throws NoSuchAlgorithmException {
var scanner = new Scanner(System.in);
System.out.println("Nonce Finder");
System.out.print("Message : ");
String message = scanner.nextLine();
System.out.print("Difficulty : ");
int d = scanner.nextInt();
System.out.println("\nCalculating...");
long startTime = System.currentTimeMillis();
long nonce = bruteforce(d, message);
long endTime = System.currentTimeMillis();
System.out.println("\nValid Nonce : " + nonce);
System.out.println("Hash : " + sha256(message + String.valueOf(nonce)));
System.out.println("Time taken : " + (endTime - startTime)/1000 + " seconds");
scanner.close();
}
public static String sha256(String text) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(text.getBytes(StandardCharsets.UTF_8));
byte[] hash = digest.digest();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < hash.length; i++) {
sb.append(Integer.toString((hash[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString().toUpperCase();
}
public static long bruteforce(int d, String s) throws NoSuchAlgorithmException {
long nonce = 0;
String pre = "";
for (; pre.length() < d; pre += "0");
while (!sha256(s + String.valueOf(nonce)).startsWith(pre)){
nonce++;
}
return nonce;
}
}
We have found that the nonce value 125107
satisfies the difficulty criteria, let’s see how our modified chain looks like
Previous Block's hash | Timestamp | Nonce | Transaction Data |
---|---|---|---|
5FECEB66FFC86F38D952786C6D696C79C2DBC239DD4E91B46729D73A27FB57E9 | 1527990931106 | 525170 | Block 1 |
00000F7500C1AACC0A1316BDA465407D15A0177231929C15FCE54DE944B65742 | 1527990931107 | 70121 | Block 2 |
000001DF83C3C9BA681A89DA3D2F3D346895109E7B4E6E9767E04BA19996BE3F | 1527990931107 | 125107 | Block 33 |
000009A057133D6F8DD724B712C31C25EF0703E87C825EACCB01122D4FF1842E | 1527990931107 | 820089 | Block 4 |
00000D7EEE3583BA18D68990281069C76381DA9B5475EB41E872796A13FBB384 | 1527990931107 | 660226 | Block 5 |
000003AA70B03F4F25D468C8A7B13ED8483B419BB6503BE8B25CB14DCC2855F8 | 1527990931107 | 31723 | Block 6 |
since block 3 has been modified, the previousHash
value contained in block 4 doesn’t match with the third block’s hash.
To correct the chain, the previous hash value in block 4 needs to be set to the current hash of block 3, so it will become
Previous Block's hash | Timestamp | Nonce | Transaction Data |
---|---|---|---|
00000277418AFAF4F19430EDE51B573FAE4C3DCB13B20352A43778802DF0E12F | 1527990931107 | 820089 | Block 4 |
and now the current hash for block 4 becomes
"DAFC46D52C86324421121FC99BEB1E6D7215C6DA288CF0600034F60995477A09"
which doesn’t satisfy the difficulty criteria and the nonce
value has to be recalculated.
With the recalculated nonce, the 4th block becomes
Previous Block's hash | Timestamp | Nonce | Transaction Data |
---|---|---|---|
00000277418AFAF4F19430EDE51B573FAE4C3DCB13B20352A43778802DF0E12F | 1527990931107 | 691412 | Block 4 |
The same happens with the remaining blocks and their nonces should also be recalculated. As we have observed the blockchain is similar in analogy to dominoes where each block can be thought of as a domino.
once a block is disturbed, all the consecutive blocks also get affected
What’s the big deal?
You might be wondering, what’s the big deal with recalculating hashes. After all, with some recalculations and time you can modify the chain right?
There are a few things to consider,
- The longest proof of work chain will be accepted as the correct chain by the P2P network.
- For the sake of simplicity, we have used tiny difficulty values and a relatively less complex algorithm, but in actual implementations, the difficulty value is quite huge and also the hashing algorithms are much more complex which makes it much harder and time consuming to recalculate the nonce values.
Graph showing changes in relative difficulty for bitcoin. Source: https://blockchain.info
- Every second, many transactions are broadcast across the network and the node that calculates the nonce value for a transaction first becomes the node having the longest proof of work chain. In such a competitive environment, tampering with the chain is computationally tedious.