In [1]:
# Import required packages for this notebook
%matplotlib inline
import hashlib
import numpy
import matplotlib.pyplot as plt
import time
from Crypto.PublicKey import RSA
from Crypto import Random
In [2]:
# Test text hashing
hash_object = hashlib.sha256(b"123")
hex_dig = hash_object.hexdigest()
print(hex_dig)
In [3]:
# Object for Person's Digital Wallet
# ** Modified to include PoW method
class DigitalWallet(object):
def __init__(self, name):
# Owner of the wallet
self._name = name
# Generate RSA keys on object creation
private_key, public_key = self.__generate_RSA_keys(2048)
# Objects RSA keys
self._private_key = private_key # This should never be sent out
self._public_keys = {self._name: public_key}
def __generate_RSA_keys(self, num_bits):
# Keys that are generated when the digital wallet is created
random_generator = Random.new().read
private_key = RSA.generate(2048, random_generator)
public_key = private_key.publickey()
return private_key, public_key
def send_public_keys(self):
# Public key can be sent to others for message encryption
return {self._name: self._public_keys[self._name].exportKey(format='PEM')}
def receive_public_key(self, key_dict):
# Recieve a public key from another person
for key, val in key_dict.items():
public_key = RSA.importKey(val)
self._public_keys[key] = public_key
def send_encrypted_message(self, to_user, message):
# Encrypt with the public key and return to user
return self._public_keys[to_user].encrypt(message, K=None)
def proof_of_work(self, encrypted_message):
init_time = time.time()
hash_message = hashlib.sha256(message).hexdigest()
first_byte = hash_message[:3]
counter = -1
while first_byte != "000":
counter +=1
#had to convert encrypted msg from tuple to byte to be hashed
hash_message = hashlib.sha256(b"".join(encrypted_message) + bytes(str(counter), encoding="UTF-8")).hexdigest()
first_byte = hash_message[:3]
final_time = time.time()
print("Time to proof = ", final_time - init_time)
return bytes(str(counter), encoding="UTF-8")
def receive_encrypted_message(self, encrypted_message, nonce):
#checking if miner did his job
hash_message = hashlib.sha256(b"".join(encrypted_message) + nonce).hexdigest()
if(hash_message[:3] == "000"):
decoded_message = self._private_key.decrypt(encrypted_message)
print(decoded_message)
else:
print("Miner has not proof of worked this message")
In [4]:
# Function for testing the Proof of Work function
def proof_of_work_test(dif, message):
start_time = time.time() # Start timer
counter = 0 # the nonce = counter
target_bytes = dif * str(0) # Brute force target
#Brute forcing proof of work till the first X chars in hashed msg are 0
while True:
#Concatenating byte and str(int) and sha256 hashing the result
hash_message = hashlib.sha256(message + bytes(str(counter),
encoding="UTF-8")).hexdigest()
check_bytes = hash_message[:dif]
# Check to see a result has been found
if check_bytes == target_bytes:
break
else:
counter += 1
# Result has been found, return delta time and value of counter
final_time = time.time()
delta_time = final_time - start_time
return (delta_time, counter)
# Message to test, difficulty set to '3' characters
message = b'Secret message for bob'
difficulty = 3
# Run the test
delta_time, counter = proof_of_work_test(difficulty, message)
# Print results
pow_result = message + bytes(str(counter), encoding="UTF-8")
hash_message = hashlib.sha256(pow_result).hexdigest()
print(pow_result)
print(hash_message)
print(delta_time, "seconds")
In [5]:
# Parameters for graph
message = b'Secret message for bob'
max_dif = 6 # Max difficulty tested
dif_range = range(1, max_dif + 1) # Add one to range to ensure we capture this value
# Create some data
test_results = [proof_of_work_test(i, message)
for i in dif_range]
for pow_time, counter in test_results:
print(pow_time, counter)
In [6]:
# Plot the results
x_data = [pow_time for pow_time, counter in test_results] # Time taken
y_data = [counter for pow_time, counter in test_results] # Number of iterations
fig = plt.figure(figsize=(10,5))
sub1 = plt.subplot(121)
sub1.set_xlabel('Difficulty')
sub1.scatter(dif_range, x_data)
sub2 = plt.subplot(122)
sub2.set_xlabel('Difficulty')
sub2.scatter(dif_range, y_data)
Out[6]:
In [7]:
# 'Alice' is a hashed value in this list
usernames = ["cd9fb1e148ccd8442e5aa74904cc73bf6fb54d1d54d333bd596aa9bb4bb4e961",
"3bc51062973c458d5a6f2d8d64a023246354ad7e064b1e4e009ec8a0699a3043",
"b5fd03dd91df1cfbd2f19c115d24d58bbda01a23fb01924bb78b2cc14f7ff1cb",
"2d1e830624b2572adc05351a7cbee2d3aa3f6a52b34fa38a260c9c78f96fcd07"]
#'123' is a hashed password in this list
passwords = ["a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3",
"a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3",
"a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3",
"a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3"]
correct_username = True
while correct_username:
username = input("Enter Username: ")
hash_user = hashlib.sha256(bytes(str(username), encoding="UTF-8")).hexdigest()
index = -1
if hash_user in usernames:
correct_username = False
index = usernames.index(hash_user)
correct_password = True;
while correct_password:
password = input("Enter Password: ")
hash_pass = hashlib.sha256(bytes(str(password), encoding="UTF-8")).hexdigest()
if hash_pass in passwords:
correct_password = False
print("Welcome ", username)
else:
print("Incorrect password try 123")
else:
print("Incorrect Username try Alice")
In [8]:
"""
Similate a basic transaction
1. Create digital wallet objects for Alice and Bob.
2. Create private and digital keys for these wallets
3. Send Bob's public key in 'PEM' format to Alice
4. Alice then encrypt's a message using Bob's public key
5. Alice sends encrypted message to Bob
6. Bob receives message and decrypts message using his private key
"""
# Just a simple idea for blockchain at the momment and putting in some pre-set usernames and balances.
#Would be good if we could put into json file and read set these initial variables then when receiver finally decrypts the msg he can update other people -i.e. Alices json file
usernames = ["cd9fb1e148ccd8442e5aa74904cc73bf6fb54d1d54d333bd596aa9bb4bb4e961",
"3bc51062973c458d5a6f2d8d64a023246354ad7e064b1e4e009ec8a0699a3043",
"b5fd03dd91df1cfbd2f19c115d24d58bbda01a23fb01924bb78b2cc14f7ff1cb",
"2d1e830624b2572adc05351a7cbee2d3aa3f6a52b34fa38a260c9c78f96fcd07"]
passwords = ["a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3",
"a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3",
"a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3",
"a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3",
"a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3"]
balances = [50,50,50,50]
#using hash for usernames so you cannot see individuals names -same as in bitcoin
hash_user= 0
hash_receiver = 0
#to find balance/password for send/receiver to easily update them at end
index_sender = -1
index_reciever = 0
amount = 0
incorrect_username = True
while incorrect_username:
username = input("Enter Username: ")
hash_user = hashlib.sha256(bytes(str(username), encoding="UTF-8")).hexdigest()
if hash_user in usernames:
incorrect_username = False
index = usernames.index(hash_user)
incorrect_password = True;
while incorrect_password:
password = input("Enter Password: ")
hash_pass = hashlib.sha256(bytes(str(password), encoding="UTF-8")).hexdigest()
if hash_pass in passwords:
incorrect_password = False
print("Welcome ", username)
else:
print("Incorrect password try 123")
else:
print("Incorrect Username try Alice, Bob, Jack, or Ryan")
incorrect_receiver = True
while incorrect_receiver:
receiver = input("Enter Reciever: ")
hash_receiver = hashlib.sha256(bytes(str(receiver), encoding="UTF-8")).hexdigest()
if hash_receiver != hash_user and hash_receiver in usernames:
incorrect_receiver = False
else:
print("Invalid receiver")
incorrect_amount = True
while incorrect_amount:
amount = input("Enter criscoin send amount = ")
if amount.isdigit() == False:
print("Integer input required")
elif balances[index]-int(amount) >= 0 and int(amount) >= 0:
incorrect_amount = False
else:
print("Insufficient credit or invalid entry")
# Build wallets for Alice and Bob
senders_wallet = DigitalWallet(name=hash_user)
receivers_wallet = DigitalWallet(name=hash_receiver)
mine = DigitalWallet(name='Miner')
# Receive a public key from Bob
receivers_public_key = receivers_wallet.send_public_keys()
senders_wallet.receive_public_key(receivers_public_key)
# Message is encrypted so only Bob and Alice can decrypt it
encrypted_message = senders_wallet.send_encrypted_message(hash_receiver, b'Secret message for bob')
#Proof of Work encrypted message recieve from Alice
nonce = mine.proof_of_work(encrypted_message)
# Send Message to Bob and Alice who can decrypt message and check nonce quickly
blockchain_update = receivers_wallet.receive_encrypted_message(encrypted_message, nonce)