Хотите всегда оставаться в курсе событий? Подписывайтесь на @cryptochan и получайте новости в нашем Telegram канале.
×
Как создать адрес биткоин-кошелька с помощью закрытого ключа
В предыдущей статье мы рассматривали различные методы генерации закрытого ключа. Какой бы метод вы ни выбрали, в конце вы получите 32 байта данных. Вот ключ, который мы получили в конце той статьи:60cf347dbc59d31c1358c8e5cf5e45b822ab85b79cb32a9f3d98184779a9efc2В этой статье мы будем использовать этот закрытый ключ для получения как открытого ключа, так и адреса для биткоин-кошелька.Наша задача – применить серию преобразований к закрытому ключу, чтобы получить открытый ключ, а затем и адрес кошелька. Большинство этих преобразований называются хэш-функциями. Эти хэш-функции являются односторонними преобразованиями, которые нельзя отменить. Мы не будем вдаваться в механизм самих функций — по этому вопросу есть много замечательных статей. Вместо этого мы рассмотрим, как использование этих функций в правильном порядке может помочь вам сгенерировать адрес биткоин-кошелька, который вы впоследствии сможете использовать.Криптография с использованием эллиптической кривойПервое, что нам нужно сделать, это применить алгоритм цифровой подписи ECDSA или Elliptic Curve к нашему закрытому ключу. Эллиптической кривой является кривая, определенная уравнением y² = x³ + ax + b с выбранной a и b. Существует целое семейство таких кривых, которые широко известны и широко используются. Для биткоина используется кривая secp256k1/. Если вы хотите узнать больше о криптографии на основе эллиптических кривых, почитайте эту статью.Применяя ECDSA к закрытому ключу, мы получаем 64-байтовое целое число. Оно состоит из двух 32-байтовых целых чисел, которые представляют соединенные вместе точки X и Y эллиптической кривой.Для нашего примера мы получили:1e7bcc70c72770dbb72fea022e8a6d07f814d2ebe4de9ae3f7af75bf706902a7b73ff919898c836396a6b0c96812c3213b99372050853bd1678da0ead14487d7 На языке Python это будет выглядеть так:private_key_bytes = codecs.decode(private_key, ‘hex’)# Get ECDSA public keykey = ecdsa.SigningKey.from_string(private_key_bytes, curve=ecdsa.SECP256k1).verifying_keykey_bytes = key.to_string()key_hex = codecs.encode(key_bytes, ‘hex’)Примечание: как видно из кода, прежде чем я использовал метод на базе модуля ECDSA, я расшифровал закрытый ключ, используя кодеки. Это больше относится к Python и меньше к самому алгоритму, но я объясню, что мы здесь делаем во избежание возможной путаницы.В Python есть как минимум два класса, которые могут хранить закрытый и открытый ключи: “str” и “bytes”. Первый – это строка, а второй – массив байтов. Криптографические методы в Python работают с классом “bytes”, принимая его в качестве входных данных и возвращая как результат.Теперь, есть маленькая загвоздка: строка, скажем, 4f3c не равна массиву байтов 4f3c, она равна массиву байтов с двумя элементами, O<. И вот тут как раз в дело вступает codecs.decode: этот метод преобразует строку в массив байтов. Все то же самое будет и для всех криптографических манипуляций, которые мы будем приводить в этой статье.Открытый ключКак только мы закончили с ECDSA, все, что нам нужно сделать, это добавить байт 0x04 в начале нашего открытого ключа. В результате мы получаем полный открытый ключ биткоина, который выглядит следующим образом: 041e7bcc70c72770dbb72fea022e8a6d07f814d2ebe4de9ae3f7af75bf706902a7b73ff919898c836396a6b0c96812c3213b99372050853bd1678da0ead14487d7 Сжатый открытый ключНо мы можем сделать лучше. Как вы помните, открытый ключ является некоторой точкой (X, Y) на кривой. Мы знаем кривую, и для каждого X есть только два Ys, которые определяют точку, которая лежит на этой кривой. Так зачем хранить Y? Вместо этого, давайте сохраним X и знак Y. Позже мы можем вернуть Y, если в этом будет необходимость.Особенности заключаются в следующем: мы берем X из открытого ключа ECDSA. Теперь, мы добавим 0x02, если последний байт Y четный, и байт 0x03, если последний байт нечетный.В нашем случае последний байт нечетный, поэтому мы добавляем 0x03, чтобы получить сжатый открытый ключ:031e7bcc70c72770dbb72fea022e8a6d07f814d2ebe4de9ae3f7af75bf706902a7Этот ключ содержит ту же информацию, но он почти в два раза короче, чем несжатый ключ. Клево!Раньше программное обеспечение кошельков использовало длинные, полные версии открытых ключей, но теперь большинство из них перешло на сжатые ключи.Шифрование открытого ключаТеперь нам нужно сгенерировать адрес кошелька. Какой бы метод генерирования открытого ключа вы ни выбрали, он проходит ту же процедуру. Очевидно, что адреса будут отличаться. В этой статье мы рассмотрим сжатую версию.Здесь нам нужно применить SHA-256 к открытому ключу, а затем применить RIPEMD-160 к результату. Порядок очень важен.SHA-256 и RIPEMD-160 являются двумя хэш-функциями, и опять же, мы не будем вдаваться в детали того, как они работают.Важно то, что теперь у нас есть 160-битное целое число, которое будет использоваться для дальнейших модификаций. Назовем это зашифрованным открытым ключом. Для нашего примера, зашифрованный открытый ключ – это 453233600a96384bb8d73d400984117ac84d7e8bЗашифрованный открытый ключ = RIPEMD-160 (SHA-256 (Открытый ключ))Вот как мы шифруем открытый ключ в 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 шестнадцатеричных цифр).С = SHA-256 (SHA-256 (зашифрованный открытый ключ основной сети))Контрольная сумма = первые 4 байта СДля расчета контрольной суммы адреса используется следующий код:# Double SHA256 to get checksumsha256_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 (вариант кодирования цифрового кода в виде буквенно-цифрового текста на основе латинского алфавита. Алфавит кодирования содержит 58 символов). Это немного странно.Вот алгоритм для преобразования шестнадцатеричного адреса в адрес 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, сжатый адрес биткоин-кошелька.Шестнадцатеричный адрес = зашифрованный открытый ключ основной сети + адрес контрольной суммы = Base58 (Шестнадцатеричный адрес)ВыводПроцесс генерации ключей кошелька можно разделить на четыре этапа:создание открытого ключа с помощью ECDSAшифрование ключа с помощью SHA-256 и RIPEMD-160расчет контрольной суммы с помощью двойной SHA-256кодирование ключа с помощью Base58.В зависимости от формы открытого ключа (полный или сжатый), мы получаем разные адреса, но оба совершенно допустимы.Вот полный алгоритм для несжатого открытого ключа:Эллиптический открытый ключ = ECDSA (закрытый ключ)Открытый ключ = 0х04 + эллиптический открытый ключЗашифрованный открытый ключ = RIPEMD-160 (SHA-256 (открытый ключ))Зашифрованный открытый ключ основной сети = 0х00 + Зашифрованный открытый ключС = SHA-256 (SHA-256 (Зашифрованный открытый ключ основной сети))Контрольная сумма = первые 4 байта СШестнадцатеричный адрес = Зашифрованный открытый ключ основной сети + Контрольная суммаАдрес = Base58 (Шестнадцатеричный адрес)Если вы хотите «поиграть» с кодом, я опубликовал его на GitHub.Я делаю обзор о криптовалютах на Medium. Первая часть – подробное описание блокчейна.
Похожие новости
- 6 Мар, 09:14
Япония хочет сделать Америку великой вновь – с помощью криптовалюты
Как писал ранее coinspot.io, депутаты Государственной думы планировали в ходе второго чтения 5 марта принять пакет законопроектов о цифровизации экономики, включая документы о регулировании отношений в криптовалютной отрасли.Сегодня законопроект, кот...