Bitcoin Forum
April 27, 2024, 10:55:46 PM *
News: Latest Bitcoin Core release: 27.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: Python. Crear dirección Bitcoin con clave privada en formato HEX o INT  (Read 1052 times)
xcbtrader (OP)
Hero Member
*****
Offline Offline

Activity: 865
Merit: 1006


View Profile
December 14, 2016, 11:39:56 PM
Last edit: December 15, 2016, 05:20:31 AM by xcbtrader
 #1

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

You get merit points when someone likes your post enough to give you some. And for every 2 merit points you receive, you can send 1 merit point to someone else!
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction.
1714258546
Hero Member
*
Offline Offline

Posts: 1714258546

View Profile Personal Message (Offline)

Ignore
1714258546
Reply with quote  #2

1714258546
Report to moderator
1714258546
Hero Member
*
Offline Offline

Posts: 1714258546

View Profile Personal Message (Offline)

Ignore
1714258546
Reply with quote  #2

1714258546
Report to moderator
Shawshank
Legendary
*
Offline Offline

Activity: 1623
Merit: 1608



View Profile
December 15, 2016, 06:20:28 AM
 #2

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)

Lightning Address: shawshank@getalby.com
xcbtrader (OP)
Hero Member
*****
Offline Offline

Activity: 865
Merit: 1006


View Profile
December 15, 2016, 07:16:18 AM
 #3

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

Shawshank
Legendary
*
Offline Offline

Activity: 1623
Merit: 1608



View Profile
December 15, 2016, 10:24:09 AM
 #4

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

Lightning Address: shawshank@getalby.com
xcbtrader (OP)
Hero Member
*****
Offline Offline

Activity: 865
Merit: 1006


View Profile
December 15, 2016, 01:49:32 PM
 #5

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

Shawshank
Legendary
*
Offline Offline

Activity: 1623
Merit: 1608



View Profile
December 15, 2016, 04:10:33 PM
 #6

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.

Lightning Address: shawshank@getalby.com
xcbtrader (OP)
Hero Member
*****
Offline Offline

Activity: 865
Merit: 1006


View Profile
December 15, 2016, 06:16:14 PM
 #7

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

xcbtrader (OP)
Hero Member
*****
Offline Offline

Activity: 865
Merit: 1006


View Profile
December 18, 2016, 10:38:57 AM
 #8

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

Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!