From bfcf1f78d9e8bde241a3b55fcddcf8ac242f60e9 Mon Sep 17 00:00:00 2001 From: Levente Pap Date: Tue, 21 Jan 2020 16:04:28 +0100 Subject: [PATCH 1/4] Add encrypt/decrypt tutorial src files --- examples/tutorials/06_send_encrypted.py | 65 ++++++++++++++++++++++++ examples/tutorials/07_fetch_decrypted.py | 41 +++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 examples/tutorials/06_send_encrypted.py create mode 100644 examples/tutorials/07_fetch_decrypted.py diff --git a/examples/tutorials/06_send_encrypted.py b/examples/tutorials/06_send_encrypted.py new file mode 100644 index 0000000..56d78e2 --- /dev/null +++ b/examples/tutorials/06_send_encrypted.py @@ -0,0 +1,65 @@ +""" +Encrypt data and store it on the Tangle. + +simplecrypt library is needed for this example (`pip install simple-crypt`)! +""" +from iota import Iota, TryteString, Tag, ProposedTransaction +from iota.crypto.addresses import AddressGenerator +from simplecrypt import encrypt +from base64 import b64encode +from getpass import getpass + +import json + +# Declare an API object +api = Iota('https://nodes.devnet.iota.org:443', testnet=True) + +# Some confidential information +data = { + 'name' : 'James Bond', + 'age' : '32', + 'job' : 'agent', + 'address' : 'London', +} + +# Convert to JSON format +json_data = json.dumps(data) + +# Ask user for a password to use for encryption +pw = getpass('Please supply a password for encryption:') + +print('Encrypting data...') +# Encrypt data +# Note, that in Python 3, encrypt returns 'bytes' +cipher = encrypt(pw, json_data) + +# Encode to base64, output contains only ASCII chars +b64_cipher = b64encode(cipher) + +print('Constructing transaction locally...') +# Convert to trytes +trytes_encrypted_data = TryteString.from_bytes(b64_cipher) + +# Generate an address from your seed to post the transfer to +my_address = AddressGenerator(b'YOURSEEDFROMTHEPREVIOUSTUTORIAL').get_addresses( + start=42, +)[0] + +# Tag is optional here +my_tag = Tag(b'CONFIDENTIALINFORMATION') + +# Prepare a transaction object +tx = ProposedTransaction( + address=my_address, + value=0, + tag=my_tag, + message=trytes_encrypted_data, +) + +print('Sending transfer...') +# Send the transaction to the network +response = api.send_transfer([tx]) + +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) \ No newline at end of file diff --git a/examples/tutorials/07_fetch_decrypted.py b/examples/tutorials/07_fetch_decrypted.py new file mode 100644 index 0000000..a71cead --- /dev/null +++ b/examples/tutorials/07_fetch_decrypted.py @@ -0,0 +1,41 @@ +""" +Decrypt data fetched from the Tangle. + +simplecrypt library is needed for this example (`pip install simple-crypt`)! +""" +from iota import Iota +from simplecrypt import decrypt +from base64 import b64decode +from getpass import getpass + +# Declare an API object +api = Iota('https://nodes.devnet.iota.org:443', testnet=True) + +# Prompt user for tail tx hash of the bundle +tail_hash = input('Tail transaction hash of the bundle: ') + +print('Looking for bundle on the Tangle...') +# Fetch bundle +bundle = api.get_bundles(tail_hash)['bundles'][0] + +if not bundle: + print('Found no bundle, exiting...') + exit() + +print('Extracting data from bundle...') +# Get all messages from the bundle and concatenate them +b64_encrypted_data = "".join(bundle.get_messages()) + +# Decode from base64 +encrypted_data = b64decode(b64_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 +data = decrypt(password, encrypted_data).decode('utf-8') + +print('Succesfully decrypted the following data:') +print(data) \ No newline at end of file From 55b1ae90a2324bd4fd0004c48592e7dfa44fd30c Mon Sep 17 00:00:00 2001 From: Levente Pap Date: Wed, 22 Jan 2020 15:06:31 +0100 Subject: [PATCH 2/4] docs: Add Tutorial 6 `Store Encrypted Data` - show simpple way of encrypting data before sending it to the Tangle --- docs/tutorials.rst | 115 +++++++++++++++++- ...end_encrypted.py => 06_store_encrypted.py} | 4 +- 2 files changed, 116 insertions(+), 3 deletions(-) rename examples/tutorials/{06_send_encrypted.py => 06_store_encrypted.py} (94%) diff --git a/docs/tutorials.rst b/docs/tutorials.rst index 067a4bb..3fc1a35 100644 --- a/docs/tutorials.rst +++ b/docs/tutorials.rst @@ -505,9 +505,122 @@ Once the bundle is confirmed, try rerunning the script from should be decremented by 1i, and you should see a new address, which was actually the ``change_address``. +6. Store Encrypted Data +----------------------- + +In this example, you will learn how to: + +- **Convert Python data structures to JSON format.** +- **Encrypt data and include it in a zero-value transaction.** +- **Generate an address with a PyOTA specific utility tool.** +- **Store the zero-value transaction with encrypted data on the Tangle.** + +.. warning:: + + We will use the ``simple-crypt`` external library for encryption/decryption. + Before proceeding to the tutorial, make sure you install it by running:: + + pip install simple-crypt + +Code +~~~~ +.. literalinclude:: ../examples/tutorials/06_store_encrypted.py + :linenos: + +Discussion +~~~~~~~~~~ +.. literalinclude:: ../examples/tutorials/06_store_encrypted.py + :lines: 1-15 + :lineno-start: 1 + +The first odd thing we notice among the imports is +:py:class:`~iota.crypto.addresses.AddressGenerator`. It is a PyOTA specific +utility that generates addresses given your seed. + +We will use the ``encrypt`` method to enchiper the data, and ``b64encode`` for +representing it as ASCII characters. ``getpass`` will prompt the user for a +password, and the ``json`` library is used for JSON formatting. + +.. literalinclude:: ../examples/tutorials/06_store_encrypted.py + :lines: 17-23 + :lineno-start: 17 + +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. Think of +what would happen if the world's most famous secret agent's identity was leaked +on the Tangle... + +.. literalinclude:: ../examples/tutorials/06_store_encrypted.py + :lines: 25-26 + :lineno-start: 25 + +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. + +.. literalinclude:: ../examples/tutorials/06_store_encrypted.py + :lines: 28-37 + :lineno-start: 28 + +Next, we will encrypt this data with a secret password we obtain from the user. + +.. note:: + + When you run this example, please remeber the password at least until the + next tutorial! + +The output of the ``encrypt`` method is a ``bytes`` object in Python3 and +contains many special characters. This is a problem, since we can only convert +ASCII characters from ``bytes`` directly into :py:class:`TryteString`. + +Therefore, we first encode our binary data into ASCII characters with `Base64`_ +encoding. + +.. literalinclude:: ../examples/tutorials/06_store_encrypted.py + :lines: 39-57 + :lineno-start: 39 + +Now, we are ready to construct the transfer. We convert the encrypted `Base64`_ +encoded data to trytes and assign it to the :py:class:`ProposedTransaction` +object's message argument. + +An address is also needed, so we generate one with the help of +:py:class:`~iota.crypto.addresses.AddressGenerator` and its +:py:meth:`~iota.crypto.addresses.AddressGenerator.get_addresses` method. Feel +free to chose the index of the generated address, and don't forget, that the +method returns a list of addresses, even if it contains only one. Put your seed +(from `4.a Generate Address`_) onto line 44 to generate an address that belongs +to you. For more detailed explanation on how addresses are generated in PyOTA, +refer to the :ref:`Generating Addresses` page. + +We also attach a custom :py:class:`Tag` to our :py:class:`ProposedTransaction`. +Note, that if our ``trytes_encrypted_data`` was longer than the maximum payload +of a transaction, the library would split it accross more transactions that +together form the transfer bundle. + +.. literalinclude:: ../examples/tutorials/06_store_encrypted.py + :lines: 59-65 + :lineno-start: 59 + +Finally, we use :py:meth:`Iota.send_transfer` to prepare the transfer and +send it to the network. + +Click on the link to check your transaction on the Tangle Explorer. + +The tail transaction (a tail transaction is the one with index 0 in the bundle) +hash is printed on the console, because you will need it in the next tutorial, +and anyway, it is a good practice to keep a reference to your transfers. + +In the next example, we will try to decode the confidential information from the +Tangle. + + + + .. _PyOTA Bug Tracker: https://github.com/iotaledger/iota.py/issues .. _bytestring: https://docs.python.org/3/library/stdtypes.html#bytes .. _tryte alphabet: https://docs.iota.org/docs/getting-started/0.1/introduction/ternary#tryte-encoding .. _Tangle Explorer: https://utils.iota.org .. _Account Module: https://docs.iota.org/docs/client-libraries/0.1/account-module/introduction/overview -.. _spending twice from the same address: https://docs.iota.org/docs/getting-started/0.1/clients/addresses#spent-addresses \ No newline at end of file +.. _spending twice from the same address: https://docs.iota.org/docs/getting-started/0.1/clients/addresses#spent-addresses +.. _Base64: https://en.wikipedia.org/wiki/Base64 \ No newline at end of file diff --git a/examples/tutorials/06_send_encrypted.py b/examples/tutorials/06_store_encrypted.py similarity index 94% rename from examples/tutorials/06_send_encrypted.py rename to examples/tutorials/06_store_encrypted.py index 56d78e2..2112b39 100644 --- a/examples/tutorials/06_send_encrypted.py +++ b/examples/tutorials/06_store_encrypted.py @@ -26,12 +26,12 @@ json_data = json.dumps(data) # Ask user for a password to use for encryption -pw = getpass('Please supply a password for encryption:') +password = getpass('Please supply a password for encryption:') print('Encrypting data...') # Encrypt data # Note, that in Python 3, encrypt returns 'bytes' -cipher = encrypt(pw, json_data) +cipher = encrypt(password, json_data) # Encode to base64, output contains only ASCII chars b64_cipher = b64encode(cipher) From c3b7153f5eb413feacd32e27694edb19dd652e22 Mon Sep 17 00:00:00 2001 From: Levente Pap Date: Thu, 23 Jan 2020 13:37:29 +0100 Subject: [PATCH 3/4] docs: Add Tutorial 7 `Fetch Encrypted Data` - show how to decrypt data from Tutorial 6 --- docs/tutorials.rst | 108 +++++++++++++++++- ...tch_decrypted.py => 07_fetch_encrypted.py} | 11 +- 2 files changed, 111 insertions(+), 8 deletions(-) rename examples/tutorials/{07_fetch_decrypted.py => 07_fetch_encrypted.py} (87%) diff --git a/docs/tutorials.rst b/docs/tutorials.rst index 3fc1a35..14a69bb 100644 --- a/docs/tutorials.rst +++ b/docs/tutorials.rst @@ -380,7 +380,7 @@ Tangle. :lines: 15-30 :lineno-start: 15 -Just like in the prevoius example, we will poll for information until we find +Just like in the previous example, we will poll for information until we find a non-zero balance. :py:meth:`~Iota.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. @@ -566,7 +566,7 @@ Next, we will encrypt this data with a secret password we obtain from the user. .. note:: - When you run this example, please remeber the password at least until the + When you run this example, please remember the password at least until the next tutorial! The output of the ``encrypt`` method is a ``bytes`` object in Python3 and @@ -614,8 +614,109 @@ and anyway, it is a good practice to keep a reference to your transfers. In the next example, we will try to decode the confidential information from the Tangle. +7. Fetch Encrypted Data +----------------------- + +In this example, you will learn how to: + +- **Fetch bundles from the Tangle based on their tail transaction hashes.** +- **Extract messages from a bundle.** +- **Decrypt encrypted messages from a bundle.** + +.. warning:: + + We will use the ``simple-crypt`` external library for encryption/decryption. + Before proceeding to the tutorial, make sure you install it by running:: + + pip install simple-crypt +Code +~~~~ +.. literalinclude:: ../examples/tutorials/07_fetch_encrypted.py + :linenos: + +Discussion +~~~~~~~~~~ +.. literalinclude:: ../examples/tutorials/07_fetch_encrypted.py + :lines: 1-14 + :lineno-start: 1 + +In contrast to `6. Store Encrypted Data`_ where we intended to encrypt data, in +this tutorial we will do the reverse, and decrypt data from the Tangle. +Therefore, we need the ``decrypt`` method from ``simplecrypt`` library and the +``b64decode`` method from ``base64`` library. + +Furthermore, ``getpass`` is needed to prompt the user for a decryption +password, and ``json`` for deserializing JSON formatted string into Python +object. + +.. literalinclude:: ../examples/tutorials/07_fetch_encrypted.py + :lines: 16-17 + :lineno-start: 16 +To fetch transactions or bundles from the Tangle, a reference is required to +retreive them from the network. Transactions are identified by their +transaction hash, while a group of transaction (a bundle) by bundle hash. +Hashes ensure the integrity of the Tangle, since they contain verifiable +information on the content of the transfer objects. + +``input()`` asks the user to give the tail transaction hash of the bundle +that holds the encrypted messages. The tail transaction is the first in the +bundle with index 0. Copy and paste the tail transaction hash from the console +output of `6. Store Encrypted Data`_ when prompted. + +.. literalinclude:: ../examples/tutorials/07_fetch_encrypted.py + :lines: 19-21 + :lineno-start: 19 + +Next, we fetch the bundle from the Tangle with the help of the +:py:meth:`~Iota.get_bundles` extended API command. It takes a list of tail +transaction hashes and returns the bundles for each of them. The response +``dict`` contains a ``bundles`` key with the value being a list of bundles +in the same order as the input argument hashes. Also note, that the bundles +in the response are actual PyOTA :py:class:`Bundle` objects. + +To simplify the code, several operations are happening on line 21: + +- Calling :py:meth:`~Iota.get_bundles` that returns a ``dict``, +- accessing the ``'bundles'`` key in the ``dict``, +- and taking the first element of the the list if bundles in the value + associated with the key. + +.. literalinclude:: ../examples/tutorials/07_fetch_encrypted.py + :lines: 23-39 + :lineno-start: 23 + +The next step is to extract the content of the message fields of the +transactions in the bundle. We call :py:meth:`Bundle.get_messages` to carry +out this operation. The method returns a list of unicode strings, essentially +the ``signature_message_fragment`` fields of the transactions, decoded from +trytes into unicode characters. + +We then combine these message chunks into one stream of characters by using +``sting.join()``. + +We know that at this stage that we can't make sense of our message, because it +is encrypted and encoded into `Base64`_. Let's peel that onion layer by layer: + +- On line 28, we decode the message into bytes with ``b64decode``. +- On line 31, we ask the user for a decryption password. +- On line 36, we decrypt the bytes cipher with the password and decode the + result into a unicode string. +- Since we used JSON formatting in the previous tutorial, there is one + additional step to arrive at our original data. On line 39, we deserialize + the JSON string into a Python object, namely a ``dict``. + +.. literalinclude:: ../examples/tutorials/07_fetch_encrypted.py + :lines: 41-42 + :lineno-start: 41 + +If everything went according to plan and the user supplied the right password, +we should see our original data printed out to the console. + +Now you know how to use the Tangle for data storage while keeping privacy. +When you need more granular access control on how and when one could read +data from the Tangle, consider using `Masked Authenticated Messaging`_ (MAM). .. _PyOTA Bug Tracker: https://github.com/iotaledger/iota.py/issues .. _bytestring: https://docs.python.org/3/library/stdtypes.html#bytes @@ -623,4 +724,5 @@ Tangle. .. _Tangle Explorer: https://utils.iota.org .. _Account Module: https://docs.iota.org/docs/client-libraries/0.1/account-module/introduction/overview .. _spending twice from the same address: https://docs.iota.org/docs/getting-started/0.1/clients/addresses#spent-addresses -.. _Base64: https://en.wikipedia.org/wiki/Base64 \ No newline at end of file +.. _Base64: https://en.wikipedia.org/wiki/Base64 +.. _Masked Authenticated Messaging: https://docs.iota.org/docs/client-libraries/0.1/mam/introduction/overview?q=masked%20auth&highlights=author;authent \ No newline at end of file diff --git a/examples/tutorials/07_fetch_decrypted.py b/examples/tutorials/07_fetch_encrypted.py similarity index 87% rename from examples/tutorials/07_fetch_decrypted.py rename to examples/tutorials/07_fetch_encrypted.py index a71cead..9bdad45 100644 --- a/examples/tutorials/07_fetch_decrypted.py +++ b/examples/tutorials/07_fetch_encrypted.py @@ -8,6 +8,8 @@ from base64 import b64decode from getpass import getpass +import json + # Declare an API object api = Iota('https://nodes.devnet.iota.org:443', testnet=True) @@ -18,10 +20,6 @@ # Fetch bundle bundle = api.get_bundles(tail_hash)['bundles'][0] -if not bundle: - print('Found no bundle, exiting...') - exit() - print('Extracting data from bundle...') # Get all messages from the bundle and concatenate them b64_encrypted_data = "".join(bundle.get_messages()) @@ -35,7 +33,10 @@ print('Decrypting data...') # Decrypt data # decrypt returns 'bytes' in Python 3, decode it into string -data = decrypt(password, encrypted_data).decode('utf-8') +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) \ No newline at end of file From 585a453a8a6c623bd77b1bab9bde17eaf565d3b9 Mon Sep 17 00:00:00 2001 From: Levente Pap Date: Fri, 24 Jan 2020 15:28:28 +0100 Subject: [PATCH 4/4] PR review enhancements --- docs/tutorials.rst | 58 ++++++++++++------------ examples/tutorials/06_store_encrypted.py | 11 +++-- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/docs/tutorials.rst b/docs/tutorials.rst index 14a69bb..b46f00e 100644 --- a/docs/tutorials.rst +++ b/docs/tutorials.rst @@ -512,7 +512,6 @@ In this example, you will learn how to: - **Convert Python data structures to JSON format.** - **Encrypt data and include it in a zero-value transaction.** -- **Generate an address with a PyOTA specific utility tool.** - **Store the zero-value transaction with encrypted data on the Tangle.** .. warning:: @@ -530,20 +529,20 @@ Code Discussion ~~~~~~~~~~ .. literalinclude:: ../examples/tutorials/06_store_encrypted.py - :lines: 1-15 + :lines: 1-18 :lineno-start: 1 -The first odd thing we notice among the imports is -:py:class:`~iota.crypto.addresses.AddressGenerator`. It is a PyOTA specific -utility that generates addresses given your seed. - -We will use the ``encrypt`` method to enchiper the data, and ``b64encode`` for +We will use the ``encrypt`` method to encipher the data, and ``b64encode`` for representing it as ASCII characters. ``getpass`` will prompt the user for a password, and the ``json`` library is used for JSON formatting. +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. + .. literalinclude:: ../examples/tutorials/06_store_encrypted.py - :lines: 17-23 - :lineno-start: 17 + :lines: 20-26 + :lineno-start: 20 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. Think of @@ -551,16 +550,16 @@ what would happen if the world's most famous secret agent's identity was leaked on the Tangle... .. literalinclude:: ../examples/tutorials/06_store_encrypted.py - :lines: 25-26 - :lineno-start: 25 + :lines: 28-29 + :lineno-start: 28 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. .. literalinclude:: ../examples/tutorials/06_store_encrypted.py - :lines: 28-37 - :lineno-start: 28 + :lines: 31-40 + :lineno-start: 31 Next, we will encrypt this data with a secret password we obtain from the user. @@ -577,20 +576,18 @@ Therefore, we first encode our binary data into ASCII characters with `Base64`_ encoding. .. literalinclude:: ../examples/tutorials/06_store_encrypted.py - :lines: 39-57 - :lineno-start: 39 + :lines: 42-58 + :lineno-start: 42 Now, we are ready to construct the transfer. We convert the encrypted `Base64`_ encoded data to trytes and assign it to the :py:class:`ProposedTransaction` -object's message argument. +object's ``message`` argument. An address is also needed, so we generate one with the help of -:py:class:`~iota.crypto.addresses.AddressGenerator` and its -:py:meth:`~iota.crypto.addresses.AddressGenerator.get_addresses` method. Feel -free to chose the index of the generated address, and don't forget, that the -method returns a list of addresses, even if it contains only one. Put your seed -(from `4.a Generate Address`_) onto line 44 to generate an address that belongs -to you. For more detailed explanation on how addresses are generated in PyOTA, +:py:meth:`~Iota.get_new_addresses` extended API method. Feel free to choose the +index of the generated address, and don't forget, that the method returns a +``dict`` with a list of addresses, even if it contains only one. +For more detailed explanation on how addresses are generated in PyOTA, refer to the :ref:`Generating Addresses` page. We also attach a custom :py:class:`Tag` to our :py:class:`ProposedTransaction`. @@ -599,8 +596,8 @@ of a transaction, the library would split it accross more transactions that together form the transfer bundle. .. literalinclude:: ../examples/tutorials/06_store_encrypted.py - :lines: 59-65 - :lineno-start: 59 + :lines: 60-66 + :lineno-start: 60 Finally, we use :py:meth:`Iota.send_transfer` to prepare the transfer and send it to the network. @@ -611,8 +608,8 @@ The tail transaction (a tail transaction is the one with index 0 in the bundle) hash is printed on the console, because you will need it in the next tutorial, and anyway, it is a good practice to keep a reference to your transfers. -In the next example, we will try to decode the confidential information from the -Tangle. +In the next example, we will try to decode the confidential information from +the Tangle. 7. Fetch Encrypted Data ----------------------- @@ -658,7 +655,7 @@ To fetch transactions or bundles from the Tangle, a reference is required to retreive them from the network. Transactions are identified by their transaction hash, while a group of transaction (a bundle) by bundle hash. Hashes ensure the integrity of the Tangle, since they contain verifiable -information on the content of the transfer objects. +information about the content of the transfer objects. ``input()`` asks the user to give the tail transaction hash of the bundle that holds the encrypted messages. The tail transaction is the first in the @@ -680,7 +677,7 @@ To simplify the code, several operations are happening on line 21: - Calling :py:meth:`~Iota.get_bundles` that returns a ``dict``, - accessing the ``'bundles'`` key in the ``dict``, -- and taking the first element of the the list if bundles in the value +- and taking the first element of the the list of bundles in the value associated with the key. .. literalinclude:: ../examples/tutorials/07_fetch_encrypted.py @@ -694,13 +691,14 @@ the ``signature_message_fragment`` fields of the transactions, decoded from trytes into unicode characters. We then combine these message chunks into one stream of characters by using -``sting.join()``. +``string.join()``. We know that at this stage that we can't make sense of our message, because it is encrypted and encoded into `Base64`_. Let's peel that onion layer by layer: - On line 28, we decode the message into bytes with ``b64decode``. -- On line 31, we ask the user for a decryption password. +- On line 31, we ask the user for thr decryption password (from the previous + tutorial). - On line 36, we decrypt the bytes cipher with the password and decode the result into a unicode string. - Since we used JSON formatting in the previous tutorial, there is one diff --git a/examples/tutorials/06_store_encrypted.py b/examples/tutorials/06_store_encrypted.py index 2112b39..f4e5d61 100644 --- a/examples/tutorials/06_store_encrypted.py +++ b/examples/tutorials/06_store_encrypted.py @@ -4,7 +4,6 @@ simplecrypt library is needed for this example (`pip install simple-crypt`)! """ from iota import Iota, TryteString, Tag, ProposedTransaction -from iota.crypto.addresses import AddressGenerator from simplecrypt import encrypt from base64 import b64encode from getpass import getpass @@ -12,7 +11,11 @@ import json # Declare an API object -api = Iota('https://nodes.devnet.iota.org:443', testnet=True) +api = Iota( + adapter='https://nodes.devnet.iota.org:443', + seed=b'YOURSEEDFROMTHEPREVIOUSTUTORIAL', + testnet=True, +) # Some confidential information data = { @@ -41,9 +44,7 @@ trytes_encrypted_data = TryteString.from_bytes(b64_cipher) # Generate an address from your seed to post the transfer to -my_address = AddressGenerator(b'YOURSEEDFROMTHEPREVIOUSTUTORIAL').get_addresses( - start=42, -)[0] +my_address = api.get_new_addresses(index=42)['addresses'][0] # Tag is optional here my_tag = Tag(b'CONFIDENTIALINFORMATION')