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

Как генерировать свой собственный ключ Bitcoin

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

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

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

Мне нужно создать закрытый ключ?

Большую часть времени вы этого не делаете. Например, если вы используете веб-кошелек, такой как Coinbase или Blockchain.info, они создают и управляют закрытым ключом для вас. Это то же самое для обменов.

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

Так зачем все равно создавать это? Вот причины, которые у меня есть:

  • Вы хотите убедиться, что никто не знает ключ
  • Вы просто хотите узнать больше о криптографии и поколении случайных чисел (RNG)

Что именно является закрытым ключом?

Формально закрытый ключ для биткойна (и многие другие криптовалюты) представляет собой серию из 32 байтов. Теперь есть много способов записать эти байты. Это может быть строка 256 и нули (32 *) или 100 рулонов для костей. Это может быть двоичная строка, Base64, A Ключ WiF , Мноническая фраза или, наконец, шестигранная строка. Для наших целей мы будем использовать шестигранную строку длиной 64 символов.

Почему ровно 32 байта? Отличный вопрос! Видите ли, чтобы создать открытый ключ от частного, биткойна использует ECDSA или алгоритм цифровой подписи эллиптической кривой. Более конкретно, он использует одну конкретную кривую под названием secp256k1 Отказ

Теперь эта кривая имеет порядок 256 битов, принимает 256 битов в качестве ввода и выводит 256-битных целых чисел. И 256 бит ровно 32 байта. Итак, чтобы поставить его другим способом, нам нужны 32 байта данных для корма на эту кривую алгоритм.

Для закрытого ключа есть дополнительное требование. Поскольку мы используем ECDSA, ключ должен быть положительным и должен быть меньше порядка кривой. Орден ecp256k1 – FFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAEEDCE6AF48A03BBFD25E8CD0364141 , который довольно большой: почти любой 32-байтовый номер будет меньше, чем он.

Наивный метод

Итак, как мы создаем 32-байтовое целое число? Первое, что приходит к уму, это просто использовать библиотеку RNG на вашем языке выбора. Python даже обеспечивает милый способ генерации достаточно лишь битов:

import random
bits = random.getrandbits(256)
# 30848827712021293731208415302456569301499384654877289245795786476741155372082
bits_hex = hex(bits)
# 0x4433d156e8c53bf5b50af07aa95a29436f29a94e0ccc5d58df8e57bdc8583c32
private_key = bits_hex[2:]
# 4433d156e8c53bf5b50af07aa95a29436f29a94e0ccc5d58df8e57bdc8583c32

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

Когда вы генерируете закрытый ключ, вы хотите быть чрезвычайно безопасным. Помните, что если кто-то узнает закрытый ключ, они могут легко украсть все монеты из соответствующего кошелька, и у вас нет шансов, чтобы когда-либо их вернуть.

Так что давайте постараемся сделать это более безопасно.

Криптографически сильный RNG.

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

В Python, криптографически сильный RNG реализован в Секреты модуль. Давайте изменим код выше, чтобы заставить конфиденциальный ключ генерации в безопасности!

import secrets
bits = secrets.randbits(256)
# 46518555179467323509970270980993648640987722172281263586388328188640792550961
bits_hex = hex(bits)
# 0x66d891b5ed7f51e5044be6a7ebe4e2eae32b960f5aa0883f7cc0ce4fd6921e31
private_key = bits_hex[2:]
# 66d891b5ed7f51e5044be6a7ebe4e2eae32b960f5aa0883f7cc0ce4fd6921e31

Это удивительно. Могу поспорить, вы не сможете воспроизвести это даже с доступом к своему ПК. Но мы можем пойти глубже?

Специализированные сайты

Есть сайты, которые генерируют случайные номера для вас. Мы рассмотрим всего два здесь. Один из них Random.org , известный генератор случайного числа общего назначения. Еще один это Bitaddress.org , который разработан специально для генерации ключевого ключа биткойнов.

Может Random.org Помогите нам генерировать ключ? Определенно, как у них есть Сервис Для генерации случайных байтов. Но здесь возникают две проблемы. Random.org Претензии быть по-настоящему случайным генератором, но вы можете доверять этому? Можете ли вы быть уверены, что это действительно случайно? Можете ли вы быть уверены, что владелец не записывает все результаты поколений, особенно те, которые выглядят как частные ключи? Ответ зависит от вас. О, и вы не можете запустить его локально, что является дополнительной проблемой. Этот метод не закреплен на 100%.

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

Итак, как это работает? Он использует вас – да, вы – как источник энтропии. Он просит вас переместить мышь или нажать случайные клавиши. Вы делаете это достаточно долго, чтобы сделать его невозможным воспроизводить результаты.

Вы заинтересованы в том, чтобы увидеть, как Bitaddress.org работает? Для образовательных целей мы посмотрим на свой код и попытаемся воспроизвести его в Python.

Bitaddress: специфики

Bitaddress создает энтропию в двух формах: движение мыши и ключевым давлением. Мы поговорим о обоих, но мы сосредоточимся на ключевых прессах, так как трудно реализовать отслеживание мыши в Python Lib. Мы ожидаем, что конечный пользователь вводит кнопки, пока у нас будет достаточно энтропии, а затем мы создадим ключ.

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

Bitaddress использует 256-байтовый массив для хранения энтропии. Этот массив переписан в циклах, поэтому, когда массив заполнен впервые, указатель выходит на ноль, и процесс заполнения запускается снова.

Программа инициирует массив с 256 байтами из window.crypto Отказ Затем он пишет временной метку, чтобы получить дополнительные 4 байта энтропии. Наконец, он получает такие данные как размер экрана, ваш часовой пояс, информацию о плагинах браузера, вашего языка и многого другого. Это дает ему еще 6 байтов.

После инициализации программа постоянно ждет для пользовательского ввода, чтобы переписать исходные байты. Когда пользователь перемещает курсор, программа записывает положение курсора. Когда пользователь нажимает кнопки, программа записывает код CHAR нажатой кнопки.

Наконец, Bitaddress использует накопленную энтропию для генерации закрытого ключа. Это должно генерировать 32 байта. Для этой задачи Bitaddress использует алгоритм RNG, называемый ARC4. Программа инициализирует ARC4 с текущим временем и собранной энтропией, затем получает байты один на один 32 раза.

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

Делать это сам

Для наших целей мы построим более простую версию BitAddress. Во-первых, мы не будем собирать данные о машине и местоположении пользователя. Во-вторых, мы будем вводить энтропию только через текст, так как вполне сложно постоянно получать позицию мыши с помощью сценария Python (Check Pyautogui Если вы хотите это сделать).

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

Инициализация пула

Здесь мы поставили байты из криптографического RNG и временем времени. __seed_int и __seed_byte являются двумя помощниками, которые вставляют энтропию в наш массив бассейна. Обратите внимание, что мы используем Секреты Отказ

def __init_pool(self):
    for i in range(self.POOL_SIZE):
        random_byte = secrets.randbits(8)
        self.__seed_byte(random_byte)
    time_int = int(time.time())
    self.__seed_int(time_int)
def __seed_int(self, n):
    self.__seed_byte(n)
    self.__seed_byte(n >> 8)
    self.__seed_byte(n >> 16)
    self.__seed_byte(n >> 24)
def __seed_byte(self, n):
    self.pool[self.pool_pointer] ^= n & 255
    self.pool_pointer += 1
    if self.pool_pointer >= self.POOL_SIZE:
        self.pool_pointer = 0

Посев с входом

Здесь мы сначала поставьте временную метку, а затем входную строку, символ по символу.

def seed_input(self, str_input):
    time_int = int(time.time())
    self.__seed_int(time_int)
    for char in str_input:
        char_code = ord(char)
        self.__seed_byte(char_code)

Генерация закрытого ключа

Эта часть может выглядеть усердно, но это на самом деле очень просто.

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

Что это значит для нас? Это означает, что в каждый момент, в любом месте кода, один простой Random.seed (0) Может уничтожить всю нашу собранную энтропию. Мы не хотим этого. К счастью, Python предоставляет Гутрите и SetState методы. Итак, чтобы сохранить нашу энтропию каждый раз, когда мы создаем ключ, мы помним состояние, которое мы остановились и установили его в следующий раз, когда мы хотим сделать ключ.

Во-вторых, мы просто убедимся, что наш ключ находится в диапазоне (1, Curve_order ). Это требование для всех частных ключей ECDSA. Curve_Order это порядок кривой TECP256K1, который является FFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAEEDCE6AF48A03BBFD25E8CD0364141 Отказ

Наконец, для удобства мы преобразуем в Hex, и разделите часть «0x».

def generate_key(self):
    big_int = self.__generate_big_int()
    big_int = big_int % (self.CURVE_ORDER — 1) # key < curve order
    big_int = big_int + 1 # key > 0
    key = hex(big_int)[2:]
    return key
def __generate_big_int(self):
    if self.prng_state is None:
    seed = int.from_bytes(self.pool, byteorder='big', signed=False)
    random.seed(seed)
    self.prng_state = random.getstate()
    random.setstate(self.prng_state)
    big_int = random.getrandbits(self.KEY_BYTES * 8)
    self.prng_state = random.getstate()
    return big_int

в действии

Давайте попробуем использовать библиотеку. На самом деле, это действительно просто: вы можете генерировать закрытый ключ в трех строках кода!

kg = KeyGenerator()
kg.seed_input('Truly random string. I rolled a dice and got 4.')
kg.generate_key()
# 60cf347dbc59d31c1358c8e5cf5e45b822ab85b79cb32a9f3d98184779a9efc2

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

Заключение

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

Генерация закрытого ключа – это только первый шаг. Следующим шагом является извлечение открытого ключа и адреса кошелька, который вы можете использовать для получения платежей. Процесс генерации кошелька отличается для биткойна и Ethereum, и я планирую написать еще две статьи на эту тему.

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

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

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