Как создаются открытые и закрытые ключи в адресе?

Я понимаю концепцию высокого уровня, меня больше интересуют конкретные детали. Как генерируется закрытый ключ. Как именно генерируется открытый ключ, как генерируется адрес из открытого ключа.

Ответы (5)

Открытый и закрытый ключи в биткойн-адресе представляют собой обычную пару ключей ECDSA . Я не копался в этом конкретном фрагменте собственного кода Биткойн, но ответвления продуктов, с которыми мне довелось работать, обычно используют криптобиблиотеку Bouncy Castle . У Bouncy Castle также есть отличное введение/руководство по использованию их библиотеки. Их примеры на Java, но они довольно просты и должны быть легко перенесены на другие языки.

Существует также отличная предварительно написанная библиотека для генерации ключей JavaScript, доступная от Tom Wu по лицензии BSD.

Как обычно при шифровании по эллиптической кривой, закрытый ключ представляет собой просто случайное число. В случае secp256k1, эллиптической кривой, используемой Биткойном, это должно быть число от 1 до 115792089237316195423570985008687907852837564279074904382605163141518161494336 (или в шестнадцатеричном формате, между 0x1и 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364140).

Этот закрытый ключ преобразуется в открытый ключ путем умножения точек EC на базовую точку кривой. Результатом является (x,y)пара координат, которая составляет открытый ключ.

Наконец, RIPEMD160(SHA256(pubkey)), где pubkey — это сериализация этих координат, вычисляется и кодируется в base58 вместе с контрольной суммой. Это становится адресом.

Как вы определили, что это максимальное значение? Я хотел бы узнать как правильно, так и неправильно, чтобы я мог учиться на ваших [правках];)
Я скопировал его с en.bitcoin.it/wiki/Secp256k1 , который сам скопировал его из документа спецификации SEC2: secg.org/collateral/sec2_final.pdf
Обновлена ​​ссылка на документ SEC2 secg.org/SEC2-Ver-1.0.pdf.
Является ли любой из этих двух шагов обратимым?
Нет, это не так (пока ECDLP труден).

Закрытые ключи Биткойн чаще всего отображаются в формате импорта кошелька (WIF), также известном как base58check (число, выраженное в базе 58 с контрольной суммой в конце и байтом версии в начале).

Чтобы создать закрытый ключ WIF, вам необходимо:

  1. Сгенерируйте секретный показатель ECDSA (закрытый ключ), используя кривую SECP256k1.
  2. Преобразуйте секретную экспоненту/закрытый ключ в формат base58check.

Вот два простых способа создания секретного показателя:

  1. Выберите случайное число в диапазоне [1, curve_order).
  2. Создайте случайную 64-символьную шестнадцатеричную строку (шестнадцатеричное строковое представление 256-битного числа) и убедитесь, что число находится в диапазоне [1, curve_order). При необходимости повторите.

Для SECP256k1 порядок кривой следующий: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140 (или 115792089237316195423570985008687907852837564279074904316L44490516314).

Это число очень близко к наибольшему 256-битному числу (0xFFF...FFF в шестнадцатеричном формате), поэтому можно ожидать, что вы никогда не превысите порядок кривой, если сгенерируете случайное 256-битное число.

Как упоминал Питер Вуилле, открытые ключи получаются путем умножения точек на базовую точку кривой и секретный показатель степени/закрытый ключ. Полученная координата (x,y) является открытым ключом.

Биткойн-адрес, как и закрытый ключ, также отображается в формате base58check. Чтобы получить адрес, делаем следующее:

  1. Вычислить hash160: ripemd160(sha256(public_key)).
  2. Преобразуйте hash160 в формат base58check.

Чтобы преобразовать число в формат base58check, просто выполните следующие шаги:

  1. преобразовать значение в массив байтов и добавить байт версии в начало
  2. вычислить первые 4 байта SHA256 (SHA256 (результат шага 1)) и назвать его контрольной суммой
  3. добавить контрольную сумму в конец результата шага 1
  4. переместите результат шага 3 в пространство ключей "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
  5. проверьте, сколько начальных нулей было в исходном двоичном значении, и добавьте их в начало результата шага 4

Вот более подробная инструкция .

Теперь, если вы не хотите беспокоиться ни о чем из этого, я бы проверил библиотеку Python Coinkit ( https://github.com/halfmoonlabs/coinkit или «pip install coinkit»).

Вы можете выполнять такие простые операции, как эти:

>>> 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'

Вы также можете создавать случайные пары ключей:

>>> k = BitcoinKeypair()

И пары ключей мозгового кошелька:

>>> 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'

Раскрытие информации: я один из создателей Coinkit.

Код Javascript с http://www.bitaddress.org также может дать вам хороший пример этого.

Как они создаются, полностью задокументировано на вики : https://en.bitcoin.it/wiki/Technical_background_of_Bitcoin_addresses .

В Яве

  1. Включите jar Java-библиотеки bitcoinj в свой путь к классам .
  2. Код:

    import com.google.bitcoin.core.*;
    
    NetworkParameters params = new MainNetParams();
    
    String publicAddress = new DumpedPrivateKey(params,
            "KzzuoFPzrPhD55icpAi7idW7z7tH8xSYo3xqTcZm3fHk3AzVxpoP").getKey()
            .toAddress(params).toString();
    
  3. Результат есть 17vFi4XjRibQPCktoMcGhZ3DmnG85r1VHE.

В JavaScript

Используя javascript-библиотеку bitaddress.org :

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

Результат есть 17vFi4XjRibQPCktoMcGhZ3DmnG85r1VHE.


Примечание 1: Раньше я делал bitcoin-cli getnewaddressи bitcoin-cli dumpprivkey <pubkey>для получения пары ключей.

Примечание 2. Чтобы упростить задачу, в своем каталоге https://github.com/pointbiz/bitaddress.org/tree/master/src просто запустите:

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

и вы получите файл размером 174 КБ, и это все, что вам нужно для запуска.

Примечание 3. Если вы хотите получить этот файл (из фиксации f6c6bbe53df28c1bf51a6216f02ad1467b36c9f7), посмотрите здесь: http://pastebin.com/raw.php?i=rH8V2j9H


Полный функциональный пример

<!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>