0% found this document useful (0 votes)
0 views17 pages

223A1131_BC_EXP2

Uploaded by

Umair Momin
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
0 views17 pages

223A1131_BC_EXP2

Uploaded by

Umair Momin
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 17

Experiment 02

Title : Cryptography in Blockchain, Merkle Root Tree Hash.

Theory :

In blockchain systems, cryptography plays a vital role in ensuring the security and
integrity of the data. One important cryptographic concept is the Merkle Root,
which is used to efficiently verify the consistency and correctness of the data in
large datasets.

A Merkle Tree is a binary tree where each leaf node represents a hash of a data
block (in this case, a transaction), and each non-leaf node is the hash of its two child
nodes. The Merkle Root is the topmost hash that uniquely represents the entire set
of transactions in a block. It is used to validate the integrity of the block’s
transactions without needing to examine all individual transactions.

In this implementation:

1. Merkle Root Construction: The build_merkle_root function constructs the


Merkle Root by recursively hashing pairs of transaction hashes. If there is an
odd number of transactions, the last one is duplicated.
2. Block Creation: When a block is created, the Merkle Root of the current
transactions is calculated and added to the block. The block's hash is then
computed based on the Merkle Root, among other properties like the nonce,
timestamp, and previous hash.
3. Proof of Work: The proof_of_work method ensures that miners must find a
valid nonce that satisfies a predefined hash condition (e.g., starting with
'000') before a block can be mined and added to the blockchain. The Merkle
Root is included in the hash calculation, ensuring the integrity of the
transactions.
4. Flask Application: The application uses Flask to provide endpoints for mining
blocks, adding transactions, and retrieving the full blockchain. Postman or a
web browser can be used to interact with these endpoints.
Code :

import hashlib
import json

from time import time


from flask import Flask, jsonify, request

class Blockchain:
def __init__(self):

self.chain = []
self.current_transactions = []

# Create the genesis block


self.create_block(previous_hash='1', nonce=100)

@staticmethod
def build_merkle_root(transactions):

"""
Builds a Merkle Tree from a list of transactions and returns the Merkle Root.

This is a simple implementation that handles an odd number of transactions


by duplicating the last one.

"""
# Return a known hash if there are no transactions

if not transactions:
return hashlib.sha256("".encode()).hexdigest()

# 1. Hash each individual transaction


transaction_hashes = []

for tx in transactions:
# Use json.dumps to create a consistent string representation of the
transaction dict

tx_string = json.dumps(tx, sort_keys=True).encode()


transaction_hashes.append(hashlib.sha256(tx_string).hexdigest())

# 2. Build the tree by repeatedly hashing pairs of hashes


while len(transaction_hashes) > 1:

# If there is an odd number of hashes, duplicate the last one


if len(transaction_hashes) % 2 != 0:

transaction_hashes.append(transaction_hashes[-1])

next_level_hashes = []
# Iterate through the hashes in pairs
for i in range(0, len(transaction_hashes), 2):

# Concatenate the pair of hashes


combined_hash_str = transaction_hashes[i] + transaction_hashes[i+1]

# Hash the combined string


new_hash = hashlib.sha256(combined_hash_str.encode()).hexdigest()
next_level_hashes.append(new_hash)
# Move to the next level of the tree

transaction_hashes = next_level_hashes

# 3. The final remaining hash is the Merkle Root

return transaction_hashes[0]

def create_block(self, nonce, previous_hash):

"""
Creates a new block and adds it to the chain.

The block now includes the Merkle Root of the transactions.


"""

# The Merkle Root is calculated from the current list of transactions


merkle_root = self.build_merkle_root(self.current_transactions)

block = {
'index': len(self.chain) + 1,
'timestamp': time(),
'transactions': self.current_transactions,
'merkle_root': merkle_root, # Added Merkle Root to the block

'nonce': nonce,
'previous_hash': previous_hash,

}
# The block's hash is calculated after all content, including the Merkle Root, is
added

block['hash'] = self.hash(block)

# Reset the current list of transactions


self.current_transactions = []
self.chain.append(block)

return block

def create_transactions(self, sender, recipient, amount):


"""
Adds a new transaction to the list of current transactions.

These will be included in the next mined block.


"""

self.current_transactions.append({
'sender': sender,

'recipient': recipient,
'amount': amount,

})
return self.last_block['index'] + 1

@staticmethod
def hash(block):
"""
Hashes a block using SHA-256.
"""

# We must make sure that the Dictionary is Ordered, or we'll have inconsistent
hashes

block_string = json.dumps(block, sort_keys=True).encode()


return hashlib.sha256(block_string).hexdigest()

@property
def last_block(self):

"""
Returns the last block in the chain.

"""
return self.chain[-1]

def proof_of_work(self, previous_hash):


"""

Simple Proof of Work Algorithm:


- Find a number 'nonce' such that hash(previous_hash, transactions, nonce)
contains leading zeros.
"""

# We calculate the Merkle Root once before starting the mining process for
efficiency.

merkle_root = self.build_merkle_root(self.current_transactions)
nonce = 0
while True:
# The block being tested must have the same structure as a final block

block_to_test = {
'index': len(self.chain) + 1,

'timestamp': time(),
'transactions': self.current_transactions,

'merkle_root': merkle_root, # Include Merkle Root in the hash calculation


'nonce': nonce,

'previous_hash': previous_hash,
}

hash_value = self.hash(block_to_test)
# Check if the hash meets the difficulty criteria (e.g., starts with '000')

if hash_value.startswith('000'):
return nonce

else:
nonce += 1

# Flask app and routes go OUTSIDE the class


app = Flask(__name__)

blockchain = Blockchain()

@app.route('/mine', methods=['GET'])
def mine():
# A block can't be mined without transactions

if not blockchain.current_transactions:
return 'No transactions to mine', 400

# Run the proof of work algorithm to get the next nonce


previous_hash = blockchain.last_block['hash']

nonce = blockchain.proof_of_work(previous_hash)

# Create the new block and add it to the chain


block = blockchain.create_block(nonce, previous_hash)

# Forge the new Block by adding it to the chain


response = {
'message': 'New block mined',

'index': block['index'],
'transactions': block['transactions'],
'merkle_root': block['merkle_root'], # Added Merkle Root to the response
'nonce': block['nonce'],

'hash': block['hash'],
'previous_hash': block['previous_hash'],

}
return jsonify(response), 200
@app.route('/transactions/new', methods=['POST'])

def new_transaction():
values = request.get_json()

required = ['sender', 'recipient', 'amount']


if not all(k in values for k in required):
return 'Missing values', 400

index = blockchain.create_transactions(values['sender'], values['recipient'],


values['amount'])
response = {'message': f'Transaction will be added to Block {index}'}
return jsonify(response), 201

@app.route('/chain', methods=['GET'])

def full_chain():
response = {
'chain': blockchain.chain,
'length': len(blockchain.chain),
}

return jsonify(response), 200

if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
Output :
{

"chain": [

"hash":
"82601465dafbc826807fac3027986113df9616568af4585f6a1f6332439d0ada",
"index": 1,

"nonce": 100,

"previous_hash": "1",

"timestamp": 1753244887.372169,

"transactions": []

},

"hash":
"bc6a8af133e67449758c49ba64485f67c388451fc55965c83c4d37a65a77f049",

"index": 2,

"nonce": 2607,

"previous_hash":
"82601465dafbc826807fac3027986113df9616568af4585f6a1f6332439d0ada",

"timestamp": 1753245158.832769,

"transactions": [

"amount": 10,

"recipient": "Bob",

"sender": "Alice"

},

"amount": 10,

"recipient": "Ayush",

"sender": "Vyapti"

]
},

"hash":
"f615bb9f2e2ce375a76a1608987dbe7c8b81c5838347db8deff6b13775b5f136",

"index": 3,

"nonce": 1051,

"previous_hash":
"bc6a8af133e67449758c49ba64485f67c388451fc55965c83c4d37a65a77f049",

"timestamp": 1753245702.6182272,

"transactions": [

"amount": 10,

"recipient": "Ayush",

"sender": "Vyapti"

},

"hash":
"9e79fc88af9585d3691f8b8b33494c8c4c6925c331d0e9a938e37a661ab08ce0",

"index": 4,

"nonce": 5424,

"previous_hash":
"f615bb9f2e2ce375a76a1608987dbe7c8b81c5838347db8deff6b13775b5f136",

"timestamp": 1753246333.6656342,

"transactions": [

{
"amount": 10,

"recipient": "Aishu",

"sender": "Nikhil"

],

"length": 4

"chain": [

"hash":
"d1006dd8d6f2ee7981d69dd62b58b59bf3001ca62df16098105aa146dc279872",

"index": 1,
"merkle_root": "",

"nonce": 100,

"previous_hash": "1",

"timestamp": 1753249583.7738278,

"transactions": []

},

"hash":
"27936348034de0e436a9fc9e55bd830afe17d85e9405a200b6c75344891aecd8",

"index": 2,

"merkle_root":
"ee691c458c41248bbeb3fab0e41eaf6866229d2a1135644679f9f41fc337c640",

"nonce": 2336,

"previous_hash":
"d1006dd8d6f2ee7981d69dd62b58b59bf3001ca62df16098105aa146dc279872",

"timestamp": 1753249662.7293055,

"transactions": [

"amount": 10,

"recipient": "B",

"sender": "V"

],

"length": 2

}
Conclusion :

This implementation demonstrates the use of Merkle Trees in blockchain to


enhance data security and integrity. By including the Merkle Root in each block, the
system efficiently verifies that all transactions within the block are valid. The mining
process, powered by Proof of Work, ensures that the blockchain remains secure
and tamper-resistant. The Flask app provides an interface for interacting with the
blockchain, allowing transactions to be added, blocks to be mined, and the full
blockchain to be viewed. This method improves scalability and security by reducing
the data needed for transaction verification.

You might also like