diff --git a/period_1/05-transaction/504_EX4_A04_Transaction_Class/Signature.py b/period_1/05-transaction/504_EX4_A04_Transaction_Class/Signature.py new file mode 100644 index 0000000..eaeaaf4 --- /dev/null +++ b/period_1/05-transaction/504_EX4_A04_Transaction_Class/Signature.py @@ -0,0 +1,35 @@ +from cryptography.exceptions import * +from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import padding + +def generate_keys(): + private_key = rsa.generate_private_key(public_exponent=65537,key_size=2048) + public_key = private_key.public_key() + return private_key, public_key + +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, public_key): + message = bytes(str(message), 'utf-8') + 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 \ No newline at end of file diff --git a/period_1/05-transaction/504_EX4_A04_Transaction_Class/Transaction.py b/period_1/05-transaction/504_EX4_A04_Transaction_Class/Transaction.py new file mode 100644 index 0000000..a52ba05 --- /dev/null +++ b/period_1/05-transaction/504_EX4_A04_Transaction_Class/Transaction.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +""" +Transaction Class + +The goal of this exercise is to learn how to complete transaction class. +A transaction is composed of a list of Inputs and a list of outputs, and few methods. +add_input and add_output are already completed in the previous tutorials. +In this exercise, we will add a sign method to the class. With this method, we can +sign a transaction. + +Your task is to: + * locate the TODOs in this file + * complete the missing part from the code + * run the test of this tutorial located in same folder. + +To test run 'Transactions_t.py' in your command line + +Notes: + * do not change class structure or method signature to not break unit tests +""" + +from Signature import * + +class Tx: + + def __init__(self): + self.inputs = [] + self.outputs = [] + self.sigs = [] + self.reqd = [] # A placeholder for any other extra required signature (e.g. escrow) + + + # TODO 1: Complete the method + # These two methods are already done in the previous tutorials + # you can copy and paste the previous codes here + 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]) + + + # TODO 2: Complete the method + # In this method: + # 1 - You should collect all data of the transaction, and then + # 2 - Sign data and add it to the variable sigs + # + # It is good idea to create a seperate private or protected method to collect all data of + # transaction before signing it. + def sign(self, private): + tx_data = self.__gather() + new_sig = sign(tx_data, private) + self.sigs.append(new_sig) + + + # It is good idea to create a seperate private or protected method to collect all data of + # transaction before signing it. + def __gather(self): + data = [] + data.append(self.inputs) + data.append(self.outputs) + data.append(self.reqd) + return data + + diff --git a/period_1/05-transaction/504_EX4_A04_Transaction_Class/Transactions_t.py b/period_1/05-transaction/504_EX4_A04_Transaction_Class/Transactions_t.py new file mode 100644 index 0000000..366d8e3 --- /dev/null +++ b/period_1/05-transaction/504_EX4_A04_Transaction_Class/Transactions_t.py @@ -0,0 +1,91 @@ +""" +This test case will verify if the provided exercise solution by a student for the Transaction.py is correct. +""" + +from Signature import * + +from Transaction import * + +def print_transaction(tx_name, tx): + print('---------------') + print(f'-- {tx_name}') + + for (index, input_item) in enumerate(tx.inputs): + payer = None + for key_name, prv_key, pbc_key in keys_list: + if pbc_key == input_item[0]: + payer = key_name + if payer != None: + print(f'In[{index+1}]: {payer} sends {input_item[1]} coin') + else: + print('There is no known Public key for sender') + + for (index, output_item) in enumerate(tx.outputs): + receiver = None + for key_name, prv_key, pbc_key in keys_list: + if pbc_key == output_item[0]: + receiver = key_name + if receiver != None: + print(f'Out[{index+1}]: {receiver} receives {output_item[1]} coin') + else: + print('There is no known Public key for receiver') + + tx_data=[] + tx_data.append(tx.inputs) + tx_data.append(tx.outputs) + tx_data.append(tx.reqd) + signed = False + for s in tx.sigs: + for key_name, _, pbc_key in keys_list: + if verify(tx_data, s, pbc_key): + signed = True + print(f'\n{tx_name} is signed by {key_name}.', end='\n') + # print(s, end='\n') + if not signed: + print('There is no signature on this Transaction') + + + print() + +if __name__ == "__main__": + + keys_list =[] + + alex_prv, alex_pbc = generate_keys() + keys_list.append(('alex', alex_prv, alex_pbc)) + + mike_prv, mike_pbc = generate_keys() + keys_list.append(('mike', mike_prv, mike_pbc)) + + rose_prv, rose_pbc = generate_keys() + keys_list.append(('rose', rose_prv, rose_pbc)) + + mara_prv, mara_pbc = generate_keys() + keys_list.append(('mara', mara_prv, mara_pbc)) + + + # -------------------------------------- + Tx1 = Tx() + Tx1.add_input(alex_pbc, 1) + Tx1.add_output(mike_pbc, 1) + Tx1.sign(alex_prv) + + # -------------------------------------- + Tx2 = Tx() + Tx2.add_input(alex_pbc, 2) + Tx2.add_output(mike_pbc, 1) + Tx2.add_output(rose_pbc, 1) + Tx2.sign(alex_prv) + + # -------------------------------------- + Tx3 = Tx() + Tx3.add_input(rose_pbc, 1.2) + Tx3.add_output(alex_pbc, 1.1) + Tx3.sign(rose_prv) + Tx3.sign(mara_prv) + + # -------------------------------------- + for tx in [Tx1, Tx2, Tx3]: + tx_name = [k for k,v in locals().items() if v == tx][0] + print_transaction(tx_name, tx) + \ No newline at end of file diff --git a/period_1/05-transaction/504_EX4_A04_Transaction_Class/output_1.txt b/period_1/05-transaction/504_EX4_A04_Transaction_Class/output_1.txt new file mode 100644 index 0000000..11314be --- /dev/null +++ b/period_1/05-transaction/504_EX4_A04_Transaction_Class/output_1.txt @@ -0,0 +1,19 @@ +--------------- +-- Tx1 +In[1]: alex sends 1 coin +Out[1]: mike receives 1 coin +Tx1 is signed by alex + +--------------- +-- Tx2 +In[1]: alex sends 2 coin +Out[1]: mike receives 1 coin +Out[2]: rose receives 1 coin +Tx2 is signed by alex + +--------------- +-- Tx3 +In[1]: rose sends 1.2 coin +Out[1]: alex receives 1.1 coin +Tx3 is signed by rose +Tx3 is signed by mara \ No newline at end of file diff --git a/period_1/05-transaction/504_EX4_A04_Transaction_Class/output_2.txt b/period_1/05-transaction/504_EX4_A04_Transaction_Class/output_2.txt new file mode 100644 index 0000000..ab5406a --- /dev/null +++ b/period_1/05-transaction/504_EX4_A04_Transaction_Class/output_2.txt @@ -0,0 +1,27 @@ +--------------- +-- Tx1 +In[1]: alex sends 1 coin +Out[1]: mike receives 1 coin + +Tx1 is signed by alex. +b'4\xadh!\xa8W\x12Ec\xae\xc3\x1a\xab]\xda\x84\x9cWC\xf0\xc2\x96\x8b_\xc3?#/\x87c\xb8\xb5\xa8g\x14v\x91mo\xfc|\x96\xdel\xca\x8b\xec\xd9\x91j%j\xd8\xcc\x90\xa2a\x87\x121\xdf\xde\x1f\x01\x06oiFp\xedi\xb5\xc3a\xe1\xea\x16\xa1H\xe2\xb6\xd9\xdb\xf0.~\xc3\xac\xa8\xea%^\xa7\x0c\x129\'\x9e\x9e\x1f\x7f\x8f$\xc5\xe3\xab#\x1aYe^\xed\xdf\xfc\xb6\x0e\xc0\xa1k|@M\xc2\x0b\xac=\xcd\x8f\xb6\xbeR\xf5\xa2\xedn0\x03\xee\xf2\xdf\xbbY\xac\xf6%\x12\xcf3\xb1\xc8\xb6Y50\x02\xbb\xa7,\xc6\xf9\xa670n\x0e\xd9\xa6\xec\xd0\x83 Q\xdaVN\xc8\xcaY\xdf\xc2m\xe0-\xbd[\xb7-o\x89\x9f\xcf\xf9)S]C\x98\xb0\xb2\xdb0"i%\x15\x9e\xba\x10\x0f\xe1\x8a5;s\xf7E\xe2\xc4J\x8a\xab\xfc(d\x82M\xac\xaf\xcf/l\x82\xc0\x1f\x10\\\xb9\xae$\x93\xa6\xef\xe1{\xbfk\xf8\x04W\xc4&.\xf6\x15\x01.' + +--------------- +-- Tx2 +In[1]: alex sends 2 coin +Out[1]: mike receives 1 coin +Out[2]: rose receives 1 coin + +Tx2 is signed by alex. +b'\xa5$\x07X(\x19\x9e\xe9\x98\xf5:\x00\xfe\xff\x07\xae\x0e\xc3\xa7\xf1\x8d\x90\xaa\x9e\x18\x19^3\x93V\x0f`L>\xc2\xea\x93\x8b-\x95\xaf\xa2\xee\x10\xd4c\t$\x81\xd5t\x99,5\x13C\xa2\x15\xf3\xe5\x04\xa6\xef\xc7L\xf0\xa6\xf2$\xb9\x89V\xa6j\xa3\x88\xf26\xf9.)]\xa3< \x9c\x1e\x84\xb3\xe6\xbe\x8f\x1dZ\xe3\xbb\xb5\x90k\x85\xef\xf9m#\x89\xaa\xd3\xa1\xc3\xdc\xf8\xb6\xa8\x9d\xb0bh\xcb`\xe2\xcb\xf5b\xe8^M\nb\xb2(Y9L\x89]\xaa\xa8\xbf\x1b\xf8& )\xc4"D+{*\xb3\xdb\xdb~\x085Bd{\xa1\xbe\xf6\x84\xc1\xe0rlv\x93\xab\xaa\xa8\x00\xc6|\xaf\xcd\x9c\xf8\x02:\xaaDuo\xc0r<\x1a\x1c\x7f\x8c\x96\x18\xdb9\x0ca\xd2\x0f\xb7h\x8cCS\xb4\xb5\x12*\x7f\xc7\x08\x8a\x8ar\xf4\xc7\x93\xfe\xc6\x10\xf2\x03\xb2\xf4n\xcc\x8d\x08\x7f~n\xbc\x11\x04\xe2\xe7\xb7\x82\xd7-\xad\xc3\xa8\xba\xcf\xba\x8a!\xe8o\x7f\x0b`\xb59\xe1' + +--------------- +-- Tx3 +In[1]: rose sends 1.2 coin +Out[1]: alex receives 1.1 coin + +Tx3 is signed by rose. +b"N\xb0\xb6\x89]\xc8\x06P\xa1d\xb5/aY\xe4\x94\xc5\xf3\xa9\xd5(\xe2\xc4s\x8e;\x1c0u\xde\x946|\xf8\xcfm\xe3\xb1\xf7w\x14\x8d\x8d88\xc4\xf8\x96u\xb8\x91!\xfc\xb3\x99\xf1\xf9\xd8\xf5\x15_L\xf8\xa6\x15\xdbI''\xe2\xf7\x94z\x19\n-\xf5qkK\x01s\xad[\x8c\x08\x06\x83\x94\xd1?u\xd8\x96\xc0J\x80n\xab\xf0\xa1\xf5\x96\xa7/\x08{\xed#\x00X\xc90\xaa\xc8\xd3UE\x10i\xd940\xeb\x81\xf0\xa6 \x97\x15L\xcf\xc2\xac\xcb\x92\xeb\x8d]Eh\xc0\xe8\xa7\xe6\xe7\xd4\xd8b\x1b8\xd3\x00L[\xb8.\x97\x9b\xcd\xc9JJ=|\xe6\x97\xfe\xe72?\xd4\xf2\xb7\xb3OK\xe4\x04\xa0/\x0b;\xf3<\xff5\x91\xc29\x1a\x84\xa5\x11\xcd\xa2\xfa\xedm\x8f\xa4\xb5@\xad}r\xb1a\x11\x12M\xc2\xf8h3\xa1\x17\x86:\xe7\xfa\x9d\\^\t\x1b\xa0`^\xdc(\x889\xfa\xbaM\x1b\x98\xaaA#\x95\x15\x1d0\xc3\x8b\xb7\x80c\x07\xd1\xd4\xfa\xb9\xa1" + +Tx3 is signed by mara. +b"hUJ\xe4*\x9b\xe0\x14\x0f7Z\xb8@\xb5\x01\xafB\xa9\xdd\xb3\x1cy/\xae\x11\xc7+/8\xe4j.\xde\xeb\xe73h\xf6\x89r\x0eF\x87\x10\x11*\x99>>\xd1\x8a\xaa\x16Q\\\xc3\x0c\x19\xa0\x8b\xab:\x14\xc6\x92g\x88\xcc\x99\x9a\xb2\xbe\xb9\x03@\xaeW\x1d\xf0M*2o\xdf:\xe0_\xf0\xfe\xe0~}\xbe]\xfe\x01\xa7\xe5\x871b\x8c\xe5\xcag\xd2\x8a\x94\xd7&\xd4\xab\xefS\x07I[a\x84\x8e0'\x01\xa7\xb9M<\x16\x01AJ\x07\x9e\xe1n\x90zV\xc8\xa0\x91\xa7X8I\xf5tb\xa4\t\xf9\xa4\x0e~\x06\x7fu\xc6\xea5\xa6Y\xb4\xe9\xc0K\xc3\x8b\xc7j\xf2\x12\x9f%\x15w\xcbvyLc\xf5S+Fc(\xe4\x93.\x06G\xe60\xbf^SU\x9b\x85\x93\x0ez\xf9b\xbcE\x0f\x13$\xab\xfd\xd7\xe8=\xef0\x84\x17G\x86s\xa8\xcb-4\xf6r\x0e\xab>\x1dW