xcbtrader (OP)
|
|
December 14, 2016, 11:39:56 PM Last edit: December 15, 2016, 05:20:31 AM by xcbtrader |
|
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: 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) 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.
|
|
|
Shawshank
Legendary
Offline
Activity: 1623
Merit: 1608
|
|
December 15, 2016, 06:20:28 AM |
|
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.htmldef 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)
|
|
|
|
xcbtrader (OP)
|
|
December 15, 2016, 07:16:18 AM |
|
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.htmldef 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.htmldef 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
Activity: 1623
Merit: 1608
|
|
December 15, 2016, 10:24:09 AM |
|
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. 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. https://github.com/richardkiss/pycoin
|
|
|
|
xcbtrader (OP)
|
|
December 15, 2016, 01:49:32 PM |
|
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
Activity: 1623
Merit: 1608
|
|
December 15, 2016, 04:10:33 PM |
|
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.
|
|
|
|
xcbtrader (OP)
|
|
December 15, 2016, 06:16:14 PM |
|
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)
|
|
December 18, 2016, 10:38:57 AM |
|
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
|
|
|
|
|