Clave privada exportada de Electrum, incapaz de recrear la dirección con Python

Creé una nueva billetera Electrum, y aquí hay una dirección:

1JkZLnmFfpVFLT2ZMtKzc6BuXMdmY41EHA

Al hacer clic derecho sobre él, elijo "Clave privada", que da:

Kzuucz58MiTbbedeVuqBaPYwG1TQrV3n2NYU2dJRZ7HEHnHsUXWx

Ahora quiero poder (aprender cómo funciona) pasar de esta clave privada a la dirección, a través de la multiplicación de curvas elípticas.

Esto es lo que probé:

import bitcoin #pybitcointools
import base58
import binascii

pvt = 'Kzuucz58MiTbbedeVuqBaPYwG1TQrV3n2NYU2dJRZ7HEHnHsUXWx'
pvtdecoded = base58.b58decode(pvt)
pvthex = binascii.hexlify(pvtdecoded)[2:-8]     # remove the first initial byte for version and 4 final bytes for checksum
pvt2 = bitcoin.decode_privkey(pvthex, 'hex')    # decode as a decimal

# generate pubkey from pvtkey with elliptic curve multiplication
public_key = bitcoin.fast_multiply(bitcoin.G, pvt2)
addr = bitcoin.pubkey_to_address(public_key)
print addr

que da: 1LNSuE4NKHTyHygeKwnU1equ7MjPMhayxBque no es la dirección original.

¿Qué ocurre? ¿Cómo recuperar la dirección original ( 1JkZLnmFfpVFLT2ZMtKzc6BuXMdmY41EHA) de la clave privada usando la multiplicación de curva elíptica?


Editar : como Kz....Wxla clave privada parece una comprimida con WIF, traté de reemplazar:

pvt2 = bitcoin.decode_privkey(pvthex, 'hex')    # decode as a decimal

por

pvt2 = bitcoin.decode_privkey('Kzuucz58MiTbbedeVuqBaPYwG1TQrV3n2NYU2dJRZ7HEHnHsUXWx', 'wif')

pero luego, después de la multiplicación de la curva elíptica, da otra dirección, ¡que todavía no es la buena! ( 18dFF3EQoPxR44TygdGxHPMe3LSLFeQe4U)

Nota: He leído en.bitcoin.it/wiki/Wallet_import_format y WIF to private key, pero todavía estoy atascado.

Respuestas (2)

En ambos casos, no está generando la dirección que corresponde a la clave pública comprimida.

En el primer caso, está creando lo que parece ser una dirección no válida. Como mínimo, la clave privada que está utilizando es incorrecta porque tiene el byte de compresión. Esto cambiará el valor que obtiene para la clave privada cuando se decodifica. Para obtener el mismo resultado que en el segundo caso, deberá eliminar un byte adicional de la clave WIF decodificada, ya que ese byte especifica la compresión. La clave que está utilizando allí tiene 33 bytes en lugar de los 32 bytes de las claves privadas reales.

En el segundo caso, no está creando la clave pública comprimida para generar la dirección. Todavía está usando la clave pública sin comprimir. En lugar de usar fast_multiplyy crear la clave pública usted mismo, debería usar privkey_to_pubkey. fast_multiplyes una operación matemática, no tiene concepto de claves públicas comprimidas. Sin embargo privkey_to_pubkey, si lo hace, creará la clave pública adecuada. Luego puede usar esa clave pública para generar la dirección.

en lugar de hacer

public_key = bitcoin.fast_multiply(bitcoin.G, pvt2)

deberías estar haciendo

public_key = bitcoin.privkey_to_pubkey(pvt)
Gracias por tu útil respuesta. Acerca de su último párrafo, ¿por qué no puedo usar una multiplicación de curva elíptica (debería haber una debajo del capó, incluso en el caso comprimido, verdad?)? Además, ¿podría simplemente publicar (para referencia futura y para estar seguro) la línea de código que deberíamos usar en lugar de fast_multiply?
Porque la compresión ocurre independientemente de las operaciones de la curva elíptica. Las operaciones de curvas elípticas no saben qué es la compresión de puntos; solo pueden operar en la curva completa. Sin embargo, las bibliotecas pueden usar la compresión de puntos, y eso debe suceder por separado de las operaciones de EC.
Gracias @AndrewChow. Lo intenté public_key = bitcoin.privkey_to_pubkey(pvt2)pero sigo recibiendo 18dFF3EQoPxR44TygdGxHPMe3LSLFeQe4Uen lugar de la dirección original 1JkZLnmFfpVFLT2ZMtKzc6BuXMdmY41EHA. ¿Qué puede estar mal?
Mirando la implementación de this pybitcointools, no necesita decodificar la clave privada cuando usa privkey_to_pubkey. Más bien, es decodificado para usted por esa función en sí. Actualizaré mi respuesta con el código correcto.
¡Muchas gracias! Estoy luchando para obtener 1JkZLnmFfpVFLT2ZMtKzc6BuXMdmY41EHAcomo salida :)
¿Probaste la edición más reciente?

Según la sugerencia de use de la respuesta aceptada privkey_to_pubkey, analicé su código, y esto también funciona:

pvt = 'Kzuucz58MiTbbedeVuqBaPYwG1TQrV3n2NYU2dJRZ7HEHnHsUXWx'
pvtdecoded = base58.b58decode(pvt)
pvthex = binascii.hexlify(pvtdecoded)[2:-10]     # remove the first initial byte for version and 4 final bytes for checksum
pvt2 = bitcoin.decode_privkey(pvthex, 'hex')     # decode as a decimal

# generate pubkey from pvtkey with elliptic curve multiplication
public_key = bitcoin.fast_multiply(bitcoin.G, pvt2)
public_key = bitcoin.encode_pubkey(public_key, 'hex_compressed')
addr = bitcoin.pubkey_to_address(public_key)
print addr    # 1JkZLnmFfpVFLT2ZMtKzc6BuXMdmY41EHA