¿Cómo se crean las claves públicas y privadas en una dirección?

Entiendo el concepto de alto nivel. Estoy más interesado en detalles específicos. Cómo se genera una clave privada. Cómo se genera exactamente la clave pública, cómo se genera la dirección a partir de la clave pública.

Respuestas (5)

Las claves públicas y privadas en una dirección de Bitcoin son un par de claves ECDSA normales. No he hurgado en esta parte particular del propio código de Bitcoin, pero los productos derivados con los que he tenido la oportunidad de trabajar normalmente usan la biblioteca criptográfica Bouncy Castle . Bouncy Castle también tiene una excelente introducción/tutorial sobre cómo usar su biblioteca. Sus ejemplos están en Java, pero es bastante simple y debería trasladarse fácilmente a otros idiomas.

También hay una excelente biblioteca escrita previamente para la generación de claves de JavaScript disponible de Tom Wu bajo la licencia BSD.

Como es normal cuando se realiza el cifrado de curva elíptica, una clave privada es simplemente un número aleatorio. En el caso de secp256k1, la curva elíptica que usa Bitcoin, tiene que ser un número entre 1 y 115792089237316195423570985008687907852837564279074904382605163141518161494336 (o en hexadecimal, entre 0x1y 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364140).

Esta clave privada se convierte en una clave pública realizando una multiplicación de puntos EC con el punto base de la curva. El resultado es un (x,y)par de coordenadas, que constituye la clave pública.

Finalmente, RIPEMD160(SHA256(pubkey))donde pubkey es una serialización de esas coordenadas, se calcula y codifica en base58, junto con una suma de verificación. Esto se convierte en la dirección.

¿Cómo determinaste que este era el valor máximo? Me gustaría aprender tanto de la manera correcta como de la incorrecta para poder aprender de sus [ediciones];)
Lo copié de en.bitcoin.it/wiki/Secp256k1 , que a su vez lo copió del documento de especificación SEC2: secg.org/collateral/sec2_final.pdf
Enlace actualizado al documento SEC2 secg.org/SEC2-Ver-1.0.pdf
¿Alguno de esos dos pasos es reversible?
No, no lo son (siempre que ECDLP sea difícil).

Las claves privadas de Bitcoin se muestran más comúnmente en formato de importación de billetera (WIF), también conocido como base58check (un número expresado en base 58 con una suma de verificación al final y un byte de versión al principio).

Para crear una clave privada WIF, debe:

  1. Genere un exponente secreto ECDSA (la clave privada) utilizando la curva SECP256k1.
  2. Convierta el exponente secreto/clave privada en formato base58check.

Aquí hay dos formas simples de generar un exponente secreto:

  1. Seleccione un número aleatorio en el rango [1, curve_order).
  2. Genere una cadena hexadecimal aleatoria de 64 caracteres (la representación de cadena hexadecimal de un número de 256 bits) y verifique que el número esté en el rango [1, curve_order]. Repita si es necesario.

Para SECP256k1, el orden de la curva es 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140 (o 1157920892373161954235709850086879078528375642790749043826051631414).

Este número está muy cerca del número más grande de 256 bits (0xFFF...FFF en hexadecimal), por lo que puede esperar que nunca exceda el orden de la curva si genera un número aleatorio de 256 bits.

Como mencionó Pieter Wuille, las claves públicas se derivan realizando la multiplicación de puntos con el punto base de la curva y el exponente secreto/clave privada. La coordenada resultante (x,y) es la clave pública.

La dirección de Bitcoin, al igual que la clave privada, también se muestra en formato base58check. Para obtener la dirección, hacemos lo siguiente:

  1. Calcula el hash160: ripemd160(sha256(public_key)).
  2. Convierta el formato hash160 a base58check.

Para convertir un número al formato base58check, simplemente realice los siguientes pasos:

  1. convierta el valor en una matriz de bytes y agregue el byte de versión al principio
  2. calcule los primeros 4 bytes de SHA256 (SHA256 (resultado del paso 1)) y llámelo checksum
  3. agregue la suma de verificación al final del resultado del paso 1
  4. mueva el resultado del paso 3 al espacio de teclas "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
  5. verifique cuántos ceros iniciales tenía el valor binario original y agréguelos al comienzo del resultado del paso 4

Aquí están las instrucciones más detalladas .

Ahora, si no quiere preocuparse por nada de esto, consultaría la biblioteca Coinkit de Python ( https://github.com/halfmoonlabs/coinkit o "pip install coinkit").

Puede realizar operaciones simples como estas:

>>> from coinkit.keypair import BitcoinKeypair
>>> hex_private_key = '91149ee24f1ee9a6f42c3dd64c2287781c8c57a6e8e929c80976e586d5322a3d'
>>> k = BitcoinKeypair(hex_private_key)
>>> k.private_key()
'91149ee24f1ee9a6f42c3dd64c2287781c8c57a6e8e929c80976e586d5322a3d'
>>> k.public_key()
'042c6b7e6da7633c8f226891cc7fa8e5ec84f8eacc792a46786efc869a408d29539a5e6f8de3f71c0014e8ea71691c7b41f45c083a074fef7ab5c321753ba2b3fe'
>>> k.wif_pk()
'5JvBUBPzU42Y7BHD7thTnySXQXMk8XEJGGQGcyBw7CCkw8RAH7m'
>>> k.address()
'13mtgVARiB1HiRyCHnKTi6rEwyje5TYKBW'

También puede crear pares de llaves aleatorios:

>>> k = BitcoinKeypair()

Y pares de llaves de billetera cerebral:

>>> passphrase = 'shepherd mais pack rate enamel horace diva filesize maximum really roar mall'
>>> k = BitcoinKeypair().from_passphrase(passphrase)
>>> k.passphrase()
'shepherd mais pack rate enamel horace diva filesize maximum really roar mall'

Divulgación: soy uno de los creadores de Coinkit.

El código Javascript de: http://www.bitaddress.org también podría brindarle un buen ejemplo de esto.

Cómo se crean está completamente documentado en wiki : https://en.bitcoin.it/wiki/Technical_background_of_Bitcoin_addresses

en Java

  1. Incluya el jar de la biblioteca Java bitcoinj en su classpath
  2. El código:

    import com.google.bitcoin.core.*;
    
    NetworkParameters params = new MainNetParams();
    
    String publicAddress = new DumpedPrivateKey(params,
            "KzzuoFPzrPhD55icpAi7idW7z7tH8xSYo3xqTcZm3fHk3AzVxpoP").getKey()
            .toAddress(params).toString();
    
  3. El resultado 17vFi4XjRibQPCktoMcGhZ3DmnG85r1VHEes

En JavaScript

Usando la biblioteca javascript de bitaddress.org :

var key = new Bitcoin.ECKey('KzzuoFPzrPhD55icpAi7idW7z7tH8xSYo3xqTcZm3fHk3AzVxpoP');
console.log(key.getBitcoinAddress());

El resultado 17vFi4XjRibQPCktoMcGhZ3DmnG85r1VHEes


Nota 1: Antes, hice bitcoin-cli getnewaddressy bitcoin-cli dumpprivkey <pubkey>para obtener el par de claves.

Nota 2: para facilitar aún más las cosas, en su directorio https://github.com/pointbiz/bitaddress.org/tree/master/src simplemente ejecute:

cat array.map.js cryptojs.js cryptojs.sha256.js cryptojs.pbkdf2.js cryptojs.hmac.js cryptojs.aes.js cryptojs.blockmodes.js cryptojs.ripemd160.js securerandom.js ellipticcurve.js secrets.js biginteger.js qrcode.js bitcoinjs-lib.js bitcoinjs-lib.base58.js bitcoinjs-lib.address.js bitcoinjs-lib.ecdsa.js bitcoinjs-lib.eckey.js bitcoinjs-lib.util.js crypto-scrypt.js > all.js

y obtienes un archivo de 174kb que es todo lo que necesitas para ejecutar.

Nota 3: si desea obtener este archivo (del compromiso f6c6bbe53df28c1bf51a6216f02ad1467b36c9f7), busque aquí: http://pastebin.com/raw.php?i=rH8V2j9H


El ejemplo funcional completo

<!DOCTYPE HTML>
<html>

<head>
    <meta charset="UTF-8">
    <script type="text/javascript" src="http://pastebin.com/raw.php?i=rH8V2j9H"></script>
</head>

<body>
    <form onsubmit="alert(new Bitcoin.ECKey(document.getElementById('pkey').value).getBitcoinAddress());">
        <label>
            Private key:
            <input id="pkey" type="text">
        </label>
    </form>
</body>
</html>