finished HW and EX
This commit is contained in:
parent
8edf706e22
commit
fb8a7d5b69
@ -0,0 +1,24 @@
|
|||||||
|
from cryptography.hazmat.backends import default_backend
|
||||||
|
from cryptography.hazmat.primitives import hashes
|
||||||
|
|
||||||
|
class CBlock:
|
||||||
|
|
||||||
|
data = None
|
||||||
|
previousHash = None
|
||||||
|
previousBlock = None
|
||||||
|
def __init__(self, data, previousBlock):
|
||||||
|
self.data = data
|
||||||
|
self.previousBlock = previousBlock
|
||||||
|
if previousBlock != None:
|
||||||
|
self.previousHash = previousBlock.computeHash()
|
||||||
|
|
||||||
|
def computeHash(self):
|
||||||
|
digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
|
||||||
|
digest.update(bytes(str(self.data),'utf8'))
|
||||||
|
digest.update(bytes(str(self.previousHash),'utf8'))
|
||||||
|
return digest.finalize()
|
||||||
|
|
||||||
|
def is_valid(self):
|
||||||
|
if self.previousBlock == None:
|
||||||
|
return True
|
||||||
|
return self.previousBlock.computeHash() == self.previousHash
|
@ -0,0 +1,41 @@
|
|||||||
|
from cryptography.exceptions import *
|
||||||
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||||
|
from cryptography.hazmat.primitives import hashes
|
||||||
|
from cryptography.hazmat.primitives.asymmetric import padding
|
||||||
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
|
||||||
|
def generate_keys():
|
||||||
|
private_key = rsa.generate_private_key(public_exponent=65537,key_size=2048)
|
||||||
|
public_key = private_key.public_key()
|
||||||
|
|
||||||
|
pbc_ser = public_key.public_bytes(
|
||||||
|
encoding=serialization.Encoding.PEM,
|
||||||
|
format=serialization.PublicFormat.SubjectPublicKeyInfo)
|
||||||
|
return private_key, pbc_ser
|
||||||
|
|
||||||
|
def sign(message, private_key):
|
||||||
|
message = bytes(str(message), 'utf-8')
|
||||||
|
signature = private_key.sign(
|
||||||
|
message,
|
||||||
|
padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH),
|
||||||
|
hashes.SHA256()
|
||||||
|
)
|
||||||
|
return signature
|
||||||
|
|
||||||
|
def verify(message, signature, pbc_ser):
|
||||||
|
message = bytes(str(message), 'utf-8')
|
||||||
|
public_key = serialization.load_pem_public_key(pbc_ser)
|
||||||
|
try:
|
||||||
|
public_key.verify(
|
||||||
|
signature,
|
||||||
|
message,
|
||||||
|
padding.PSS(mgf=padding.MGF1(hashes.SHA256()),
|
||||||
|
salt_length=padding.PSS.MAX_LENGTH),
|
||||||
|
hashes.SHA256()
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
except InvalidSignature:
|
||||||
|
return False
|
||||||
|
except:
|
||||||
|
print("Error executing 'public_key.verify'")
|
||||||
|
return False
|
@ -0,0 +1,66 @@
|
|||||||
|
from Signature import *
|
||||||
|
|
||||||
|
class Tx:
|
||||||
|
inputs = None
|
||||||
|
outputs =None
|
||||||
|
sigs = None
|
||||||
|
reqd = None
|
||||||
|
def __init__(self):
|
||||||
|
self.inputs = []
|
||||||
|
self.outputs = []
|
||||||
|
self.sigs = []
|
||||||
|
self.reqd = []
|
||||||
|
|
||||||
|
def add_input(self, from_addr, amount):
|
||||||
|
self.inputs.append((from_addr, amount))
|
||||||
|
|
||||||
|
def add_output(self, to_addr, amount):
|
||||||
|
self.outputs.append((to_addr, amount))
|
||||||
|
|
||||||
|
def add_reqd(self, addr):
|
||||||
|
self.reqd.append(addr)
|
||||||
|
|
||||||
|
def sign(self, private):
|
||||||
|
message = self.__gather()
|
||||||
|
newsig = sign(message, private)
|
||||||
|
self.sigs.append(newsig)
|
||||||
|
|
||||||
|
def is_valid(self):
|
||||||
|
total_in = 0
|
||||||
|
total_out = 0
|
||||||
|
message = self.__gather()
|
||||||
|
for addr,amount in self.inputs:
|
||||||
|
found = False
|
||||||
|
for s in self.sigs:
|
||||||
|
if verify(message, s, addr):
|
||||||
|
found = True
|
||||||
|
if not found:
|
||||||
|
# print ("No good sig found for " + str(message))
|
||||||
|
return False
|
||||||
|
if amount < 0:
|
||||||
|
return False
|
||||||
|
total_in = total_in + amount
|
||||||
|
for addr in self.reqd:
|
||||||
|
found = False
|
||||||
|
for s in self.sigs:
|
||||||
|
if verify(message, s, addr):
|
||||||
|
found = True
|
||||||
|
if not found:
|
||||||
|
return False
|
||||||
|
for addr,amount in self.outputs:
|
||||||
|
if amount < 0:
|
||||||
|
return False
|
||||||
|
total_out = total_out + amount
|
||||||
|
|
||||||
|
if total_out > total_in:
|
||||||
|
# print("Outputs exceed inputs")
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __gather(self):
|
||||||
|
data=[]
|
||||||
|
data.append(self.inputs)
|
||||||
|
data.append(self.outputs)
|
||||||
|
data.append(self.reqd)
|
||||||
|
return data
|
@ -0,0 +1,57 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Transactions -> Ledger (Block Validation): Exercise
|
||||||
|
|
||||||
|
The goal of this exercise is to learn how a blockchain for the transactions is implemented.
|
||||||
|
In this scenario the implementation of the block is extended with a validation function for the block.
|
||||||
|
Each block contains his own hash value, transaction data and the hash value of previous block.
|
||||||
|
Check the provided code in both files, Signature.py, Transaction.py and Blockchain.py.
|
||||||
|
In Blockchain.py the is_valid() method is provided to check the validity of the block,
|
||||||
|
rebuild the Block module to satisfy our testing scenario.
|
||||||
|
The testing scenario here covers tempering the data of one block.
|
||||||
|
This tempering should be detectable.
|
||||||
|
|
||||||
|
Your task is to:
|
||||||
|
* locate the TODOs in this file
|
||||||
|
* complete the missing part from the code
|
||||||
|
* run the test of this exercise located in same folder.
|
||||||
|
|
||||||
|
To test run 'TxBlock_t.py' in your command line
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
* do not change class structure or method signature to not break unit tests
|
||||||
|
* Check previous tutorials for more information on this topic
|
||||||
|
"""
|
||||||
|
from BlockChain import CBlock
|
||||||
|
from Signature import generate_keys, sign, verify
|
||||||
|
from Transaction import Tx
|
||||||
|
|
||||||
|
class TxBlock (CBlock):
|
||||||
|
previousHash = None
|
||||||
|
previousBlock = None
|
||||||
|
data = None
|
||||||
|
# TODO 1: Init
|
||||||
|
# TODO 1: Initialize the block
|
||||||
|
# Each block contains a list for the data and a hash value to previous block
|
||||||
|
def __init__(self, previousBlock):
|
||||||
|
# TODO 1: Initialize the block
|
||||||
|
# Each block contains a list for the data and a hash value to previous block
|
||||||
|
self.previousBlock = previousBlock
|
||||||
|
self.data = []
|
||||||
|
if previousBlock != None:
|
||||||
|
self.previousHash = previousBlock.computeHash()
|
||||||
|
|
||||||
|
def addTx(self, Tx_in):
|
||||||
|
self.data.append(Tx_in)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO 3: Check the validity of each transaction in the data list
|
||||||
|
# and check the validity of other blocks in the chain to make the cchain tamper-proof
|
||||||
|
# Expected return value is true or false
|
||||||
|
def is_valid(self):
|
||||||
|
if self.previousBlock != None:
|
||||||
|
if self.previousBlock.computeHash() != self.previousHash:
|
||||||
|
return False
|
||||||
|
for t in self.data:
|
||||||
|
if Tx.is_valid(t) == False:
|
||||||
|
return False
|
||||||
|
return True
|
@ -0,0 +1,110 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
This test case will verify if the provided solution by a student for TxBlock.py is correct.
|
||||||
|
In this test scenario 6 blocks will be created (1 genesis and 5 child blocks).
|
||||||
|
A total of 8 transactions will be created.
|
||||||
|
Tempering the data on block b1 by adding a valid transaction to it should be detected.
|
||||||
|
"""
|
||||||
|
from BlockChain import CBlock
|
||||||
|
from Signature import generate_keys, sign, verify
|
||||||
|
from Transaction import Tx
|
||||||
|
import pickle
|
||||||
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
from cryptography.hazmat.backends import default_backend
|
||||||
|
|
||||||
|
from TxBlock import *
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
alex_prv, alex_pbc = generate_keys()
|
||||||
|
mike_prv, mike_pbc = generate_keys()
|
||||||
|
rose_prv, rose_pbc = generate_keys()
|
||||||
|
mara_prv, mara_pbc = generate_keys()
|
||||||
|
|
||||||
|
# Valid Blocks
|
||||||
|
####################
|
||||||
|
# Create 2 valid transactions Tx1 and Tx2
|
||||||
|
Tx1 = Tx()
|
||||||
|
Tx1.add_input(alex_pbc, 1)
|
||||||
|
Tx1.add_output(rose_pbc, 1)
|
||||||
|
Tx1.sign(alex_prv)
|
||||||
|
|
||||||
|
Tx2 = Tx()
|
||||||
|
Tx2.add_input(mike_pbc,1.1)
|
||||||
|
Tx2.add_output(rose_pbc, 1)
|
||||||
|
Tx2.sign(mike_prv)
|
||||||
|
|
||||||
|
# Add Tx1 and Tx2 to the first block (genesis block)
|
||||||
|
root = TxBlock(None)
|
||||||
|
root.addTx(Tx1)
|
||||||
|
root.addTx(Tx2)
|
||||||
|
|
||||||
|
# Create 2 more valid transactions Tx3 and Tx4
|
||||||
|
Tx3 = Tx()
|
||||||
|
Tx3.add_input(rose_pbc,1.1)
|
||||||
|
Tx3.add_output(alex_pbc, 1)
|
||||||
|
Tx3.sign(rose_prv)
|
||||||
|
|
||||||
|
Tx4 = Tx()
|
||||||
|
Tx4.add_input(mike_pbc,1)
|
||||||
|
Tx4.add_output(mara_pbc, 1)
|
||||||
|
Tx4.add_reqd(rose_pbc)
|
||||||
|
Tx4.sign(mike_prv)
|
||||||
|
Tx4.sign(rose_prv)
|
||||||
|
|
||||||
|
# Add Tx3 and Tx4 to the second block (the child of the genesis block)
|
||||||
|
B1 = TxBlock(root)
|
||||||
|
B1.addTx(Tx3)
|
||||||
|
B1.addTx(Tx4)
|
||||||
|
|
||||||
|
# Creat new valid transaction Tx5
|
||||||
|
Tx5 = Tx()
|
||||||
|
Tx5.add_input(rose_pbc, 2.3)
|
||||||
|
Tx5.add_output(mike_pbc, 2.3)
|
||||||
|
Tx5.sign(rose_prv)
|
||||||
|
# Create a new block (a child of the block B1), and the transaction Tx5 to the block
|
||||||
|
B2 = TxBlock(B1)
|
||||||
|
B2.addTx(Tx5)
|
||||||
|
|
||||||
|
for b in [root, B1, B2]:
|
||||||
|
if b.is_valid():
|
||||||
|
print ("Success! Valid block is verified.")
|
||||||
|
else:
|
||||||
|
print ("Error! Valid block is not verified.")
|
||||||
|
|
||||||
|
|
||||||
|
# Invalid Blocks
|
||||||
|
######################
|
||||||
|
# Creat an invalid transaction Tx6
|
||||||
|
Tx6 = Tx()
|
||||||
|
Tx6.add_input(mara_pbc, 2.0)
|
||||||
|
Tx6.add_output(rose_pbc, 15.3)
|
||||||
|
Tx6.sign(mara_prv)
|
||||||
|
B3 = TxBlock(B2)
|
||||||
|
B3.addTx(Tx6)
|
||||||
|
|
||||||
|
# Creat an invalid transaction Tx7
|
||||||
|
Tx7 = Tx()
|
||||||
|
Tx7.add_input(rose_pbc, 2.3)
|
||||||
|
Tx7.add_output(mike_pbc, 2.3)
|
||||||
|
Tx7.sign(mike_prv)
|
||||||
|
B4 = TxBlock(B3)
|
||||||
|
B4.addTx(Tx7)
|
||||||
|
|
||||||
|
# Creat an invalid transaction Tx8
|
||||||
|
Tx8 = Tx()
|
||||||
|
Tx8.add_input(mike_pbc, 0.9)
|
||||||
|
Tx8.add_output(mara_pbc, 0.8)
|
||||||
|
Tx8.add_reqd(rose_pbc)
|
||||||
|
Tx8.sign(mike_prv)
|
||||||
|
B5 = TxBlock(B4)
|
||||||
|
B5.addTx(Tx8)
|
||||||
|
|
||||||
|
# Tamper the block before B1 by adding a valid transaction to it
|
||||||
|
# This will make the block B1 (the block after the tampered block) invalid
|
||||||
|
B2.previousBlock.addTx(Tx4)
|
||||||
|
|
||||||
|
for b in [B2, B3, B4, B5]:
|
||||||
|
if b.is_valid():
|
||||||
|
print ("Error! Invalid block is verified.")
|
||||||
|
else:
|
||||||
|
print ("Success! Invalid blocks is detected.")
|
@ -0,0 +1,7 @@
|
|||||||
|
Success! Valid block is verified.
|
||||||
|
Success! Valid block is verified.
|
||||||
|
Success! Valid block is verified.
|
||||||
|
Success! Invalid blocks is detected.
|
||||||
|
Success! Invalid blocks is detected.
|
||||||
|
Success! Invalid blocks is detected.
|
||||||
|
Success! Invalid blocks is detected.
|
@ -0,0 +1,24 @@
|
|||||||
|
from cryptography.hazmat.backends import default_backend
|
||||||
|
from cryptography.hazmat.primitives import hashes
|
||||||
|
|
||||||
|
class CBlock:
|
||||||
|
|
||||||
|
data = None
|
||||||
|
previousHash = None
|
||||||
|
previousBlock = None
|
||||||
|
def __init__(self, data, previousBlock):
|
||||||
|
self.data = data
|
||||||
|
self.previousBlock = previousBlock
|
||||||
|
if previousBlock != None:
|
||||||
|
self.previousHash = previousBlock.computeHash()
|
||||||
|
|
||||||
|
def computeHash(self):
|
||||||
|
digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
|
||||||
|
digest.update(bytes(str(self.data),'utf8'))
|
||||||
|
digest.update(bytes(str(self.previousHash),'utf8'))
|
||||||
|
return digest.finalize()
|
||||||
|
|
||||||
|
def is_valid(self):
|
||||||
|
if self.previousBlock == None:
|
||||||
|
return True
|
||||||
|
return self.previousBlock.computeHash() == self.previousHash
|
@ -0,0 +1,41 @@
|
|||||||
|
from cryptography.exceptions import *
|
||||||
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||||
|
from cryptography.hazmat.primitives import hashes
|
||||||
|
from cryptography.hazmat.primitives.asymmetric import padding
|
||||||
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
|
||||||
|
def generate_keys():
|
||||||
|
private_key = rsa.generate_private_key(public_exponent=65537,key_size=2048)
|
||||||
|
public_key = private_key.public_key()
|
||||||
|
|
||||||
|
pbc_ser = public_key.public_bytes(
|
||||||
|
encoding=serialization.Encoding.PEM,
|
||||||
|
format=serialization.PublicFormat.SubjectPublicKeyInfo)
|
||||||
|
return private_key, pbc_ser
|
||||||
|
|
||||||
|
def sign(message, private_key):
|
||||||
|
message = bytes(str(message), 'utf-8')
|
||||||
|
signature = private_key.sign(
|
||||||
|
message,
|
||||||
|
padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH),
|
||||||
|
hashes.SHA256()
|
||||||
|
)
|
||||||
|
return signature
|
||||||
|
|
||||||
|
def verify(message, signature, pbc_ser):
|
||||||
|
message = bytes(str(message), 'utf-8')
|
||||||
|
public_key = serialization.load_pem_public_key(pbc_ser)
|
||||||
|
try:
|
||||||
|
public_key.verify(
|
||||||
|
signature,
|
||||||
|
message,
|
||||||
|
padding.PSS(mgf=padding.MGF1(hashes.SHA256()),
|
||||||
|
salt_length=padding.PSS.MAX_LENGTH),
|
||||||
|
hashes.SHA256()
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
except InvalidSignature:
|
||||||
|
return False
|
||||||
|
except:
|
||||||
|
print("Error executing 'public_key.verify'")
|
||||||
|
return False
|
@ -0,0 +1,104 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
The goal of this exercise is to complete the transaction module.
|
||||||
|
In this exercise you need to add a __repr__() function that will be used
|
||||||
|
to show the details of transaction.
|
||||||
|
|
||||||
|
Your task is to:
|
||||||
|
* locate the TODOs in this file
|
||||||
|
* complete the missing part from the code
|
||||||
|
* run the test of this exercise located in same folder.
|
||||||
|
|
||||||
|
To test run 'TxBlock_t.py' in your command line
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
* do not change class structure or method signature to not break unit tests
|
||||||
|
* Check previous tutorials for more information on this topic
|
||||||
|
"""
|
||||||
|
|
||||||
|
from Signature import *
|
||||||
|
|
||||||
|
class Tx:
|
||||||
|
inputs = None
|
||||||
|
outputs =None
|
||||||
|
sigs = None
|
||||||
|
reqd = None
|
||||||
|
def __init__(self):
|
||||||
|
self.inputs = []
|
||||||
|
self.outputs = []
|
||||||
|
self.sigs = []
|
||||||
|
self.reqd = []
|
||||||
|
|
||||||
|
def add_input(self, from_addr, amount):
|
||||||
|
self.inputs.append((from_addr, amount))
|
||||||
|
|
||||||
|
def add_output(self, to_addr, amount):
|
||||||
|
self.outputs.append((to_addr, amount))
|
||||||
|
|
||||||
|
def add_reqd(self, addr):
|
||||||
|
self.reqd.append(addr)
|
||||||
|
|
||||||
|
def sign(self, private):
|
||||||
|
message = self.__gather()
|
||||||
|
newsig = sign(message, private)
|
||||||
|
self.sigs.append(newsig)
|
||||||
|
|
||||||
|
def is_valid(self):
|
||||||
|
total_in = 0
|
||||||
|
total_out = 0
|
||||||
|
message = self.__gather()
|
||||||
|
for addr,amount in self.inputs:
|
||||||
|
found = False
|
||||||
|
for s in self.sigs:
|
||||||
|
if verify(message, s, addr):
|
||||||
|
found = True
|
||||||
|
if not found:
|
||||||
|
# print ("No good sig found for " + str(message))
|
||||||
|
return False
|
||||||
|
if amount < 0:
|
||||||
|
return False
|
||||||
|
total_in = total_in + amount
|
||||||
|
for addr in self.reqd:
|
||||||
|
found = False
|
||||||
|
for s in self.sigs:
|
||||||
|
if verify(message, s, addr):
|
||||||
|
found = True
|
||||||
|
if not found:
|
||||||
|
return False
|
||||||
|
for addr,amount in self.outputs:
|
||||||
|
if amount < 0:
|
||||||
|
return False
|
||||||
|
total_out = total_out + amount
|
||||||
|
|
||||||
|
if total_out > total_in:
|
||||||
|
# print("Outputs exceed inputs")
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __gather(self):
|
||||||
|
data=[]
|
||||||
|
data.append(self.inputs)
|
||||||
|
data.append(self.outputs)
|
||||||
|
data.append(self.reqd)
|
||||||
|
return data
|
||||||
|
|
||||||
|
# TODO :
|
||||||
|
# Complete __repr__() method.
|
||||||
|
# for the desired format, check the 'output.txt' file.
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
repr = ""
|
||||||
|
repr += "INPUTS:\n"
|
||||||
|
for addr, amount in self.inputs:
|
||||||
|
repr += str(amount) + " from " + str(addr) + "\n"
|
||||||
|
repr += "OUTPUTS:\n"
|
||||||
|
for addr, amount in self.outputs:
|
||||||
|
repr += str(amount) + " to " + str(addr) + "\n"
|
||||||
|
repr += "REQD:\n"
|
||||||
|
for addr in self.reqd:
|
||||||
|
repr += str(addr) + "\n"
|
||||||
|
repr += "SIGS:\n"
|
||||||
|
for sig in self.sigs:
|
||||||
|
repr += str(sig) + "\n"
|
||||||
|
return repr
|
@ -0,0 +1,57 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
The goal of this exercise is to complete the TXBlock class. We want be able to correctly store and
|
||||||
|
load a block on disk. You have already completed every required modules seperately in the previous tutorials.
|
||||||
|
In this exercise, you have to integrate all the previously created modules, and ensure
|
||||||
|
all components are properly working together.
|
||||||
|
|
||||||
|
In addition, we would also like to see details of a transaction. For this part, check the assignment
|
||||||
|
for Transaction.py file
|
||||||
|
|
||||||
|
Your task is to:
|
||||||
|
* locate the TODOs in this file
|
||||||
|
* complete the missing part from the code
|
||||||
|
* run the test of this exercise located in same folder.
|
||||||
|
|
||||||
|
To test run 'TxBlock_t.py' in your command line
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
* do not change class structure or method signature to not break unit tests
|
||||||
|
* Check previous tutorials for more information on this topic
|
||||||
|
"""
|
||||||
|
|
||||||
|
from BlockChain import CBlock
|
||||||
|
from Signature import generate_keys, sign, verify
|
||||||
|
|
||||||
|
from Transaction import Tx
|
||||||
|
|
||||||
|
class TxBlock (CBlock):
|
||||||
|
previousHash = None
|
||||||
|
previousBlock = None
|
||||||
|
data = None
|
||||||
|
# TODO 1: Init
|
||||||
|
# TODO 1: Initialize the block
|
||||||
|
# Each block contains a list for the data and a hash value to previous block
|
||||||
|
def __init__(self, previousBlock):
|
||||||
|
# TODO 1: Initialize the block
|
||||||
|
# Each block contains a list for the data and a hash value to previous block
|
||||||
|
self.previousBlock = previousBlock
|
||||||
|
self.data = []
|
||||||
|
if previousBlock != None:
|
||||||
|
self.previousHash = previousBlock.computeHash()
|
||||||
|
|
||||||
|
def addTx(self, Tx_in):
|
||||||
|
self.data.append(Tx_in)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO 3: Check the validity of each transaction in the data list
|
||||||
|
# and check the validity of other blocks in the chain to make the cchain tamper-proof
|
||||||
|
# Expected return value is true or false
|
||||||
|
def is_valid(self):
|
||||||
|
if self.previousBlock != None:
|
||||||
|
if self.previousBlock.computeHash() != self.previousHash:
|
||||||
|
return False
|
||||||
|
for t in self.data:
|
||||||
|
if Tx.is_valid(t) == False:
|
||||||
|
return False
|
||||||
|
return True
|
@ -0,0 +1,129 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
This test case will verify if the provided solution by a student for TxBlock.py is correct.
|
||||||
|
In this test scenario 6 blocks will be created (1 genesis and 5 child blocks).
|
||||||
|
A total of 8 transactions will be created.
|
||||||
|
Tempering the data on block b1 by adding a valid transaction to it should be detected.
|
||||||
|
In addition, Transaction should be printed formmated and human-readable. You shoud add a method
|
||||||
|
to transaction file to represent a transaction in the desired format.
|
||||||
|
|
||||||
|
For the correct format check the 'output.txt' file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from BlockChain import CBlock
|
||||||
|
from Signature import generate_keys, sign, verify
|
||||||
|
import pickle
|
||||||
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
from cryptography.hazmat.backends import default_backend
|
||||||
|
|
||||||
|
# from Transaction import Tx
|
||||||
|
|
||||||
|
from TxBlock import *
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
alex_prv, alex_pbc = generate_keys()
|
||||||
|
mike_prv, mike_pbc = generate_keys()
|
||||||
|
rose_prv, rose_pbc = generate_keys()
|
||||||
|
mara_prv, mara_pbc = generate_keys()
|
||||||
|
|
||||||
|
# Valid Blocks
|
||||||
|
####################
|
||||||
|
# Create 2 valid transactions Tx1 and Tx2
|
||||||
|
Tx1 = Tx()
|
||||||
|
Tx1.add_input(alex_pbc, 1)
|
||||||
|
Tx1.add_output(rose_pbc, 1)
|
||||||
|
Tx1.sign(alex_prv)
|
||||||
|
|
||||||
|
Tx2 = Tx()
|
||||||
|
Tx2.add_input(mike_pbc,1.1)
|
||||||
|
Tx2.add_output(rose_pbc, 1)
|
||||||
|
Tx2.sign(mike_prv)
|
||||||
|
|
||||||
|
# Add Tx1 and Tx2 to the first block (genesis block)
|
||||||
|
root = TxBlock(None)
|
||||||
|
root.addTx(Tx1)
|
||||||
|
root.addTx(Tx2)
|
||||||
|
|
||||||
|
# Create 2 more valid transactions Tx3 and Tx4
|
||||||
|
Tx3 = Tx()
|
||||||
|
Tx3.add_input(rose_pbc,1.1)
|
||||||
|
Tx3.add_output(alex_pbc, 1)
|
||||||
|
Tx3.sign(rose_prv)
|
||||||
|
|
||||||
|
Tx4 = Tx()
|
||||||
|
Tx4.add_input(mike_pbc,1)
|
||||||
|
Tx4.add_output(mara_pbc, 1)
|
||||||
|
Tx4.add_reqd(rose_pbc)
|
||||||
|
Tx4.sign(mike_prv)
|
||||||
|
Tx4.sign(rose_prv)
|
||||||
|
|
||||||
|
# Add Tx3 and Tx4 to the second block (the child of the genesis block)
|
||||||
|
B1 = TxBlock(root)
|
||||||
|
B1.addTx(Tx3)
|
||||||
|
B1.addTx(Tx4)
|
||||||
|
|
||||||
|
# Save the block B1 on the disk
|
||||||
|
savefile = open("block.dat", "wb")
|
||||||
|
pickle.dump(B1, savefile)
|
||||||
|
savefile.close()
|
||||||
|
|
||||||
|
# Creat new valid transaction Tx5
|
||||||
|
Tx5 = Tx()
|
||||||
|
Tx5.add_input(rose_pbc, 2.3)
|
||||||
|
Tx5.add_output(mike_pbc, 2.3)
|
||||||
|
Tx5.sign(rose_prv)
|
||||||
|
# Create a new block (a child of the block B1), and the transaction Tx5 to the block
|
||||||
|
B2 = TxBlock(B1)
|
||||||
|
B2.addTx(Tx5)
|
||||||
|
|
||||||
|
# Load the block B1 from the disk
|
||||||
|
loadfile = open("block.dat" ,"rb")
|
||||||
|
load_B1 = pickle.load(loadfile)
|
||||||
|
loadfile.close()
|
||||||
|
|
||||||
|
for b in [root, B1, B2, load_B1]:
|
||||||
|
if b.is_valid():
|
||||||
|
print ("Success! Valid block is verified.")
|
||||||
|
else:
|
||||||
|
print ("Error! Valid block is not verified.")
|
||||||
|
|
||||||
|
# Invalid Blocks
|
||||||
|
######################
|
||||||
|
# Creat an invalid transaction Tx6
|
||||||
|
Tx6 = Tx()
|
||||||
|
Tx6.add_input(mara_pbc, 2.0)
|
||||||
|
Tx6.add_output(rose_pbc, 15.3)
|
||||||
|
Tx6.sign(mara_prv)
|
||||||
|
B3 = TxBlock(B2)
|
||||||
|
B3.addTx(Tx6)
|
||||||
|
|
||||||
|
# Creat an invalid transaction Tx7
|
||||||
|
Tx7 = Tx()
|
||||||
|
Tx7.add_input(rose_pbc, 2.3)
|
||||||
|
Tx7.add_output(mike_pbc, 2.3)
|
||||||
|
Tx7.sign(mike_prv)
|
||||||
|
B4 = TxBlock(B3)
|
||||||
|
B4.addTx(Tx7)
|
||||||
|
|
||||||
|
# Creat an invalid transaction Tx8
|
||||||
|
Tx8 = Tx()
|
||||||
|
Tx8.add_input(mike_pbc, 0.9)
|
||||||
|
Tx8.add_output(mara_pbc, 0.8)
|
||||||
|
Tx8.add_reqd(rose_pbc)
|
||||||
|
Tx8.sign(mike_prv)
|
||||||
|
B5 = TxBlock(B4)
|
||||||
|
B5.addTx(Tx8)
|
||||||
|
|
||||||
|
# Tamper the block before B1 by adding a valid transaction to it
|
||||||
|
# This will make the block B1 (the block after the tampered block) invlaid
|
||||||
|
B1.previousBlock.addTx(Tx4)
|
||||||
|
|
||||||
|
for b in [B1, B3, B4, B5]:
|
||||||
|
if b.is_valid():
|
||||||
|
print("Error! Invalid block is verified.")
|
||||||
|
else:
|
||||||
|
print("Success! Invalid blocks is detected.")
|
||||||
|
|
||||||
|
print('Tx4\n', Tx4)
|
||||||
|
print('Tx5\n', Tx5)
|
@ -0,0 +1,29 @@
|
|||||||
|
Success! Valid block is verified.
|
||||||
|
Success! Valid block is verified.
|
||||||
|
Success! Valid block is verified.
|
||||||
|
Success! Valid block is verified.
|
||||||
|
Success! Invalid blocks is detected.
|
||||||
|
Success! Invalid blocks is detected.
|
||||||
|
Success! Invalid blocks is detected.
|
||||||
|
Success! Invalid blocks is detected.
|
||||||
|
Tx4
|
||||||
|
INPUTS:
|
||||||
|
1 from b'-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA17Qc21PHEjqP7CLg1v1l\nYaSRy4gu5MXWcjbflmInox6IbMD/7P37kuvWRw/ruVCidoy8JmwasDGDv6Z9vRfN\nYSIssLziMcbhWUdEMLlI5Qu1Vf1eUzAxUEhQ4SBUi21BYX5uKoZm+rzd/idTi00W\nLI9c3/mKx5+i8pUBNFOXAijlqr5akxmqox2CN5cynKt2YK3ADOJPY8+hFT7s99Vd\np/3EWf4hyFWXWSnMTCs+n42pYf5ZA3/kRFzMI8x070zfNNqjgseXQuyc0br4U1Jt\nnAJaE4OzKez4rEF1tyZ9YBxX+D1ZshZpozdLxIyO4JUa4913zHFlz6CcIMH3a1hI\nVQIDAQAB\n-----END PUBLIC KEY-----\n'
|
||||||
|
OUTPUTS:
|
||||||
|
1 to b'-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxGLdr2pV+nnQBH7oDP/9\nnBx5rc8zQJAsXSyL/HQAb+x3bhxRditCqsrShEIZpix7OZmMy8R8C8R+M6OAmeMy\nKGXxGD80WINSJgzSy2SZwAbKVNCzFEPVg/5tNgAzZBkeAZ8ddgrFzago2eeJwjyr\nthcdfnlJzw+LIXkIbG0AmU9XGRE3HpxlY0k5BJZ1LoWVezq+ip/nAO2i0Ht/rGxN\njmJvvDjGkawaHbeNIGdhEqIJp2/sKCJg0OyU7r1QbAwlbF61fEyzCVEH+PrqHmlI\nnCrP/qkxr/7bcWADbM2rX1sB8ueSAu70EIPeFtdGCDr+vzc7qphelFnzK8ekwiFD\nYQIDAQAB\n-----END PUBLIC KEY-----\n'
|
||||||
|
EXTRA REQUIRED SIGNATURES:
|
||||||
|
b'-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1HKkpz+xIVe4B7oT7I+V\nx6FYBlT0H9BRUdOnYHKaUVNdR8WnlJBFzdl5oDOOfpzvtJdQtM6RD1lKPdKhvelE\nlemnTqBKT4aeZtSrbmTHhbJgS7cgyVTi3w2Ct7ye/ypyMPoFZlLCI7L7UGyzLKlQ\npnOJTouYzwgN7m7T3IaAYYwrRwCMczq+IKARPPfA8wMcdb1/tM7voqGmiSb5Z0fz\nHsd/MWcKuL3ZGBkx3lT2QEXuTT3OO6V8LdVWMU0kEaM0lS30KzVIT7CNmbyBe7kc\nsBnZ0Q79GlQaLnsDphPUrbndsr3jp4Wmx0H9JzLNNnJrvmOnWKTgHi5BTylVxMe7\nWQIDAQAB\n-----END PUBLIC KEY-----\n'
|
||||||
|
SIGNATURES:
|
||||||
|
b'G\xcb\xc0\xf4ULc|~4#{\xc7\xf2\x8f:\xa7\xef\xb5H@&\xaaQ,K/\x9b\x92\xaa\xbd\xa7\xe66\xf5q\xf1\x90XD\xf5>AO\x19\x11\x9f\x89\x0b\xcc\xb9]Zu\xf0x\xe8k&\x8b\xb6k\xeb9\x81\x9a\x0b\xf7\\yl\xdcc7\xfbP\xd5W\xb5\xa2\x1bY\x1a\\d\xfe\xe8.\xf9\xecG%\xc9\xcb\x1ab\xee<nu\x08<\xe9\x90X\xd6\xa6qd\xd6#\xcd\x13\xc5I\x99\xd7\xfc\xaaP\xf4t\xf7\x14\x92\xcbu\xa2\xdeE\x19\xd3\x82\xb4S\xa3L\xe4\xe8\x85\x92\x12O\xd3@H\xf4OR\x0b\x82\tI\x9eR\xc1xW\xbe8\x82\\\xaf\x00\xf5\xc5\xbfN\xc3\xcde\xc7\xd2\x93\xba\x11\xf7\xf9]\xf6\xb1\xbb(7\xf8H\xec\xbb\xf1Y\xc5\xd6q\xb21\xe5\x90"7 \xe1\')\x8e\x0c\xae\x9a\xc8\x05*hF\x86\xed\x12\x08\xe2\x96U \xcb\xea\xe2\xed\xean\x12\xc9\xd1\x80\xdb\xd6\xf7\xffJ\x19\xdeTv5!\xaf\xee\x95\xf3\xa0\xc3g\xe7\xc6e\xa2,E\xf0\x16'
|
||||||
|
b'\x05\xf0\xd3\xd1\xde^\xceB\xb6\x03.\xcf\x92`\xc4\xe3\x9d%\xc1\xce\xaa\xfao\x80\xe77\xfcg\x7f\x8a\xbb\x87\x1fz\x81\xad\x96\xc64\x07\xd9%\x01f\x04\xf1\xfa\xa5\xad?\xf5I9\x9de%\xe8\xf13\x1c.w\x0eT\x10hb\x04\x1c\xf9\xe5\x1b!\x99\xb5fr\xe3\x87\xc3?\xec\xe7^;w\xb3\xcdT\xd6\x82Zb\xa7 \x9e\x85k8\xf5\x98\xf6\x9d\xf3\xaf\x88^\x8f5\xe8\xa4}\xa4Q@G\x1f\xa8\xf6\xcf\xdbG\x8fHG\xe7x\\\xb7\xf6\xed\xe1\x03?\x81\xcavS_\xcc\xc0\xa6\xf0\x99\xaa\x86ZZQ\xebI*6\xaf!\xec\xe9l\x9f\x13\x93\xf4\xce\x94,\xd0.\x19`\xefV\x87/l#x\x84<%\x19\xba\xa8\x12\xec\xd3\x88_vW\x9ak\xa60\t\x80k\xda\xf4\xd2\xf6\xa0b\x9e]\xe1N\x06\xbd\xe5J\xc8\x7f\\`\x01]Q\xbf\xa8\x83\xc0\xab\xe1\x8c\xc3\x7f\xcf\xbf\xd2s#\xb5&,gP\x03\xb4\x95\xe5\xdf\xf7I@\xdb\xe4$\xe76l\xa4\xbeMN59'
|
||||||
|
END
|
||||||
|
|
||||||
|
Tx5
|
||||||
|
INPUTS:
|
||||||
|
2.3 from b'-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1HKkpz+xIVe4B7oT7I+V\nx6FYBlT0H9BRUdOnYHKaUVNdR8WnlJBFzdl5oDOOfpzvtJdQtM6RD1lKPdKhvelE\nlemnTqBKT4aeZtSrbmTHhbJgS7cgyVTi3w2Ct7ye/ypyMPoFZlLCI7L7UGyzLKlQ\npnOJTouYzwgN7m7T3IaAYYwrRwCMczq+IKARPPfA8wMcdb1/tM7voqGmiSb5Z0fz\nHsd/MWcKuL3ZGBkx3lT2QEXuTT3OO6V8LdVWMU0kEaM0lS30KzVIT7CNmbyBe7kc\nsBnZ0Q79GlQaLnsDphPUrbndsr3jp4Wmx0H9JzLNNnJrvmOnWKTgHi5BTylVxMe7\nWQIDAQAB\n-----END PUBLIC KEY-----\n'
|
||||||
|
OUTPUTS:
|
||||||
|
2.3 to b'-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA17Qc21PHEjqP7CLg1v1l\nYaSRy4gu5MXWcjbflmInox6IbMD/7P37kuvWRw/ruVCidoy8JmwasDGDv6Z9vRfN\nYSIssLziMcbhWUdEMLlI5Qu1Vf1eUzAxUEhQ4SBUi21BYX5uKoZm+rzd/idTi00W\nLI9c3/mKx5+i8pUBNFOXAijlqr5akxmqox2CN5cynKt2YK3ADOJPY8+hFT7s99Vd\np/3EWf4hyFWXWSnMTCs+n42pYf5ZA3/kRFzMI8x070zfNNqjgseXQuyc0br4U1Jt\nnAJaE4OzKez4rEF1tyZ9YBxX+D1ZshZpozdLxIyO4JUa4913zHFlz6CcIMH3a1hI\nVQIDAQAB\n-----END PUBLIC KEY-----\n'
|
||||||
|
EXTRA REQUIRED SIGNATURES:
|
||||||
|
SIGNATURES:
|
||||||
|
b'\xb7\xdc\xe9\xe0\xb7\x848\xc22dy^o\xdd/\xacQ\x04?<.\x05\xdc\x00\xde\xf4\x1aH\xa2 ?z\xca\x96f\x0c\xa7\xe7v\xbf.\x8f/\x97@<\xba\xbf\xb6\xa4\xfc\xd9\xc0U\n6B\xb1t\x16\xc5W&`\xd6Bo\x91*\xd0o\xd9*r\x8b\xba\x8e(\xaeT\x9b0\xf7\x9f\xb4hRW\x08\xf2\xd3m\x18\xc3\xca\x13C\xeb\x98\x81\x1cWz]}\x9b\xc4\xc3\xc0\x8egmf\n\xbej\xe6\xf0owN\xb8\xaaw\x16X\xac\xa7\xe6\x87\xc3\x8f\xa1_\xff\xc7\xaa\xa5)\xa9\xe3x\x0eEI\xe0\xff\x18\xbc\xb1p\xe6\xc9\x11\x04\x86\x027\x9e\xa01\xb2\x13\xd1tr\x17Nv\xee\xa3\x84\xf8C\\\x0c\xa1\x08x\xa9\x8d\xd0t\xad!\x17d\xcb\x1f\xaaoY\xbb\x1ew\xb0UU,lnR\x95M\x1f\x1cLl0\xe0\x96S\x0e)\xf4q\xff\xd6\x83\x97\xaa\xc7\x81\xeaM\xc9%]\x06]\x02J\x11\x073\xe60\x05\xd0\xf2\xe3\xe1,r\xfb\x1aV7]\t\xea\xf7\xf5\xe0\xfes'
|
||||||
|
END
|
Loading…
x
Reference in New Issue
Block a user