Aclaración de scripts multisig deterministas jerárquicos BIP32

Como todos saben, soy un gran defensor de la biblioteca pybitcointools Python 2.7/3.x de Vitalik Buterin. Tengo algunos problemas para entender los conceptos de BIP32, que están codificados en los módulos deterministas / compuestos .

En particular, este código :

# 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

Tuve problemas para firmar 2 de 2 Tx P2SH/HD con Electrum, que solo pude firmar con éxito usando createrawtransaction\ signrawtransactionen Bitcoin-CLI.

¿Cómo se implementa exactamente P2SH en combinación con carteras HD (preferiblemente en términos del código Python antes mencionado)?

¿Tiene problemas para crear estos productos o firmar una transacción gastándolos una vez que los ha creado?
@NickODell Me gustaría poder firmar usando el código de Python. No quiero confundir demasiado las cosas, pero Electrum 2.0.4 firma parcialmente, devolviendo estos datos JSON: gist.github.com/d6397e62bdb78f905cfa ... No tiene sentido porque sustituye la clave pública extendida en el script. (Nota: los datos son seguros para compartir, no se preocupe por las llaves robadas o lo que sea)
También me interesaría saber cómo se puede implementar multisig con la billetera HD. ¿Genera automáticamente direcciones multisig?

Respuestas (1)

OK, lo tengo funcionando con pybitcointools .

El comando, bip32_hdm_scriptcomo se puede inferir, devuelve el hexadecimal del script redimido de P2SH usando las claves maestras públicas/privadas BIP32 especificadas (que no es diferente al uso mk_multisig_script(pubkey1 pubkey2 pubkey3 2)para un P2SH 2 de 3). Del mismo modo, bip32_hdm_addrdevuelve la dirección P2SH que se obtiene del script de redención.

El problema es que estamos tratando con rutas y demás, y la función tiene problemas con los tipos de objetos.

Usemos claves privadas maestras sembradas con 0,1 y 2, respectivamente...

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

La firma con claves privadas maestras no funcionará directamente , obtengamos las claves públicas maestras:

b32mpubs = map(bip32_privtopub, b32mprivs)

Ahora, en este ejemplo, queremos descender a path 0/1, en un multigrado 2 de 3. Esto está representado por un int , 2y una tupla (¡solo!) de la ruta, entonces (0, 1).

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

Ahora, usamos bip32_hdm_addrpara obtener la dirección P2SH.

>>> bip32_hdm_addr(redeemscript) 5221029057ffd5c48f95c46c5e12b837cd0e4a7538dfa8ab9eb3479593724a6109ffb4210316776496822873767c6a91efe85a55871fc4a944c1d1ccab52cebd386cef29d4210318ae5429f67dbf61f54ae947f38637f4bffa1e252922b431eeed397cac49a22953ae

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


OTRA VEZ: no intente firmar con claves privadas maestras usando bip32_hdm_script, no sea que devuelva un script redimido, que cuando se deserializa, da:

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

¿Ves cómo las claves del script redimido tienen una longitud de 33 bytes? ¿Y no empieza con el 02/03/04? Eso hará que una dirección P2SH no se pueda usar, ¡así que tenga cuidado con esta trampa!