In this post we will be going over Algorand wallet security and wallet and account interaction. Specifically we will be looking at the steps and mechanisms involved in:
- Generating a wallet
- Generating accounts in the wallet
- Generating accounts outside of the wallet and importing them into the wallet
- Backing up a wallet
- Backing up a specific account that is within a wallet
- Recovering a wallet
- Recovering accounts that were generated within a wallet
- Importing multi-signature accounts into a wallet
Please make sure you have an Algorand TestNet node running and make sure that you start the kmd process.
goal kmd start -d [DATA DIR]
Also, please make sure you have the Python SDK installed.
Developers (and crypto users in general) typically think of crypto addresses as some identifier of fixed or arbitrary length that has a corresponding secret key that you use to trigger spending functions from an address. Developers (and the general crypto audience, again) are also likely familiar with the concept of mnemonic phrases that are used as a fail-safe to recover an address (or more specifically, to recover access to funds that are associated with an address) if access to a crypto address is restricted, lost or compromised. For an in-depth security tutorial please read these great series of posts by Sharon Halevi.
What is an Address / Account?
Algorand addresses are unique identifiers for public keys. This applies to single pubkeys where there is only one pubkey involved, as well to multisignature addresses where there exists a series of pubkeys. These pubkeys and their corresponding private keys use Ed25519 high-speed, high-security elliptic-curve signatures- which is the EdDSA signature scheme that using SHA-512 and Curve25519. There is no intention to take a deep dive into the world of cryptography with this post, but just so there is point of relation- Bitcoin uses ECDSA signature scheme.
Ed25519 is interesting because unlike ECDSA signatures, this scheme uses something called foolproof session keys which are signatures that are generated deterministically. This accomplishes pseudorandomness by hashing a long-term secret key together with the input message. The benefit here is that it circumvents the risk of leaking private keys due to a faulty random number generator, which is an inherent risk in the ECDSA signature scheme.
An address wraps an Ed25519 public key, which is a 32-byte array and the string representation is computed by appending a 4-byte checksum (computed by taking the last 4 bytes of a SHA512/256 digest of the public key) to the public key, giving us a 36-byte array.
Algorand addresses are often [erroneously] referred to as public keys. Keep this in mind if you are a developer because you do need to be aware of this distinction.
The term account and address seem to be used interchangeably as there is only so much you can do with enforcing vocabulary, but an Algorand account is technically an address on the blockchain that has specific onchain data associated with it. Most basically, this is a minimum balance (of 0.1 Algos (100,000 microalgos)) and other more intricate properties like whether or not the account is online and/or has earned rewards. Accounts can be generated offline and the network will not know of their existence until they have a minimum balance.
What is a Wallet?
Wallets on the Algorand network are generated using a process called key management daemon (kmd). Wallets store a collection of accounts. The kmd process stores a collection of wallets and manages the interaction of the accounts within the wallets. Accounts/Addresses can be generated inside of the wallet and non-kmd generated accounts can be imported into a kmd wallet. In the previous sentence I said “accounts/addresses” because the addresses don’t need to have a minimum balance (the network does not need to know about them) to be managed or housed inside of a kmd wallet.
The caveat with this functionality is that if a kmd wallet is restored (instantiated on another device), those non-kmd generated accounts need to be imported again and not simply generated.
To restore a kmd wallet you need the master derivation key (mdk) of the wallet and subsequently, you need the mnemonic that can be extracted from the mdk.
Once the wallet mnemonic is retrieved, you can use the
mnemonic.to_master_derivation_key() method to extract the mdk and run
create_wallet() using kmd to instantiate your wallet. The reason why the code is showing you how to extract the mnemonic from the mdk and then extract the mdk back from the mnemonic is that for security and practical purposes, the mnemonic is what users of wallets utilize as a backup.
Now let’s take a look at how to import a standalone account into a kmd wallet. In the following code snippet, we loop through all the wallets that are part of your kmd instance using
list_wallets() to expose the wallets metadata and select whichever wallet you are looking for by changing the string it’s being matched against.
if arrayitem.get("name") == "wallet1":
walletid = arrayitem.get("id")
We, again, run
account.generate_account() as we did in the first code snippet and import the account by passing in the
wallethandle into the
One of the most important wallet parameters you will need to work with kmd is the
wallethandle. So once you loop through your wallets and find the kmd wallet you are interested in interacting with, part of the metadata of the wallet includes the
walletid is what needs to be passed into
init_wallet_handle() to extract the kmd
walletid = None
wallets = kcl.list_wallets()
for arrayitem in wallets:
if arrayitem.get("name") == "wallet1":
walletid = arrayitem.get("id")
print("Wallet ID:", walletid)
wallethandle = kcl.init_wallet_handle(walletid, "testpassword")
print("Wallet Handle:", wallethandle)
This wallet handle is then passed into methods like
import_key() for importing stand-alone accounts:
importedaccount = kcl.import_key(wallethandle, private_key)
generate_key() to generate a kmd-based account
address = kcl.generate_key(wallethandle)
as well as importing multsignature accounts with
imported_multisig = kcl.import_multisig(wallethandle, msig)
and finally, one that we’ve seen a few times now
list_keys() to list out the accounts that are a part of the kmd wallet
accounts = kcl.list_keys(wallethandle)
The final piece of code I wanted to demonstrate before we sign off is backing up a kmd-account. And that is done by 1) initing the wallet to extract the
wallethandle 2) exporting the private_key from the account using
export_key() and 3) deriving the mnemonic back up phrase from the private_key using
All of these code samples can be found on github and with these examples you should have a solid foundation to build on with kmd.
Thanks for the read!
We’re doing a lot of exciting development here at Algorand and building a developer community is top priority for us. If you have any questions, please feel free to reach out to me firstname.lastname@example.org or post a question in the forums.
We are working very hard to get a new developer documentation website up and running to account for our new features that were released in Q4 of 2019. So stay tuned for that and start building!