Рубрики
Без рубрики

Как создать адрес биткойна кошелька из закрытого ключа

Автор оригинала: Timur Badretdinov.

В предыдущей статье мы смотрели на разные методы для создания закрытого ключа. Какой бы этот метод вы выберете, вы получите 32 байта данных. Вот тот, который мы получили в конце этой статьи:

60CF347DBC59D31C1358C8E5CF5E45B822AB85B79CB32A9F3D98184779A9EFC2.

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

То, что мы хотим сделать, это применить ряд преобразований в закрытый ключ, чтобы получить открытый ключ, а затем адрес кошелька. Большинство этих преобразований называются хеш-функциями. Эти хеш-функции – односторонние преобразования, которые не могут быть изменены. Мы не пойдем к механике самих функций – есть много замечательных статей, которые охватывают это. Вместо этого мы посмотрим, как использовать эти функции в правильном порядке, могут привести вас к адресу биткойнов кошелька, который вы можете использовать.

Эллиптическая кривая криптография

Первое, что нам нужно сделать, это применить алгоритм цифровой подписи ECDSA или Elliptic Curve Curve в нашем закрытом ключ. Эллиптическая кривая – кривая, определенная уравнением Y² + AX + B с выбранным А и B Отказ Существует целая семья таких кривых, которые широко известны и используются. Биткойн использует secp256k1 изгиб. Если вы хотите узнать больше о криптографии эллиптической кривой, я направлю вам на Эта статья Отказ

Применяя ECDSA в закрытый ключ, мы получаем 64-байтовое целое число. Это состоит из двух 32-байтовых целых чисел, которые представляют X и Y точки на эллиптической кривой, объединенной вместе.

Для нашего примера мы получили: 1E7BCC70C72770DBB72FEA022E8A6D07F814D2EBE4DE9AE3F7AF75BF706902AAF7B73FF919898C8363919898C836396A6B0C96812C3213B99372050853BD1678DA0EAD14487D7 Отказ

В Python это будет выглядеть так:

public_key_bytes = codecs.decode(public_key, 'hex')
# Run SHA-256 for the public key
sha256_bpk = hashlib.sha256(public_key_bytes)
sha256_bpk_digest = sha256_bpk.digest()
# Run RIPEMD-160 for the SHA-256
ripemd160_bpk = hashlib.new('ripemd160')
ripemd160_bpk.update(sha256_bpk_digest)
ripemd160_bpk_digest = ripemd160_bpk.digest()
ripemd160_bpk_hex = codecs.encode(ripemd160_bpk_digest, 'hex')

Примечание. Как вы можете видеть из кода, прежде чем я использовал метод из ECDSA Модуль, я декодировал закрытый ключ, используя кодеки Отказ Это имеет отношение к Python и меньше к самому алгоритму, но я объясню, что мы здесь делаем, чтобы удалить возможную путаницу.

В Python есть как минимум два класса, которые могут держать частные и открытые ключи: «стр» и «байты». Первая – это строка, а вторая – это байтовый массив. Криптографические методы в Python работают с классом «байт», принимая его в качестве ввода и возврата его в качестве результата.

Теперь немного поймать: нить, скажем, 4f3c не равна массива байта 4f3c , это равняется байтовому массиву двумя элементами, O & LT ;. И это wh в Codecs.dec Способ ODE: это преобразует строку в байтовый массив. Это будет то же самое для всех криптографических манипуляций, которые мы сделаем в этой статье.

Открытый ключ

Как только мы закончим с ECDSA, все, что нам нужно сделать, это добавить байты 0x04 В начале нашего открытого ключа. Результатом является полный открытый ключ Bitcoin, который равен: 041E7BCC70C72770DBB72FEA022E8A6D07F814D2EBE4DE9AE3F7AF75BF706902AF75B73FF919898C836396A6B0C96812C3213B996812C3213B99372050853BD1678DA0EAD14487D7 для нас.

Сжатый открытый ключ

Но мы можем сделать лучше. Как вы можете вспомнить, открытый ключ является какой-то точкой (X, Y) на кривой. Мы знаем кривую, и для каждого X есть только два Ys, которые определяют точку, которая лежит на этой кривой. Так зачем держать Y? Вместо этого давайте сохраним X и знак Y. Позже мы можем вывести от этого, если это необходимо.

Особенности следующие: мы берем X из открытого ключа ECDSA. Теперь мы добавляем 0x02 Если последний байт Y даже, и байт 0x03 Если последний байт нечетным.

В нашем случае последний байт нечетным, поэтому мы добавляем 0x03 Чтобы получить сжатый открытый ключ: 031E7BCC70C72770DBB72FEA022E8A6D07F814D2EBE4DE9AE3F7AF75BF706902A7 Отказ Этот ключ содержит ту же информацию, но почти вдвое больше, чем несжатый ключ. Прохладный!

Ранее программное обеспечение для кошелька использовали длинные полные версии открытых ключей, но теперь большинство из них переключилась на сжатые клавиши.

Шифрование открытого ключа

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

Что нам нужно сделать здесь, – применить SHA-256 к открытому ключу, а затем применить Ripemd-160 к результату. Заказ важен.

SHA-256 и RIPEMD-160 – два хэш-функция, и опять же, мы не будем уходить в детали того, как они работают. Вас, что теперь у нас есть 160-битное целое число, которое будет использоваться для дальнейших модификаций. Давайте назовем это зашифрованный открытый ключ. Для нашего примера зашифрованный открытый ключ – 453233600A96384BB8D73D400984117AC84D7E8B Отказ

Вот как мы шифруйте открытый ключ в Python:

public_key_bytes = codecs.decode(public_key, 'hex')# Run SHA-256 for the public keysha256_bpk = hashlib.sha256(public_key_bytes)sha256_bpk_digest = sha256_bpk.digest()# Run RIPEMD-160 for the SHA-256ripemd160_bpk = hashlib.new('ripemd160')ripemd160_bpk.update(sha256_bpk_digest)ripemd160_bpk_digest = ripemd160_bpk.digest()ripemd160_bpk_hex = codecs.encode(ripemd160_bpk_digest, 'hex')

Добавление сети байта

У биткойна есть две сети, основные и тесты. Главная сеть – это сеть, которую все люди используют для передачи монет. Тестовая сеть была создана – вы уже догадались – проверить новые функции и программное обеспечение.

Мы хотим создать адрес, чтобы использовать его в Mainnet, поэтому нам нужно добавить 0x00 Байты в зашифрованный открытый ключ. Результатом является 00453233600A96384BB8D73D400984117AC84D7E8B Отказ Для Testnet, это было бы 0x6f байты.

Контрольная сумма

Теперь нам нужно рассчитать контрольную сумму нашего ключа Mainnet. Идея контрольной суммы состоит в том, чтобы убедиться, что данные (в нашем случае ключа) не были повреждены во время передачи. Программное обеспечение для кошелька должно посмотреть на контрольную сумму и отметить адрес как недействительный, если ошибки контрольной суммы.

Чтобы рассчитать контрольную сумму ключа, нам нужно применить SHA-256 дважды, а затем сделать первые 4 байта результата. Для нашего примера двойной SHA-256 – 512F43C48517A75E58A7EC4C554ECD1A8F9603C891B46325006ABF39C5C6B995 И поэтому контрольная сумма 512F43C4 (Обратите внимание, что 4 байта – 8 шестнадцатеричных цифр).

Код для расчета адресной контрольной суммы является следующим:

# Double SHA256 to get checksum
sha256_nbpk = hashlib.sha256(network_bitcoin_public_key_bytes)
sha256_nbpk_digest = sha256_nbpk.digest()
sha256_2_nbpk = hashlib.sha256(sha256_nbpk_digest)
sha256_2_nbpk_digest = sha256_2_nbpk.digest()
sha256_2_hex = codecs.encode(sha256_2_nbpk_digest, 'hex')
checksum = sha256_2_hex[:8]

Получить адрес

Наконец, чтобы сделать адрес, мы просто объединяем ключ Mainnet и контрольную сумму. Это делает это 00453233600A96384BB8D73D400984117AC84D7E8B512F43C4 Для нашего примера.

Это оно! Это адрес кошелька для закрытого ключа в начале статьи.

Но вы можете заметить, что что-то выключено. Вы, вероятно, видели горстку биткойновских адресов, и они не выглядели так. Ну, причина в том, что они кодируются с Base58 Отказ Это немного странно.

Вот алгоритм для преобразования шестигранного адреса на адрес Base58:

def base58(address_hex):
    alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
    b58_string = ''
    # Get the number of leading zeros
    leading_zeros = len(address_hex) — len(address_hex.lstrip('0'))
    # Convert hex to decimal
    address_int = int(address_hex, 16)
    # Append digits to the start of string
    while address_int > 0:
        digit = address_int % 58
        digit_char = alphabet[digit]
        b58_string = digit_char + b58_string
        address_int //= 58
    # Add '1' for each 2 leading zeros
    ones = leading_zeros // 2
    for one in range(ones):
        b58_string = '1' + b58_string
    return b58_string

Что мы получаем 17JSMEYGBBEUEEPVT4PFTYATESQFB9KI1F1 сжатый биткойн кошелек адреса.

Заключение

Процесс генерации ключей кошелька может быть разделен на четыре шага:

  • Создание открытого ключа с ECDSA
  • Шифрование ключа с SHA-256 и Ripemd-160
  • Расчет контрольной суммы с двойной SHA-256
  • Кодирование ключа с base58.

В зависимости от формы открытого ключа (полный или сжатый) мы получаем разные адреса, но оба совершенно действительны.

Вот полный алгоритм для несжатого открытого ключа:

Если вы хотите играть с кодом, я опубликовал его на Github Repository Отказ

Я делаю курс по криптовалютам здесь на новостях FreeCodeCamp. первая часть это подробное описание блокчана.

Я также публикую случайные мысли о Crypto на Twitter Так что вы можете проверить это.