4

As everyone is aware, I'm a huge proponent of Vitalik Buterin's pybitcointools Python 2.7/3.x library. I am having a some trouble understanding the BIP32 concepts, which are coded in the deterministic/composite modules.

In particular, this code:

# BIP32 hierarchical deterministic multisig script
def bip32_hdm_script(*args):
    if len(args) == 3:
        keys, req, path = args
    else:
        i, keys, path = 0, [], []
        while len(args[i]) > 40:
            keys.append(args[i])
            i += 1
        req = int(args[i])
        path = map(int, args[i+1:])
    pubs = sorted(map(lambda x: bip32_descend(x, path), keys))  # 
    return mk_multisig_script(pubs, req)    # (req = required sigs) ... returns redeemScript hex


# BIP32 hierarchical deterministic multisig address
def bip32_hdm_addr(*args):
    return scriptaddr(bip32_hdm_script(*args))   # returns P2SH address

I've had issues signing 2-of-2 P2SH/HD Txs with Electrum which I could only successfully sign using createrawtransaction \ signrawtransaction in Bitcoin-CLI.

How exactly is P2SH in combination with HD wallets implemented (preferably in terms of the aforementioned Python code)?

  • Are you having trouble with creating these outputs, or signing a transaction spending them once you've created them? – Nick ODell Apr 15 '15 at 2:11
  • @NickODell I'd like to be able to sign using the Python code. I don't want to confuse things too much, but Electrum 2.0.4 partially signs, returning this JSON data: gist.github.com/d6397e62bdb78f905cfa ... It makes no sense because it's substituted the extended public key in the script. (NB the data is safe to share, no worries about stolen keys or whatever) – Wizard Of Ozzie Apr 15 '15 at 2:16
  • I'd be also interested to know how multisig can be implemented with the HD wallet. Does it automatically generates multisig addresses? – abeikverdi Apr 15 '15 at 16:06
1

OK, I got it working with pybitcointools.

The command, bip32_hdm_script, as one can infer, returns hex of the P2SH redeemscript using the specified BIP32 master public/private keys (which is no different to using mk_multisig_script(pubkey1 pubkey2 pubkey3 2) for a 2-of-3 P2SH). Likewise, bip32_hdm_addr returns the P2SH address one gets from the redeemscript.

The catch is we're dealing with paths and such, and the function has issues with object types.

Let's use master private keys seeded with 0,1 and 2, respectively...

b32mprivkeys = [ bip32_master_key(str(x)) for x in range(3)] gives ['xprv9s21ZrQH143K2FsoUgfptxnkXbTjWSyu7oPKz2BtJm5yWC8pZMtxbx66FhZoY2e6Fwz2rZ4zPZrgpNJHRd68RtQNcFFVbwGf7Vapo4spoqL', 'xprv9s21ZrQH143K2r9LvVthYjmsCLwZGpAc4uAAeovjhf7vaAbiunLgRdp8DAo4fSGUMuYQzzGfNGkdsR9xq6vcaKQSTa2VQx7o31N3kxcZi9k', 'xprv9s21ZrQH143K2AV64RkNhLQEHTphnaGZqrGBhXTw9gBTMfvDAPiKFWpkBmt9otxA2X14bRS6mPdxohX4QCP3PMi8TG7KvCriGcsQHwDHVfT']

Signing with master private keys won't work directly, let's get the master pubkeys:

b32mpubs = map(bip32_privtopub, b32mprivs)

Now, in this example, we want to descend to path 0/1, in a 2-of-3 multisig. This is represented by an int, 2, and a tuple (only!) of the path, so (0, 1).

redeemscript = bip32_hdm_script(b32mpubss, 2, (0, 1)) = 5221029057ffd5c48f95c46c5e12b837cd0e4a7538dfa8ab9eb3479593724a6109ffb4210316776496822873767c6a91efe85a55871fc4a944c1d1ccab52cebd386cef29d4210318ae5429f67dbf61f54ae947f38637f4bffa1e252922b431eeed397cac49a22953ae

Now, we use bip32_hdm_addr to get the P2SH address.

>>> bip32_hdm_addr(redeemscript) 5221029057ffd5c48f95c46c5e12b837cd0e4a7538dfa8ab9eb3479593724a6109ffb4210316776496822873767c6a91efe85a55871fc4a944c1d1ccab52cebd386cef29d4210318ae5429f67dbf61f54ae947f38637f4bffa1e252922b431eeed397cac49a22953ae

Note, FWIW, >>> bip32_hdm_addr(redeemscript) == scriptaddr(redeemscript) True


AGAIN: Do not try signing with master private keys using bip32_hdm_script, lest you return a redeemscript, which when deserialised, gives:

slice( # we want the privkeys only deserialize_script(bip32_hdm_script(b32mprivkeys, 2, (0, 1))), 1, 4)

See how the keys from the redeemscript are 33 bytes long? And don't start with 02/03/04? That'll make an unusable P2SH address, so beware this pitfall!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.