Wallets play a pivotal role in the world of cryptocurrencies and blockchain. The importance of wallets cannot be underplayed in any blockchain solution, more so with public blockchains. The whole crypto-economy is based on the availability of wallets for investors / users.

Both investors as well as developers face the challenge of choosing a good crypto wallet. Software developers face this challenge because many solutions host wallets for their investors / users.

Security should be the prime concern when it comes to choosing wallets. However, security itself is a complex subject and never guaranteed. It is an expert’s domain. In this light, it becomes very important to understand; what to look for in a wallet and supplement this knowledge with reviews and documentation provided by wallet providers to decide which wallet to choose.

This post attempts to bring forth some of the important aspects that one must look for while choosing wallets. These aspects are important regardless of whether you choose a cold wallet or a hot wallet. The article then dives deeper into the technical details of how these features / aspects are implemented by wallets. They follow a certain set of standards, which are explained below.

Finally a small list of wallets that support these standards in mentioned in the Conclusion section. This article is not an endorsement of any of the listed wallets.

Interoperability, recoverability, security

Multi-currency, multi-account

Hierarchical deterministic wallets

Hardened v/s Normal keys

Mnemonic codes seeded wallets

Technical details

BIP-39

Mnemonic codes from random number

Seed from mnemonic codes

Private, Public keys from Seed

BIP-32

BIP-43 and BIP-44

Conclusion

Interoperability, recoverability, security

If a wallet is found unsuitable, it must be possible to switch to another wallet, without having to create new addresses / accounts. Transferring coins / tokens to new addresses cost crypto-currency. This is important because security cannot be guaranteed by any wallet. Even if usability is poor, a user may want to switch the wallet software. Therefore interoperability is important.

Many bitcoins and ethers have been lost for ever, because users have lost their private keys. It is a huge loss so far. Therefore, being able to recover from the loss of a file or mobile phone or hard disk or merely accidental uninstall of software is very important. Recovery must be guaranteed.

A good source of randomness is very important in cryptography. Security depends up on it. A seeded wallet (described later in the article) must have a good source of randomness. Sometimes a good source of randomness is considered from quantum / thermal processes or radio noise etc. However, it is mostly infeasible to have such wallets and therefore a cryptographically secure pseudo random number generator must be used by the wallet. One of my earlier article helps in understanding these concepts of security.

Multi-currency, multi-account

Having to maintain multiple wallets for different blockchains will not only get annoying, it can even be less secure. Extending the scope of one’s study and keeping abreast with all the latest developments regarding those wallets is a tedious task. It takes away time and energy. Having a multi-currency, multi-account wallet saves that time on an ongoing basis. There may be a news update about a particular breach / loop-hole in a wallet. There may even be a software update that could be missed. Hence, it is always better to have a multi purpose wallet, which can be used on different blockchains.

BIP-43, BIP-44 are regarded as a gold standard for multi-currency, multi-account wallets. At the time of writing, slightly over 600 different currencies / coins are registered on BIP-44. The link below has the complete list:

https://github.com/satoshilabs/slips/blob/master/slip-0044.md

A snippet of what you find in the link is pasted above.

Technical details of BIP-43 and BIP-44 are covered later on in this article.

If a wallet is BIP-44 compliant, it does not mean that it supports all the coins / currencies mentioned in the list above. To be able to create a transaction on a blockchain, the wallet needs to support the particular blockchain’s protocol. Always check for which currencies are supported by the wallet rather than relying on the list above.

Hierarchical deterministic wallets

Private keys for the coins / accounts must not be lost. If they are lost, the coins are lost for ever. These private keys can be used to generate public keys, and from them the addresses of accounts and coins on different blockchains. It is advised and considered a best practice, that every transaction must use a separate address. This quickly leads to a situation where users have to manage / maintain a huge number of keys. In “old times”, not so long ago really, wallets used to generate random keys, and it led to a situation, where there were too many keys that users had to manage (take backups, make the backups secure etc..). This kind of wallet is now-a-days called JBOK wallet (Just a Bunch Of Keys). It is no longer advised to use such wallets.

Thankfully, there are hierarchical deterministic wallets, which allow for generating child keys from a parent key. This is done deterministically, which means there is no randomness in this process. Hence, the user has to manage only one master key. From this master key, child keys can be generated. In this case the master key becomes the parent. The generated child keys can in turn be used as parent keys to generate the “grand-children” keys and so on. A key-tree is thus formed from the master key. It could be argued that if the master key is compromised, all the child keys are also compromised. It is a question of judgement how many master keys one wants to hold and secure. High value accounts could be kept off line in cold / hardware wallets. While some low value, regular usage keys can be kept on hot wallets.

BIP-32 is widely regarded as a standard for hierarchical deterministic wallets. Wallets that support BIP-32 standard, allow creating more than 4 billion child keys (2^32 child keys) from 1 parent key. To make it harder for an attacker, along with the private / public key a chain code is needed to generate child keys. The technical details are discussed later on in this article.

Further each child can act as a parent, and generate 4 billion more child keys. Therefore it is unlikely that an investor will run out of private keys if the investor’s wallet follows the BIP-32 standard.

Out of the 4 billion child keys, half (2^31 child keys) are “hardened keys”, while the rest are “normal keys”.

Hardened v/s Normal keys

In most cases, hardened keys are better suited, as they provide additional security. However, there is a specific use case where using normal keys is far better.

BIP-32 provides a mechanism to generate public keys from a “parent public key” and a “chain code”. There is no need to have the private key for this. This is applicable only for normal keys and not for hardened keys. In the following use-case, this feature is exploited to keep the private keys secured by actually not generating them at all!

For a website to receive payments in crypto-currencies, an address needs to be generated for every transaction. For generating new addresses, all one needs is new public keys. With the feature described above, new public keys are generated on the web server, and no private key is ever needed to be available to the web server.

As the web server allows incoming traffic from the internet, it is prone to attacks, and hence it is better to use the normal child public keys generated this way, than to risk generating private keys on such servers. When the acquired coins need to be spent, the corresponding private keys can be generated on a “safe” service (possibly disconnected from the internet). This could be a hardware wallet which is used to sign the transactions provided it follows the BIP-32 “standard”.

The use-case described above warrants a separate article on what should be the architecture of such a system and how it can be achieved.

Mnemonic codes seeded wallets

Humans are at best incapable of coming up with secure passwords. When it comes to generating keys from such passwords, wallets must not rely on human intelligence. Instead wallets must use Cryptographically Secure Pseudo Random Number Generators (CSPRNG) and supplement it with such passwords or passphrase.

There is a way to generate private and public keys from a set of English words (for that matter other languages as well). The BIP-39 proposes how to generate such human readable words from a source of entropy like CSPRNG. Further a bit of math and algorithm is applied (described below in detail) and a private key is generated. If these words are stored securely (safely written on a piece of paper, and stored in a locker), the wallet can generate the same key from these words. This can become a master key for the hierarchical deterministic wallets.

The advantage of this wallet is that the source of entropy (randomness) is not humans, and yet it provides a good way to capture the keys in a format that humans can easily understand and store securely.

Technical details

BIP-39

This is a Bitcoin Improvement Proposal which suggests how to implement mnemonic codes seeded wallet from 12 to 24 human language words. Although a Bitcoin Improvement Proposal, it is used for almost all the blockchains (that rely upon Elliptic Curve Cryptography), even Ethereum.

BIP-39 proposal is explained below in simpler terms. First we will look at generating mnemonic codes (12 to 24 words), and then generating the seed from which the master private key is derived. A good source of randomness is needed, and we assume it is CSPRNG (which is true in most wallets).

For those keen to see an implementation: mnemonic.cpp. The link points to the source code provided with the libbitcoin’s GitHub repository. To see what is happening here, simply see the function create_mnemonic. If you are more comfortable with python, this link (mnemonic.py) by Trezor is also a good reference. Look for the function to_mnemonic.

Mnemonic codes from random number

For the purpose of making it easy to understand, let us assume that we use CSPRNG to generate a 128 bit random number. Also, let us assume we prefer English language words.

Treat the random data as an integer (128 bits). check_bits: Divide this random number by 32 to get a the checksum concatenate the random integer (128 bits) with check_bits (4 bits) final number is 132 bits from step 3. split up the 132 bits, such that each split unit is 11 bits long we have 132/11 = 12 such split units. Each unit represents a word. Therefore we have 12 words from above. at the index of each 11 bit number, find the word from this wordlist.

Thus we get 12 different words which represent a 132 bit number. This 132 bit number was generated using a CSPRNG. The last 4 bits (the checksum) can be used for validation.

Seed from mnemonic codes

So far so good, we generated human recognisable words from a cryptographically secure extremely large random number. We are able to do this deterministically. Now let’s generate a private key.

To generate a private key, we first “stretch” the word list from above. Stretching is nothing but hashing the bytes multiple times. The number of times it gets hashed is 2048 according to BIP-39. The hashing function is HMAC-SHA512. This generates a 512 bit number. This is the seed for private keys.

The PBKDF2 function is used for stretching. To understand what it does, one can refer to my earlier article Wallets: Securing storage. See the section Key derivation from password / passphrase, it has the explanation of what the PBKDF2 does.

Criticism

BIP-39 has its own share of criticism. Electrum one of the popular wallet has deviated from BIP-39 mnemonic codes. It argues that there are shortcomings in the BIP-39 and has gone ahead with its seed generation called the Electrum Seed Version System. A user of the Electrum 2.0 wallet will have to look for compatible wallets of that system (for the purpose of interoperability).

Private, Public keys from Seed

To get the private key, which gets used as the root key / master key in the Hierarchical Deterministic wallets, the wallet needs to further run the following algorithm:

Hash the seed with HMAC-SHA512 algorithm using “Bitcoin seed” as the salt. Private key = Take the most significant 256 bits (32 bytes) use ECC to generate public key from the private key.

For those keen to see an implementation: hd_private.cpp. See the function hd_private::from_seed , and proceed with your investigation from there.

BIP-32

The BIP-32 proposal advices how hierarchical deterministic wallets must be implemented. As described earlier, a master key is needed to generate the key-tree. Thus the master key is the root parent key. Each child can in turn be a parent to other child keys. Along with the master key, a chain code is needed to further generate child keys. For this, the seed generated in the section above is used as follows:

Hash the seed with HMAC-SHA512 algorithm using “Bitcoin seed” as the salt. Private key = Take the most significant 256 bits (32 bytes) Chain code = Take the least significant 256 bits (32 bytes) These two together are called extended private key.

The extended private key when base58encoded, has “xprv” as its prefix, as an example see below:

Mnemonic codes : mutual embark path sweet subway skull exchange grunt skill aspect bright farm cradle replace vital BIP-39 seed : 891245fb10987aed5768097c2264e81479ffe8f85756f912d1efd929a0734a55a772a4af7efe79ee3dca5dd16e0d11397d580582a01028f636a2d1c0cc243097 BIP-32 extended master private key : xprv 9s21ZrQH143K2cZ2ioEWq7L2zNfUdcXQKHLD9F6qcP4xzynRcsEWK7EPn1W9Awa2qcpTvwgCcw4TTVA6jKHF8697GKzfuydH7qP3RHzYyNC

To derive child keys, the child key derivation function needs the parent key, parent chain code and the child_index between 0 to 4294967295 (2^32 – 1). If the index is greater than 2147483647 (2^31 – 1), then it is considered as a hardened key. The algorithm to generate private child keys is as follows:

Check whether i ≥ 231 (whether the child is a hardened key). If so (hardened child): let I = HMAC-SHA512(Key = c par , Data = 0x00 || ser 256 (k par ) || ser 32 (i)). (Note: The 0x00 pads the private key to make it 33 bytes long.) If not (normal child): let I = HMAC-SHA512(Key = c par , Data = ser P (point(k par )) || ser 32 (i)). Split I into two 32-byte sequences, I L and I R . The returned child key k i is parse 256 (I L ) + k par (mod n). The returned chain code c i is I R . In case parse 256 (I L ) ≥ n or k i = 0, the resulting key is invalid, and one should proceed with the next value for i. (Note: this has probability lower than 1 in 2127.)

The above steps are copied directly from BIP-32 proposal, as it is already explaining what the algorithm is. A small thing to note is that in Step 3, the addition is not the usual mathematical addition we are used to. This is a special kind of addition in accordance with Elliptical Curve Cryptography. A similar algorithm for deriving normal public keys from parent public key, chain code and index is provided in the proposal. Also, for those who want to see a sample implementation: hd_private.cpp see the function hd_private::derive_private

A huge number of keys may be generated by a hierarchical deterministic wallet. To regenerate private keys there must be a way to express, which key needs to be generated again. To denote which key needs to be generated / derived, a standard notation like a path is agreed upon, it looks similar to:

m/35'/43'/765 (just an unrealistic sample to explain) From the master extended key derive the child at index 2^31+35 (hardened key) From generated extended key derive the child at index 2^31+43 (hardened key) From generated extended key derive the child at index 765 (normal key)

BIP-43 and BIP-44

The BIP-43 proposal advices on having a ‘purpose’ in the path of the BIP-32 hierarchy. This purpose field is used by BIP-44 as 44′. This means that the child of master key with index 44′ (2^31 + 44) will enable multi-currency, multi-account wallets as per the BIP-44 proposal.

A real looking path, for the mnemonic and seed shown in the above example:

BIP-44 path : m/44'/0'/0'/0/0 private key : L2L1y9hR8XywZY4ExQkVmUJNS2ixouDTTbfo9atgiTz3jGDGYdDN public key : 02001c0137c4dac2dfc346ccd2f60022616dcd32d36cc78771cb8e014f1118b95a address : 1E3XFS1qXw8YDPzoVNVy7HzjTwZCbf2ce2

The BIP-44 defines 5 levels in the path. We will look at the definition and decipher what the path in the above example is about.

m / purpose’ / coin_type’ / account’ / change / address_index

In the example above m/44’/…. indicates that this follows the BIP-44 recommendation of key hierarchy. The coin_type’ is 0′ (2^31), this means it is Bitcoin. The account’ is 0′, the first account. The change is 0 (normal, not hardened). This level in the path can only have either 0 or 1. 1 indicates that in UTXO based blockchains like Bitcoin, it is the change that the spender wants to collect back in a transaction. For account based systems, like Ethereum, this would always be 0. The address_index is 0 which means it is the first address. It is recommended that a new address is generated for each transaction on public blockchains, otherwise it compromises anonymity.

Conclusion

As with most security products, it is better to rely upon standards. There are many wallets that support these standards. These are some of the wallets that support the mentioned standards: Jaxx, MetaMask, MyCrypto, MyEtherWallet, Keepkey, Ledger and Trezor. This article is not a guarantee or a review of any of the wallets described here. However, the information is based on what has been collected from a book Mastering Ethereum, GitHub (source code and BIPs) and the internet.