In IOTA, addresses are generated deterministically from seeds. This ensures that your account can be accessed from any location, as long as you have the seed.
Note that this also means that anyone with access to your seed can spend your iotas! Treat your seed(s) the same as you would the password for any other financial service.
PyOTA’s crytpo functionality is currently very slow; on average it takes 8-10 seconds to generate each address.
These performance issues will be fixed in a future version of the library; please bear with us!
In the meantime, you can install a C extension that boosts PyOTA’s performance significantly (speedups of 60x are common!).
To install the extension, run
pip install pyota[ccurl].
The following process takes place when you generate addresses in IOTA:
First, a sub-seed is derived from your seed by adding
indexto it, and hashing it once with the Kerl hash function.
Then the sub-seed is absorbed and squeezed in a sponge function 27 times for each security level. The result is a private key that varies in length depending on security level.
A private key with
security_level = 1consists of 2187 trytes, which is exactly 27 x 81 trytes. As the security level increases, so does the length of the private key: 2 x 2187 trytes for
security_level = 2, and 3 x 2187 trytes for
security_level = 3.
A private key is split into 81-tryte segments, and these segments are hashed 26 times. A group of 27 hashed segments is called a key fragment. Observe, that a private key has one key fragment for each security level.
Each key fragment is hashed once more to generate key digests, that are combined and hashed once more to get the 81-tryte address.
An address is the public key pair of the corresponding private key. When you spend iotas from an address, you need to sign the transaction with a key digest that was generated from the address’s corresponing private key. This way you prove that you own the funds on that address.
PyOTA provides two methods for generating addresses:
Using the API¶
from iota import Iota api = Iota('http://localhost:14265', b'SEED9GOES9HERE') # Generate 5 addresses, starting with index 0. gna_result = api.get_new_addresses(count=5) # Result is a dict that contains a list of addresses. addresses = gna_result['addresses'] # Generate 1 address, starting with index 42: gna_result = api.get_new_addresses(index=42) addresses = gna_result['addresses'] # Find the first unused address, starting with index 86: gna_result = api.get_new_addresses(index=86, count=None) addresses = gna_result['addresses']
To generate addresses using the API, invoke its
method, using the following parameters:
index: int: The starting index (defaults to 0). This can be used to skip over addresses that have already been generated.
count: Optional[int]: The number of addresses to generate (defaults to 1).
None, the API will generate addresses until it finds one that has not been used (has no transactions associated with it on the Tangle and was never spent from). It will then return the unused address and discard the rest.
security_level: int: Determines the security level of the generated addresses. See Security Levels below.
Depending on the
Iota.get_new_addresses() can be
operated in two modes.
countis greater than 0, the API generates
countnumber of addresses starting from
index. It does not check the Tangle if addresses were used or spent from before.
None, the API starts generating addresses starting from
index. Then, for each generated address, it checks the Tangle if the address has any transactions associated with it, or if the address was ever spent from. If both of the former checks return “no”, address generation stops and the address is returned (a new address is found).
Take care when using the online mode after a snapshot. Transactions referencing a generated address may have been pruned from a node’s ledger, therefore the API could return an already-used address as “new” (note: The snapshot has no effect on the “was ever spent from” check).
To make your application more robust to handle snapshots, it is recommended
that you keep a local database with at least the indices of your used addresses.
After a snapshot, you could specify
index parameter as the last
index in your local used addresses database, and keep on generating truly
PyOTA is planned to receive the account module in the future, that makes the library stateful and hence would solve the issue mentioned above.
from iota.crypto.addresses import AddressGenerator generator = AddressGenerator(b'SEED9GOES9HERE') # Generate a list of addresses: addresses = generator.get_addresses(start=0, count=5) # Generate a list of addresses in reverse order: addresses = generator.get_addresses(start=42, count=10, step=-1) # Create an iterator, advancing 5 indices each iteration. iterator = generator.create_iterator(start=86, step=5) for address in iterator: ...
If you want more control over how addresses are generated, you can use
AddressGenerator can create iterators, allowing your application to
generate addresses as needed, instead of having to generate lots of
addresses up front.
You can also specify an optional
step parameter, which allows you to
skip over multiple addresses between iterations… or even iterate over
addresses in reverse order!
AddressGenerator(seed: Union[AnyStr, bytearray, TryteString], security_level: int = 2, checksum: bool = False)¶
Generates new addresses using a standard algorithm.
This class does not check if addresses have already been used; if you want to exclude used addresses, invoke
Note also that
AddressGeneratorinternally, so you get the best of both worlds when you use the API (:
seed (TrytesCompatible) – The seed to derive addresses from.
security_level (int) –
When generating a new address, you can specify a security level for it. The security level of an address affects how long the private key is, how secure a spent address is against brute-force attacks, and how many transactions are needed to contain the signature.
Could be either 1, 2 or 3.
checksum (bool) – Whether to generate address with or without checksum.
get_addresses(start: int, count: int = 1, step: int = 1) → List[iota.types.Address]¶
Generates and returns one or more addresses at the specified index(es).
This is a one-time operation; if you want to create lots of addresses across multiple contexts, consider invoking
create_iterator()and sharing the resulting generator object instead.
This method may take awhile to run if the starting index and/or the number of requested addresses is a large number!
start (int) – Starting index. Must be >= 0.
count (int) – Number of addresses to generate. Must be > 0.
step (int) – Number of indexes to advance after each address. This may be any non-zero (positive or negative) integer.
Always returns a list, even if only one address is generated.
The returned list will contain
countaddresses, except when
step * count < start(only applies when
countis lower than 1.
create_iterator(start: int = 0, step: int = 1) → Generator[iota.types.Address, None, None]¶
Creates an iterator that can be used to progressively generate new addresses.
Returns an iterator that will create addresses endlessly. Use this if you have a feature that needs to generate addresses “on demand”.
start (int) –
This method may take awhile to reset if
startis a large number!
step (int) –
Number of indexes to advance after each address.
The generator may take awhile to advance between iterations if
stepis a large number!
Generator[Address, None, None]object that you can iterate to generate addresses.
gna_result = api.get_new_addresses(security_level=3) generator =\ AddressGenerator( seed = b'SEED9GOES9HERE', security_level = 3, )
If desired, you may change the number of iterations that
iota.Iota.get_new_addresses uses internally when generating new
addresses, by specifying a different
security_level when creating a new
security_level should be between 1 and 3, inclusive. Values outside
this range are not supported by the IOTA protocol.
Use the following guide when deciding which security level to use:
security_level=1: Least secure, but generates addresses the fastest.
security_level=2: Default; good compromise between speed and security.
security_level=3: Most secure; results in longer signatures in transactions.