From 8e7e6e4f47d34dbfaec65ca6319f60de25ca6cb7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Prajczer=20P=C3=A9ter?= <prajczer.peter@hallgato.ppke.hu>
Date: Thu, 26 Mar 2020 08:09:05 +0100
Subject: [PATCH] added basefile for lecture

---
 ITKoin_02_Prajczer_Peter.py | 251 ++++++++++++++++++++++++++++++++++++
 1 file changed, 251 insertions(+)
 create mode 100644 ITKoin_02_Prajczer_Peter.py

diff --git a/ITKoin_02_Prajczer_Peter.py b/ITKoin_02_Prajczer_Peter.py
new file mode 100644
index 0000000..3139809
--- /dev/null
+++ b/ITKoin_02_Prajczer_Peter.py
@@ -0,0 +1,251 @@
+from Crypto.PublicKey import RSA
+from Crypto.Signature import pkcs1_15
+from Crypto.Hash import SHA256
+import json
+from base64 import b64encode, b64decode
+from pprint import pprint
+import pickle
+
+
+
+class ITKoin:
+    def __init__ (self):
+        self.chain_filename = 'chain_01.txt'
+        self.pending_transactions_filename = 'pending_01.txt'
+        self.unspent_outputs_filename = 'unspent_01.txt'
+        self.my_privatekey_filename = 'csmkey_03_priv.pem'
+        self.chain = []
+        self.pending_transactions = []
+        self.unspent_outputs = []
+        self.my_unspent_outputs = []
+#        self.my_privatekey
+#        self.my_publickey
+#        self.my_id
+        self.ITKoin_users = ['csmkey_03_id.txt', 'csmkey_04_id.txt'] # Ez egy lista, ahová s résztvevők id-jait tartalmazó file-neveket kell felsorolni
+        self.initial_csaposhi_offering = 100
+
+
+    def generate_rsa_key(self, filename): # a filenév tövével kell meghívni és három file-t generál: a privát és publikus kulcsoknak, ill. az ID-nak
+        key = RSA.generate(2048)
+        publickey = key.publickey()
+        privatekey_filename = filename + '_priv.pem'
+        f = open(privatekey_filename, 'wb')
+        f.write(key.export_key())
+        f.close()
+        publickey_filename = filename + '_pub.pem'
+        f = open(publickey_filename, 'wb')
+        f.write(publickey.export_key())
+        f.close()
+        publickey_string = publickey.export_key().decode('ascii') # bináris stringet karakter stringgé konvertáljuk, hogy a json.dumps működjön rajta
+        recipient_id_filename = filename + '_id.txt'
+        f = open(recipient_id_filename, 'wb')
+        f.write(self.create_hashhexvalue(publickey_string).encode('ascii')) # a hexa string hash értéket bináris stringgé konvertáljuk a file-ba íráshoz
+        f.close()
+        return
+
+    def load_my_private_key (self):
+        fileobject = open(self.my_privatekey_filename, 'r')
+        self.my_privatekey = RSA.import_key(fileobject.read())
+        self.my_publickey = self.my_privatekey.publickey()
+        publickey_string = self.my_publickey.export_key().decode('ascii') # bináris stringet karakter stringgé konvertáljuk, hogy a json.dumps működjön rajta
+        self.my_id = self.create_hashhexvalue(publickey_string) # a hexa string hash értéket bináris stringgé konvertáljuk a file-ba íráshoz
+        pprint(self.my_id)
+        return
+
+    @staticmethod
+    def load_public_key (filename):
+        fileobject = open(filename, 'r')
+        key = RSA.import_key(fileobject.read())
+        return key.publickey()
+
+    @staticmethod
+    def load_id (filename):
+        fileobject = open(filename, 'r')
+        id = fileobject.read()
+        return id
+
+    @staticmethod
+    def create_hashobject (data):
+        stringdump = json.dumps(data)
+        hashobject = SHA256.new(stringdump.encode())
+        return hashobject
+
+    @staticmethod
+    def create_hashhexvalue (data):
+        stringdump = json.dumps(data)
+        hashobject = SHA256.new(stringdump.encode())
+        return hashobject.hexdigest()
+
+    @staticmethod
+    def create_hashvalue (data):
+        stringdump = json.dumps(data)
+        hashobject = SHA256.new(stringdump.encode())
+        return hashobject.digest()
+
+    def create_signature (self, data):
+        signatureobject = pkcs1_15.new(self.my_privatekey) # hozz létre egy signature objektumot
+        hashobject = self.create_hashobject(data) # az adatot töltsd be egy hash objektumba a create_hashobject(data) használatával
+        signaturevalue = signatureobject.sign(hashobject) # készítsd el az aláírás értéket a sign függvénnyel
+        print(signaturevalue)
+        b64signaturevalue = b64encode(signaturevalue) # kódold base64 kódolással
+        print(b64signaturevalue)
+        print(b64signaturevalue.decode())
+        return b64signaturevalue.decode()
+
+    def verify_signature(self, data, b64signaturevalue, rsapublickey):
+        verifyobject = pkcs1_15.new(rsapublickey) # hozz létre egy verify objektumot
+        hashobject = self.create_hashobject(data) # az adatot töltsd be egy hash objektumba a create_hashobject(data) használatával
+        signaturevalue = b64decode(b64signaturevalue.encode()) # dekódold base64 kódolással az aláírás értéket
+        signatureerror = verifyobject.verify(hashobject, signaturevalue) # ellenőrizd az aláírást
+        validsignature = not signatureerror # értéke: True, ha az aláírás érvényes
+        return validsignature
+
+    @staticmethod
+    def save_list(list, filename):
+        f = open(filename, 'wb')
+        pickle.dump(list, f)
+        f.close()
+        return
+
+    def load_chain(self):
+        fileobject = open(self.chain_filename, 'rb')
+        self.chain = pickle.load(fileobject)
+        pprint(self.chain)
+        return
+
+    def load_pending_transactions(self):
+        fileobject = open(self.pending_transactions_filename, 'rb')
+        self.pending_transactions = pickle.load(fileobject)
+        pprint(self.pending_transactions)
+        validated_pending_transactions = []
+        while len(self.pending_transactions) != 0:
+            transaction = self.pending_transactions.pop()
+            if True: # itt validálni kellene az adott tranzakciót, a nem érvényeseket eldobja, de nem áll le
+                validated_pending_transactions.append(transaction)
+        self.pending_transactions = validated_pending_transactions
+        return
+
+    def find_unspent_outputs(self):
+        self.unspent_outputs = []
+        self.my_unspent_outputs = []
+        for transaction in self.chain[0]['transactions']:
+            self.unspent_outputs.append([transaction['txid'], 0, self.initial_csaposhi_offering])
+            for output in transaction['outputs']:
+                if output['recipient']==self.my_id:
+                    self.my_unspent_outputs.append([transaction['txid'], 0, output['csaposhi']])
+        for block in self.chain[1:]:
+            for transaction in block['transactions']:
+                for output in transaction['outputs']:
+                    self.unspent_outputs.append([transaction['txid'], transaction['outputs'].index(output), output['csaposhi']])
+                    if output['recipient'] == self.my_id:
+                        self.my_unspent_outputs.append([transaction['txid'], transaction['outputs'].index(output), output['csaposhi']])
+                for input in transaction['inputs']:
+                    self.unspent_outputs.remove(input) # minden input biztosan szerepelt a lánc korábbi outputjaként
+                    if input in self.my_unspent_outputs: # a remove() hibát dob, ha úgy törlünk a listából valamit, hogy nem is volt benne
+                        self.my_unspent_outputs.remove(input)
+        pprint(self.unspent_outputs)
+        pprint(self.my_unspent_outputs)
+        return
+
+    def mine(self):
+        if len(self.chain) == 0:
+            previous_block_header_hash = 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
+        else:
+            previous_block = self.chain[-1]
+            previous_block_header = previous_block['block_header']
+            previous_block_header_hash = self.create_hashhexvalue(previous_block_header)
+
+        nonce = 0
+
+        block_header = {
+            'nonce': nonce,
+            'previous_block_header_hash': previous_block_header_hash,
+            'transactions_hash' : self.create_hashhexvalue(self.pending_transactions),
+        }
+        while True:
+            block_header_hash = self.create_hashhexvalue(block_header)
+            if block_header_hash[:4] == "0000":
+                break
+            block_header['nonce'] += 1
+
+        block = {
+            'block_header': block_header,
+            'transactions': self.pending_transactions
+        }
+        pprint(block)
+
+        self.chain.append(block)
+        pprint (self.chain)
+        self.save_list(self.chain, self.chain_filename)
+        self.pending_transactions = []
+        self.save_list(self.pending_transactions, self.pending_transactions_filename)
+        return
+
+    def generate_first_block(self):
+        self.pending_transactions = []
+        while len(self.ITKoin_users) > 0:
+            recipient_id = self.load_id (self.ITKoin_users.pop()) # előveszi a következő id file nevét és beolvassa az id-t
+            for tr in self.pending_transactions: # nem szerepelhet kétszer ugyanaz a recipient, mert akkor a txid azonos lesz
+                for op in tr['outputs']:
+                    if recipient_id == op['recipient']:
+                        pprint ('HIBA: Ismétlődő recipient adatok az első blokk generálásakor.')
+                        return False
+            outputs = [{
+                'csaposhi': self.initial_csaposhi_offering,
+                'recipient': recipient_id}]
+            transaction = {
+                'inputs': [],
+                'outputs': outputs}
+            transaction ['txid'] = self.create_hashhexvalue(transaction) # a tranzakció lenyomata lesz az azonosítója egyben
+            self.pending_transactions.append(transaction)
+        pprint(self.pending_transactions)
+        self.mine()
+        return
+
+    def new_transaction(self, csaposhi, recipient): # a megadott összeg átadása recipientnek, a maradék visszautalása
+        sum = 0
+        used_outputs=[]
+        while (sum < csaposhi):
+            next_output=self.my_unspent_outputs.pop()
+            pprint(next_output)
+            used_outputs.append(next_output)
+            pprint(next_output)
+            sum += next_output[2] # ebben a listapozícióban van a hivatkozott outputban kapott összeg
+            pprint(sum)
+        inputs = used_outputs
+        pprint(inputs)
+        for input in inputs: # az inputsban szándékosan nincs benne az akkori recipient, mert ezt abból a tranzakcióból kell kivenni és ellenőrizni
+            input.append(self.create_signature(input[0])) # input[3] az aláírás érték base64 kódolással
+            input.append(self.my_publickey.export_key().decode('ascii')) # input[4] a publikus kulcsom PEM formátumban
+            pprint(self.verify_signature(input[0], input[3], RSA.import_key(input[4])))
+        outputs = [{
+            'csaposhi': csaposhi,
+            'recipient': recipient}]
+        if sum > csaposhi: # ha van visszajáró, azt visszautaljuk magunknak
+            outputs.append({
+                'csaposhi': sum-csaposhi,
+                'recipient': self.my_id})
+        transaction = {
+            'inputs': inputs,
+            'outputs': outputs}
+        transaction ['txid'] = self.create_hashhexvalue(transaction) # a tranzakció lenyomata lesz az azonosítója egyben
+        self.pending_transactions.append(transaction)
+        pprint(self.pending_transactions)
+        return
+
+
+
+mycoin=ITKoin()
+# mycoin.generate_rsa_key('csmkey_04')
+mycoin.generate_first_block()
+mycoin.load_my_private_key()
+mycoin.load_chain()
+mycoin.find_unspent_outputs()
+mycoin.new_transaction(20, 'c5425eda6099b4f481357fb12d17cda62e6f391ac49c83e9d465128dc47109b0')
+#signature = mycoin.create_signature(2)
+#pprint(signature)
+#pprint(mycoin.my_publickey)
+#print(mycoin.verify_signature(2, signature, mycoin.my_publickey))
+
+mycoin.mine()
+
-- 
GitLab