Vamos a realizar un ejercicio práctico de creación de las claves de Bitcoin con Python.
Antes que nada advertir que no recomendamos utilizar este método si tienes intención de que esta clave privada sea la llave de tus fondos de bitcoin, para ello lo más conveniente es generar esa(s) clave(s) a partir de las palabras de la semilla más una passphrase y desde un dispositivo que no esté conectado a Internet (off-line). Aquí dejo un post Generar claves privadas en Bitcoin de forma segura y barata sobre una de las posibles formas de creación de las claves de forma segura.
Si optásemos por utilizar la librería de bitcoin de Python esto se resolvería en estas 4 líneas de código, pero la intención que buscamos es hacerlo a un nivel más bajo para entender las operaciones que se hacen en bitcoin para esta generación de estas claves.
from bitcoin import *
my_private_key = random_key()
my_public_key = privtopub(my_private_key)
my_bitcoin_address = pubtoaddr(my_public_key)
# Instalamos los módulos base58 y ecdsa
!pip install base58 !pip install ecdsa
Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/
Requirement already satisfied: base58 in /usr/local/lib/python3.8/dist-packages (2.1.1)
Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/
Requirement already satisfied: ecdsa in /usr/local/lib/python3.8/dist-packages (0.18.0)
Requirement already satisfied: six>=1.9.0 in /usr/local/lib/python3.8/dist-packages (from ecdsa) (1.15.0)
# Importamos las siguientes librerías
import os
import binascii
import base58
import ecdsa
import hashlib
from hashlib import sha256
import codecs
import time
import random
# Generación aleatoria de la clave privada
my_privatekey = ""
entropy = str(os.urandom(32)) \
+ str(random.randrange(2**256)) \
+ str(int(time.time() * 1000000))
binary_data = entropy if isinstance(entropy, bytes) else bytes(entropy, 'utf-8')
my_privatekey_bytes = hashlib.sha256(binary_data).digest()
if isinstance(my_privatekey_bytes, str):
my_privatekey = my_privatekey_bytes
else:
my_privatekey = ''.join('{:02x}'.format(y) for y in my_privatekey_bytes)
# Generación de la dirección pública a partir de la clave privada
my_publickey_raw = ecdsa.SigningKey.from_string(my_privatekey_bytes, curve=ecdsa.SECP256k1)
my_publickey_raw_verify = my_publickey_raw.verifying_key
my_publickey_bytes = my_publickey_raw_verify.to_string()
# Conversión de la clave pública al formato hexadecimal desde los bytes
my_publickey_hex = codecs.encode(my_publickey_bytes, 'hex')
# Se añade los bytes 0x04 al principio de la clave pública de Bitcoin
my_publickey = (b'04' + my_publickey_hex).decode("utf-8")
print("Public key: ", my_publickey)
# Dependiendo de si el último byte es par o impar se añade un 02 o un 03
if (ord(bytearray.fromhex(my_publickey[-2:])) % 2 == 0):
my_publickey_comp = '02'
else:
my_publickey_comp = '03'
my_publickey_comp += my_publickey[2:66]
print("Public key compressed: ", my_publickey_comp)
# Se realiza la operaión hash de SHA-256 al array de bytes
hex_byte_array = bytearray.fromhex(my_publickey_comp)
sha256 = hashlib.sha256()
sha256.update(hex_byte_array)
sha256.hexdigest() # .hexdigest() is hex ASCII
# Hashing RIPMED-160 al resultado del SHA-256
rip160 = hashlib.new('ripemd160')
rip160.update(sha256.digest())
key_hash = rip160.hexdigest()
# Se añade el byte de version delate del hash de RIPEMD-160 (0x00 para la Main Network)
modified_key_hash = "00" + key_hash
# Hash SHA-256 del RIPEMD-160 resultante, después de la codificación Base58Check
sha256 = hashlib.sha256()
hex_byte_array = bytearray.fromhex(modified_key_hash)
sha256.update(hex_byte_array)
sha256.hexdigest()
# Se realiza un segundo hash SHA-256 del resutado del previo hash SHA-256
sha256_2 = hashlib.sha256()
sha256_2.update(sha256_2.digest())
sha256_2.hexdigest()
# Se toman los primeros 4 bytes del segundo hash SHA-256 para el checksum
checksum = sha256_2.hexdigest()[:8]
# Y por último para obtener la dirección pública se añaden los 4 bytes del checksum y se codifica en base58
byte_25_address = modified_key_hash + checksum
byte_25_address_array = bytearray.fromhex(byte_25_address)
my_address = base58.b58encode(bytes(byte_25_address_array)).decode('utf-8')
print("Address: ", my_address)
Public key: 041c283524f5311709bf66828cb4226a3a2c85d8e643575af155dba0ce538ef4f8ef797194e9c1996cba79d02a2138e6ae809621d69a68a087edc5ba8b5adf4623
Public key compressed: 031c283524f5311709bf66828cb4226a3a2c85d8e643575af155dba0ce538ef4f8
Address: 1DtuGzYHST7HHCVbYuzr6AJmgZUKMYkgw3
Enlace al proyecto en Github, Bitcoin generación de dirección pública
Categories: Bitcoin, BTC, Code, Notebook, Python, Script, Security
Leave a Reply