Libbitcoin: Create a Non-Native Segwit Multisig Address(P2SH-P2WSH)

Libbitcoin: Create a Non-Native Segwit Multisig Address(P2SH-P2WSH)

Create a Non-Native Segwit Multisig Address

Creating a multisig address that is spendable via segwit and payable via non-segwit aware wallets is very similar to creating a standard non-native segwit address.

First, we need to create a standard multisig script for the witness script.

this script will then be hashed with sha256 and the resulting 34-byte script hash will be preceeded by the OP_0 to create the redeem script.

OP_0 [SHA256(witness_script)]

From here, it is treated like a standard P2SH. The HASH160 of the redeem script will be base58 encoded to create the payment address.

This program is going to generate a 2 of 3 multisig Non-Native segwit address.

First we are going to write a function which takes 3 keys and generates the multisig script.

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

using namespace bc;
using namespace bc::wallet;
using namespace bc::machine;
using namespace bc::chain;
script getWitnessScript(ec_public key1, ec_public key2, ec_public key3) {
	//make key list
	point_list keys {key1.point(), key2.point(), key3.point()};
	//create 2/3 multisig script
	script multisig = script::to_pay_multisig_pattern(2u, keys);
	return multisig;
}

Next we are going to need a function to create the redeem script. This function is going to hash the multisig script with a single SHA256 hash and then create an operations list of a OP_0 and the multiscript hash data and then create a script from those operations.

script getRedeemScript(ec_public key1, ec_public key2, ec_public key3) {
	//create 2/3 multisig script
	script multisig = getWitnessScript(key1, key2, key3);

	//sha256 the script
	data_chunk multisig_hash = to_chunk(sha256_hash(multisig.to_data(0)));

	//redeem script
	operation::list redeemscript_ops {operation(opcode(0)), operation(multisig_hash)};
	script redeem_script = script(redeemscript_ops);

	return redeem_script;
}

Now, we can start building our program in the main function. By first declaring our three public keys. I generated my via BX.

//Generated with bx seed | bx ec-new
//bx ec-to-public [privatekey]
//private keys
// 0: e4ad55ecfd41062cec616762b73457c4d6bab35f3cb7dbe2fbab3f6a4d921bde
// 1: 3edef3e2d2152156e6816c06e65f64baff4fc0831cf25ae86df016a5cb651747
// 2: 5398432f87ad7b09d2aa6c3c2653d24a97b96fe1205d75f6d0dcf62b6c3414e1
int main() {
	//Define 3 public keys to use
	ec_public key1("02e1a13910e955222a0b5b4e1d2395f02fdb38de69c7643950ebefd0c767874448");
	ec_public key2("03c98cdcca5164394ed25fe9783c5eb289669a4cc69ff0492d3ef15b409428ce8d");
	ec_public key3("03eacfd3a4c110b88f8703bd738316dc7270a9ba95841feaa303a644d46eb8ba5a");

}

Then we can use those keys to create the witness script and output it to the console.


	//create 2/3 multisig script
	script multisig = getWitnessScript(key1, key2, key3);
	std::cout << "Multisig Script: " << multisig.to_string(0) << std::endl;

Then we can do the same thing with the redeem script.

	//redeem script
	script redeem_script = getRedeemScript(key1, key2, key3); 
	std::cout << "Redeem Script: " << redeem_script.to_string(0) << std::endl;

Now, we can simply pass the redeem script to a payment_address constructor and specify the testnet to create our address which will be payable regardless of whether or not the payer is segwit aware.

We can then use this payment_address object to display the embedded script hash and base58 address on the console.

	//make address from script
	payment_address address = payment_address(redeem_script, payment_address::testnet_p2sh);

	std::cout << "Redeem Script Hash: " << encode_base16(address.hash()) << std::endl;
	std::cout << "Payment Address: " << address.encoded() << std::endl;

Further, we can create the scriptpubKey from the address hash and display it to the console.


	//scriptPubKey
	script P2SH_P2WSH = script(script::to_pay_script_hash_pattern(address.hash()));

	std::cout << "Locking Script: " << P2SH_P2WSH.to_string(0) << std::endl;

And as always, we can compile and run with:

$ g++ -std=c++11 -o address P2SH-P2WSH-Address.cpp $(pkg-config --cflags libbitcoin --libs libbitcoin)
$ ./address

As always, full code can be found on github.

Segwit multisig address

Leave a Reply

Your email address will not be published.