Optimizing Blockchain Security: Implementing Whitelist Functionality with Merkle Trees

Wajahat Hussain
Coinmonks
Published in
4 min readOct 28, 2023

--

Merkle tree

Introduction

Blockchain technology has revolutionized secure and transparent transactions. One of its key components, the Merkle Tree, plays a pivotal role in ensuring data integrity within a decentralized network. In this article, we will explore the concept of Merkle Trees, their significance in blockchain, and how they can be employed for efficient whitelisting processes.

Understanding Merkle Trees

At its core, a Merkle Tree is a binary tree where each leaf node represents the hash of a data block. The non-leaf nodes, in turn, contain the hash values of their child nodes. This hierarchical structure allows for efficient verification of the integrity of transactions within a block.

Merkle Trees in Blockchain

Merkle trees are integral to the structure of a blockchain. They serve two key purposes:

1. Efficient Data Verification:

In a blockchain, each block contains a set of transactions. Without Merkle trees, verifying the inclusion of a specific transaction in a block would be a time-consuming process, as you’d have to traverse all transactions in the block. Merkle trees allow for quick verification by hashing transactions in a tree structure and storing only the root hash, known as the Merkle root, in the block header.

Each block comprises of block header + Merkle tree

2. Security and Tamper Detection:

Merkle trees are crucial for detecting tampering with transactions. Any change in a transaction’s data will result in a different hash value, which propagates up the tree to the Merkle root. Miners can easily compare the Merkle root in the header with the one stored in the block’s data to identify tampered data.

Whitelisting with Merkle Trees

In the context of blockchain security, whitelisting is the practice of authenticating specific entities or transactions. Utilizing Merkle Trees, this process can be streamlined. Here’s how:

Generating a Merkle Tree for Whitelisting Addresses


app.post('/whiteListedAddress', async (req, res) => {
try {

const { address } = req.body;

if (!Array.isArray(address)) {
console.error('Address is not an array or is undefined.');
res.status(500).send({status: 0, message:'Address is not an array or is undefined.'});
}
// Hashing All Leaf Individual
const leaves = await Promise.all(address.map(async (leaf) => {
return keccak256(leaf);
}))

// Constructing Merkle Tree
const tree = new MerkleTree(leaves, keccak256, {
sortPairs: true,
});

// Utility Function to Convert From Buffer to Hex
const buf2Hex = (x) => "0x" + x.toString("hex");

// Get Root of Merkle Tree
console.log(`Here is Root Hash: ${buf2Hex(tree.getRoot())}`);

let data = [];

// Pushing all the proof and leaf in data array
address.forEach((address) => {
const leaf = keccak256(address);

const proof = tree.getProof(leaf);

let tempData = [];

proof.map((x) => tempData.push(buf2Hex(x.data)));

data.push({
address: address,
leaf: buf2Hex(leaf),
proof: tempData,
});
});

// Create WhiteList Object to write JSON file

let whiteList = {
whiteList: data,
};

// Stringify whiteList object and formating
const metadata = JSON.stringify(whiteList, null, 2);

// Write whiteList.json file in root dir
fs.writeFile(`whiteList.json`, metadata, (err) => {
if (err) {
throw err;
}
});

res.status(200).send({ status: 1, message: "Root Hash created success", data: buf2Hex(tree.getRoot()) })

} catch (err) {
console.error(`error message:`)
console.error(err)
res.status(500).send({ status: 0, message: "Something went wrong", error: err.message })
}

})

generated file

{
"whiteList": [
{
"address": "0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db",
"leaf": "0x04a10bfd00977f54cc3450c9b25c9b3a502a089eba0097ba35fc33c4ea5fcb54",
"proof": [
"0x999bf57501565dbd2fdcea36efa2b9aef8340a8901e3459f4a4c926275d36cdb",
"0x5931b4ed56ace4c46b68524cb5bcbf4195f1bbaacbe5228fbd090546c88dd229"
]
},
{
"address": "0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2",
"leaf": "0x999bf57501565dbd2fdcea36efa2b9aef8340a8901e3459f4a4c926275d36cdb",
"proof": [
"0x04a10bfd00977f54cc3450c9b25c9b3a502a089eba0097ba35fc33c4ea5fcb54",
"0x5931b4ed56ace4c46b68524cb5bcbf4195f1bbaacbe5228fbd090546c88dd229"
]
},
{
"address": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4",
"leaf": "0x5931b4ed56ace4c46b68524cb5bcbf4195f1bbaacbe5228fbd090546c88dd229",
"proof": [
"0x39a01635c6a38f8beb0adde454f205fffbb2157797bf1980f8f93a5f70c9f8e6"
]
}
]
}

GitHub Repository:https://github.com/Wajahat-Husain/Merkle-Tree

Implementing Whitelist Verification in Smart Contracts

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";

contract MerkleTreeWhiteListCounter {
bytes32 public rootHash;
uint256 public count;
address public owner;

constructor(bytes32 _rootHash){
rootHash = _rootHash;
}

modifier onlyOwner(address caller){
require(owner == caller,"Must be owner");
_;
}

modifier isWhiteListedAddress(bytes32[] calldata proof, address walletAddress){
require(isValidProof(proof,keccak256(abi.encodePacked(walletAddress))),"Not WhiteListed Address");
_;
}

function isValidProof(bytes32[] calldata proof, bytes32 leaf) private view returns (bool) {
return MerkleProof.verify(proof, rootHash, leaf);
}

function updateRootHash(bytes32 _rootHash) onlyOwner(msg.sender) external{
rootHash = _rootHash;
}

function whiteListIncrement(bytes32[] calldata proof, address walletAddress) isWhiteListedAddress(proof, walletAddress) external {
count++;
}
}

Advantages of Merkle Tree-Based Whitelists

  • Efficiency: Merkle Trees enable rapid verification, making whitelist management quick and hassle-free.
  • Security: The cryptographic nature of Merkle Trees ensures the integrity and confidentiality of whitelist data.
  • Scalability: As the whitelist grows, Merkle Trees maintain their efficiency, ensuring smooth operations even in large-scale networks.
  • Resource Optimization: Merkle Trees reduce the storage and computational resources needed for whitelist verification.

Conclusion

By harnessing the power of Merkle Trees, blockchain networks can establish secure and streamlined whitelisting processes. This efficient method not only enhances data integrity but also contributes to the overall robustness of blockchain systems. As blockchain technology continues to evolve, understanding and implementing Merkle Trees for tasks like whitelisting will be integral to ensuring a trustworthy and efficient decentralized future.

Note: This article provides a concise overview and a basic implementation example. Further implementation details and real-world use cases can be explored based on specific project requirements.

--

--

Wajahat Hussain
Coinmonks

Blockchain enthusiast crafting innovative Dapps. Full-stack expert, backend integration, database management. Redefining with scalable solutions.