Libbitcoin: Interactive HD Keychain Part 1/2

HD Keychain.

So, now that we’ve looked into how HD keys are used, I’ve decided to put together a proper HD keychain program that will allow a user to manage Hierarchical Deterministic keys from the command line.

The program I build is going to have the following features:

• Allow the user to generate a new wallet from entropy
• Allow the user to import a wallet from its mnemonic seed
• Allow the user to display:

o The mnemonic
o The master private key
o Its children’s private keys
o a child Address
o a range of child addresses
o All keys at once

This program is not going to support building and signing transactions and it won’t be connected to the blockchain and therefore will not be able to check balances. Thus, this program is technically a keychain rather than a wallet.

So, to implement this wallet I am going to create an HD_Wallet class to hold all the functionality and in a separate driver file I will have functions that handle interfacing with the user.

To start I am going to fire up sublime, create a file named HD_Wallet.cpp and include my necessary headers.

	#include <bitcoin/bitcoin.hpp>
	#include <string.h>
	#include <iostream>

	using namespace bc;

After, I’m going to create a class called HD_Wallet and declare 2 constructor functions, one to create an object from entropy and another to create an object from a mnemonic seed. Additionally, I’m going to need to declare variables for the necessary keys as private members of the class. So, my class skeleton is going to look like this.


class HD_Wallet
{
public:

	//constructor
	HD_Wallet(const data_chunk Userentropy)
	{
		
	}

	HD_Wallet(const wallet::word_list mnemonicSeed)
	{

	}
private:
	//members
	data_chunk entropy;
	data_chunk seed;
	wallet::word_list mnemonic;
	wallet::hd_private privateKey;
	wallet::hd_public publicKey;


};

Now that I have the basics of this object I need to fill out the constructor function, starting with the constructor from entropy. First I’m going to take the entropy argument, which should be 16 byte (64-bit) datachunk, and store it in the classes entropy member. Next, I need to set the mnemonic member by using libbitcoin’s create_mnemonic function and passing it the entropy variable. Once I have the mnemonic, I can create the wallets seed by using the decode_mnemonic function and storing the returned hash in the seed variable. From there, I just need to set the master private key and public key using the libbitcoin objects we saw in my previous post.

Here’s how my first constructor looks:


HD_Wallet(const data_chunk Userentropy)
{
	entropy = Userentropy;
	mnemonic = wallet::create_mnemonic(entropy);
	seed = to_chunk(wallet::decode_mnemonic(mnemonic));		
    privateKey = wallet::hd_private(seed);
	publicKey = privateKey.to_public();
}

Mnemonics

Mnemonics are a human readable way to represent a wallets seed. Our HD wallet is created by using a pseudo-random number generator to create 64 bits of random data which is then hashed using a specialized HMAC512 function which is then used as the seed for creating the private/public key pair.

The encode_mnemonics function in the libbitcoin framework takes the 128 bits of entropy and, using a specialized word list, encodes it as a series of words, where every 3 words represents 32 bits of data. Our 128 bits of data is then represented by 12 words which the user can write down and store somewhere physically.

The decode_mnemonics function then takes a mnemonic as an argument and returns it’s hashed 512 bit seed. Note that the decode function will not return the original 128 bits of data that was encoded to create the seed as the seed already represents this data in the form of words rather than hexadecimal encoding.

The hashed 512 bit seed can then be passed to an HD_private constructor to generate a wallet’s private key.

Thus, in order to make my mnemonic constructor function for importing a wallet we are going to need to pass a mnemonic word_list as an argument to the function. From there I need to use the decode function to get the hashed seed and cast that seed as a data chunk type before storing it in the seed variable. Once I have the seed, I can just save the mnemonic in the proper variable and use the private / public key constructors with the data_chunk seed. The import wallet constructor should look like this.


HD_Wallet(const wallet::word_list mnemonicSeed)
{
	seed = to_chunk(wallet::decode_mnemonic(mnemonicSeed));
	mnemonic = mnemonicSeed;
	privateKey = wallet::hd_private(seed);
	publicKey = privateKey.to_public();


}

Child Keys

Now that I’ve built the constructor functions I am going to need to make the accessor functions in order to allow my user to access child keys and addresses of the wallet. In order to do this I simply need to use the member functions of the libbitcoin objects I went over in my previous post. Notice that I allow the user to pass the index of the desired child key pair they want. Here’s how my accessors ended up looking:


	wallet::hd_private childPrivateKey(int index)
	{
		return privateKey.derive_private(index);
	}

	wallet::hd_public childPublicKey(int index)
	{
		return publicKey.derive_public(index);
	}

	wallet::payment_address childAddress(int index)
	{
		return wallet::ec_public(childPublicKey(index).point()).to_payment_address();
	}

Display

Now I’m going to create the display functions to output the keys. Since the accessor functions I wrote return libbitcoin’s specialized objects, I can easily access a string encoded version of the key by accessing the serializer functions through the accessor in my custom class. For the child keys, I also pass an index variable and create a separate function to display a range of child addresses by creating a loop to call the display function with different indices.

Here’s how my display functions look:

	void displayPrivateKey()
	{
		std::cout << "\nPrivate Key:" << privateKey.encoded() << std::endl;
	}

	void displayChildPrivateKey(int index)
	{
		std::cout << "\nChild Key: " << childPrivateKey(index).encoded() << std::endl;
	}

	void displayAddress(int index)
	{
		std::cout << "\nAddress: " << childAddress(index).encoded() << std::endl;
	}

	void addressRange(int start, int end)
	{
		while(start != end)
		{
			displayAddress(start);
			start++;
		}
	}

Finally, I just need to add a function to display the mnemonic seed. To do this, I’m going to first use and if statement to validate the mnemonic and then cast the word_list variable as a string using the join function. From there I can just use the standard cout function to display it.


	void displayMnemonic()
	{
		if(wallet::validate_mnemonic(mnemonic))
		{
			std::string mnemonicString = join(mnemonic);
			std::cout << "\n" << mnemonicString << std::endl;

		}else{
			std::cout << "mnemonic invalid!" << std::endl;
		}
	}

Now that I have all the display functions I can create a function to display all the keys by simply calling all of the functions I’ve just created, like so:


void dumpKeys()
{
	displayMnemonic();
	displayPrivateKey();
	displayChildPrivateKey(1);
	displayAddress(1);

}

With that, I’ve created my entire HD wallet keychain class. In part 2 of this post I will be creating the command line interface to use this object. As always the full code to this tutorial can be found at https://github.com/AaronJaramillo/LibbitcoinTutorial

Leave a Reply

Your email address will not be published.