Generate Bitcoin HD Wallet Addresses Using libbitcoit-system with Boost in C++ in Linux

This is my very small but challenging (for me) pet project that can be named “Hello bitcoin World!” that I made in a day having no prior knowledge about it from a programming point of view. It is not related to Unreal Engine.

Idea: Create a C++ function that generates a hierarchical deterministic wallet (HD Wallet) addresses using seed, master key and private key, down the hierarchy the levels defined in BIP 44 standard, in Linux using libbitcoin-system (Bitcoin development library) with Boost.

For those who are familiar with the topic, there is very likely nothing new to learn from my beginner experience. Anyways, for the curious ones, here I go ๐Ÿ™‚

My little zoo setup

  • Windows 10 v.22H2 (with the latest updates installed)
  • WSL2 (allows to run a Linux environment on your Windows machine)
  • Ubuntu 22.04
  • g++ v.11.4
  • LIBBITCOIN_SYSTEM_VERSION “3.8.0”, Boost : 1.73.0 (installation guide)

The Code

github

// Copyright DevRespawn.com (MBCG). All Rights Reserved.

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

/*
* Generates addresses for hierarchical deterministic wallet (or "HD Wallet")
* @index Sequential index to generate child keys
*/
std::pair<std::string, std::string> gen_address(uint32_t index) 
{
    using namespace bc;

    // Seed phrase (mnemonic)
    std::string seed_phrase = "one two one two one two ...";

    // Convert mnemonic to seed 
    auto seed = wallet::decode_mnemonic(split(seed_phrase));

    // Derivation of master private key hd_master_key
    data_chunk seed_chunk(to_chunk(seed));
    wallet::hd_private m(seed_chunk, wallet::hd_private::mainnet);
    std::cout << "HD master private key (m) == " << m << '\n';
    
    // Derivation of master public key M
    wallet::hd_public M = m.to_public();
    std::cout << "HD master public key (M) == " << M << '\n';

    // Derive children of master key m (BIP-44 path: "m/44'/0'/0'/0/0). Six levels total, from the 6th level child keys are generated by sequential index
    // note: wallet::hd_first_hardened_key can be used for creating hardened keys (for purpose, coin and account levels)
    auto m0 = m.derive_private(44);               // Level 2. Purpose code: 44 is for BIP-0044
    auto m10 = m0.derive_private(0);              // Level 3, Index 0. Coin type: 0 is for Bitcoun (see SLIP-0044)
    auto m100 = m10.derive_private(0);            // Level 4, Index 0. Account: 0 is for the account with index == 0
    auto m1000 = m100.derive_private(0);          // Level 5, Index 0. Change addresses: 0 is for external chain, 1 is for internal (change) chain
    auto child_key = m1000.derive_private(index); // Level 6, Index 0. Index of address specified in "change addresses" (child key)

    // Derive hd_public of any hd_private object of same level & index
    auto M0 = m0.to_public();
    auto M10 = m10.to_public();
    auto M100 = m100.to_public();
    auto M1000 = m1000.to_public();

    // Get the public key
    wallet::hd_public child_public = child_key.to_public();
    wallet::ec_public ec_pub(child_public.point());

    // Generate payment address
    wallet::payment_address pay_addr(ec_pub);

    // Payment address and WIF private key
    std::string wif_key = child_key.encoded();

    return {pay_addr.encoded(), wif_key};
}

void test_gen_address(uint32_t index)
{
    std::string title = "Generating addresses in HD wallet for index == "  +  std::to_string(index); 
    std::cout << "**** " << title << '\n';
    auto result = gen_address(index);
    std::cout << "Address: " << result.first << '\n';
    std::cout << "WIF: " << result.second << '\n';
    std::cout << "**** End of " << title << '\n';
}

int main() 
{
    test_gen_address(0);
    test_gen_address(1);
    return 0;
}

Output

Links for the curious ones

If you’re a beginner in the Bitcoin space, like I am, the following links might be as helpful for you as they were for me ๐Ÿ™‚