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.

Dominoes collapsing

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.

Bitcoin relative difficulty graph 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.

Source Code