Blockchain Principles and Applications Lab Instructions Wenbing Zhao

Blockchain Principles and Applications: Lab Instructions Wenbing Zhao Department of Electrical Engineering and Computer Science Cleveland State University 12/28/2021 Python, IOTA, and Kivy 1

Setting Up the Programming Environment n n We will be using the python programming language and the IOTA distributed ledger in the lab exercises To make the lab more interesting, we will be using python -based graphical UI framework called Kivy Because this library has a lot of dependency, it is best to run our labs within a python virtual environment All our labs will be done with specific directory that runs the virtual environment 12/28/2021 Python, IOTA, and Kivy 2

Setting Up the Programming Environment python -m venv blockchain n To set up the environment, run: If you are running on a Mac, please use python 3 instead of python n n Then, cd to the directory blockchain, execute a script as follows if on source bin/activate Mac/Linux: If on Windows: Scriptsactivate. bat Next, we will be installing the kivy library. Run the following within our directory (blockchain): python -m pip install kivy In Lab#6, we will be using simple-crypt module If you are using python 3. 9 and have previously installed Py. Crypto, lab#6 won’t work, please uninstall Py. Crypto and install an improved module: python -m pip uninstall Py. Crypto q Then (even if you have not ever installed pycrypto), install pycryptodome: python –m pip install -U Py. Cryptodome q Finally, install simple-crypt q python -m pip install simple-crypt --no-dependencies is necessary on Windows to avoid errors If you are running on a Mac, run: python -m pip install simple-crypt 12/28/2021 Python, IOTA, and Kivy 3

Setting Up the Programming Environment IOTA python client (pyota) Installation and API information: n n https: //pyota. readthedocs. io/en/latest/ We want to install both the basic pyota client and the local extension, particularly the local proof of work module pip install pyota[ccurl] pip install pyota[pow] 12/28/2021 Python, IOTA, and Kivy 4

Working With Kivy n n n Doing all the blockchain labs in a terminal is boring. That is why we will be using Kivy But we don’t need to learn too much about Kivy, just enough to make things a little interesting In Kivy, a widget is an onscreen control that the user will interact with All graphical user interface toolkits come with a set of widgets Some common widgets include buttons, combo boxes, and tabs Kivy has many widgets built into its framework 12/28/2021 Python, IOTA, and Kivy 5

Kivy App Basic Structure n n n Every Kivy application needs to subclass App and override build() This is where you’ll put your UI code or make calls to other functions that define your UI code In the Hello World app, you create a Label widget and pass in its text, size_hint, and pos_hint. These last two arguments are not required. 12/28/2021 Python, IOTA, and Kivy 6

Kivy App Basic Structure n size_hint tells Kivy the proportions to use when creating the widget. It takes two numbers: q q n n n The first number is the x size hint and refers to the width of the control. The second number is the y size hint and refers to the height of the control. Both of these numbers can be anywhere between 0 and 1. The default value for both hints is 1 You can also use pos_hint to position the widget In the code block above, you tell Kivy to center the widget on the x and y axes 12/28/2021 Python, IOTA, and Kivy 7

Kivy Layout n n Each GUI framework that you use has its own method of arranging widgets With Kivy, you’ll use Layouts. There are several different types of Layouts that you can use. Here are some of the most common ones: q q q n n Box. Layout Float. Layout Grid. Layout You can search Kivy’s documentation (https: //kivy. org/doc/stable/apikivy. uix. layout. html) for a full list of available Layouts You can also look in kivy. uix for the actual source code 12/28/2021 Python, IOTA, and Kivy 8

Kivy Box. Layout n n n import Box. Layout from kivy. uix. boxlayout and instantiate it Then create a list of colors, which are themselves lists of Red-Blue-Green (RGB) colors Finally, loop over a range of 5, creating a button btn for each iteration To make things a bit more fun, set the background_color of the button to a random color Then add the button to your layout with layout. add_widget(btn) 12/28/2021 Python, IOTA, and Kivy 9

Kivy Box. Layout n n When you create a layout, there a few arguments you should know padding: You can specify the padding in pixels between the layout and its children in one of three ways: q q q n n A four-argument list: [padding_left, padding_top, padding_right, padding_bottom] A two-argument list: [padding_horizontal, padding_vertical] A singular argument: padding=10 spacing: You can add space between the children widgets with this argument orientation: You can change the default orientation of the Box. Layout from horizontal to vertical 12/28/2021 Python, IOTA, and Kivy 10

Kivy: Add Events n n Kivy is mostly event-based. The framework responds to user keypresses, mouse events, and touch events Kivy has the concept of a Clock that you can use to schedule function calls for some time in the future We will add a button event to the previous code You call button. bind() and link the on_press event to Main. App. on_press_button() q q This method implicitly takes in the widget instance, which is the button object itself A message will print to stdout whenever the user presses your button 12/28/2021 Python, IOTA, and Kivy 11

IOTA: Basic Concepts n n n Ternary IOTA token Seed Address Transaction Bundle 12/28/2021 Python, IOTA, and Kivy 12

IOTA: Ternary n n n IOTA uses the ternary numerical system to represent data The smallest unit of information is a trit, that can have a value of -1, 0 or 1 A combination of 3 trits equals one tryte, therefore a tryte can have 3 * 3 = 27 different values To represent a tryte, IOTA encodes these 27 values into characters based on the tryte alphabet In Py. OTA, trits are represented as a sequence of numerical values (List[int]) while trytes have their own class called Tryte. String. 12/28/2021 Python, IOTA, and Kivy 13

IOTA: Token n n The IOTA token is a unit of value that can be transferred over an IOTA network through transfer bundles The IOTA token was launched on the Mainnet in June 2017 At this point, the nodes in the network were hard-coded with a total supply of 2, 779, 530, 283 277, 761 This large supply allows each of the billions of devices, which are expected to be a part of the Internet of Things, to have its own wallet and transact micropayments with other devices 12/28/2021 Python, IOTA, and Kivy 14

IOTA: Seed n n n Seed in IOTA is your unique password It is the digital key that unlocks your safe that holds your tokens, or proves the ownership of messages Seeds in Py. OTA are always 81 trytes long and may only contain characters from the tryte alphabet Never share your seed with anyone, and never use online generators to create a seed The library can help you to create your own locally and it does not require internet connection: iota. crypto. Seed. random(). 12/28/2021 Python, IOTA, and Kivy 15

IOTA: Address n n To send or receive any transaction (let them be zero-value or value transacitons) in IOTA, you will need to specify an address An address is like a physical mailbox on your entrance door: anyone can drop things in your mailbox (send you messages or tokens), but only you can empty it (withdraw tokens) Addresses should not be re-used once they are spent from. You can receive as many transactions to an address as you wish, but only spend from that address once Addresses are generated from your seed through cryptographic functions q q q There are 957 different addresses that one might generate from a seed, which is quite a lot Given your seed, the index and security level parameters specify which address will be generated from it. The process is deterministic, meaning that same input paramteres always generate the same address Addresses are 81 trytes long and may contain extra 9 trytes for checksum. The checksum may be used to verify that an address is in fact a valid IOTA address 12/28/2021 Python, IOTA, and Kivy 16

IOTA: Transaction n A transaction is a single transfer instruction that can either withdraw IOTA tokens from an address, deposit them into an address, or have zero-value (contain data, a message, or a signature) If you want to send anything to an IOTA network, you must send it to a node as a transaction Transactions are always 2673 trytes long and their structure is defined by the protocol. They can be classified into three categories: q q q n n Input transaction: A transaction that withdraws tokens from an address Output transaction: A transaction that deposits tokens to an address Zero-value transaction: A transaction that has 0 value and might carry messages or signatures Depending on the type of the transaction, different fields are required to be filled A transaction’s unique identifier in IOTA is the Transaction. Hash, that is generated from the trytes of the transaction. q If any trytes change in the transaction, the returning transaction hash would alter 12/28/2021 Python, IOTA, and Kivy 17

IOTA: Transaction n To become accepted by the network, a transaction has to be attached to the Tangle The attachment process means that the transaction should reference two unconfirmed transactions (tips) in the Tangle and do a small proof-of-work This process might be performed by a node, or by using the local proof-of-work feature of the client libraries 12/28/2021 Python, IOTA, and Kivy 18

IOTA: Transaction n A bundle is a group of transactions that rely on each other’s validity q n For example, a transaction that deposits IOTA tokens into an address relies on another transaction to withdraw those IOTA tokens from another address. Therefore, those transactions must be in the same bundle. In other words, a bundle is collection of transactions, treated as an atomic unit when attached to the Tangle q q Unlike a block in a blockchain, bundles are not first-class citizens in IOTA; only transactions get stored in the Tangle Instead, bundles must be inferred by following linked transactions with the same bundle hash 12/28/2021 Python, IOTA, and Kivy 19

IOTA: Transaction n n Transactions in the bundle are linked together through their trunk. Transaction fields, furthermore they are indexed within the bundle and contain a bundle. Hash field that is a unique identifier for the bundle Bundles can be classified into two categories: q q Transfer bundles: Bundles that contain input and output transactions. A bundle always has to be balanced, meaning that input transaction values should equal to output transaction values Zero-value bundles: Bundles that contain only zero-value transactions 12/28/2021 Python, IOTA, and Kivy 20

IOTA Lab#1: Hello Node n In this lab, you will learn how to: q q q Import the iota package into your application Instantiate an API object for communication with the IOTA network Request information about the IOTA node you are connected to # Import neccessary modules from iota import Iota from pprint import pprint n n n First things first, we need to import in our application the modules we intend to use Py. OTA provide the iota package, therefore, whenever you need something from the library, you need to import it from there Notice, how we import the Iota object, that defines a so-called extended API object. We will use this to send and receive data from the network We also import the pprint method that prettifies the output before printing it to the console 12/28/2021 Python, IOTA, and Kivy 21

IOTA Lab#1: Hello Node # Declare an API object api = Iota('https: //nodes. devnet. iota. org: 443') n n Next, we declare an API object Since this object handles the communication, we need to specify an IOTA node to connect to in the form of an URI q Note, that the library will parse this string and will throw an exception if it is not a valid one # Request information about the node response = api. get_node_info() n Then we can call the Iota. get_node_info() method of the API object to get some basic info about the node 12/28/2021 Python, IOTA, and Kivy 22

IOTA Lab#1: Hello Node # Using pprint instead of print for a nicer looking result in the console pprint(response) n n Finally, we print out the response All API methods return a python dictionary Refer to the method’s documentation to determine what exactly is in the response dictionary Here for example, we could list the features of the node: pprint(response['features']) 12/28/2021 Python, IOTA, and Kivy 23

IOTA Lab#1: Hello Node n n n Running the code is fine, but it is a little boring Let’s try to integrate Pyota and Kivy to operate in a Graphical User Interface instead We will be adding a button. When the button is clicked, we will connect an IOTA node and get the node info We then will show the info in a text box We will be using the Box. Layout. Below is the behavior of the app: 12/28/2021 Python, IOTA, and Kivy 24

IOTA Lab#1: Hello Node import kivy import random from iota import Iota from kivy. app import App from kivy. uix. button import Button from kivy. uix. label import Label from kivy. uix. boxlayout import Box. Layout from kivy. uix. textinput import Text. Input red = [1, 0, 0, 1] green = [0, 1, 0, 1] blue = [0, 0, 1, 1] purple = [1, 0, 1, 1] class IOTALab 1(App): def build(self): layout = Box. Layout(padding=10, orientation="vertical") colors = [red, green, blue, purple] btn = Button(text="Connect to IOTA and Get Node Info", background_color=random. choice(colors), height=20) btn. bind(on_press=self. connect_to_iota) layout. add_widget(btn) self. label = Text. Input(text="Response will be displayed here", size_hint=(1. 0, . 5), pos_hint={'center_x': . 5, 'center_y': . 5}) layout. add_widget(self. label) return layout def connect_to_iota(self, instance): # Declare an API object api = Iota('https: //nodes. devnet. iota. org: 443') # Request information about the node response = api. get_node_info() self. label. text = str(response) def on_pressbtn(self, instance): print("you pressed button: ", instance. text) if __name__ == "__main__": app = IOTALab 1() app. run() 12/28/2021 Python, IOTA, and Kivy 25

IOTA Lab#1: Homework n Study the API documentation on the response for the node info, and create multiple for 3 major types of info using labels 12/28/2021 Python, IOTA, and Kivy 26

IOTA Lab#2: Send Data n In this lab, you will learn how to: q q Encode data to be stored on the Tangle Generate a random IOTA address that doesn’t belong to anyone Create a zero-value transaction with custom payload Send a transaction to the network. 12/28/2021 Python, IOTA, and Kivy 27

IOTA Lab#2: Send Data from iota import Iota, Tryte. String, Address, Tag, Proposed. Transaction from pprint import pprint # Declare an API object api = Iota('https: //nodes. devnet. iota. org: 443') n We have seen similar import before. This time, we also import Tryte. String, Address, Tag, Proposed. Transaction # Prepare custom data my_data = Tryte. String. from_unicode('Hello from the Tangle!') n Here, we encode our message with Tryte. String. from_unicode() into trytes 12/28/2021 Python, IOTA, and Kivy 28

IOTA Lab#2: Send Data # Generate a random address that doesn't have to belong to anyone my_address = Address. random(90) print("my address: ", str(my_address)) n n n To put anything (transactions) on the Tangle, it needs to be associated with an address We can use the Tryte. String. random() (an Address is just a Tryte. String with some additional attributes and fixed length) method to generate one The method takes a length parameter. Because IOTA Address can be either 81 or 90 trytes, that is the length you should put it q q q An error will be returned if you input more than 90 as the length But no error is thrown if you use a number lower than 90, even 0! But any length less than 81 will lead to a tryte being set to 9 12/28/2021 Python, IOTA, and Kivy 29

IOTA Lab#2: Send Data # Tag is optional here my_tag = Tag(b'MY 9 FIRST 9 TAG') n n n To tag our transaction, we might define a custom Tag object Note that the b means we are passing a bytestring value instead of a unicode string. This is so that Py. OTA interprets our input as literal trytes, rather than a unicode string that needs to be encoded into trytes When passing a bytestring to a Py. OTA class, each byte is interpreted as a tryte; therefore we are restricted to the tryte alphabet (26 English alphabet and number 9) 12/28/2021 Python, IOTA, and Kivy 30

IOTA Lab#2: Send Data # Prepare a transaction object tx = Proposed. Transaction( address=my_address, value=0, tag=my_tag, message=my_data ) n n n It’s time to construct the transaction According to Transaction Types, Py. OTA uses Proposed. Transaction to build transactions that are not yet broadcast to the network value=0 means this is a zero-value transaction 12/28/2021 Python, IOTA, and Kivy 31

IOTA Lab#2: Send Data # Send the transaction to the network response = api. send_transfer([tx], min_weight_magnitude=9) n Next, we send the transfer to the node for tip selection, proof-of-work calculation, broadcasting and storing q n n The API takes care of all these tasks, and returns the resulting Bundle object send_transfer() takes a list of Proposed. Transaction objects as its transfers argument q q n Make sure that the pow module is installed with pyota, otherwise, the node will reject the transaction For none-zero value transfer: consists of multiple transactions linked together in a bundle For 0 -value transfer, only a single transaction Due the new development on the IOTA node, you now must specify the min_weight_magnitude, which must be 9 12/28/2021 Python, IOTA, and Kivy 32

IOTA Lab#2: Send Data pprint('Check your transaction on the Tangle!') pprint('https: //utils. iota. org/transaction/%s/devnet' % response['bundle'][0]. hash) n n n Finally, we print out the transaction’s link on the Tangle Explorer Observe how we extract the transaction hash from the response dict We take the first element of the bundle, as it is just a sequence of transactions, and access its hash attribute 12/28/2021 Python, IOTA, and Kivy 33

IOTA Lab#2: Integrate with Kivy n n With Kivy providing GUI, we can ask the user to input a message as the data in a transaction to send to IOTA, and ask the user to customize the tag to be included in the transaction We also display the automatically generated Address, and the response we received from the IOTA 12/28/2021 Python, IOTA, and Kivy 34

IOTA Lab#2: Integrate with Kivy from six import add_metaclass import random from iota import Iota, Tryte. String, Address, Tag, Proposed. Transaction from kivy. app import App from kivy. uix. button import Button from kivy. uix. label import Label from kivy. uix. boxlayout import Box. Layout from kivy. uix. textinput import Text. Input red = [1, 0, 0, 1] green = [0, 1, 0, 1] blue = [0, 0, 1, 1] purple = [1, 0, 1, 1] class IOTALab 2(App): def build(self): # declare several memeber variables for transaction self. my_data = "Type message to be included in Transaction" self. my_address = "The generated Address will be displayed here" self. my_tag = "MY 9 FIRST 9 TAG" self. response = "Response will be displayed here" layout = Box. Layout(padding=10, orientation="vertical") colors = [red, green, blue, purple] txtbox = Text. Input(text=self. my_data, size_hint=(1. 0, . 1), pos_hint={'center_x': . 5, 'center_y': . 5}) layout. add_widget(txtbox) txtbox. bind(text=self. on_inputtext) btn = Button(text="Generate My Address", background_color=random. choice(colors), height=20) btn. bind(on_press=self. generate_my_adddress) layout. add_widget(btn) self. addresstxt = Label(text=self. my_address, size_hint=(1. 0, . 1), pos_hint={'center_x': . 5, 'center_y': . 5}) layout. add_widget(self. addresstxt) 12/28/2021 Python, IOTA, and Kivy 35

IOTA Lab#2: Integrate with Kivy tagtxt = Text. Input(text=self. my_tag, size_hint=(1. 0, . 1), pos_hint={'center_x': . 5, 'center_y': . 5}) layout. add_widget(tagtxt) tagtxt. bind(text=self. on_inputtag) sendbtn = Button(text="Send Data to IOTA", background_color=random. choice(colors), height=20) sendbtn. bind(on_press=self. send_to_iota) layout. add_widget(sendbtn) self. txnresponselabel = Label(text=self. my_address, size_hint=(1. 0, . 1), pos_hint={'center_x': . 5, 'center_y': . 5}) layout. add_widget(self. txnresponselabel) return layout def on_inputtext(self, instance, value): self. my_data = value print("data is updated to: ", value) def on_inputtag(self, instance, value): self. my_tag = value print("tag is updated to: ", value) def generate_my_adddress(self, instance): self. my_address = Address. random(90) print("my_address: ", str(self. my_address)) self. addresstxt. text = str(self. my_address) 12/28/2021 Python, IOTA, and Kivy 36

IOTA Lab#2: Integrate with Kivy def send_to_iota(self, instance): tagstr = bytes(self. my_tag, 'utf-8') my_tag = Tag(tagstr) # we need to convert the data into trytestring data = Tryte. String. from_unicode(self. my_data) # Prepare a transaction object tx = Proposed. Transaction( address=self. my_address, value=0, tag=my_tag, message=data ) # Declare an API object api = Iota('https: //nodes. devnet. iota. org: 443') # Send the transaction to the network response = api. send_transfer([tx], min_weight_magnitude=9) print('Check your transaction on the Tangle!') print('https: //utils. iota. org/transaction/%s/devnet' % response['bundle'][0]. hash) self. txnresponselabel. text = str(response['bundle'][0]. hash) if __name__ == "__main__": app = IOTALab 2() app. run() 12/28/2021 Python, IOTA, and Kivy 37

IOTA Lab#2: Homework n n n Study the IOTA document to find out the maximum message size and confirm it using our program Design a tag scheme so that you can request transactions sent by you on a particular year, month, and/or day Modify the Kivy interface to add a Text. Input so that you can provide your tag 12/28/2021 Python, IOTA, and Kivy 38

IOTA Lab#3: Fetch Data n In this lab, you will learn how to: q q Fetch transaction objects from the Tangle based on a criteria Decode messages from transactions 12/28/2021 Python, IOTA, and Kivy 39

IOTA Lab#3: Fetch Data from iota import Iota, Address from iota. codecs import Trytes. Decode. Error # Declare an API object api = Iota('https: //nodes. devnet. iota. org: 443') n The usual part again, but we also import Trytes. Decode. Error from iota. codec. We will use this to detect if the fetched trytes contain encoded text # Address to fetch data from # addy = Address(b'WWO 9 DRAUDDSDSTTUPKJRNPSYLWAVQBBXISLKLTNDPVKOPMUERDUELLUPHNT 9 L 9 YWBDKOLYVWRAFRKIBLP') n n We declare an IOTA address on the Tangle to fetch data from You can replace this address with your own from the previous lab 2 Send Data, or just run it as it is 12/28/2021 Python, IOTA, and Kivy 40

IOTA Lab#3: Fetch Data print('Fetching data from the Tangle. . . ') # Fetch the transaction objects of the address from the Tangle response = api. find_transaction_objects(addresses=[addy]) n n n We use find_transaction_objects() extended API method to gather the transactions that belong to our address This method is also capable of returning Transaction objects for bundle hashes, tags or approving transactions Note that you can supply multiple of these, the method always returns a dict with a list of transactions 12/28/2021 Python, IOTA, and Kivy 41
![IOTA Lab#3: Fetch Data if not response['transactions']: print('Couldn't find data for the given address. IOTA Lab#3: Fetch Data if not response['transactions']: print('Couldn't find data for the given address.](http://slidetodoc.com/presentation_image_h2/38dbec7508f3dcd95fd5bd787b7a7b7c/image-42.jpg)
IOTA Lab#3: Fetch Data if not response['transactions']: print('Couldn't find data for the given address. ') else: print('Found: ') # Iterate over the fetched transaction objects for tx in response['transactions']: # data is in the signature_message_fragment attribute as trytes, we need # to decode it into a unicode string data = tx. signature_message_fragment. decode(errors='ignore') print(data) n n n Finally, we extract the data we are looking for from the transaction objects A Transaction has several attributes, one of which is the signature_message_fragment This contains the payload message for zero-value transactions, and the digital signature that authorizes spending for value transactions Since we are interested in data now, we decode its content (raw trytes) into text We pass the errors='ignore' argument to the decode() method to drop values we can’t decode using utf-8, or if the raw trytes can’t be decoded into legit bytes. A possible reason for the latter can be if the attribute contains a signature rather than a message 12/28/2021 Python, IOTA, and Kivy 42

IOTA Lab#3: Homework n Integrate Kivy with the code given so that all input and output from print (or pprint) are taken/displayed on the GUI q n Specifically, the tag must be part of the GUI Use the tag scheme designed in lab#2 to request transactions you have generated 12/28/2021 Python, IOTA, and Kivy 43

IOTA Lab#4: Token Preliminary n In this lab, we will learn how to q q Request an Address that we can use for non-value transactions with IOTA Obtain free devnet IOTA tokens for our lab Obtain balance of the tokens that we own Get our Account data 12/28/2021 Python, IOTA, and Kivy 44

IOTA Lab#4: Generate an Address n n n To generate an IOTA address that can receive IOTA tokens, we must ask the IOTA platform IOTA API asks a seed parameter. We can either predefined a seed (that is, a password) manually, or randomly generate a seed If you choose to use a randomly generated seed, please record it once you run the program! gen_address. py from iota import Iota # Py. OTA is only compatible with Python 3. 6 and 3. 7 # If you are using Python 3. x that is higher than 3. 7, only Py. OTA 2. 1. 0 is installed # Py. OTA version 2. 2, 9 b 1 added Seed to the top level from iota. crypto. types import Seed # Generate a random seed, or use one you already have (for the devnet) print('Generating a random seed. . . ') my_seed = Seed. random() # my_seed = Seed(b'MYCUSTOMSEED') print('Your seed is: ' + str(my_seed)) 12/28/2021 Python, IOTA, and Kivy 45

IOTA Lab#4: Generate an Address n n n Next, we pass the seed argument to the API class’s init method Whenever the API needs to work with addresses or private keys, it will derive them from this seed Your seed never leaves the library and your computer. Treat your (mainnet) seed like any other password for a financial service: safe. If your seed is compromised, attackers can steal your funds gen_address. py # Declare an API object api = Iota( adapter='https: //nodes. devnet. iota. org: 443', seed=my_seed, ) 12/28/2021 Python, IOTA, and Kivy 46

IOTA Lab#4: Generate an Address n n n To generate a new address, we call get_new_addresses() extended API method Without arguments, this will return a dict with the first unused address starting from index 0 An unused address is address that has no transactions referencing it on the Tangle and was never spent from If we were to generate more addresses starting from a desired index, we could specify the start and count parameters Read more about how to generate addresses in Py. OTA at Generating Addresses: https: //pyota. readthedocs. io/en/latest/addresses. html#generatingaddresses gen_address. py print('Generating the first unused address. . . ') # Generate the first unused address from the seed response = api. get_new_addresses() # each time returns only a single address addy = response['addresses'][0] 12/28/2021 Python, IOTA, and Kivy 47

IOTA Lab#4: Generate an Address n n Lastly, the address is printed to the console, so that you can copy it Visit https: //faucet. devnet. iota. org/ and enter the address to receive free devnet tokens of 1000 i gen_address. py print('Your new address is: ' + str(addy)) print('Go to https: //faucet. devnet. iota. org/ and enter you address to receive free devnet tokens. ') 12/28/2021 Python, IOTA, and Kivy 48

IOTA Lab#4: Check Balance n n After you have acquired the free devnet tokens for an account, you may check the balance for that address Make sure you modify the given code with your address! get_balance. py from iota import Iota, Address import time # Put your address from Tutorial 4. a here # 2 nd address: CJTR 9 UBFJVHSXQX 9 JOBYTUZLAHSYLAEPMR 9 YIMFKGSIW 9 QSJEHINGQPTILWLXTRX 9 ENQLBOGCCHHYQOKC my_address = Address(b'NPKAKDNDSXXHLIPDSXW 9 DUMRCBUTGTSMGGNSJHHWCZYCZNQBTCGFY 9 RENMYKOAXKDQBQGCHBNICYX 9 JXX') # Declare an API object api = Iota(adapter='https: //nodes. devnet. iota. org: 443') 12/28/2021 Python, IOTA, and Kivy 49

IOTA Lab#4: Check Balance n n Our script will poll the network for the address balance as long as the returned balance is zero Therefore, the address you declared as my_address should have some balance get_balances() returns the confirmed balance of the address You could supply multiple addresses at the same time and get their respective balances in a single call # Script actually runs until you load up your address success = False while not success: print('Checking balance on the Tangle for a specific address. . . ') # API method to check balance response = api. get_balances(addresses=[my_address]) get_balance. py # response['balances'] is a list! if response['balances'][0]: print('Found the following information for address ' + str(my_address) + ': ') print('Balance: ' + str(response['balances'][0]) + 'i') success = True else: print('Zero balance found, retrying in 30 seconds. . . ') time. sleep(30) 12/28/2021 Python, IOTA, and Kivy 50

IOTA Lab#4: Get Account Data n n n Account here means the addresses and funds that belong to a particular seed Gather addresses, balance and bundles associated with your seed on the Tangle Note that the api might keep looping without find an address that has a positive balance, in which case, please generate a new address from the same seed and ask for the free devnet tokens for the new addres get_acc_data. py from iota import Iota from iota. crypto. types import Seed from pprint import time # Put your seed here my_seed = Seed(b'DAZRCRJKKLIJPZQEJPAG 9 FDAPJANONKELUETHSJZLTIUVNLRHLIK 9 UAITVHTAZOOLHSDDH 9 BVDSRSLDSH') # Declare an API object api = Iota( adapter='https: //nodes. devnet. iota. org: 443', seed=my_seed, ) # Script actually runs until it finds balance success = False 12/28/2021 Python, IOTA, and Kivy 51

IOTA Lab#4: Get Account Data n n Just like in the previous example, we will poll for information until we find a nonzero balance get_account_data() without arguments generates addresses from index 0 until it finds the first unused. Then, it queries the node about bundles of those addresses and sums up their balance while not success: print('Checking account information on the Tangle. . . ') # Gather addresses, balance and bundles response = api. get_account_data() get_acc_data. py # response['balance'] is an integer! if response['balance']: print('Found the following information based on your seed: ') pprint(response) success = True else: print('Zero balance found, retrying in 30 seconds. . . ') time. sleep(30) 12/28/2021 Python, IOTA, and Kivy 52

IOTA Lab#4: Get Account Data n n If you just created an address and requested the free tokens, the program might loop many times before it find an address that has a balance You will see something like this: Checking account information on the Tangle. . . Zero balance found, retrying in 30 seconds. . . Checking account information on the Tangle. . . Found the following information based on your seed: {'addresses': [Address(b'CXXUZBRZMOJVTVSWKRH 9 WWLCEYKOMMREGWEMDSYATK 9 ZYACDUQEZLVFFFJ 9 YMTEKBRJQG KKOEITGCESMC')], 'balance': 1000, 'bundles': [<iota. transaction. base. Bundle object at 0 x 10 e 9 dc 490>]} 12/28/2021 Python, IOTA, and Kivy 53

IOTA Lab#4: Get Account Data n n After you have done lab#5, come back and check the account data again You will see something like this: Checking account information on the Tangle. . . Found the following information based on your seed: {'addresses': [Address(b'CXXUZBRZMOJVTVSWKRH 9 WWLCEYKOMMREGWEMDSYATK 9 ZYACDUQEZLVFFFJ 9 YMTEKBRJQGKKOEITGCESMC'), Address(b'CUIQFHXERISUORQCWZQKXCKPWSAETOPVOAVV 9 XJAUPMHAZTPOXWTCZXZOUCXBTBVYXVNWUZJCS 9 KXZIPC'), Address(b'A 9 PLTCMXKMQVKCA 9 DJDAF 9 DYDM 9 UKLGFURRWXABHIKYDDIKSZKMYINPCRJAESHBOZUINQFFEDNSENYSUD'), Address(b'JVAIDSOCSMO 9 AFLCCQXQOGYVVPWJYOAHSVFGOJKXNSBRWSK 99 HWJKOHUXICZIACDRBRTENECJDZNVQDJ 9'), Address(b'NMMPKRYWVKLPZJCUZJ 9 RVZJUEQOY 9 YWFTBQEJFVOFAWLFKPKCGEQHJQKKFW 9 MGAEWGLOSXZUUSTIONUOX'), Address(b'ABJSCINDQARKMCCGNOBSSQLTZMVVLFWHZDVGMSPADQZV 9 APEMOBWAXHQCBBTYPWWIKMKUYTVUVN 9 XVZMY'), Address(b'LRASOGDJMBMRGNC 9 GMRQNMRQCMATR 9 DIXFCAEODCRNIXETIGZB 9 TKZGZTHUDDLCGQXTPBCEGJJODAFNND'), Address(b'WHBKRLHCHCWHZHBKRYRZ 9 XDCCPCBWSNHVVYEO 9 BWKQYKQRGSGSRVSZIGDYDSFDAGGDAJ 9 IVMVNBFATNUC'), Address(b'ETEOGJDXEZDXFENJTVELFWADKDHDTIXGDUMCSTSFDDSCWAWLPPD 9 SUKZWMLDIVDHYD 99 NIXGFCMQOGCGX'), Address(b'DENLGNVBUYEORPWLRSPIOUCMQSMZKUVDQURKOUVPOQW 9 TYADERVXYQSEYPNL 9 WBAMWYUH 9 OIWGILOLQXD'), Address(b'HYIJNKZWMUU 9 NCBUDBBNMCFIDJJZBOOZYYXFNGTOPKBE 9 YFJXCYBXHEAATUSF 9 IELCBTUHIWSSFIFGYMC'), Address(b'DQXQWUUFSXHBQPXUTAYEWRLLRSVNXQHEFAMICFYWXEYJYXAXXVSIIGDTTSVFAYWLYWSCFNIQIEBXTIY 9 Y'), Address(b'ZVXNXPPYTHLASDRZWDJKFCORNRMHFQZCWQJLPTPUG 9 TZUKIZQXTEPLGKIIFVULJVDHNIVRIF 9 ZEQNRLOC'), Address(b'JPAUH 9 KR 9 IKLIFJGTVPZKDAC 9 ADCSFCLANSJIACEHCCWPNFIUVEVSEDQYFDYJXRLDVFIJBDQVQAPMVVDC'), Address(b'ITHTPOTFVQKTSHIGAELXDSNMUPJPGXADPROSVWHCJQLLEQNWQNFMJLQOGXEATFFO 9 SKVPWVEI 9 BSXMPWB'), Address(b'TBJCGEAALJMYONPIHDVRSMGIWEPRWHJ 9 XTITLENSZAKDEHUW 9 RCDINHOGZGYLMGWQIR 9 UM 9 WIILAXCOYX'), Address(b'9 NPEHRVQWEYSWSGARTLFDYMWMQHSLABTDUA 9 HOYUWZHOXZZVOLPCWPHVBPZEWMAOJOYULEQRPTNWEZMC 9'), Address(b'JGNAHYWGCJUMAOPKOBXONOZGDLIYUYNKXJOETDXWUVOMWLKLNOMJOKVUTCVZQUCWYLBYEQSVYCKKVGTBC'), Address(b'UPSJPQUMNUBPRCUKTMWNSDEHWHUVYXIBBEKVYPICOJPAUWSSZFNFYSNYCUKLEEDQLTPXIKRYKNRSYFEPW')], 'balance': 982, 'bundles': [<iota. transaction. base. Bundle object at 0 x 10366 ca 60>, <iota. transaction. base. Bundle object at 0 x 103663190>, <iota. transaction. base. Bundle object at 0 x 103648 f 40>, <iota. transaction. base. Bundle object at 0 x 10366 ac 10>, <iota. transaction. base. Bundle object at 0 x 103658220>, <iota. transaction. base. Bundle object at 0 x 10365 ca 90>, <iota. transaction. base. Bundle object at 0 x 103669070>, <iota. transaction. base. Bundle object at 0 x 103677280>, <iota. transaction. base. Bundle object at 0 x 103662940>, <iota. transaction. base. Bundle object at 0 x 1036557 c 0>, <iota. transaction. base. Bundle object at 0 x 10366 cf 10>, <iota. transaction. base. Bundle object at 0 x 103660940>, <iota. transaction. base. Bundle object at 0 x 103650 d 00>, <iota. transaction. base. Bundle object at 0 x 1035 a 9 fa 0>, <iota. transaction. base. Bundle object at 0 x 10364 ef 10>, <iota. transaction. base. Bundle object at 0 x 10365 fac 0>, <iota. transaction. base. Bundle object at 0 x 10367 b 490>, <iota. transaction. base. Bundle object at 0 x 103640 df 0>, <iota. transaction. base. Bundle object at 0 x 103656 a 00>]} 12/28/2021 Python, IOTA, and Kivy 54

IOTA Lab#4: Homework n Integrate Kivy with the code given (in three python programs) to make a single app: q q q The app can take a custom seed from the user The app can request an address from api and display the address so that the user can proceed to request free devnet tokens Add a button, when click, query iota for the balance for a particular address Add another button, when click, query iota for the entire account data Specifically, the tag must be part of the GUI 12/28/2021 Python, IOTA, and Kivy 55

IOTA Lab#5: Value Transaction n In this lab, we will learn how to q q q Construct a value transfer with Py. OTA Send a value transfer to a designated IOTA address Analyze a bundle of transactions on the Tangle 12/28/2021 Python, IOTA, and Kivy 56

IOTA Lab#5: Value Transaction n We are going to send a value transaction, that requires us to prove that we own the address containing the funds to spend Therefore, we need our seed from which the address was generated We pass this seed to the API object, that will utilize it for signing the transfer from iota import Iota, Address, Tryte. String, Proposed. Transaction, Tag # Py. OTA version 2. 2, 9 b 1 added Seed to the top level from iota. crypto. types import Seed from pprint import pprint send_token. py # Put your seed that owns tokens (devnet) my_seed = Seed(b'DAZRCRJKKLIJPZQEJPAG 9 FDAPJANONKELUETHSJZLTIUVNLRHLIK 9 UAITVHTAZOOLHSDDH 9 BVDSRSLDSH') # Declare an API object api = Iota( adapter='https: //nodes. devnet. iota. org: 443', seed=my_seed, ) 12/28/2021 Python, IOTA, and Kivy 57

IOTA Lab#5: Value Transaction n In IOTA, funds move across addresses, therefore we need to define a receiver address For testing value transfers, you should send the funds only to addresses that you control; if you use a randomly-generated receiver address, you won’t be able to recover the funds afterward! You could generate a new Address, or just paste a valid IOTA address that you own send_token. py # Addres to receive 1 i receiver = Address(b'CJTR 9 UBFJVHSXQX 9 JOBYTUZLAHSYLAEPMR 9 YIMFKGSIW 9 QSJEHINGQPTILWLXTRX 9 ENQLBOGCCHHYQOKC') 12/28/2021 Python, IOTA, and Kivy 58

IOTA Lab#5: Value Transaction n We declare a Proposed. Transaction object like we did before in lab#2, but this time, with value=1 parameter The smallest value you can send is 1 iota (“ 1 i”), there is no way to break it into smaller chunks You can also attach a message to the transaction, for example a little note to the beneficiary of the payment send_token. py print('Constructing transfer of 1 i. . . ') # Create the transfer object tx = Proposed. Transaction( address=receiver, value=1, message=Tryte. String. from_unicode('I just sent you 1 i, use it wisely!'), tag=Tag('VALUETX'), ) pprint(vars(tx)) 12/28/2021 Python, IOTA, and Kivy 59

IOTA Lab#5: Value Transaction n Let’s see what has been prepared for the transfer with the pprint(vars(tx)) statement: {'_legacy_tag': None, 'address': Address(b'CJTR 9 UBFJVHSXQX 9 JOBYTUZLAHSYLAEPMR 9 YIMFKGSIW 9 QSJEHINGQPTILWLXTRX 9 ENQLBOGCCHHYQOKC'), 'attachment_timestamp': 0, 'attachment_timestamp_lower_bound': 0, 'attachment_timestamp_upper_bound': 0, 'branch_transaction_hash': Transaction. Hash(b'99999999999999999999999999999999999999999'), 'bundle_hash': None, 'current_index': None, 'hash': None, 'is_confirmed': None, 'last_index': None, 'message': Tryte. String(b'SBEAYCIDGDHDEAGDTCBDHDEAMDCDIDEAVAXCQAEAIDGDTCEAXCHDEAKDXCGDTC 9 DMDFA'), 'nonce': Nonce(b'99999999999999'), 'signature_message_fragment': None, 'tag': Tag(b'VALUETX 9999999999'), 'timestamp': 1621034899, 'trunk_transaction_hash': Transaction. Hash(b'99999999999999999999999999999999999999999'), 'value': 1} 12/28/2021 Python, IOTA, and Kivy 60

IOTA Lab#5: Value Transaction n To actually send the transfer, all you need to do is call send_transfer() extended API method. This method will take care of: q q q Gathering inputs (addresses you own and have funds) to fund the 1 i transfer Generating a new change_address, and automatically sending the remaining funds (balance of chosen inputs - 1 i) from inputs to change_address Constructing the transfer bundle with necessary input and output transactions Finalizing the bundle and signing the spending transactions Doing proof-of-work for each transaction in the bundle and sending it to the network # Prepare the transfer and send it to the network response = api. send_transfer(transfers=[tx], min_weight_magnitude=9) send_token. py bundlehash = response['bundle']. hash print('https: //utils. iota. org/bundle/%s/devnet' % bundlehash) 12/28/2021 Python, IOTA, and Kivy 61

IOTA Lab#5: Value Transaction n n Next, let’s find out exactly what has been produced by this api using the find_transaction_objects api In lab#3, we used the address to find the objects. This time we use the bundle hash send_token. py txns = api. find_transaction_objects(bundles=[bundlehash]) if not txns['transactions']: print('Couldn't find data for the given address. ') else: print('Found: ') # Iterate over the fetched transaction objects for tx in txns['transactions']: pprint(vars(tx)) 12/28/2021 Python, IOTA, and Kivy 62

IOTA Lab#5: Value Transaction n We do have four transactions in the bundle, 1 input and 3 outputs. But why are there so many transactions? q q There is one transaction that withdraws iotas, this has negative value. To authorize this spending, a valid signature is included in the transaction’s signature_message_fragment field The signature however is too long to fit into one transaction, therefore the library appends a new, zero-value transaction to the bundle that holds the second part of the signature. This you see on the output side of the bundle A 1 i transaction to the receiver address spends part of the withdrawn amount The rest is transfered to change_address in a new output transaction 12/28/2021 Python, IOTA, and Kivy 63

IOTA Lab#5: Value Transaction n First transaction {'_legacy_tag': Tag(b'BHLUETX 9999999999'), 'address': Address(b'CJTR 9 UBFJVHSXQX 9 JOBYTUZLAHSYLAEPMR 9 YIMFKGSIW 9 QSJEHINGQPTILWLXTRX 9 ENQLBOGCCHHYQOKC'), 'attachment_timestamp': 1621034942454, 'attachment_timestamp_lower_bound': 0, 'attachment_timestamp_upper_bound': 11, 'branch_transaction_hash': Transaction. Hash(b'HBXXLKZVQCZOKPTCDI 9 XYZGWMOER 9 QXXYFJEBVFZCZJXPEF 9 SGQBEHJJ 9 SANCRE 9 BOYDUTHYCGNENT 999'), 'bundle_hash': Bundle. Hash(b'NMXIGRESBYFWH 9 DRYSIFYYWKJIIUQABWYBTUADWIUDGRLQYLWZGQZG 9 RCI 9 THKORDPPFKCGJVDU 9 IRDXZ'), 'current_index': 0, 'hash': Transaction. Hash(b'SMGYOTSKFOWAFNMIKPXHQLTIEYYXFOZVLNOECQRIYGKXNU 9 CYGNCHYC 9 TDOVQEOIDAKWYMGUISZWOA 999'), 'is_confirmed': None, 'last_index': 3, 'nonce': Nonce(b'BY 9999 I 99999999'), 'signature_message_fragment': Fragment(b'SBEAYCIDGDHDEAGDTCBDHDEAMDCDIDEAVAXCQAEAIDGDTCEAXCHDEAKDXCGDTC 9 DMDFA 999999999…'), 'tag': Tag(b'VALUETX 9999999999'), 'timestamp': 1621034899, 'trunk_transaction_hash': Transaction. Hash(b'RNKRFLMOGGWAMYGOQWA 9 SDGZSONSDWYRBZRGFUZQLTBOGWGYSHDPBXITUXITOHGYRIFUVYIMCMNFJO 999'), 'value': 1} Note the Fragment part is truncated! The Address starting with CJTR will receive 1 i 12/28/2021 Python, IOTA, and Kivy 64

IOTA Lab#5: Value Transaction n Second transaction {'_legacy_tag': Tag(b'VALUETX 9999999999'), 'address': Address(b'JGNAHYWGCJUMAOPKOBXONOZGDLIYUYNKXJOETDXWUVOMWLKLNOMJOKVUTCVZQUCWYLBYEQSVYCKKVGTBC'), 'attachment_timestamp': 1621034942388, 'attachment_timestamp_lower_bound': 0, 'attachment_timestamp_upper_bound': 11, 'branch_transaction_hash': Transaction. Hash(b'HBXXLKZVQCZOKPTCDI 9 XYZGWMOER 9 QXXYFJEBVFZCZJXPEF 9 SGQBEHJJ 9 SANCRE 9 BOYDUTHYCGNENT 999'), 'bundle_hash': Bundle. Hash(b'NMXIGRESBYFWH 9 DRYSIFYYWKJIIUQABWYBTUADWIUDGRLQYLWZGQZG 9 RCI 9 THKORDPPFKCGJVDU 9 IRDXZ'), 'current_index': 1, 'hash': Transaction. Hash(b'RNKRFLMOGGWAMYGOQWA 9 SDGZSONSDWYRBZRGFUZQLTBOGWGYSHDPBXITUXITOHGYRIFUVYIMCMNFJO 999'), 'is_confirmed': None, 'last_index': 3, 'nonce': Nonce(b'EC 99999 F 99999999'), 'signature_message_fragment': Fragment(b'EOEZQOWOVSZ 9 IMHOAHKIDQRSAZCY 9 WUUKTCWSXPFAAAQCCCPOWDFUAKKQXTWCZTHWSWYTMBAXHNW 9 QNIDMJO…'), 'tag': Tag(b'VALUETX 9999999999'), 'timestamp': 1621034920, 'trunk_transaction_hash': Transaction. Hash(b'IMMXVFLOFVUKZEADJCCJNRKTSURZYZRVLSHNIHAH 9 LLURZSXS 9 ESAKAKQUDVCIHMEZWKAZGQNSVEGJ 999'), 'value': -983} Note the Fragment part is truncated! The Address starting with JGNA will be deducted of 983 i, which is the entire balance associated with this address 12/28/2021 Python, IOTA, and Kivy 65

IOTA Lab#5: Value Transaction n Third transaction {'_legacy_tag': Tag(b'VALUETX 9999999999'), 'address': Address(b'JGNAHYWGCJUMAOPKOBXONOZGDLIYUYNKXJOETDXWUVOMWLKLNOMJOKVUTCVZQUCWYLBYEQSVYCKKVGTBC'), 'attachment_timestamp': 1621034942309, 'attachment_timestamp_lower_bound': 0, 'attachment_timestamp_upper_bound': 11, 'branch_transaction_hash': Transaction. Hash(b'HBXXLKZVQCZOKPTCDI 9 XYZGWMOER 9 QXXYFJEBVFZCZJXPEF 9 SGQBEHJJ 9 SANCRE 9 BOYDUTHYCGNENT 999'), 'bundle_hash': Bundle. Hash(b'NMXIGRESBYFWH 9 DRYSIFYYWKJIIUQABWYBTUADWIUDGRLQYLWZGQZG 9 RCI 9 THKORDPPFKCGJVDU 9 IRDXZ'), 'current_index': 2, 'hash': Transaction. Hash(b'IMMXVFLOFVUKZEADJCCJNRKTSURZYZRVLSHNIHAH 9 LLURZSXS 9 ESAKAKQUDVCIHMEZWKAZGQNSVEGJ 999'), 'is_confirmed': None, 'last_index': 3, 'nonce': Nonce(b'UY 9999 XF 99999999'), 'signature_message_fragment': Fragment(b'WO 9 IHNXETQZ 9 HVCLQLBNHOKDWSZVREUBYADTFPBDNPEDBYQNVRYIRNBGSMZNJOUHYZZSTPIUKGBYYYZF 9 BPIBO 9…'), 'tag': Tag(b'VALUETX 9999999999'), 'timestamp': 1621034920, 'trunk_transaction_hash': Transaction. Hash(b'XVSOJXILLAOF 9 TMNLSQIUFSQYAFYCWIPV 9 WIUKQRJSUHQZATKHNFRZVBOTHSKCHXMRNODFDNQBMBDM 999'), 'value': 0} Note the Fragment part is truncated! Extra transaction to store the signature fragment 12/28/2021 Python, IOTA, and Kivy 66

IOTA Lab#5: Value Transaction n Fourth transaction {'_legacy_tag': Tag(b'VALUETX 9999999999'), 'address': Address(b'UPSJPQUMNUBPRCUKTMWNSDEHWHUVYXIBBEKVYPICOJPAUWSSZFNFYSNYCUKLEEDQLTPXIKRYKNRSYFEPW'), 'attachment_timestamp': 1621034942246, 'attachment_timestamp_lower_bound': 0, 'attachment_timestamp_upper_bound': 11, 'branch_transaction_hash': Transaction. Hash(b'UYAFQYJXNXOLBWFRRYTBUBWHZEHCOAEUTFJMYZULIQLHNMZNAOJXOHNTAZWSAQLDTZEFRVALEDKAGH 999'), 'bundle_hash': Bundle. Hash(b'NMXIGRESBYFWH 9 DRYSIFYYWKJIIUQABWYBTUADWIUDGRLQYLWZGQZG 9 RCI 9 THKORDPPFKCGJVDU 9 IRDXZ'), 'current_index': 3, 'hash': Transaction. Hash(b'XVSOJXILLAOF 9 TMNLSQIUFSQYAFYCWIPV 9 WIUKQRJSUHQZATKHNFRZVBOTHSKCHXMRNODFDNQBMBDM 999'), 'is_confirmed': None, 'last_index': 3, 'nonce': Nonce(b'ED 9999 FD 99999999'), 'signature_message_fragment': Fragment(b'999999999999999999999999999999999999999999999…'), 'tag': Tag(b'VALUETX 9999999999'), 'timestamp': 1621034940, 'trunk_transaction_hash': Transaction. Hash(b'HBXXLKZVQCZOKPTCDI 9 XYZGWMOER 9 QXXYFJEBVFZCZJXPEF 9 SGQBEHJJ 9 SANCRE 9 BOYDUTHYCGNENT 999'), 'value': 982} Note the Fragment part is truncated! The change_address starting with UPSJ will receive a credit of 982 i 12/28/2021 Python, IOTA, and Kivy 67

IOTA Lab#5: Homework n n Study pyota API documentation and learn how to specify a particular input address when preparing for a value transaction Integrate Kivy with the code given in this lab. The GUI should contain: q q q The amount of token to be transferred in the transaction The payee address The status of the transaction in terms of the bundle hash 12/28/2021 Python, IOTA, and Kivy 68

IOTA Lab#6: Store/Fetch Encrypted Data n In this lab, we will learn how to q q q Convert Python data structures to JSON format Encrypt data and include it in a zero-value transaction Store the zero-value transaction with encrypted data on the Tangle Fetch transactions from the Tangle based on their addresses (already done this) Extract messages from a transaction (already done this) Decrypt encrypted messages from a transaction 12/28/2021 Python, IOTA, and Kivy 69

IOTA Lab#6: Store/Fetch Encrypted Data n We will need an address to upload the data, therefore we need to supply the seed to the Iota API instance. The address will be generated from this seed from iota import Iota, Tryte. String, Tag, Proposed. Transaction from simplecrypt import encrypt, decrypt from base 64 import b 64 encode, b 64 decode from getpass import getpass from pprint import pprint encryption. py import json # Declare an API object api = Iota( adapter='https: //nodes. devnet. iota. org: 443', seed=b'YOURSEEDFROMTHEPREVIOUSTUTORIAL', ) 12/28/2021 Python, IOTA, and Kivy 70

IOTA Lab#6: Store/Fetch Encrypted Data n n n The data to be stored is considered confidential information, therefore we can’t just put it on the Tangle as plaintext so everyone can read it We will use the encrypt method to encipher the data, and b 64 encode for representing it as ASCII characters getpass will prompt the user for a password, and the json library is used for JSON formatting # Some confidential information data = { 'name' : 'James Bond', 'age' : '32', 'job' : 'agent', 'address' : 'London', } encryption. py Notice, that data is a Python dict object. As a common way of exchanging data on the web, we would like to convert it to JSON format. The json. dumps() method does exactly that, and the result is a JSON formatted plaintext. # Convert to JSON format json_data = json. dumps(data) 12/28/2021 Python, IOTA, and Kivy 71

IOTA Lab#6: Store/Fetch Encrypted Data n Next, we will encrypt this data with a secret password we obtain from the user # Ask user for a password to use for encryption password = getpass('Please supply a password for encryption: ') encryption. py print('Encrypting data. . . ') # Encrypt data # Note, that in Python 3, encrypt returns 'bytes' cipher = encrypt(password, json_data) # Encode to base 64, output contains only ASCII chars b 64_cipher = b 64 encode(cipher) 12/28/2021 Python, IOTA, and Kivy 72

IOTA Lab#6: Store/Fetch Encrypted Data n n The output of the encrypt method is a bytes-object in Python 3 and contains many special characters. This is a problem, since we can only convert ASCII characters from bytes directly into Tryte. String Therefore, we first encode our binary data into ASCII characters with Base 64 encoding print('Constructing transaction locally. . . ') # Convert to trytes_encrypted_data = Tryte. String. from_bytes(b 64_cipher) encryption. py # Generate an address from your seed to post the transfer to my_address = api. get_new_addresses(index=0)['addresses'][0] # Tag is optional here my_tag = Tag(b'CONFIDENTIALINFORMATION') # Prepare a transaction object tx = Proposed. Transaction( address=my_address, value=0, tag=my_tag, message=trytes_encrypted_data, ) 12/28/2021 Python, IOTA, and Kivy 73

IOTA Lab#6: Store/Fetch Encrypted Data n n n We use api. send_transfer() to prepare the transfer and send it to the network The tail transaction (a tail transaction is the one with index 0 in the bundle) hash is printed on the console Theoretically, this hash can be used to retrieve the bundle with api. get_bundles([tailhash])[‘bundles’][0]. But it doesn’t work with pyota 2. 1. 0 print('Sending transfer. . . ') # Send the transaction to the network response = api. send_transfer([tx], min_weight_magnitude=9) tailhash = response['bundle']. tail_transaction. hash bundlehash = response['bundle'][0]. hash encryption. py print('Check your transaction on the Tangle!') print('https: //utils. iota. org/transaction/%s/devnet' % response['bundle'][0]. hash) print('Tail transaction hash of the bundle is: %s' % response['bundle']. tail_transaction. hash) 12/28/2021 Python, IOTA, and Kivy 74
![IOTA Lab#6: Store/Fetch Encrypted Data We use api. find_transaction_objects(addresses=[my_address]) to fetch the n transactions IOTA Lab#6: Store/Fetch Encrypted Data We use api. find_transaction_objects(addresses=[my_address]) to fetch the n transactions](http://slidetodoc.com/presentation_image_h2/38dbec7508f3dcd95fd5bd787b7a7b7c/image-75.jpg)
IOTA Lab#6: Store/Fetch Encrypted Data We use api. find_transaction_objects(addresses=[my_address]) to fetch the n transactions that bear this address n We then iterate through all transactions received n Note that if you run the program multiple times without changing the address, you will see multiple transactions encryption. py txns = api. find_transaction_objects(addresses=[my_address]) print('Extracting data from bundle. . . ') if not txns['transactions']: print('Couldn't find data for the given address. ') else: # Iterate over the fetched transaction objects for tx in txns['transactions']: b 64_encrypted_data = tx. signature_message_fragment. decode(errors='ignore') # Decode from base 64 encrypted_data = b 64 decode(b 64_encrypted_data) # Prompt for passwword password = getpass('Password to be used for decryption: ') print('Decrypting data. . . ') # Decrypt data # decrypt returns 'bytes' in Python 3, decode it into string json_data = decrypt(password, encrypted_data). decode('utf-8') # Convert JSON string to python dict object data = json. loads(json_data) print('Succesfully decrypted the following data: ') print(data) 12/28/2021 Python, IOTA, and Kivy 75

IOTA Lab#6: Store/Fetch Encrypted Data We extract the content of the message field of each transactions using tx. n n n tx. signature_message_fragment. decode(errors='ignore’) This method already decodes the content from trytes into unicode characters We then we decode the message into bytes with b 64 decode() We will ask the user for the decryption password Then we decrypt the bytes cipher with the password and decode the result into a unicode string encryption. py there is one additional step to arrive at our original data. On line 39, we deserialize the JSON string # Prompt for passwword into a Python object, namely a dict. b 64_encrypted_data = tx. signature_message_fragment. decode(errors='ignore') # Decodewe fromused base 64 JSON formatting in the previous tutorial, Since encrypted_data = b 64 decode(b 64_encrypted_data) password = getpass('Password to be used for decryption: ') print('Decrypting data. . . ') # Decrypt data # decrypt returns 'bytes' in Python 3, decode it into string json_data = decrypt(password, encrypted_data). decode('utf-8') # Convert JSON string to python dict object data = json. loads(json_data) print('Succesfully decrypted the following data: ') print(data) 12/28/2021 Python, IOTA, and Kivy 76

IOTA Lab#6: Homework n Integrate Kivy with the code given in this lab into a single app. The GUI should contain: q q q q The message (in json format) you want to encrypt Your password The encrypted text The address to be used for the transaction A button to prepare a transaction containing the encrypted message and send to iota A button to retrieve the transaction from iota The decrypted text 12/28/2021 Python, IOTA, and Kivy 77
- Slides: 77