#include <iostream>
#include <vector>
#include <string>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <iomanip>
class TreeNode {
public:
std::string value;
std::string hashValue;
TreeNode* left;
TreeNode* right;
TreeNode(const std::string& val, const std::string& hash) : value(val), hashValue(hash), left(nullptr), right(nullptr) {}
};
std::string sha256(const std::string &input) {
unsigned char hash[SHA256_DIGEST_LENGTH];
EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
EVP_DigestInit(mdctx, EVP_sha256());
EVP_DigestUpdate(mdctx, input.c_str(), input.length());
EVP_DigestFinal(mdctx, hash, NULL);
EVP_MD_CTX_free(mdctx);
std::stringstream hashStream;
hashStream << std::hex << std::setfill('0');
for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
hashStream << std::setw(2) << static_cast<int>(hash[i]);
}
return hashStream.str();
}
TreeNode* createIntermediateNode(TreeNode* leftNode, TreeNode* rightNode) {
std::string concatenatedValue = leftNode->value + rightNode->value; // Concatenate values instead of hash values
TreeNode* intermediateNode = new TreeNode(concatenatedValue, sha256(concatenatedValue));
intermediateNode->left = leftNode;
intermediateNode->right = rightNode;
return intermediateNode;
}
void duplicateLastNodeIfOdd(std::vector<TreeNode*>& nodes) {
if (nodes.size() % 2 != 0) {
nodes.push_back(new TreeNode(nodes.back()->value, nodes.back()->hashValue));
}
}
void printTree(TreeNode* node, const std::string& prefix, bool isLeft) {
if (node != nullptr) {
std::cout << prefix;
std::cout << (isLeft ? "├──" : "└──");
std::cout << "Data: " << node->value << " | Hash: " << node->hashValue;
std::cout << std::endl;
printTree(node->left, prefix + (isLeft ? "│ " : " "), true);
printTree(node->right, prefix + (isLeft ? "│ " : " "), false);
}
}
void printTreeVisualizer(TreeNode* node) {
printTree(node, "", false);
}
int main() {
std::vector<std::string> inputArray;
int numInputs;
std::cout << "Enter the number of inputs: ";
std::cin >> numInputs;
for (int i = 0; i < numInputs; ++i) {
std::string input;
std::cout << "Enter input " << i + 1 << ": ";
std::cin >> input;
inputArray.push_back(input);
}
int numLeafNodes = inputArray.size();
std::vector<TreeNode*> leafNodes;
// Create leaf nodes
for (const std::string& data : inputArray) {
TreeNode* leafNode = new TreeNode(data, sha256(data));
leafNodes.push_back(leafNode);
}
std::vector<TreeNode*> intermediateNodes = leafNodes;
// Construct the tree
while (intermediateNodes.size() > 1) {
duplicateLastNodeIfOdd(intermediateNodes);
std::vector<TreeNode*> newIntermediateNodes;
for (size_t i = 0; i < intermediateNodes.size(); i += 2) {
TreeNode* intermediateNode = createIntermediateNode(intermediateNodes[i], intermediateNodes[i + 1]);
newIntermediateNodes.push_back(intermediateNode);
}
intermediateNodes = newIntermediateNodes;
}
TreeNode* root = intermediateNodes[0];
// printf("\nMerkle Root: %s\n", root->hashValue);
std::cout << "\nMerkle Root: " << root->hashValue << std::endl;
// Display the tree structure using the visualizer
std::cout << "Tree Structure:\n\n";
printTreeVisualizer(root);
printf("\n");
// Clean up memory (deallocating nodes)
for (TreeNode* node : leafNodes) {
delete node;
}
return 0;
}