Last active
August 7, 2018 19:10
-
-
Save JBaczuk/02ccba7778cfb92e36842591ee48003f to your computer and use it in GitHub Desktop.
libbitcoin Wallet Example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <bitcoin/bitcoin.hpp> | |
#include <string.h> | |
#include <iostream> | |
using namespace bc; | |
using namespace wallet; | |
void create_address_wif_wallet() { | |
// ******* part 1 ******* | |
// Begin with a private key | |
auto my_secret = base16_literal( | |
"f3c8f9a6198cca98f481edde13bcc031b1470a81e367b838fe9e0a9db0f5993d"); | |
// Derive pubkey point | |
ec_compressed my_pubkey; | |
secret_to_public(my_pubkey, my_secret); | |
// Pubkeyhash: sha256 + hash160 | |
auto my_pubkeyhash = bitcoin_short_hash(my_pubkey); | |
// Prefix for mainnet = 0x00 | |
one_byte addr_prefix = { { 0x00 } }; //Testnet 0x6f | |
// Byte sequence = prefix + pubkey + checksum(4-bytes) | |
data_chunk prefix_pubkey_checksum(to_chunk(addr_prefix)); | |
extend_data(prefix_pubkey_checksum, my_pubkeyhash); | |
append_checksum(prefix_pubkey_checksum); | |
// Base58 encode byte sequence -> Bitcoin Address | |
std::cout << encode_base58(prefix_pubkey_checksum) << std::endl; | |
// You can directly generate Bitcoin addresses | |
// with Libbitcoin wallet types: ec_private/ec_public | |
// described in the following section | |
//******* part 2 ******* | |
// WIF encoded private key | |
// Additional Information: Mainnet, PubKey compression | |
one_byte secret_prefix = { { 0x80 } }; //Testnet Prefix: 0xEF | |
one_byte secret_compressed = { { 0x01} }; //Omitted if uncompressed | |
// Apply prefix, suffix & append checksum | |
auto prefix_secret_comp_checksum = to_chunk(secret_prefix); | |
extend_data(prefix_secret_comp_checksum, my_secret); | |
extend_data(prefix_secret_comp_checksum, secret_compressed); | |
append_checksum(prefix_secret_comp_checksum); | |
// WIF (mainnet/compressed) | |
std::cout << encode_base58(prefix_secret_comp_checksum) << std::endl; | |
// ******* part 3 ******* | |
// Instantiate ec_private object | |
// ec_private::mainnet = 0x8000 (Mainnet Prefixes 0x80,0x00) | |
// ec_private::testnet = 0xEF6F (Testnet Prefixes 0xEF,0x6F) | |
ec_private my_private(my_secret, ec_private::mainnet, true); | |
std::cout << my_private.to_payment_address() << std::endl; | |
std::cout << my_private.encoded() << std::endl; //WIF private key | |
// ******* part 4 ******* | |
// ec_public from ec_private | |
// (compression implied from ec_private input) | |
ec_public my_public(my_private); | |
// ec_public from point | |
// (compression not implied, supplied as arguments) | |
ec_public my_public2(my_pubkey, true); //compression = true | |
// Payment addresses: | |
// Will always default to mainnet if no argument supplied | |
// regardless of version in ec_private constructor argument | |
payment_address my_addr = my_public.to_payment_address(); | |
payment_address my_addr2 = my_public2.to_payment_address(); //0x00, 0x6f | |
std::cout << (my_addr.encoded() == my_addr2.encoded()) << std::endl; | |
} | |
void create_mnemonic_from_entropy() { | |
// ******* part 1 ******* | |
// 128, 160, 192, 224, 256 bits of Entropy are valid | |
// We generate 128 bits of Entropy | |
data_chunk my_entropy_128(16); //16 bytes = 128 bits | |
pseudo_random_fill(my_entropy_128); | |
// Instantiate mnemonic word_list | |
word_list my_word_list = create_mnemonic(my_entropy_128); | |
std::cout << join(my_word_list) << std::endl; //join to a single string with spaces | |
} | |
void create_hd_children() { | |
// ******* part 1 ******* | |
// Load mnemonic sentence into word list | |
std::string my_sentence = "market parent marriage drive umbrella custom leisure fury recipe steak have enable"; | |
auto my_word_list = split(my_sentence, " ", true); | |
// Create an optional secret passphrase | |
std::string my_passphrase = "my secret passphrase"; | |
// Create 512bit seed (without optional secret passphrase) | |
auto hd_seed = decode_mnemonic(my_word_list); | |
// Create 512bit seed (with optional secret passphrase) | |
// Requires: Libbitcoin compiled with ICU. | |
// auto hd_seed = decode_mnemonic(my_word_list, my_passphrase); | |
// ******* part 2 ******* | |
// We reuse 512 bit hd_seed from the previous example | |
// Derivation of master private key m | |
data_chunk seed_chunk(to_chunk(hd_seed)); | |
hd_private m(seed_chunk, hd_private::mainnet); | |
// Derivation of master public key M | |
hd_public M = m.to_public(); | |
// ******* part 3 ******* | |
// Derive children of master key m | |
auto m0 = m.derive_private(0); | |
auto m1 = m.derive_private(1); | |
auto m2 = m.derive_private(2); | |
// Derive grandchild private keys | |
auto m10 = m1.derive_private(0); //Depth 2, Index 0 | |
auto m11 = m1.derive_private(1); //Depth 2, Index 1 | |
auto m12 = m1.derive_private(2); //Depth 2, Index 2 | |
auto m100 = m10.derive_private(0); //Depth 3, Index 0 | |
auto m101 = m10.derive_private(1); //Depth 3, Index 1 | |
auto m102 = m10.derive_private(2); //Depth 3, Index 1 | |
// Derive grandchild public keys | |
auto M00 = m0.derive_public(0); //Depth 2, Index 0 | |
auto M01 = m0.derive_public(1); //Depth 2, Index 1 | |
auto M02 = m0.derive_public(2); //Depth 2, Index 2 | |
// ... | |
// Derive hd_public of any hd_private object | |
// of same depth & index | |
auto M102 = m102.to_public(); | |
// ******* part 4 ******* | |
// Derive public children of master key M | |
auto M0 = M.derive_public(0); //Depth 1, Index 0 | |
auto M1 = M.derive_public(1); //Depth 1, Index 1 | |
auto M2 = M.derive_public(2); //Depth 1, Index 2 | |
// Derive further public children | |
auto M10 = M1.derive_public(0); //Depth 2, Index 0 | |
auto M11 = M1.derive_public(1); //Depth 2, Index 1 | |
auto M12 = M1.derive_public(2); //Depth 2, Index 2 | |
auto M100 = M10.derive_public(0); //Depth 3, Index 0 | |
auto M101 = M10.derive_public(1); //Depth 3, Index 1 | |
// ... | |
// No private children can be derived | |
// from child public keys! | |
} | |
void create_extended_hardened_keys() { | |
// Load mnemonic sentence into word list | |
std::string my_sentence = "market parent marriage drive umbrella custom leisure fury recipe steak have enable"; | |
auto my_word_list = split(my_sentence, " ", true); | |
// Create an optional secret passphrase | |
std::string my_passphrase = "my secret passphrase"; | |
// Create 512bit seed | |
auto hd_seed = decode_mnemonic(my_word_list); //2nd argument: my_passphrase | |
data_chunk seed_chunk(to_chunk(hd_seed)); | |
// ******* part 1 ******* | |
// Generate master private key | |
// hd_private::mainnet = 0x0488ADE40488B21E | |
// Versions for both private and public keys | |
hd_private m(seed_chunk, hd_private::mainnet); | |
auto m1 = m.derive_private(1); | |
// Public key mainnet prefix 0488B21E | |
// is implicitly passed on to M | |
hd_public M = m1.to_public(); | |
// Extended Private Key: | |
// m1 serialised in extended private key format | |
auto m1_xprv = m.to_hd_key(); | |
// 4 Bytes: Version in hex | |
auto m1_xprv_ver = slice<0,4>(m1_xprv); | |
std::cout << encode_base16(m1_xprv_ver) << std::endl; | |
// 1-Byte: Depth | |
auto m1_xprv_depth = slice<4,5>(m1_xprv); | |
std::cout << encode_base16(m1_xprv_depth) << std::endl; | |
// 4-Bytes: Parent Fingerprint | |
auto m1_xprv_parent = slice<5,9>(m1_xprv); | |
std::cout << encode_base16(m1_xprv_parent) << std::endl; | |
// 4-Bytes: Index Number | |
auto m1_xprv_index = slice<9,13>(m1_xprv); | |
std::cout << encode_base16(m1_xprv_index) << std::endl; | |
// 32-Bytes: Chain Code | |
auto m1_xprv_chaincode = slice<13,45>(m1_xprv); | |
std::cout << encode_base16(m1_xprv_chaincode) << std::endl; | |
// 34-Bytes: Private Key (with 0x00 prefix) | |
auto m1_xprv_private = slice<45,78>(m1_xprv); | |
std::cout << encode_base16(m1_xprv_private) << std::endl; | |
// 4-Bytes: double sha256 checksum | |
auto m1_xprv_checksum = slice<78,82>(m1_xprv); | |
std::cout << encode_base16(m1_xprv_checksum) << std::endl; | |
// //checksum test | |
// auto checksum_test = slice<0,78>(m1_xprv); | |
// auto checksum_test_slice = to_chunk(checksum_test); | |
// append_checksum(checksum_test_slice); | |
// auto rest = slice<78,82>(to_array<82>(checksum_test_slice)); | |
// std::cout << encode_base16(rest) << std::endl; | |
// ******* part 2 ******* | |
// Hardened private key derivation with index >= 1 << 31 | |
auto m0 = m.derive_private(0); | |
auto m00h = m.derive_private(hd_first_hardened_key); | |
auto m01h = m.derive_private(1 + hd_first_hardened_key); | |
auto m02h = m.derive_private(2 + hd_first_hardened_key); | |
// Hardened public key can only be derived from private key | |
auto M00h = m00h.to_public(); | |
// or from parent private key | |
auto M00h_ = m.derive_public(hd_first_hardened_key); | |
// Above keys are equivalent | |
std::cout << (M00h == M00h_) << std::endl; | |
} | |
int main() { | |
std::cout << "Address, WIF, Wallets: " << "\n"; | |
create_address_wif_wallet(); | |
std::cout << "\n"; | |
std::cout << "Mnemonic Word Lists: " << "\n"; | |
create_mnemonic_from_entropy(); | |
std::cout << "\n"; | |
create_hd_children(); | |
std::cout << "Extended & Hardened Keys: " << "\n"; | |
create_extended_hardened_keys(); | |
std::cout << "\n"; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment