Libbitcoin: Generating a Segwit Address

Libbitcoin: Generating a Segwit Address

Saving money on bitcoin transaction fees with segregated witness first requires you to receive bitcoin in the form of segwit utxos. This post will go over a libbitcoin script for generating a testnet P2SH-P2WKH address to send your bitcoins to and have them ready for spending in segwit transactions.

In order to begin spending bitcoins via segregated witness transactions you need receive pay-to-witness-key-hash outputs. So, the first thing you need to create is a witness program that consist of a version number 0 and compressed hash of your public key.

One thing we need to be sure of is that we always use a compressed public key to generate a P2WKH address. So, first I define a function for getting the compressed public key from a mnemonic by decoding it to its seed and then calling the point getter to get the ec compressed public key.

ec_compressed getPublicKey() 
{
 std::string mnemonic = "portion shop border uniform loan grab dismiss boss wild magnet strong supreme era swing else keep voyage forest";
 data_chunk seed = to_chunk(decode_mnemonic(split(mnemonic)));
 hd_private privateKey = hd_private(seed, hd_private::testnet);
 ec_compressed compressedPublicKey = privateKey.to_public().point();
 return compressedPublicKey;
}

Then we need to define a function that will create a the P2WKH which simply looks like this:

0 [Compressed Public Key Hash]

To do this we need to create a bitcoin short hash of the compressed public key which we will pass as an argument. This short hash amounts to a RIPEMD160 hash of a SHA256 hash of the compressed public key point.  We then return this key hash as a data chunk in an operations list prefixed with an opcode 0 object.

operation::list witnessProgram(ec_compressed publicKey) 
{
 short_hash KeyHash = bitcoin_short_hash(publicKey);
 return {operation(opcode(0)), operation(to_chunk(KeyHash))};
}

Now we can create a script object for our witness program and print it out to the console.

int main()
{
//Output Compressed Public Key
 std::cout << "Public Key: "<< encode_base16(getPublicKey()) << std::endl;
//Output Witness Program
 script P2WPKH = script(witnessProgram(getPublicKey()));
 std::cout << "Witness Program: " << P2WPKH.to_string(0) << std::endl;
}
 

Now in order to make these P2WPKH outputs payable by anyone regardless of their segwit awareness, we need to wrap them in a P2SH address. To do this we first save a short hash of the witness program and pass it to a P2SH script pattern factory.

int main()
{
 //Output Compressed Public Key
 std::cout << "Public Key: "<< encode_base16(getPublicKey()) << std::endl;
 //Output Witness Program
 script P2WPKH = script(witnessProgram(getPublicKey()));
 std::cout << "Witness Program: " << P2WPKH.to_string(0) << std::endl;

 //Create P2SH script
 short_hash WitnessProgramHash = bitcoin_short_hash(P2WPKH.to_data(0));
 script P2SH_P2WPKH = script::to_pay_script_hash_pattern(WitnessProgramHash); 
} 

Then we can print out the P2SH_P2WPKH script pubkey as a string to the console.

We can also print the payment address by passing the witness program script to the payment address object and calling the encoded accessor.

int main()
{
 //Output Compressed Public Key
 std::cout << "Public Key: "<< encode_base16(getPublicKey()) << std::endl;
 //Output Witness Program
 script P2WPKH = script(witnessProgram(getPublicKey()));
 std::cout << "Witness Program: " << P2WPKH.to_string(0) << std::endl;

 //Create P2SH script
 short_hash WitnessProgramHash = bitcoin_short_hash(P2WPKH.to_data(0));
 script P2SH_P2WPKH = script::to_pay_script_hash_pattern(WitnessProgramHash);

 //Print our P2SH script and address
 std::cout <<"P2SH Script: " <<P2SH_P2WPKH.to_string(0) << std::endl;
 std::cout << "Payment Address: " <<payment_address(P2WPKH, payment_address::testnet_p2sh).encoded() << std::endl;
} 

As usual this program can be compiled and run via the Command line:

$ g++ -std=c++11 -o segwit segwit.cpp $(pkg-config --cflags libbitcoin --libs libbitcoin)
$ ./segwit

You’ll note that the payment address begins with a 2, this denotes a testnet Pay-To-Script-Hash address since segwit address can be paid to the same as P2SH. A mainnet segwit address with start with a 3.

Segwit_Address_Output

Any testnet coins sent to this address will be ready to spend with a fee-discounted segwit transaction.

Leave a Reply

Your email address will not be published.