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.