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

1656579373 kak sozdat adres bitkojn koshelka iz chastnogo klyucha

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

60cf347dbc59d31c1358c8e5cf5e45b822ab85b79cb32a9f3d98184779a9efc2

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

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

Криптография с эллиптической кривой

Первое, что нам нужно сделать, это применить алгоритм цифровой подписи ECDSA или эллиптической кривой к нашему частному ключу. Эллиптическая кривая — это кривая, определяемая уравнением y² = x³ + ax + b с избранным a и b. Существует целое семейство таких кривых, широко известных и используемых. Биткойн использует secp256k1 кривая. Если вы хотите узнать больше о криптографии с эллиптической кривой, я направлю вас в эту статью.

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

Для нашего примера мы получили: 1e7bcc70c72770dbb72fea022e8a6d07f814d2ebe4de9ae3f7af75bf706902a7b73ff919898c836396a6b0c96812c3213b99372050853bd1678da0ead14487d7.

У 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 модуля, я расшифровал закрытый ключ с помощью codecs. Это больше относится к Python и меньше к самому алгоритму, но я объясню, что мы здесь делаем, чтобы устранить возможную неразбериху.

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

Теперь есть небольшая загвоздка: шнурок, скажем, 4f3c не равна массиву байтов 4f3cон равен массиву байтов с двумя элементами, O<. И вот чтоat codecs.decМетод ode делает: он превращает строчку в массив байтов. Это будет все равно для всех криптографических манипуляций, которые мы будем делать в этой статье.

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

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

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

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

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

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

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

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

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

Здесь нам нужно применить SHA-256 к открытому ключу, а затем применить RIPEMD-160 к результату. Важен порядок.

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

9Fj7FyUVc7zLwLodE7JvoHXfY81g6DndArUd

Вот как мы шифруем открытый ключ в 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’)

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

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

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

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

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

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

rcb40Z2plVojizglRqDG3Y4fIxy1m77Gsnnu

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

# 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]

Получение адреса

Наконец, чтобы создать адрес, мы просто соединим ключ основной сети и контрольную сумму. Это делает это 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

То, что мы получаем 17JsmEygbbEUEpvt4PFtYaTeSqfb9ki1F1сжатый адрес кошелька биткойн.

saUvqNSzw5b7ATtpSh3RUMS3WwEeBFVNU9m8

Вывод

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

  • создание открытого ключа с помощью ECDSA
  • шифрование ключа с помощью SHA-256 и RIPEMD-160
  • вычисление контрольной суммы с помощью двойного SHA-256
  • кодировку ключа с помощью Base58.

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

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

r1G799LERTJzPvyfibbkVdRpJDzMbgPRbmmu

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

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

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *