From c43218e0e37077b99b9cc1576f3334bf90d70d97 Mon Sep 17 00:00:00 2001 From: Spekulaas <“ryan@aterve.nl”> Date: Wed, 27 Sep 2023 10:16:13 +0200 Subject: [PATCH] finished lesson 5 --- .../Signature.py | 35 ++++++ .../Transaction.py | 92 ++++++++++++++++ .../Transactions_t.py | 103 ++++++++++++++++++ .../output.txt | 9 ++ 4 files changed, 239 insertions(+) create mode 100644 period_1/05-transaction/505_HW4_A05_Transaction_Validation/Signature.py create mode 100644 period_1/05-transaction/505_HW4_A05_Transaction_Validation/Transaction.py create mode 100644 period_1/05-transaction/505_HW4_A05_Transaction_Validation/Transactions_t.py create mode 100644 period_1/05-transaction/505_HW4_A05_Transaction_Validation/output.txt diff --git a/period_1/05-transaction/505_HW4_A05_Transaction_Validation/Signature.py b/period_1/05-transaction/505_HW4_A05_Transaction_Validation/Signature.py new file mode 100644 index 0000000..eaeaaf4 --- /dev/null +++ b/period_1/05-transaction/505_HW4_A05_Transaction_Validation/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/505_HW4_A05_Transaction_Validation/Transaction.py b/period_1/05-transaction/505_HW4_A05_Transaction_Validation/Transaction.py new file mode 100644 index 0000000..0bc4ac8 --- /dev/null +++ b/period_1/05-transaction/505_HW4_A05_Transaction_Validation/Transaction.py @@ -0,0 +1,92 @@ +#!/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(), and sign() are already completed in the previous tutorials and exercise. +In this hoemwork, we will add another method is_valid() to the class. With this method, we can +validate 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: + inputs = None + outputs =None + sigs = None + reqd = None + + def __init__(self): + self.inputs = [] + self.outputs = [] + self.sigs = [] + self.reqd = [] # A placeholder for any other extra required signature (e.g. escrow) + + 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 + # We would like to have another method to add extra required signature if needded (e.g. escrow) + # with this method, we can specify other required signature to the transaction by adding the + # public key of the required signature + # If this signature is needed, later we can check if the transaction is also signed by that person/party. + def add_reqd(self, addr): + self.reqd.append(addr) + + + # TODO 3: Complete the method + # This method is also already done in the previous tutorials. + # you can copy and paste the previous codes here + def sign(self, private): + tx_data = self.__gather() + new_sig = sign(tx_data, private) + self.sigs.append(new_sig) + + def __gather(self): + data = [] + data.append(self.inputs) + data.append(self.outputs) + data.append(self.reqd) + return data + + def is_valid(self): + total_in = 0 + total_out = 0 + for (addr, amount) in self.inputs: + found = False + for s in self.sigs: + if verify(self.__gather(), s, addr): + found = True + if not found: + return False + if amount < 0: + return False + total_in = total_in + amount + for (addr, amount) in self.outputs: + if amount < 0: + return False + total_out = total_out + amount + + for sender in self.reqd: + found = False + for s in self.sigs: + if verify(self.__gather(), s, sender): + found = True + if not found: + return False + if total_out > total_in: + return False + return True diff --git a/period_1/05-transaction/505_HW4_A05_Transaction_Validation/Transactions_t.py b/period_1/05-transaction/505_HW4_A05_Transaction_Validation/Transactions_t.py new file mode 100644 index 0000000..faa221c --- /dev/null +++ b/period_1/05-transaction/505_HW4_A05_Transaction_Validation/Transactions_t.py @@ -0,0 +1,103 @@ +""" +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 * + +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() + + # Check Valid Transactions + # Test 1 + # -------------------------------------- + Tx1 = Tx() + Tx1.add_input(alex_pbc, 1) + Tx1.add_output(mike_pbc, 1) + Tx1.sign(alex_prv) + + # Test 2 + # -------------------------------------- + Tx21 = Tx() + Tx21.add_input(alex_pbc, 2) + Tx21.add_output(mike_pbc, 1) + Tx21.add_output(rose_pbc, 1) + Tx21.sign(alex_prv) + + Tx22 = Tx() + Tx22.add_input(rose_pbc, 1.2) + Tx22.add_output(alex_pbc, 1.1) + Tx22.add_reqd(mara_pbc) + Tx22.sign(rose_prv) + Tx22.sign(mara_prv) + + for transaction in [Tx1, Tx21, Tx22]: + if transaction.is_valid(): + print("SUCCESS! Valid transaction is verified.") + else: + print("ERROR! Valid transaction is not verified.") + + # Check Invalid Transactions + # Test 3 + # -------------------------------------- + # Wrong signatures + Tx3 = Tx() + Tx3.add_input(alex_pbc, 1) + Tx3.add_output(mike_pbc, 1) + Tx3.sign(mike_prv) + + # Test 4 + # -------------------------------------- + # Escrow Tx not signed by the arbiter + Tx4 = Tx() + Tx4.add_input(rose_pbc, 1.2) + Tx4.add_output(mike_pbc, 1.1) + Tx4.add_reqd(mara_pbc) + Tx4.sign(rose_prv) + + # Test 5 + # -------------------------------------- + # Two input addrs, signed by one + Tx5 = Tx() + Tx5.add_input(rose_pbc, 1) + Tx5.add_input(mara_pbc, 0.1) + Tx5.add_output(mike_pbc, 1.1) + Tx5.sign(mara_prv) + + # Test 6 + # -------------------------------------- + # Outputs exceed inputs + Tx6 = Tx() + Tx6.add_input(mara_pbc, 1.2) + Tx6.add_output(alex_pbc, 1) + Tx6.add_output(alex_pbc, 2) + Tx6.sign(mara_prv) + + # Test 7 + # -------------------------------------- + # Negative values + Tx7 = Tx() + Tx7.add_input(mike_pbc, -1) + Tx7.add_output(alex_pbc, -1) + Tx7.sign(mike_prv) + + # Test 8 + # -------------------------------------- + # Modified Tx + Tx8 = Tx() + Tx8.add_input(mike_pbc, 1) + Tx8.add_output(alex_pbc, 1) + Tx8.sign(mike_prv) + + # outputs = [(alex_pbc,1)] change to [(rose_pbc,1)] + Tx8.outputs[0] = (rose_pbc, 1) + + for transaction in [Tx3, Tx4, Tx5, Tx6, Tx7, Tx8]: + if transaction.is_valid(): + print("ERROR! Invalid transaction is verified.") + else: + print("SUCCESS! Invalid transaction is not verified.") \ No newline at end of file diff --git a/period_1/05-transaction/505_HW4_A05_Transaction_Validation/output.txt b/period_1/05-transaction/505_HW4_A05_Transaction_Validation/output.txt new file mode 100644 index 0000000..2f17e97 --- /dev/null +++ b/period_1/05-transaction/505_HW4_A05_Transaction_Validation/output.txt @@ -0,0 +1,9 @@ +SUCCESS! Valid transaction is verified. +SUCCESS! Valid transaction is verified. +SUCCESS! Valid transaction is verified. +SUCCESS! Invalid transaction is not verified. +SUCCESS! Invalid transaction is not verified. +SUCCESS! Invalid transaction is not verified. +SUCCESS! Invalid transaction is not verified. +SUCCESS! Invalid transaction is not verified. +SUCCESS! Invalid transaction is not verified. \ No newline at end of file