Author

Topic: Python. Crear dirección Bitcoin con clave privada en formato HEX o INT (Read 1062 times)

hero member
Activity: 865
Merit: 1006
Por cierto...

Se me ocurrió hacer una prueba de aleatoriedad a los 2 algoritmos, y mi sorpresa fué que no es tan aleatorio como yo pensaba.

Hice un pequeño programa que generaba 100000 direcciones y miraba cuantas se repetían. Evidentemente, para ser seguro, el resultado tendría que ser 0... Pues no...

Hice 2 pruebas y me salía que había repetido, en una 364 direcciones y en la otra, 345...

Por si a alguien le interesa saberlo.

Saludos
hero member
Activity: 865
Merit: 1006
Para que te hagas una idea, con mi programa se calcula una dirección en 0.0138 seg.
Con este código se calcula una en 1.03 seg.

En el código que tú muestras al principio se llama a las librerías nativas de OpenSSL, código binario que se ejecuta directamente por el sistema operativo, muy rápido pero que requiere que OpenSSL esté instalado en la máquina para que funcione. El segundo código es todo puro python, no se llama a librerías nativas. Puede que esa sea la diferencia.

Seguro que si
legendary
Activity: 1623
Merit: 1608
Para que te hagas una idea, con mi programa se calcula una dirección en 0.0138 seg.
Con este código se calcula una en 1.03 seg.

En el código que tú muestras al principio se llama a las librerías nativas de OpenSSL, código binario que se ejecuta directamente por el sistema operativo, muy rápido pero que requiere que OpenSSL esté instalado en la máquina para que funcione. El segundo código es todo puro python, no se llama a librerías nativas. Puede que esa sea la diferencia.
hero member
Activity: 865
Merit: 1006
Muchas gracias por tu aportación.

Funciona correctamente, pero tiene un inconveniente muy grande... Es muy lenta!!!

Para que te hagas una idea, con mi programa se calcula una dirección en 0.0138 seg.
Con este código se calcula una en 1.03 seg.

No se a que se debe este tiempo desmesurado, pero es lo que me da.

Un saludo
legendary
Activity: 1623
Merit: 1608
Como has dicho que no quieres utilizar pycoin, simplemente he agrupado el código en un único fichero sin utilizar pycoin, solo las librerías de python. He comprobado que funciona, parece que bien, pero por si acaso, haz una segunda revisión.

Code:
import hashlib, ecdsa

b58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
 
def base58encode(n):
    result = ''
    while n > 0:
        result = b58[n%58] + result
        n /= 58
    return result

def base256decode(s):
    result = 0
    for c in s:
        result = result * 256 + ord(c)
    return result

def countLeadingChars(s, ch):
    count = 0
    for c in s:
        if c == ch:
            count += 1
        else:
            break
    return count

def base58CheckEncode(version, payload):
    s = chr(version) + payload
    checksum = hashlib.sha256(hashlib.sha256(s).digest()).digest()[0:4]
    result = s + checksum
    leadingZeros = countLeadingChars(result, '\0')
    return '1' * leadingZeros + base58encode(base256decode(result))

def privateKeyToWif(key_hex):    
    return base58CheckEncode(0x80, key_hex.decode('hex'))
    
def privateKeyToPublicKey(s):
    sk = ecdsa.SigningKey.from_string(s.decode('hex'), curve=ecdsa.SECP256k1)
    vk = sk.verifying_key
    return ('\04' + sk.verifying_key.to_string()).encode('hex')
    
def pubKeyToAddr(s):
    ripemd160 = hashlib.new('ripemd160')
    ripemd160.update(hashlib.sha256(s.decode('hex')).digest())
    return base58CheckEncode(0, ripemd160.digest())

def keyToAddr(s):
    return pubKeyToAddr(privateKeyToPublicKey(s))

# Warning: this random function is not cryptographically strong and is just for example
# private_key = ''.join(['%x' % random.randrange(16) for x in range(0, 64)])
private_key = 'a03465bcde123456a03465bcde123456a03465bcde123456a03465bcde123457'
print (privateKeyToWif(private_key))
print (keyToAddr(private_key))

Pycoin realmente merece la pena.  Smiley
https://github.com/richardkiss/pycoin
hero member
Activity: 865
Merit: 1006
Aunque no lo he probado personalmente, aquí tienes el código que necesitas utilizando la librería pycoin.

El valor hexadecimal que se pasa como parámetro a la función privateKeyToWif y también a la función keyToAddr, corresponde a la salida de tu función generar_HEX.

http://www.righto.com/2014/02/bitcoins-hard-way-using-raw-bitcoin.html

Code:
def privateKeyToWif(key_hex):   
    return utils.base58CheckEncode(0x80, key_hex.decode('hex'))
   
def privateKeyToPublicKey(s):
    sk = ecdsa.SigningKey.from_string(s.decode('hex'), curve=ecdsa.SECP256k1)
    vk = sk.verifying_key
    return ('\04' + sk.verifying_key.to_string()).encode('hex')
   
def pubKeyToAddr(s):
    ripemd160 = hashlib.new('ripemd160')
    ripemd160.update(hashlib.sha256(s.decode('hex')).digest())
    return utils.base58CheckEncode(0, ripemd160.digest())

def keyToAddr(s):
    return pubKeyToAddr(privateKeyToPublicKey(s))

# Warning: this random function is not cryptographically strong and is just for example
private_key = ''.join(['%x' % random.randrange(16) for x in range(0, 64)])
print keyUtils.privateKeyToWif(private_key)
print keyUtils.keyToAddr(private_key)
Aunque no lo he probado personalmente, aquí tienes el código que necesitas utilizando la librería pycoin.

El valor hexadecimal que se pasa como parámetro a la función privateKeyToWif y también a la función keyToAddr, corresponde a la salida de tu función generar_HEX.

http://www.righto.com/2014/02/bitcoins-hard-way-using-raw-bitcoin.html

Code:
def privateKeyToWif(key_hex):    
    return utils.base58CheckEncode(0x80, key_hex.decode('hex'))
    
def privateKeyToPublicKey(s):
    sk = ecdsa.SigningKey.from_string(s.decode('hex'), curve=ecdsa.SECP256k1)
    vk = sk.verifying_key
    return ('\04' + sk.verifying_key.to_string()).encode('hex')
    
def pubKeyToAddr(s):
    ripemd160 = hashlib.new('ripemd160')
    ripemd160.update(hashlib.sha256(s.decode('hex')).digest())
    return utils.base58CheckEncode(0, ripemd160.digest())

def keyToAddr(s):
    return pubKeyToAddr(privateKeyToPublicKey(s))

# Warning: this random function is not cryptographically strong and is just for example
private_key = ''.join(['%x' % random.randrange(16) for x in range(0, 64)])
print keyUtils.privateKeyToWif(private_key)
print keyUtils.keyToAddr(private_key)

Muchas gracias por tu respuesta.
De todas formas, lo que no quiero es usar una nueva librería, ya que eso, con otras ya lo tengo solucionado.
Lo que me gustaría sería de todas las instrucciones SSL que tiene esta que he puesto, que cosas hay que modificar para que en lugar de crear una key al azar, lo haga según un número en HEX o en INT que yo le ponga.
Seguro que se puede hacer

Un saludo
legendary
Activity: 1623
Merit: 1608
Aunque no lo he probado personalmente, aquí tienes el código que necesitas utilizando la librería pycoin.

El valor hexadecimal que se pasa como parámetro a la función privateKeyToWif y también a la función keyToAddr, corresponde a la salida de tu función generar_HEX.

http://www.righto.com/2014/02/bitcoins-hard-way-using-raw-bitcoin.html

Code:
def privateKeyToWif(key_hex):    
    return utils.base58CheckEncode(0x80, key_hex.decode('hex'))
    
def privateKeyToPublicKey(s):
    sk = ecdsa.SigningKey.from_string(s.decode('hex'), curve=ecdsa.SECP256k1)
    vk = sk.verifying_key
    return ('\04' + sk.verifying_key.to_string()).encode('hex')
    
def pubKeyToAddr(s):
    ripemd160 = hashlib.new('ripemd160')
    ripemd160.update(hashlib.sha256(s.decode('hex')).digest())
    return utils.base58CheckEncode(0, ripemd160.digest())

def keyToAddr(s):
    return pubKeyToAddr(privateKeyToPublicKey(s))

# Warning: this random function is not cryptographically strong and is just for example
private_key = ''.join(['%x' % random.randrange(16) for x in range(0, 64)])
print keyUtils.privateKeyToWif(private_key)
print keyUtils.keyToAddr(private_key)
hero member
Activity: 865
Merit: 1006
Buenas a todos.

Tengo un programa hecho en python, que funciona muy bien y muy rápido, para crear pares de direcciones bitcoin (wif/addr) de forma aleatoria.

Mi problema es que me gustaría crear una dirección bitcoin, pero con una clave privada que yo creo en HEX con este pequeño script:

Code:
def generar_HEX(nDecimal):
aHex = hex(nDecimal)
aHex = aHex[2:].upper()
aHex = ((64-len(aHex)) * '0') + aHex
return aHex

priv = generar_HEX(1400)  # Pongo 1400 por poner algo


Mi código que me genera los pares de direcciones de forma aleatoria es: (lo pongo por si a alguien le puede servir ya que funciona muy bien)

Code:
import ctypes
import hashlib

import time
import sys

ssl_library = ctypes.cdll.LoadLibrary('libssl.so')

def base58_encode(num):
alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
base_count = len(alphabet)
encode = ''
if (num < 0):
return ''
    
while (num >= base_count):    
mod = num % base_count
encode = alphabet[mod] + encode
num = num // base_count
 
if (num):
encode = alphabet[num] + encode
 
return encode
 
def gen_ecdsa_pair():
    NID_secp160k1 = 708
    NID_secp256k1 = 714
    k = ssl_library.EC_KEY_new_by_curve_name(NID_secp256k1)
 
    if ssl_library.EC_KEY_generate_key(k) != 1:
        raise Exception("internal error?")
 
    bignum_private_key = ssl_library.EC_KEY_get0_private_key(k)
    size = (ssl_library.BN_num_bits(bignum_private_key)+7)//8
    storage = ctypes.create_string_buffer(size)
    ssl_library.BN_bn2bin(bignum_private_key, storage)
    private_key = storage.raw
 
    size = ssl_library.i2o_ECPublicKey(k, 0)
    storage = ctypes.create_string_buffer(size)
    ssl_library.i2o_ECPublicKey(k, ctypes.byref(ctypes.pointer(storage)))
    public_key = storage.raw
 
    ssl_library.EC_KEY_free(k)
    return public_key, private_key
 
def ecdsa_get_coordinates(public_key):
    x = bytes(public_key[1:33])
    y = bytes(public_key[33:65])
    return x, y
 
def generate_address(public_key):
    assert isinstance(public_key, bytes)
 
    x, y = ecdsa_get_coordinates(public_key)
  
    s = b'\x04' + x + y
 
    hasher = hashlib.sha256()
    hasher.update(s)
    r = hasher.digest()
 
    hasher = hashlib.new('ripemd160')
    hasher.update(r)
    r = hasher.digest()

    return '1' + base58_check(r, version=0)
 
def base58_check(src, version=0):
    src = bytes([version]) + src
    hasher = hashlib.sha256()
    hasher.update(src)
    r = hasher.digest()
 
    hasher = hashlib.sha256()
    hasher.update(r)
    r = hasher.digest()
 
    checksum = r[:4]
    s = src + checksum
 
    return base58_encode(int.from_bytes(s, 'big'))
 
def crear_addr_fast():
public_key, private_key = gen_ecdsa_pair()
hex_private_key = ''.join(["{:02x}".format(i) for i in private_key])

if len(hex_private_key) == 64:
wif = base58_check(private_key, version=128)
addr = generate_address(public_key)
return addr, wif
else:
return '', ''

addr, wif = crear_addr_fast()
print ('ADDR: ' + addr)
print ('WIF: ' + wif)

¿alguien sabe que tengo que modificar para que la clave privada no me la genere aleatóriamente?

He probado muchas cosas ... y no hay manera

Un saludo
Jump to: