Cómo generar pares de claves públicas y privadas a partir de las 12 palabras semilla en python

Básicamente seguí las instrucciones aquí Cómo generar direcciones de micelio a partir de las 12 palabras en python

Así que mi código es similar:

from bip32utils import BIP32Key
from bip32utils import BIP32_HARDEN
from bip32utils import Base58
import os, bip39

strength_bits = 128
entropy = os.urandom(strength_bits // 8)
wallet_generator = bip39.Mnemonic('english')
mnemonic = wallet_generator.to_mnemonic(entropy)
assert wallet_generator.to_entropy(mnemonic) == entropy  # see, bijective!

# Or specify the mnemonic directly if you prefer:
mnemonic = 'aware report movie exile buyer drum poverty supreme gym oppose float elegant'
passphrase = 'test'

seed = bip39.Mnemonic.to_seed(mnemonic, passphrase=passphrase)
key = BIP32Key.fromEntropy(seed)
account_number = 0
i = 0
print "Address: " + key.ChildKey(44 + BIP32_HARDEN) \
         .ChildKey(0 + BIP32_HARDEN) \
         .ChildKey(account_number + BIP32_HARDEN) \
         .ChildKey(0) \
         .ChildKey(i) \
         .Address()

Y verifiqué usando https://iancoleman.io/bip39/#english que la dirección generada es de hecho la primera dirección que también generó esta página web. Sin embargo, también quiero obtener los pares de claves pública y privada usando esta misma biblioteca. Originalmente probé:

print "Public Key: " + Base58.check_encode(key.ChildKey(44 + BIP32_HARDEN) \
         .ChildKey(0 + BIP32_HARDEN) \
         .ChildKey(account_number + BIP32_HARDEN) \
         .ChildKey(0) \
         .ChildKey(i) \
         .PublicKey())

print "Private Key: " + Base58.check_encode(key.ChildKey(44 + BIP32_HARDEN) \
         .ChildKey(0 + BIP32_HARDEN) \
         .ChildKey(account_number + BIP32_HARDEN) \
         .ChildKey(0) \
         .ChildKey(i) \
         .PrivateKey())

Sin embargo, el resultado de estas dos llamadas no es el mismo que el proporcionado por el sitio web anterior para la misma dirección.

Entonces mi pregunta es: ¿cuál es la forma correcta de generar los pares de claves pública y privada?

Editar: para aclarar, para la mnemónica y la frase de contraseña exactas anteriores, el sitio web que estoy usando como referencia me dice que la primera dirección y el par de claves deben ser:ingrese la descripción de la imagen aquí

Mientras que la salida del código python anterior es:

Address: 1K6WQtD7bLQ5nQ14GyBV33mBWSbkiRKhQs
Public Key: 62Yi9HBYYagf8CY1Ve2fquHKjBqAA7GFjGUUtkUHbkP5PHzv3W
Private Key: EGHMsAp7nY7Jo9F589zCU227KBLTDhiwRq5vYVvRVZxJNPJn4

Entonces la dirección coincide, pero no el par de llaves.

¿Estás seguro de que no coincide? Veo que está usando PublicKey()vs Address(), ¿quería la clave pública o la dirección?
Quiero la clave pública y la clave privada. La dirección ya es correcta. Edité la pregunta para agregar el resultado de muestra de la página web de referencia y el script de Python como referencia

Respuestas (3)

Pruebe la siguiente demostración y el resultado es el mismo con https://iancoleman.io/bip39/ .

$ python3.6 test.py
{'addr': '1A9vZ4oPLb29szfRWVFe1VoEe7a2qEMjvJ',
 'coin': 'BTC',
 'mnemonic_words': 'aware report movie exile buyer drum poverty supreme gym oppose float elegant',
 'privatekey': 'L3g3hhYabnBFbGqd7qReebwCrRkGhAzaX4cBpYSv5S667sWJAn5A',
 'publickey': '029dc2912196f2ad7a830747c2490287e4ff3ea52c417598681a955dcdf473b6c0'}

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import pprint
import binascii
import mnemonic
import bip32utils

def bip39(mnemonic_words):
    mobj = mnemonic.Mnemonic("english")
    seed = mobj.to_seed(mnemonic_words)

    bip32_root_key_obj = bip32utils.BIP32Key.fromEntropy(seed)
    bip32_child_key_obj = bip32_root_key_obj.ChildKey(
        44 + bip32utils.BIP32_HARDEN
    ).ChildKey(
        0 + bip32utils.BIP32_HARDEN
    ).ChildKey(
        0 + bip32utils.BIP32_HARDEN
    ).ChildKey(0).ChildKey(0)

    # return {
    #     'mnemonic_words': mnemonic_words,
    #     'bip32_root_key': bip32_root_key_obj.ExtendedKey(),
    #     'bip32_extended_private_key': bip32_child_key_obj.ExtendedKey(),
    #     'bip32_derivation_path': "m/44'/0'/0'/0",
    #     'bip32_derivation_addr': bip32_child_key_obj.Address(),
    #     'coin': 'BTC'
    # }

    return {
        'mnemonic_words': mnemonic_words,
        # 'bip32_root_key': bip32_root_key_obj.ExtendedKey(),
        # 'bip32_extended_private_key': bip32_child_key_obj.ExtendedKey(),
        # 'path': "m/44'/0'/0'/0",
        'addr': bip32_child_key_obj.Address(),
        'publickey': binascii.hexlify(bip32_child_key_obj.PublicKey()).decode(),
        'privatekey': bip32_child_key_obj.WalletImportFormat(),
        'coin': 'BTC'
    }


if __name__ == '__main__':
    mnemonic_words = "aware report movie exile buyer drum poverty supreme gym oppose float elegant"
    pprint.pprint(bip39(mnemonic_words))
¿Cómo se escribe el resultado en un archivo txt? pitón 3
@debug, ¿qué pasa si quiero hacer esto para ether en lugar de Bitcoin? ¿Qué aspectos del código debo cambiar para hacer esto?

Encontré el problema creo.

No debe hacer el Base58.check_encode

Para imprimir la clave pública, use el método .hex().

Además, https://iancoleman.io/bip39/#english imprime la clave privada en el formulario WIF, por lo que debe hacer .WalletImportFormat() en lugar de .PrivateKey() si desea obtener el mismo resultado que iancoleman.io. Esta vez, no es necesario usar .hex() (de nuevo, no es necesario codificar en base58)

La clave pública debe estar en hexadecimal como @MohamedLEGH señaló anteriormente. Con respecto a la clave privada, primero debe agregarle el código de red. Vea el paso 2 aquí .