Mastering Bitcoin

Mastering Bitcoin


6. Claves, Direcciones, Carteras » Direcciones Bitcoin » Formatos de Claves » Implementando Claves y Direcciones en Python

Página 35 de 98

Claves privadas comprimidas

Irónicamente el término «clave privada comprimida» es engañoso, ya que al exportar una clave privada como WIF comprimida resulta de hecho siendo un byte más larga que una clave privada «descomprimida». Esto es debido a que añade el sufijo 01, el cual significa que proviene de una cartera más reciente y no debe ser usada para producir claves públicas comprimidas. Las claves privadas no son comprimidas y no pueden ser comprimidas. El término «clave privada comprimida» en realidad significa «clave privada a partir de la cual debe derivarse una clave pública comprimida», mientras que «clave privada descomprimida» realmente significa «clave privada a partir de la cual debe derivarse una clave pública descomprimida». Para evitar mayor confusión debes referirte a los formatos de exportación como «WIF comprimido» o «WIF» en vez de referirte a las claves privadas como «comprimidas».

Recuerda, estos formatos no son usados de manera intercambiable. En una cartera más reciente que implementa claves públicas comprimidas las claves privadas serán exhibidas únicamente como WIF comprimido (con prefijo K o L). Si la cartera es una implementación más antigua y no usa claves públicas comprimidas, las claves privadas solo serán exhibidas como WIF (con prefijo 5). El objetivo aquí es comunicar a la cartera que importará estas claves privadas si debe buscar en la cadena de bloques por direcciones y claves públicas comprimidas o descomprimidas.

Si una cartera bitcoin es capaz de implementar claves públicas comprimidas las usará en todas las transacciones. Las claves privadas en la cartera serán usadas para derivar los puntos de clave pública sobre la curva, los cuales serán comprimidos. Las claves públicas comprimidas serán usadas para producir direcciones bitcoin y esas serán usadas en transacciones. Al exportar claves privadas desde una nueva cartera que implementa claves públicas comprimidas, el Formato de Importación de Cartera es modificado, con el añadido del sufijo de un byte 01 a la clave privada. La clave privada resultante codificada en Base58Check se llama «WIF Comprimido» y comienza con la letra K o L en vez de con un «5» como es el caso de claves codificadas en WIF (descomprimido) de carteras más antiguas. Ejemplo: Misma clave, formatos distintos muestra la misma clave codificada en formatos WIF y WIF comprimido.

Tabla 4. Ejemplo: Misma clave, formatos distintos

¡«Claves privadas comprimidas» es un nombre poco apropiado! No son comprimidas; en cambio, el formato WIF comprimido significa que deben ser usadas para derivar claves públicas comprimidas y sus direcciones bitcoin correspondientes. Irónicamente, una clave privada codificada con WIF comprimido es un byte más largo ya que tiene el sufijo 01 añadido para distinguirlo de una «descomprimida».

Implementando Claves y Direcciones en Python

La biblioteca bitcoin en Python más completa es pybitcointools por Vitalik Buterin. En Generación y formato de clave y dirección con la biblioteca pybitcointools, usamos la biblioteca (importada como «bitcoin») para generar y mostrar claves y direcciones en varios formatos.

Ejemplo 4. Generación y formato de clave y dirección con la biblioteca pybitcointools

import bitcoin

# Generate a random private key

valid_private_key = False

while not valid_private_key:

private_key = bitcoin.random_key()

decoded_private_key = bitcoin.decode_privkey(private_key, 'hex')

valid_private_key = 0 < decoded_private_key < bitcoin.N

print "Private Key (hex) is: ", private_key

print "Private Key (decimal) is: ", decoded_private_key

# Convert private key to WIF format

wif_encoded_private_key = bitcoin.encode_privkey(decoded_private_key, 'wif') print "Private Key (WIF) is: ", wif_encoded_private_key

# Add suffix "01" to indicate a compressed private key

compressed_private_key = private_key + '01'

print "Private Key Compressed (hex) is: ", compressed_private_key

# Generate a WIF format from the compressed private key (WIF-compressed) wif_compressed_private_key = bitcoin.encode_privkey(

bitcoin.decode_privkey(compressed_private_key, 'hex'), 'wif')

print "Private Key (WIF-Compressed) is: ", wif_compressed_private_key

# Multiply the EC generator point G with the private key to get a public key point public_key = bitcoin.fast_multiply(bitcoin.G, decoded_private_key)

print "Public Key (x,y) coordinates is:", public_key

# Encode as hex, prefix 04

hex_encoded_public_key = bitcoin.encode_pubkey(public_key,'hex')

print "Public Key (hex) is:", hex_encoded_public_key

# Compress public key, adjust prefix depending on whether y is even or odd (public_key_x, public_key_y) = public_key

if (public_key_y % 2) == 0:

compressed_prefix = '02'

else:

compressed_prefix = '03'

hex_compressed_public_key = compressed_prefix + bitcoin.encode(public_key_x, 16) print "Compressed Public Key (hex) is:", hex_compressed_public_key

# Generate bitcoin address from public key

print "Bitcoin Address (b58check) is:", bitcoin.pubkey_to_address(public_key)

# Generate compressed bitcoin address from compressed public key

print "Compressed Bitcoin Address (b58check) is:", \ bitcoin.pubkey_to_address(hex_compressed_public_key) Ejecutando key-to-address-ecc-example.py muestra la salida de ejecutar este código.

Ejemplo 5. Ejecutando key-to-address-ecc-example.py

$ python key-to-address-ecc-example.py

Private Key (hex) is:

Private Key (decimal) is:

26563230048437957592232553826663696440606756685920117476832299673293013768870

Private Key (WIF) is:

5JG9hT3beGTJuUAmCQEmNaxAuMacCTfXuw1R3FCXig23RQHMr4K

Private Key Compressed (hex) is:

3aba4162c7251c891207b747840551a71939b0de081f85c4e44cf7c13e41daa601Private Key (WIF-Compressed) is:

KyBsPXxTuVD82av65KZkrGrWi5qLMah5SdNq6uftawDbgKa2wv6S

Public Key (x,y) coordinates is:

(41637322786646325214887832269588396900663353932545912953362782457239403430124L,

16388935128781238405526710466724741593761085120864331449066658622400339362166L)

Public Key (hex) is:

045c0de3b9c8ab18dd04e3511243ec2952002dbfadc864b9628910169d9b9b00ec

243bcefdd4347074d44bd7356d6a53c495737dd96295e2a9374bf5f02ebfc176

Compressed Public Key (hex) is:

025c0de3b9c8ab18dd04e3511243ec2952002dbfadc864b9628910169d9b9b00ec

Bitcoin Address (b58check) is:

1thMirt546nngXqyPEz532S8fLwbozud8

Compressed Bitcoin Address (b58check) is:

14cxpo3MBCYYWCgF74SWTdcmxipnGUsPw3

Un script mostrando la matemática de curva elíptica usada para claves bitcoin es otro ejemplo, usando la biblioteca Python ECDSA para la matemática de curva elíptica y sin usar ninguna biblioteca bitcoin especializada.

Ejemplo 6. Un script mostrando la matemática de curva elíptica usada para claves bitcoin import ecdsa

import os

from ecdsa.util import string_to_number, number_to_string

# secp256k1, http://www.oid-info.com/get/1.3.132.0.10

_p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2FL

_r = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141L

_b = 0x0000000000000000000000000000000000000000000000000000000000000007L

_a = 0x0000000000000000000000000000000000000000000000000000000000000000L

_Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798L

_Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8L

curve_secp256k1 = ecdsa.ellipticcurve.CurveFp(_p, _a, _b)

generator_secp256k1 = ecdsa.ellipticcurve.Point(curve_secp256k1, _Gx, _Gy, _r) oid_secp256k1 = (1, 3, 132, 0, 10)

SECP256k1 = ecdsa.curves.Curve("SECP256k1", curve_secp256k1, generator_secp256k1, oid_secp256k1)

ec_order = _r

curve = curve_secp256k1

generator = generator_secp256k1

def random_secret():

convert_to_int = lambda array: int("".join(array).encode("hex"), 16)

# Collect 256 bits of random data from the OS's cryptographically secure random generator

byte_array = os.urandom(32)

return convert_to_int(byte_array)

def get_point_pubkey(point):

if point.y() & 1:

key = '03' + '%064x' % point.x()

else:

key = '02' + '%064x' % point.x()

return key.decode('hex')

def get_point_pubkey_uncompressed(point):

key = '04' + \

'%064x' % point.x() + \

'%064x' % point.y()

return key.decode('hex')

# Generate a new private key.

secret = random_secret()

print "Secret: ", secret

# Get the public key point.

point = secret * generator

print "EC point:", point

print "BTC public key:", get_point_pubkey(point).encode("hex")

# Given the point (x, y) we can create the object using:

point1 = ecdsa.ellipticcurve.Point(curve, point.x(), point.y(), ec_order) assert point1 == point

Instalando la biblioteca Python ECDSA y ejecutando el script ec_math.py muestra la salida producida al ejecutar este script.

El ejemplo previo usa os.urandom, el cual refleja un generador de números aleatorios criptográficamente seguro (CSRNG) provisto por el sistema operativo. En el caso de un sistema tipo UNIX, como Linux, obtendrá sus números de /dev/urandom; y en el caso de Windows llamará a CryptGenRandom(). Si no se encuentra una fuente de azar confiable, se lanzará un error NotImplementedError. Mientras que el generador de números aleatorios usado aquí es para propósitos demostrativos, no es apropiado para generar claves bitcoin de calidad de producción ya que no fue implementado con seguridad suficiente.

Ejemplo 7. Instalando la biblioteca Python ECDSA y ejecutando el script ec_math.py $ # Instalar el administrador de paquetes Python PIP

$ sudo apt-get install python-pip

$ # Instalar la biblioteca Python ECDSA

$ sudo pip install ecdsa

$ # Ejecutar el script

$ python ec-math.py

Secret:

38090835015954358862481132628887443905906204995912378278060168703580660294000

EC point:

(70048853531867179489857750497606966272382583471322935454624595540007269312627, 105262206478686743191060800263479589329920209527285803935736021686045542353380) BTC public key: 029ade3effb0a67d5c8609850d797366af428f4a0d5194cb221d807770a1522873

Ir a la siguiente página

Report Page